Skip to content

Commit 3a60c8f

Browse files
committed
Distinguish printf-like functions that support %m from those that don't.
The elog/ereport family of functions certainly support the %m format spec, because they implement it "by hand". But elsewhere we have printf wrappers that might or might not allow it depending on whether the platform's printf does. (Most non-glibc versions don't, and notably, src/port/snprintf.c doesn't.) Hence, rather than using the gnu_printf format archetype interchangeably for all these functions, use it only for elog/ereport. This will allow us to get compiler warnings for mistakes like the ones fixed in commit a13b47a, at least on platforms where printf doesn't take %m and gcc is correctly configured to know it. (Unfortunately, that won't happen on Linux, nor on macOS according to my testing. It remains to be seen what the buildfarm's gcc-on-Windows animals will think of this, but we may well have to rely on less-popular platforms to warn us about unportable code of this kind.) Discussion: https://postgr.es/m/2975.1526862605@sss.pgh.pa.us
1 parent 5c047fd commit 3a60c8f

File tree

5 files changed

+32
-28
lines changed

5 files changed

+32
-28
lines changed

config/c-compiler.m4

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ fi])# PGAC_C_SIGNED
1919

2020
# PGAC_C_PRINTF_ARCHETYPE
2121
# -----------------------
22-
# Set the format archetype used by gcc to check printf type functions. We
23-
# prefer "gnu_printf", which includes what glibc uses, such as %m for error
24-
# strings and %lld for 64 bit long longs. GCC 4.4 introduced it. It makes a
25-
# dramatic difference on Windows.
22+
# Set the format archetype used by gcc to check elog/ereport functions.
23+
# This should accept %m, whether or not the platform's printf does.
24+
# We use "gnu_printf" if possible, which does that, although in some cases
25+
# it might do more than we could wish.
2626
AC_DEFUN([PGAC_PRINTF_ARCHETYPE],
27-
[AC_CACHE_CHECK([for printf format archetype], pgac_cv_printf_archetype,
27+
[AC_CACHE_CHECK([for printf format archetype for %m], pgac_cv_printf_archetype,
2828
[ac_save_c_werror_flag=$ac_c_werror_flag
2929
ac_c_werror_flag=yes
3030
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
@@ -34,8 +34,8 @@ __attribute__((format(gnu_printf, 2, 3)));], [])],
3434
[pgac_cv_printf_archetype=gnu_printf],
3535
[pgac_cv_printf_archetype=printf])
3636
ac_c_werror_flag=$ac_save_c_werror_flag])
37-
AC_DEFINE_UNQUOTED([PG_PRINTF_ATTRIBUTE], [$pgac_cv_printf_archetype],
38-
[Define to gnu_printf if compiler supports it, else printf.])
37+
AC_DEFINE_UNQUOTED([PG_PRINTF_ATTRIBUTE_M], [$pgac_cv_printf_archetype],
38+
[Define as a format archetype that accepts %m, if available, else printf.])
3939
])# PGAC_PRINTF_ARCHETYPE
4040

4141

configure

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13362,8 +13362,8 @@ _ACEOF
1336213362
;;
1336313363
esac
1336413364

13365-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for printf format archetype" >&5
13366-
$as_echo_n "checking for printf format archetype... " >&6; }
13365+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for printf format archetype for %m" >&5
13366+
$as_echo_n "checking for printf format archetype for %m... " >&6; }
1336713367
if ${pgac_cv_printf_archetype+:} false; then :
1336813368
$as_echo_n "(cached) " >&6
1336913369
else
@@ -13394,7 +13394,7 @@ fi
1339413394
$as_echo "$pgac_cv_printf_archetype" >&6; }
1339513395

1339613396
cat >>confdefs.h <<_ACEOF
13397-
#define PG_PRINTF_ATTRIBUTE $pgac_cv_printf_archetype
13397+
#define PG_PRINTF_ATTRIBUTE_M $pgac_cv_printf_archetype
1339813398
_ACEOF
1339913399

1340013400

src/include/c.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,14 @@
126126
/* GCC and XLC support format attributes */
127127
#if defined(__GNUC__) || defined(__IBMC__)
128128
#define pg_attribute_format_arg(a) __attribute__((format_arg(a)))
129-
#define pg_attribute_printf(f,a) __attribute__((format(PG_PRINTF_ATTRIBUTE, f, a)))
129+
/* Use for functions wrapping stdio's printf, which often doesn't take %m: */
130+
#define pg_attribute_printf(f,a) __attribute__((format(printf, f, a)))
131+
/* Use for elog/ereport, which implement %m for themselves: */
132+
#define pg_attribute_printf_m(f,a) __attribute__((format(PG_PRINTF_ATTRIBUTE_M, f, a)))
130133
#else
131134
#define pg_attribute_format_arg(a)
132135
#define pg_attribute_printf(f,a)
136+
#define pg_attribute_printf_m(f,a)
133137
#endif
134138

