Merge branch 'ds/trace2-tolerate-failed-timestamp' into seen

Functions like `xstrfmt()` and `xcalloc()` have been banned from use
in the trace2 API codebase to prevent calls to `die()` which lead to
unwanted process exits and recursion when memory allocation fails.

* ds/trace2-tolerate-failed-timestamp:
  trace2: remove use of xcalloc()
  trace2: remove use of ALLOC_GROW()
  trace2: remove use of xstrfmt()
  trace2: remove use of ALLOC_ARRAY()
  trace2: remove use of xstrdup()
  trace2: tolerate failed timestamp formatting
  banned-die: create header for banning of functions
seen
Junio C Hamano 2026-08-31 13:53:25 -07:00
commit 075cd7bce4
16 changed files with 250 additions and 31 deletions

32
banned-die.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef BANNED_DIE_H
#define BANNED_DIE_H

#include "banned.h"

/*
* This header lists functions that must not be used by low-level APIs
* because they can cause Git to terminate.
*/

#undef die
#define die BANNED(die)

#undef xsnprintf
#define xsnprintf(...) BANNED(xsnprintf)

#undef xstrdup
#define xstrdup(str) BANNED(xstrdup)

#undef xcalloc
#define xcalloc(nmemb, size) BANNED(xcalloc)

#undef xstrfmt
#define xstrfmt(...) BANNED(xstrfmt)

#undef ALLOC_ARRAY
#define ALLOC_ARRAY(x, alloc) BANNED(ALLOC_ARRAY)

#undef ALLOC_GROW
#define ALLOC_GROW(x, nr, alloc) BANNED(ALLOC_GROW)

#endif /* BANNED_DIE_H */

View File

@ -332,7 +332,8 @@ test_expect_success 'unsafe URLs are redacted by default in cmd_start events' '


GIT_TRACE2_EVENT="$(pwd)/trace.event" \ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
test-tool trace2 300redact_start git clone https://user:pwd@example.com/ clone2 && test-tool trace2 300redact_start git clone https://user:pwd@example.com/ clone2 &&
test_grep ! user:pwd trace.event test_grep ! user:pwd trace.event &&
test_grep "user:<REDACTED>@example.com/" trace.event
' '


test_expect_success 'unsafe URLs are redacted by default in child_start events' ' test_expect_success 'unsafe URLs are redacted by default in child_start events' '
@ -341,7 +342,8 @@ test_expect_success 'unsafe URLs are redacted by default in child_start events'


GIT_TRACE2_EVENT="$(pwd)/trace.event" \ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
test-tool trace2 301redact_child_start git clone https://user:pwd@example.com/ clone2 && test-tool trace2 301redact_child_start git clone https://user:pwd@example.com/ clone2 &&
test_grep ! user:pwd trace.event test_grep ! user:pwd trace.event &&
test_grep "user:<REDACTED>@example.com/" trace.event
' '


test_expect_success 'unsafe URLs are redacted by default in exec events' ' test_expect_success 'unsafe URLs are redacted by default in exec events' '
@ -350,7 +352,8 @@ test_expect_success 'unsafe URLs are redacted by default in exec events' '


GIT_TRACE2_EVENT="$(pwd)/trace.event" \ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
test-tool trace2 302redact_exec git clone https://user:pwd@example.com/ clone2 && test-tool trace2 302redact_exec git clone https://user:pwd@example.com/ clone2 &&
test_grep ! user:pwd trace.event test_grep ! user:pwd trace.event &&
test_grep "user:<REDACTED>@example.com/" trace.event
' '


test_expect_success 'unsafe URLs are redacted by default in def_param events' ' test_expect_success 'unsafe URLs are redacted by default in def_param events' '
@ -359,7 +362,8 @@ test_expect_success 'unsafe URLs are redacted by default in def_param events' '


GIT_TRACE2_EVENT="$(pwd)/trace.event" \ GIT_TRACE2_EVENT="$(pwd)/trace.event" \
test-tool trace2 303redact_def_param url https://user:pwd@example.com/ && test-tool trace2 303redact_def_param url https://user:pwd@example.com/ &&
test_grep ! user:pwd trace.event test_grep ! user:pwd trace.event &&
test_grep "user:<REDACTED>@example.com/" trace.event
' '


test_done test_done

View File

@ -17,6 +17,8 @@
#include "trace2/tr2_tgt.h" #include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h" #include "trace2/tr2_tls.h"
#include "trace2/tr2_tmr.h" #include "trace2/tr2_tmr.h"
/* banned-die must be last. */
#include "banned-die.h"


static int trace2_enabled; static int trace2_enabled;
static int trace2_redact = 1; static int trace2_redact = 1;
@ -259,7 +261,10 @@ int trace2_is_enabled(void)
static const char *redact_arg(const char *arg) static const char *redact_arg(const char *arg)
{ {
const char *p, *colon; const char *p, *colon;
const char *redact = ":<REDACTED>";
char *redacted;
size_t at; size_t at;
size_t prefix_len, suffix_len, redacted_len, redact_len;


if (!trace2_redact || if (!trace2_redact ||
(!skip_prefix(arg, "https://", &p) && (!skip_prefix(arg, "https://", &p) &&
@ -274,7 +279,25 @@ static const char *redact_arg(const char *arg)
if (!colon) if (!colon)
return arg; return arg;


return xstrfmt("%.*s:<REDACTED>%s", (int)(colon - arg), arg, p + at); redact_len = strlen(redact);
prefix_len = colon - arg;
suffix_len = strlen(p + at);

if (unsigned_add_overflows(prefix_len, suffix_len) ||
unsigned_add_overflows(prefix_len + suffix_len, redact_len) ||
unsigned_add_overflows(prefix_len + suffix_len + redact_len, 1))
return NULL;

redacted_len = prefix_len + suffix_len + redact_len + 1;

redacted = malloc(redacted_len);
if (!redacted)
return NULL;

memcpy(redacted, arg, prefix_len);
memcpy(redacted + prefix_len, redact, redact_len);
memcpy(redacted + prefix_len + redact_len, p + at, suffix_len + 1);
return redacted;
} }


/* /*
@ -299,11 +322,17 @@ static const char **redact_argv(const char **argv)


if (!argv[i]) if (!argv[i])
return argv; return argv;
if (!redacted)
return NULL;


for (j = 0; argv[j]; j++) for (j = 0; argv[j]; j++)
; /* keep counting */ ; /* keep counting */


ALLOC_ARRAY(ret, j + 1); ret = calloc(j + 1, sizeof(*ret));
if (!ret) {
free((char *)redacted);
return NULL;
}
ret[j] = NULL; ret[j] = NULL;


for (j = 0; j < i; j++) for (j = 0; j < i; j++)
@ -311,7 +340,14 @@ static const char **redact_argv(const char **argv)
ret[i] = redacted; ret[i] = redacted;
for (++i; argv[i]; i++) { for (++i; argv[i]; i++) {
redacted = redact_arg(argv[i]); redacted = redact_arg(argv[i]);
ret[i] = redacted ? redacted : argv[i]; if (!redacted) {
for (j = 0; j < i; j++)
if (ret[j] != argv[j])
free((void *)ret[j]);
free(ret);
return NULL;
}
ret[i] = redacted;
} }


return ret; return ret;
@ -344,6 +380,8 @@ void trace2_cmd_start_fl(const char *file, int line, const char **argv)
us_elapsed_absolute = tr2tls_absolute_elapsed(us_now); us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);


redacted = redact_argv(argv); redacted = redact_argv(argv);
if (!redacted)
return;


for_each_wanted_builtin (j, tgt_j) for_each_wanted_builtin (j, tgt_j)
if (tgt_j->pfn_start_fl) if (tgt_j->pfn_start_fl)
@ -512,6 +550,7 @@ void trace2_child_start_fl(const char *file, int line,
uint64_t us_now; uint64_t us_now;
uint64_t us_elapsed_absolute; uint64_t us_elapsed_absolute;
const char **orig_argv = cmd->args.v; const char **orig_argv = cmd->args.v;
const char **redacted;


if (!trace2_enabled) if (!trace2_enabled)
return; return;
@ -529,7 +568,10 @@ void trace2_child_start_fl(const char *file, int line,
* temporarily replace the original argv (inside the `strvec`) * temporarily replace the original argv (inside the `strvec`)
* with a possibly redacted version. * with a possibly redacted version.
*/ */
cmd->args.v = redact_argv(orig_argv); redacted = redact_argv(orig_argv);
if (!redacted)
return;
cmd->args.v = redacted;


for_each_wanted_builtin (j, tgt_j) for_each_wanted_builtin (j, tgt_j)
if (tgt_j->pfn_child_start_fl) if (tgt_j->pfn_child_start_fl)
@ -621,6 +663,8 @@ int trace2_exec_fl(const char *file, int line, const char *exe,
exec_id = tr2tls_locked_increment(&tr2_next_exec_id); exec_id = tr2tls_locked_increment(&tr2_next_exec_id);


redacted = redact_argv(argv); redacted = redact_argv(argv);
if (!redacted)
return exec_id;


for_each_wanted_builtin (j, tgt_j) for_each_wanted_builtin (j, tgt_j)
if (tgt_j->pfn_exec_fl) if (tgt_j->pfn_exec_fl)

View File

@ -7,6 +7,8 @@
#include "trace2/tr2_cfg.h" #include "trace2/tr2_cfg.h"
#include "trace2/tr2_sysenv.h" #include "trace2/tr2_sysenv.h"
#include "wildmatch.h" #include "wildmatch.h"
/* banned-die must be last. */
#include "banned-die.h"


static struct string_list tr2_cfg_patterns = STRING_LIST_INIT_DUP; static struct string_list tr2_cfg_patterns = STRING_LIST_INIT_DUP;
static int tr2_cfg_loaded; static int tr2_cfg_loaded;

View File

@ -1,6 +1,8 @@
#include "git-compat-util.h" #include "git-compat-util.h"
#include "strbuf.h" #include "strbuf.h"
#include "trace2/tr2_cmd_name.h" #include "trace2/tr2_cmd_name.h"
/* banned-die must be last. */
#include "banned-die.h"


#define TR2_ENVVAR_PARENT_NAME "GIT_TRACE2_PARENT_NAME" #define TR2_ENVVAR_PARENT_NAME "GIT_TRACE2_PARENT_NAME"



View File

@ -2,6 +2,8 @@
#include "trace2/tr2_tgt.h" #include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h" #include "trace2/tr2_tls.h"
#include "trace2/tr2_ctr.h" #include "trace2/tr2_ctr.h"
/* banned-die must be last. */
#include "banned-die.h"


/* /*
* A global counter block to aggregate values from the partial sums * A global counter block to aggregate values from the partial sums
@ -53,7 +55,11 @@ static struct tr2_counter_metadata tr2_counter_metadata[TRACE2_NUMBER_OF_COUNTER
void tr2_counter_increment(enum trace2_counter_id cid, uint64_t value) void tr2_counter_increment(enum trace2_counter_id cid, uint64_t value)
{ {
struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
struct tr2_counter *c = &ctx->counter_block.counter[cid]; struct tr2_counter *c;

if (tr2tls_is_fallback(ctx))
return;
c = &ctx->counter_block.counter[cid];


c->value += value; c->value += value;


@ -67,6 +73,8 @@ void tr2_update_final_counters(void)
struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
enum trace2_counter_id cid; enum trace2_counter_id cid;


if (tr2tls_is_fallback(ctx))
return;
if (!ctx->used_any_counter) if (!ctx->used_any_counter)
return; return;


@ -88,6 +96,8 @@ void tr2_emit_per_thread_counters(tr2_tgt_evt_counter_t *fn_apply)
struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
enum trace2_counter_id cid; enum trace2_counter_id cid;


if (tr2tls_is_fallback(ctx))
return;
if (!ctx->used_any_per_thread_counter) if (!ctx->used_any_per_thread_counter)
return; return;



View File

@ -5,6 +5,8 @@
#include "trace2/tr2_dst.h" #include "trace2/tr2_dst.h"
#include "trace2/tr2_sid.h" #include "trace2/tr2_sid.h"
#include "trace2/tr2_sysenv.h" #include "trace2/tr2_sysenv.h"
/* banned-die must be last. */
#include "banned-die.h"


/* /*
* How many attempts we will make at creating an automatically-named trace file. * How many attempts we will make at creating an automatically-named trace file.

View File

@ -3,6 +3,8 @@
#include "strbuf.h" #include "strbuf.h"
#include "trace2/tr2_tbuf.h" #include "trace2/tr2_tbuf.h"
#include "trace2/tr2_sid.h" #include "trace2/tr2_sid.h"
/* banned-die must be last. */
#include "banned-die.h"


#define TR2_ENVVAR_PARENT_SID "GIT_TRACE2_PARENT_SID" #define TR2_ENVVAR_PARENT_SID "GIT_TRACE2_PARENT_SID"



View File

@ -4,6 +4,8 @@
#include "config.h" #include "config.h"
#include "dir.h" #include "dir.h"
#include "tr2_sysenv.h" #include "tr2_sysenv.h"
/* banned-die must be last. */
#include "banned-die.h"


/* /*
* Each entry represents a trace2 setting. * Each entry represents a trace2 setting.
@ -73,7 +75,9 @@ static int tr2_sysenv_cb(const char *key, const char *value,
if (!value) if (!value)
return config_error_nonbool(key); return config_error_nonbool(key);
free(tr2_sysenv_settings[k].value); free(tr2_sysenv_settings[k].value);
tr2_sysenv_settings[k].value = xstrdup(value); tr2_sysenv_settings[k].value = strdup(value);
if (!tr2_sysenv_settings[k].value)
return 0;
return 0; return 0;
} }
} }
@ -109,7 +113,7 @@ const char *tr2_sysenv_get(enum tr2_sysenv_variable var)
const char *v = getenv(tr2_sysenv_settings[var].env_var_name); const char *v = getenv(tr2_sysenv_settings[var].env_var_name);
if (v && *v) { if (v && *v) {
free(tr2_sysenv_settings[var].value); free(tr2_sysenv_settings[var].value);
tr2_sysenv_settings[var].value = xstrdup(v); tr2_sysenv_settings[var].value = strdup(v);
} }
tr2_sysenv_settings[var].getenv_called = 1; tr2_sysenv_settings[var].getenv_called = 1;
} }

View File

@ -1,47 +1,68 @@
#include "git-compat-util.h" #include "git-compat-util.h"
#include "tr2_tbuf.h" #include "tr2_tbuf.h"
/* banned-die must be last. */
#include "banned-die.h"


void tr2_tbuf_local_time(struct tr2_tbuf *tb) void tr2_tbuf_local_time(struct tr2_tbuf *tb)
{ {
struct timeval tv; struct timeval tv = { 0 };
struct tm tm; struct tm tm = { 0 };
time_t secs; time_t secs;
int len;


gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
secs = tv.tv_sec; secs = tv.tv_sec;
localtime_r(&secs, &tm); localtime_r(&secs, &tm);


xsnprintf(tb->buf, sizeof(tb->buf), "%02d:%02d:%02d.%06ld", tm.tm_hour, len = snprintf(tb->buf, sizeof(tb->buf), "%02d:%02d:%02d.%06ld",
tm.tm_min, tm.tm_sec, (long)tv.tv_usec); tm.tm_hour, tm.tm_min, tm.tm_sec, (long)tv.tv_usec);

if (len < 0 || (size_t)len >= sizeof(tb->buf)) {
const char *blank = "00:00:00.000000";
strlcpy(tb->buf, blank, sizeof(tb->buf));
}
} }


void tr2_tbuf_utc_datetime_extended(struct tr2_tbuf *tb) void tr2_tbuf_utc_datetime_extended(struct tr2_tbuf *tb)
{ {
struct timeval tv; struct timeval tv = { 0 };
struct tm tm; struct tm tm = { 0 };
time_t secs; time_t secs;
int len;


gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
secs = tv.tv_sec; secs = tv.tv_sec;
gmtime_r(&secs, &tm); gmtime_r(&secs, &tm);


xsnprintf(tb->buf, sizeof(tb->buf), len = snprintf(tb->buf, sizeof(tb->buf),
"%4d-%02d-%02dT%02d:%02d:%02d.%06ldZ", tm.tm_year + 1900, "%4d-%02d-%02dT%02d:%02d:%02d.%06ldZ",
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
(long)tv.tv_usec); tm.tm_hour, tm.tm_min, tm.tm_sec, (long)tv.tv_usec);

if (len < 0 || (size_t)len >= sizeof(tb->buf)) {
const char *blank = "1900-00-00T00:00:00.000000Z";
strlcpy(tb->buf, blank, sizeof(tb->buf));
}
} }


void tr2_tbuf_utc_datetime(struct tr2_tbuf *tb) void tr2_tbuf_utc_datetime(struct tr2_tbuf *tb)
{ {
struct timeval tv; struct timeval tv = { 0 };
struct tm tm; struct tm tm = { 0 };
time_t secs; time_t secs;
int len;


gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
secs = tv.tv_sec; secs = tv.tv_sec;
gmtime_r(&secs, &tm); gmtime_r(&secs, &tm);


xsnprintf(tb->buf, sizeof(tb->buf), "%4d%02d%02dT%02d%02d%02d.%06ldZ", len = snprintf(tb->buf, sizeof(tb->buf),
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, "%4d%02d%02dT%02d%02d%02d.%06ldZ",
tm.tm_min, tm.tm_sec, (long)tv.tv_usec); tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, (long)tv.tv_usec);

if (len < 0 || (size_t)len >= sizeof(tb->buf)) {
const char *blank = "19000000T000000.000000Z";
strlcpy(tb->buf, blank, sizeof(tb->buf));
}
} }

View File

@ -13,6 +13,8 @@
#include "trace2/tr2_tgt.h" #include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h" #include "trace2/tr2_tls.h"
#include "trace2/tr2_tmr.h" #include "trace2/tr2_tmr.h"
/* banned-die must be last. */
#include "banned-die.h"


static struct tr2_dst tr2dst_event = { static struct tr2_dst tr2dst_event = {
.sysenv_var = TR2_SYSENV_EVENT, .sysenv_var = TR2_SYSENV_EVENT,

View File

@ -11,6 +11,8 @@
#include "trace2/tr2_tgt.h" #include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h" #include "trace2/tr2_tls.h"
#include "trace2/tr2_tmr.h" #include "trace2/tr2_tmr.h"
/* banned-die must be last. */
#include "banned-die.h"


static struct tr2_dst tr2dst_normal = { static struct tr2_dst tr2dst_normal = {
.sysenv_var = TR2_SYSENV_NORMAL, .sysenv_var = TR2_SYSENV_NORMAL,

View File

@ -14,6 +14,8 @@
#include "trace2/tr2_tgt.h" #include "trace2/tr2_tgt.h"
#include "trace2/tr2_tls.h" #include "trace2/tr2_tls.h"
#include "trace2/tr2_tmr.h" #include "trace2/tr2_tmr.h"
/* banned-die must be last. */
#include "banned-die.h"


static struct tr2_dst tr2dst_perf = { static struct tr2_dst tr2dst_perf = {
.sysenv_var = TR2_SYSENV_PERF, .sysenv_var = TR2_SYSENV_PERF,

View File

@ -3,6 +3,8 @@
#include "thread-utils.h" #include "thread-utils.h"
#include "trace.h" #include "trace.h"
#include "trace2/tr2_tls.h" #include "trace2/tr2_tls.h"
/* banned-die must be last. */
#include "banned-die.h"


/* /*
* Initialize size of the thread stack for nested regions. * Initialize size of the thread stack for nested regions.
@ -12,6 +14,9 @@
#define TR2_REGION_NESTING_INITIAL_SIZE (100) #define TR2_REGION_NESTING_INITIAL_SIZE (100)


static struct tr2tls_thread_ctx *tr2tls_thread_main; static struct tr2tls_thread_ctx *tr2tls_thread_main;
static struct tr2tls_thread_ctx tr2tls_thread_fallback = {
.thread_name = "unknown",
};
static uint64_t tr2tls_us_start_process; static uint64_t tr2tls_us_start_process;


static pthread_mutex_t tr2tls_mutex; static pthread_mutex_t tr2tls_mutex;
@ -36,16 +41,23 @@ void tr2tls_start_process_clock(void)
struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_base_name, struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_base_name,
uint64_t us_thread_start) uint64_t us_thread_start)
{ {
struct tr2tls_thread_ctx *ctx = xcalloc(1, sizeof(*ctx)); struct tr2tls_thread_ctx *ctx = calloc(1, sizeof(*ctx));
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;


if (!ctx)
goto fallback;

/* /*
* Implicitly "tr2tls_push_self()" to capture the thread's start * Implicitly "tr2tls_push_self()" to capture the thread's start
* time in array_us_start[0]. For the main thread this gives us the * time in array_us_start[0]. For the main thread this gives us the
* application run time. * application run time.
*/ */
ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE; ctx->alloc = TR2_REGION_NESTING_INITIAL_SIZE;
ctx->array_us_start = (uint64_t *)xcalloc(ctx->alloc, sizeof(uint64_t)); ctx->array_us_start = calloc(ctx->alloc, sizeof(uint64_t));
if (!ctx->array_us_start) {
free(ctx);
goto fallback;
}
ctx->array_us_start[ctx->nr_open_regions++] = us_thread_start; ctx->array_us_start[ctx->nr_open_regions++] = us_thread_start;


ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id); ctx->thread_id = tr2tls_locked_increment(&tr2_next_thread_id);
@ -61,6 +73,10 @@ struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_base_name,
pthread_setspecific(tr2tls_key, ctx); pthread_setspecific(tr2tls_key, ctx);


return ctx; return ctx;

fallback:
pthread_setspecific(tr2tls_key, &tr2tls_thread_fallback);
return &tr2tls_thread_fallback;
} }


struct tr2tls_thread_ctx *tr2tls_get_self(void) struct tr2tls_thread_ctx *tr2tls_get_self(void)
@ -83,6 +99,11 @@ struct tr2tls_thread_ctx *tr2tls_get_self(void)
return ctx; return ctx;
} }


int tr2tls_is_fallback(const struct tr2tls_thread_ctx *ctx)
{
return ctx == &tr2tls_thread_fallback;
}

int tr2tls_is_main_thread(void) int tr2tls_is_main_thread(void)
{ {
if (!HAVE_THREADS) if (!HAVE_THREADS)
@ -99,6 +120,9 @@ void tr2tls_unset_self(void)


pthread_setspecific(tr2tls_key, NULL); pthread_setspecific(tr2tls_key, NULL);


if (tr2tls_is_fallback(ctx))
return;

free((char *)ctx->thread_name); free((char *)ctx->thread_name);
free(ctx->array_us_start); free(ctx->array_us_start);
free(ctx); free(ctx);
@ -107,8 +131,36 @@ void tr2tls_unset_self(void)
void tr2tls_push_self(uint64_t us_now) void tr2tls_push_self(uint64_t us_now)
{ {
struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
uint64_t *new_array;
size_t new_alloc;

if (tr2tls_is_fallback(ctx))
return;

if (ctx->nr_skipped_regions) {
ctx->nr_skipped_regions++;
return;
}

if (ctx->nr_open_regions >= ctx->alloc) {
if (ctx->alloc >
SIZE_MAX / (2 * sizeof(*ctx->array_us_start))) {
ctx->nr_skipped_regions++;
return;
}
new_alloc = ctx->alloc * 2;

new_array = realloc(ctx->array_us_start,
new_alloc * sizeof(*ctx->array_us_start));
if (!new_array) {
ctx->nr_skipped_regions++;
return;
}

ctx->array_us_start = new_array;
ctx->alloc = new_alloc;
}


ALLOC_GROW(ctx->array_us_start, ctx->nr_open_regions + 1, ctx->alloc);
ctx->array_us_start[ctx->nr_open_regions++] = us_now; ctx->array_us_start[ctx->nr_open_regions++] = us_now;
} }


@ -116,6 +168,14 @@ void tr2tls_pop_self(void)
{ {
struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); struct tr2tls_thread_ctx *ctx = tr2tls_get_self();


if (tr2tls_is_fallback(ctx))
return;

if (ctx->nr_skipped_regions) {
ctx->nr_skipped_regions--;
return;
}

if (!ctx->nr_open_regions) if (!ctx->nr_open_regions)
BUG("no open regions in thread '%s'", ctx->thread_name); BUG("no open regions in thread '%s'", ctx->thread_name);


@ -126,6 +186,9 @@ void tr2tls_pop_unwind_self(void)
{ {
struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); struct tr2tls_thread_ctx *ctx = tr2tls_get_self();


if (tr2tls_is_fallback(ctx))
return;

while (ctx->nr_open_regions > 1) while (ctx->nr_open_regions > 1)
tr2tls_pop_self(); tr2tls_pop_self();
} }
@ -136,6 +199,10 @@ uint64_t tr2tls_region_elasped_self(uint64_t us)
uint64_t us_start; uint64_t us_start;


ctx = tr2tls_get_self(); ctx = tr2tls_get_self();
if (tr2tls_is_fallback(ctx))
return 0;
if (ctx->nr_skipped_regions)
return 0;
if (!ctx->nr_open_regions) if (!ctx->nr_open_regions)
return 0; return 0;


@ -155,6 +222,10 @@ uint64_t tr2tls_absolute_elapsed(uint64_t us)
static void tr2tls_key_destructor(void *payload) static void tr2tls_key_destructor(void *payload)
{ {
struct tr2tls_thread_ctx *ctx = payload; struct tr2tls_thread_ctx *ctx = payload;

if (tr2tls_is_fallback(ctx))
return;

free((char *)ctx->thread_name); free((char *)ctx->thread_name);
free(ctx->array_us_start); free(ctx->array_us_start);
free(ctx); free(ctx);

View File

@ -20,6 +20,7 @@ struct tr2tls_thread_ctx {
uint64_t *array_us_start; uint64_t *array_us_start;
size_t alloc; size_t alloc;
size_t nr_open_regions; /* plays role of "nr" in ALLOC_GROW */ size_t nr_open_regions; /* plays role of "nr" in ALLOC_GROW */
size_t nr_skipped_regions;
int thread_id; int thread_id;
struct tr2_timer_block timer_block; struct tr2_timer_block timer_block;
struct tr2_counter_block counter_block; struct tr2_counter_block counter_block;
@ -53,6 +54,12 @@ struct tr2tls_thread_ctx *tr2tls_create_self(const char *thread_base_name,
*/ */
struct tr2tls_thread_ctx *tr2tls_get_self(void); struct tr2tls_thread_ctx *tr2tls_get_self(void);


/*
* Return true if the context is the non-allocating fallback used after an
* allocation failure. Callers must not modify a fallback context.
*/
int tr2tls_is_fallback(const struct tr2tls_thread_ctx *ctx);

/* /*
* return true if the current thread is the main thread. * return true if the current thread is the main thread.
*/ */

View File

@ -3,6 +3,8 @@
#include "trace2/tr2_tls.h" #include "trace2/tr2_tls.h"
#include "trace2/tr2_tmr.h" #include "trace2/tr2_tmr.h"
#include "trace.h" #include "trace.h"
/* banned-die must be last. */
#include "banned-die.h"


#define MY_MAX(a, b) ((a) > (b) ? (a) : (b)) #define MY_MAX(a, b) ((a) > (b) ? (a) : (b))
#define MY_MIN(a, b) ((a) < (b) ? (a) : (b)) #define MY_MIN(a, b) ((a) < (b) ? (a) : (b))
@ -37,8 +39,11 @@ static struct tr2_timer_metadata tr2_timer_metadata[TRACE2_NUMBER_OF_TIMERS] = {
void tr2_start_timer(enum trace2_timer_id tid) void tr2_start_timer(enum trace2_timer_id tid)
{ {
struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
struct tr2_timer *t = &ctx->timer_block.timer[tid]; struct tr2_timer *t;


if (tr2tls_is_fallback(ctx))
return;
t = &ctx->timer_block.timer[tid];
t->recursion_count++; t->recursion_count++;
if (t->recursion_count > 1) if (t->recursion_count > 1)
return; /* ignore recursive starts */ return; /* ignore recursive starts */
@ -49,10 +54,13 @@ void tr2_start_timer(enum trace2_timer_id tid)
void tr2_stop_timer(enum trace2_timer_id tid) void tr2_stop_timer(enum trace2_timer_id tid)
{ {
struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
struct tr2_timer *t = &ctx->timer_block.timer[tid]; struct tr2_timer *t;
uint64_t ns_now; uint64_t ns_now;
uint64_t ns_interval; uint64_t ns_interval;


if (tr2tls_is_fallback(ctx))
return;
t = &ctx->timer_block.timer[tid];
assert(t->recursion_count > 0); assert(t->recursion_count > 0);


t->recursion_count--; t->recursion_count--;
@ -90,6 +98,8 @@ void tr2_update_final_timers(void)
struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
enum trace2_timer_id tid; enum trace2_timer_id tid;


if (tr2tls_is_fallback(ctx))
return;
if (!ctx->used_any_timer) if (!ctx->used_any_timer)
return; return;


@ -136,6 +146,8 @@ void tr2_emit_per_thread_timers(tr2_tgt_evt_timer_t *fn_apply)
struct tr2tls_thread_ctx *ctx = tr2tls_get_self(); struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
enum trace2_timer_id tid; enum trace2_timer_id tid;


if (tr2tls_is_fallback(ctx))
return;
if (!ctx->used_any_per_thread_timer) if (!ctx->used_any_per_thread_timer)
return; return;