From: Fujii Masao Date: Thu, 14 May 2026 03:30:34 +0000 (+0900) Subject: pgbench: fix verbose error message corruption with multiple threads X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=61f8a85a577fd0ea0bf924a88064187bed31eb48;p=thirdparty%2Fpostgresql.git pgbench: fix verbose error message corruption with multiple threads When pgbench runs with multiple threads and verbose error reporting is enabled (--verbose-errors), multiple clients can build verbose error messages concurrently. Previously, a function-local static PQExpBuffer was used for these messages, causing the buffer to be shared across threads. This was not thread-safe and could result in corrupted or incorrect log output. Fix this by using a local PQExpBufferData instead of a static buffer. This keeps verbose error messages correct during concurrent execution. Backpatch to v15, where this issue was introduced. Author: Fujii Masao Reviewed-by: Michael Paquier Reviewed-by: Alex Guo Reviewed-by: Chao Li Discussion: https://postgr.es/m/CAHGQGwER1AjGXpkKB9t9820NBhMQ_Ghv7=HsKeodUr3=SZsF4g@mail.gmail.com Backpatch-through: 15 --- diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 69b12a919a4..0b2bb9340b5 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -3630,22 +3630,19 @@ getTransactionStatus(PGconn *con) static void printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry) { - static PQExpBuffer buf = NULL; + PQExpBufferData buf; - if (buf == NULL) - buf = createPQExpBuffer(); - else - resetPQExpBuffer(buf); + initPQExpBuffer(&buf); - printfPQExpBuffer(buf, "client %d ", st->id); - appendPQExpBufferStr(buf, (is_retry ? - "repeats the transaction after the error" : - "ends the failed transaction")); - appendPQExpBuffer(buf, " (try %u", st->tries); + printfPQExpBuffer(&buf, "client %d ", st->id); + appendPQExpBufferStr(&buf, (is_retry ? + "repeats the transaction after the error" : + "ends the failed transaction")); + appendPQExpBuffer(&buf, " (try %u", st->tries); /* Print max_tries if it is not unlimited. */ if (max_tries) - appendPQExpBuffer(buf, "/%u", max_tries); + appendPQExpBuffer(&buf, "/%u", max_tries); /* * If the latency limit is used, print a percentage of the current @@ -3654,12 +3651,14 @@ printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry) if (latency_limit) { pg_time_now_lazy(now); - appendPQExpBuffer(buf, ", %.3f%% of the maximum time of tries was used", + appendPQExpBuffer(&buf, ", %.3f%% of the maximum time of tries was used", (100.0 * (*now - st->txn_scheduled) / latency_limit)); } - appendPQExpBufferStr(buf, ")\n"); + appendPQExpBufferStr(&buf, ")\n"); - pg_log_info("%s", buf->data); + pg_log_info("%s", buf.data); + + termPQExpBuffer(&buf); } /*