135139
/* GCC, Sunpro and XLC support aligned, packed and noreturn */

src/include/pg_config.h.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -809,8 +809,8 @@
809809
/* PostgreSQL major version as a string */
810810
#undef PG_MAJORVERSION
811811

812-
/* Define to gnu_printf if compiler supports it, else printf. */
813-
#undef PG_PRINTF_ATTRIBUTE
812+
/* Define as a format archetype that accepts %m, if available, else printf. */
813+
#undef PG_PRINTF_ATTRIBUTE_M
814814

815815
/* PostgreSQL version as a string */
816816
#undef PG_VERSION

src/include/utils/elog.h

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -133,25 +133,25 @@ extern int errcode(int sqlerrcode);
133133
extern int errcode_for_file_access(void);
134134
extern int errcode_for_socket_access(void);
135135

136-
extern int errmsg(const char *fmt,...) pg_attribute_printf(1, 2);
137-
extern int errmsg_internal(const char *fmt,...) pg_attribute_printf(1, 2);
136+
extern int errmsg(const char *fmt,...) pg_attribute_printf_m(1, 2);
137+
extern int errmsg_internal(const char *fmt,...) pg_attribute_printf_m(1, 2);
138138

139139
extern int errmsg_plural(const char *fmt_singular, const char *fmt_plural,
140-
unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4);
140+
unsigned long n,...) pg_attribute_printf_m(1, 4) pg_attribute_printf_m(2, 4);
141141

142-
extern int errdetail(const char *fmt,...) pg_attribute_printf(1, 2);
143-
extern int errdetail_internal(const char *fmt,...) pg_attribute_printf(1, 2);
142+
extern int errdetail(const char *fmt,...) pg_attribute_printf_m(1, 2);
143+
extern int errdetail_internal(const char *fmt,...) pg_attribute_printf_m(1, 2);
144144

145-
extern int errdetail_log(const char *fmt,...) pg_attribute_printf(1, 2);
145+
extern int errdetail_log(const char *fmt,...) pg_attribute_printf_m(1, 2);
146146

147147
extern int errdetail_log_plural(const char *fmt_singular,
148148
const char *fmt_plural,
149-
unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4);
149+
unsigned long n,...) pg_attribute_printf_m(1, 4) pg_attribute_printf_m(2, 4);
150150

151151
extern int errdetail_plural(const char *fmt_singular, const char *fmt_plural,
152-
unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4);
152+
unsigned long n,...) pg_attribute_printf_m(1, 4) pg_attribute_printf_m(2, 4);
153153

154-
extern int errhint(const char *fmt,...) pg_attribute_printf(1, 2);
154+
extern int errhint(const char *fmt,...) pg_attribute_printf_m(1, 2);
155155

156156
/*
157157
* errcontext() is typically called in error context callback functions, not
@@ -165,7 +165,7 @@ extern int errhint(const char *fmt,...) pg_attribute_printf(1, 2);
165165

166166
extern int set_errcontext_domain(const char *domain);
167167

168-
extern int errcontext_msg(const char *fmt,...) pg_attribute_printf(1, 2);
168+
extern int errcontext_msg(const char *fmt,...) pg_attribute_printf_m(1, 2);
169169

170170
extern int errhidestmt(bool hide_stmt);
171171
extern int errhidecontext(bool hide_ctx);
@@ -222,13 +222,13 @@ extern int getinternalerrposition(void);
222222
#endif /* HAVE__VA_ARGS */
223223

224224
extern void elog_start(const char *filename, int lineno, const char *funcname);
225-
extern void elog_finish(int elevel, const char *fmt,...) pg_attribute_printf(2, 3);
225+
extern void elog_finish(int elevel, const char *fmt,...) pg_attribute_printf_m(2, 3);
226226

227227

228228
/* Support for constructing error strings separately from ereport() calls */
229229

230230
extern void pre_format_elog_string(int errnumber, const char *domain);
231-
extern char *format_elog_string(const char *fmt,...) pg_attribute_printf(1, 2);
231+
extern char *format_elog_string(const char *fmt,...) pg_attribute_printf_m(1, 2);
232232

233233

234234
/* Support for attaching context information to error reports */
@@ -407,9 +407,9 @@ extern void set_syslog_parameters(const char *ident, int facility);
407407
#endif
408408

409409
/*
410-
* Write errors to stderr (or by equal means when stderr is
411-
* not available). Used before ereport/elog can be used
412-
* safely (memory context, GUC load etc)
410+
* Write errors to stderr (or by comparable means when stderr is not
411+
* available). Used before ereport/elog can be used safely (memory context,
412+
* GUC load etc). Note that this does *not* accept "%m".
413413
*/
414414
extern void write_stderr(const char *fmt,...) pg_attribute_printf(1, 2);
415415

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy