From e862af5ef74f0a41788ab4bf72ce33fbbb2bdfc2 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 10 Aug 2026 19:02:28 +0200 Subject: [PATCH] MEDIUM: debug: use \x1e (RS) to delimit the condition from vaargs in DBG_COUNT() The principle here is to reduce the reliance on multiple pointers in the debug_count struct while still keeping a delimitation between records. For this, we use the ASCII record separator character (\x1e or RS) that is not present in the rest of our messages and has no reason to land there by accident. This slightly reduces the code size (2kB) but the purpose is to prepare a next step where these definitions will benefit the BUG_ON*() macros. --- include/haproxy/bug.h | 7 ++++--- src/debug.c | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/include/haproxy/bug.h b/include/haproxy/bug.h index 7e11ed2c7..061e5bad9 100644 --- a/include/haproxy/bug.h +++ b/include/haproxy/bug.h @@ -322,7 +322,8 @@ extern __attribute__((__weak__)) struct debug_count __stop_dbg_cnt HA_SECTION_S /* This macro adds a pass counter at the line where it's declared. It can be * used by the various BUG_ON, COUNT_IF etc flavors. The condition is only * passed for the sake of being turned into a string; the caller is expected - * to have already verified it. + * to have already verified it. The descripton and optional comments are + * delimited by \x1e (record separator). */ #define __DBG_COUNT(_cond, _file, _line, _type, ...) do { \ static struct debug_count __dbg_cnt_##_line HA_SECTION("dbg_cnt") \ @@ -333,8 +334,8 @@ extern __attribute__((__weak__)) struct debug_count __stop_dbg_cnt HA_SECTION_S .type = _type, \ .desc = (sizeof("" #_cond) > 1) ? \ (sizeof("" __VA_ARGS__) > 1) ? \ - "\"" #_cond "\" [" __VA_ARGS__ "]" : \ - "\"" #_cond "\"" : \ + "" #_cond "\x1e" __VA_ARGS__ : \ + "" #_cond : \ "" __VA_ARGS__, \ .count = 0, \ }; \ diff --git a/src/debug.c b/src/debug.c index 8484d0f36..a9cb9ed8f 100644 --- a/src/debug.c +++ b/src/debug.c @@ -2567,6 +2567,7 @@ static int debug_iohandler_counters(struct appctx *appctx) chunk_printf(&trash, "Count Type Location function(): \"condition\" [comment]\n"); for (ptr = ctx->start; ptr != ctx->stop; ptr++) { const char *p, *name; + const char *rs; /* record separator */ if (ctx->types && !(ctx->types & (1 << ptr->type))) continue; @@ -2579,11 +2580,21 @@ static int debug_iohandler_counters(struct appctx *appctx) name = p + 1; } + /* make rs point either to the RS or to \0 */ + rs = strchr(ptr->desc, '\x1e'); + if (!rs) + rs = ptr->desc + strlen(ptr->desc); + if (ptr->type < DBG_COUNTER_TYPES) - chunk_appendf(&trash, "%-10u %3s %s:%d %s()%s%s%s\n", + chunk_appendf(&trash, + "%-10u %3s %s:%d %s()" // cnt, type, name, line, func + "%s%.*s%s%s%s%s%s\n", // \" \", ... ptr->count, bug_type[ptr->type], name, ptr->line, ptr->func, - *ptr->desc ? ": " : "", ptr->desc, + *ptr->desc ? ": \"" : "", + (uint)(rs - ptr->desc), ptr->desc, /* .*s: first part */ + *ptr->desc ? "\"" : "", + *rs ? " [" : "", *rs ? rs + 1 : "", *rs ? "]" : "", /* opt comment */ (ptr->type == DBG_COUNT_IF && !debug_enable_counters) ? " (stopped)" : ""); if (applet_putchk(appctx, &trash) == -1) { @@ -2708,6 +2719,12 @@ static int init_debug() for (ptr = &__start_dbg_cnt; ptr < &__stop_dbg_cnt; ptr++) { for (p = ptr->desc; *p; p++) { if (*p < 0x20 || *p >= 0x7f) { + /* \x1E (record separator) is used as the delimiter between + * description and comments. It may only appear once and may + * not appear at the end of the string. + */ + if (*p == '\x1e' && *(p + 1) && !strchr(p + 1, '\x1e')) + continue; ha_warning("Invalid character 0x%02x at position %d in description string at %s:%d %s()\n", (uchar)*p, (int)(p - ptr->desc), ptr->file, ptr->line, ptr->func); ret = ERR_WARN; -- 2.47.3