v2-0001-Fix-incorrect-fprintf-usage-in-log_error-FRONTEND-pa.patch
text/plain
Filename: v2-0001-Fix-incorrect-fprintf-usage-in-log_error-FRONTEND-pa.patch
Type: text/plain
Part: 0
Patch
Format: format-patch
Series: patch v2-0001
Subject: Fix va_list handling in log_error() and add vwrite_stderr()
| File | + | − |
|---|---|---|
| src/backend/utils/error/elog.c | 13 | 3 |
| src/include/utils/elog.h | 1 | 0 |
| src/port/win32security.c | 1 | 1 |
From de3ed61590ef80e2d28649aab722dc549b6576ea Mon Sep 17 00:00:00 2001
From: Bryan Green <dbryan.green@gmail.com>
Date: Mon, 13 Oct 2025 14:53:58 -0500
Subject: [PATCH] Fix va_list handling in log_error() and add vwrite_stderr()
The log_error() function in win32security.c was incorrectly passing
a va_list to variadic functions, which would cause the va_list pointer
to be treated as a single argument rather than expanding the arguments
properly.
Specifically:
- In the non-FRONTEND path, it called write_stderr(fmt, ap) where
write_stderr() expects variadic arguments (...), not a va_list
- In the FRONTEND path, it called fprintf(stderr, fmt, ap) where
fprintf() also expects variadic arguments, not a va_list
This bug likely went undetected because the error paths in
pgwin32_is_admin() are rarely exercised - they only trigger when
Windows security API calls fail catastrophically (out of memory,
security subsystem corruption, etc.).
To fix this, add a new vwrite_stderr() function that accepts a
va_list parameter, following the standard C library pattern of
providing both variadic and va_list versions (like printf/vprintf,
fprintf/vfprintf, etc.).
Changes:
- Add vwrite_stderr() to handle va_list arguments
- Refactor write_stderr() to call vwrite_stderr() internally
- Fix log_error() to use vwrite_stderr() for non-FRONTEND path
- Fix log_error() to use vfprintf() for FRONTEND path
This ensures proper argument expansion in both code paths.
---
src/backend/utils/error/elog.c | 16 +++++++++++++---
src/include/utils/elog.h | 1 +
src/port/win32security.c | 2 +-
3 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index b7b9692f8c..399ab67fcf 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -3786,13 +3786,24 @@ write_stderr(const char *fmt,...)
{
va_list ap;
+ va_start(ap, fmt);
+ vwrite_stderr(fmt, ap);
+ va_end(ap);
+}
+
+
+/*
+ * Write errors to stderr (or by equal means when stderr is
+ * not available) - va_list version
+ */
+void
+vwrite_stderr(const char *fmt,va_list ap)
+{
#ifdef WIN32
char errbuf[2048]; /* Arbitrary size? */
#endif
fmt = _(fmt);
-
- va_start(ap, fmt);
#ifndef WIN32
/* On Unix, we just fprintf to stderr */
vfprintf(stderr, fmt, ap);
@@ -3815,5 +3826,4 @@ write_stderr(const char *fmt,...)
fflush(stderr);
}
#endif
- va_end(ap);
}
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 348dafbf90..001ab93ae6 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -528,5 +528,6 @@ extern void write_jsonlog(ErrorData *edata);
* safely (memory context, GUC load etc)
*/
extern void write_stderr(const char *fmt,...) pg_attribute_printf(1, 2);
+extern void vwrite_stderr(const char *fmt, va_list ap) pg_attribute_printf(1, 0);
#endif /* ELOG_H */
diff --git a/src/port/win32security.c b/src/port/win32security.c
index a46b82dd04..af3537ab82 100644
--- a/src/port/win32security.c
+++ b/src/port/win32security.c
@@ -31,7 +31,7 @@ log_error(const char *fmt,...)
va_start(ap, fmt);
#ifndef FRONTEND
- write_stderr(fmt, ap);
+ vwrite_stderr(fmt, ap);
#else
fprintf(stderr, fmt, ap);
#endif
--
2.49.0