Received: from malur.postgresql.org ([2a02:16a8:dc51::56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1g097h-0001we-Lt for pgsql-hackers@arkaria.postgresql.org; Wed, 12 Sep 2018 17:40:18 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1g097g-0001Ft-2I for pgsql-hackers@arkaria.postgresql.org; Wed, 12 Sep 2018 17:40:16 +0000 Received: from makus.postgresql.org ([2001:4800:1501:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1g097f-0001FY-Di for pgsql-hackers@lists.postgresql.org; Wed, 12 Sep 2018 17:40:15 +0000 Received: from sss.pgh.pa.us ([66.207.139.130]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.89) (envelope-from ) id 1g097a-00021o-4x for pgsql-hackers@lists.postgresql.org; Wed, 12 Sep 2018 17:40:14 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.14.4/8.14.4) with ESMTP id w8CHe1BB001305; Wed, 12 Sep 2018 13:40:01 -0400 From: Tom Lane To: Michael Paquier cc: Thomas Munro , Alvaro Herrera , PostgreSQL Hackers Subject: Re: Allowing printf("%m") only where it actually works In-reply-to: <20180912070739.GK25160@paquier.xyz> References: <20180528150125.j2x3mp62ssbeg3h5@alvherre.pgsql> <2685.1527520461@sss.pgh.pa.us> <8770.1533931511@sss.pgh.pa.us> <16896.1533935042@sss.pgh.pa.us> <14925.1534040609@sss.pgh.pa.us> <1437.1534100930@sss.pgh.pa.us> <13183.1534624490@sss.pgh.pa.us> <30022.1534705920@sss.pgh.pa.us> <20180912070739.GK25160@paquier.xyz> Comments: In-reply-to Michael Paquier message dated "Wed, 12 Sep 2018 16:07:39 +0900" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <1267.1536773973.0@sss.pgh.pa.us> Date: Wed, 12 Sep 2018 13:40:01 -0400 Message-ID: <1304.1536774001@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <1267.1536773973.1@sss.pgh.pa.us> Michael Paquier writes: > I would have liked to look at this patch in details, but it failed to > apply. Could you rebase? Ah, yeah, the dlopen patch touched a couple of the same places. Rebase attached --- no substantive changes. regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="0001-create-strerror-wrapper-2.patch"; charset="us-ascii" Content-ID: <1267.1536773973.2@sss.pgh.pa.us> Content-Description: 0001-create-strerror-wrapper-2.patch Content-Transfer-Encoding: quoted-printable diff --git a/configure b/configure index dd77742..1aefc57 100755 *** a/configure --- b/configure *************** esac *** 15602,15620 **** = fi = - ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror" - if test "x$ac_cv_func_strerror" =3D xyes; then : - $as_echo "#define HAVE_STRERROR 1" >>confdefs.h - = - else - case " $LIBOBJS " in - *" strerror.$ac_objext "* ) ;; - *) LIBOBJS=3D"$LIBOBJS strerror.$ac_objext" - ;; - esac - = - fi - = ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" if test "x$ac_cv_func_strlcat" =3D xyes; then : $as_echo "#define HAVE_STRLCAT 1" >>confdefs.h --- 15602,15607 ---- diff --git a/configure.in b/configure.in index 3ada48b..3a23913 100644 *** a/configure.in --- b/configure.in *************** else *** 1660,1666 **** AC_CHECK_FUNCS([fpclass fp_class fp_class_d class], [break]) fi = ! AC_REPLACE_FUNCS([crypt dlopen fls getopt getrusage inet_aton mkdtemp ra= ndom rint srandom strerror strlcat strlcpy strnlen]) = case $host_os in = --- 1660,1666 ---- AC_CHECK_FUNCS([fpclass fp_class fp_class_d class], [break]) fi = ! AC_REPLACE_FUNCS([crypt dlopen fls getopt getrusage inet_aton mkdtemp ra= ndom rint srandom strlcat strlcpy strnlen]) = case $host_os in = diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/sock= et.c index f4356fe..af35cfb 100644 *** a/src/backend/port/win32/socket.c --- b/src/backend/port/win32/socket.c *************** pgwin32_select(int nfds, fd_set *readfds *** 690,728 **** memcpy(writefds, &outwritefds, sizeof(fd_set)); return nummatches; } - = - = - /* - * Return win32 error string, since strerror can't - * handle winsock codes - */ - static char wserrbuf[256]; - const char * - pgwin32_socket_strerror(int err) - { - static HANDLE handleDLL =3D INVALID_HANDLE_VALUE; - = - if (handleDLL =3D=3D INVALID_HANDLE_VALUE) - { - handleDLL =3D LoadLibraryEx("netmsg.dll", NULL, DONT_RESOLVE_DLL_REFER= ENCES | LOAD_LIBRARY_AS_DATAFILE); - if (handleDLL =3D=3D NULL) - ereport(FATAL, - (errmsg_internal("could not load netmsg.dll: error code %lu", GetLa= stError()))); - } - = - ZeroMemory(&wserrbuf, sizeof(wserrbuf)); - if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_FROM_HMODULE, - handleDLL, - err, - MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), - wserrbuf, - sizeof(wserrbuf) - 1, - NULL) =3D=3D 0) - { - /* Failed to get id */ - sprintf(wserrbuf, "unrecognized winsock error %d", err); - } - return wserrbuf; - } --- 690,692 ---- diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog= .c index 16531f7..22e5d87 100644 *** a/src/backend/utils/error/elog.c --- b/src/backend/utils/error/elog.c *************** static void send_message_to_server_log(E *** 178,185 **** static void write_pipe_chunks(char *data, int len, int dest); static void send_message_to_frontend(ErrorData *edata); static char *expand_fmt_string(const char *fmt, ErrorData *edata); - static const char *useful_strerror(int errnum); - static const char *get_errno_symbol(int errnum); static const char *error_severity(int elevel); static void append_with_tabs(StringInfo buf, const char *str); static bool is_log_level_output(int elevel, int log_min_level); --- 178,183 ---- *************** expand_fmt_string(const char *fmt, Error *** 3360,3366 **** */ const char *cp2; = ! cp2 =3D useful_strerror(edata->saved_errno); for (; *cp2; cp2++) { if (*cp2 =3D=3D '%') --- 3358,3364 ---- */ const char *cp2; = ! cp2 =3D strerror(edata->saved_errno); for (; *cp2; cp2++) { if (*cp2 =3D=3D '%') *************** expand_fmt_string(const char *fmt, Error *** 3384,3602 **** = = /* - * A slightly cleaned-up version of strerror() - */ - static const char * - useful_strerror(int errnum) - { - /* this buffer is only used if strerror() and get_errno_symbol() fail *= / - static char errorstr_buf[48]; - const char *str; - = - #ifdef WIN32 - /* Winsock error code range, per WinError.h */ - if (errnum >=3D 10000 && errnum <=3D 11999) - return pgwin32_socket_strerror(errnum); - #endif - str =3D strerror(errnum); - = - /* - * Some strerror()s return an empty string for out-of-range errno. Thi= s - * is ANSI C spec compliant, but not exactly useful. Also, we may get - * back strings of question marks if libc cannot transcode the message = to - * the codeset specified by LC_CTYPE. If we get nothing useful, first = try - * get_errno_symbol(), and if that fails, print the numeric errno. - */ - if (str =3D=3D NULL || *str =3D=3D '\0' || *str =3D=3D '?') - str =3D get_errno_symbol(errnum); - = - if (str =3D=3D NULL) - { - snprintf(errorstr_buf, sizeof(errorstr_buf), - /*------ - translator: This string will be truncated at 47 - characters expanded. */ - _("operating system error %d"), errnum); - str =3D errorstr_buf; - } - = - return str; - } - = - /* - * Returns a symbol (e.g. "ENOENT") for an errno code. - * Returns NULL if the code is unrecognized. - */ - static const char * - get_errno_symbol(int errnum) - { - switch (errnum) - { - case E2BIG: - return "E2BIG"; - case EACCES: - return "EACCES"; - #ifdef EADDRINUSE - case EADDRINUSE: - return "EADDRINUSE"; - #endif - #ifdef EADDRNOTAVAIL - case EADDRNOTAVAIL: - return "EADDRNOTAVAIL"; - #endif - case EAFNOSUPPORT: - return "EAFNOSUPPORT"; - #ifdef EAGAIN - case EAGAIN: - return "EAGAIN"; - #endif - #ifdef EALREADY - case EALREADY: - return "EALREADY"; - #endif - case EBADF: - return "EBADF"; - #ifdef EBADMSG - case EBADMSG: - return "EBADMSG"; - #endif - case EBUSY: - return "EBUSY"; - case ECHILD: - return "ECHILD"; - #ifdef ECONNABORTED - case ECONNABORTED: - return "ECONNABORTED"; - #endif - case ECONNREFUSED: - return "ECONNREFUSED"; - #ifdef ECONNRESET - case ECONNRESET: - return "ECONNRESET"; - #endif - case EDEADLK: - return "EDEADLK"; - case EDOM: - return "EDOM"; - case EEXIST: - return "EEXIST"; - case EFAULT: - return "EFAULT"; - case EFBIG: - return "EFBIG"; - #ifdef EHOSTUNREACH - case EHOSTUNREACH: - return "EHOSTUNREACH"; - #endif - case EIDRM: - return "EIDRM"; - case EINPROGRESS: - return "EINPROGRESS"; - case EINTR: - return "EINTR"; - case EINVAL: - return "EINVAL"; - case EIO: - return "EIO"; - #ifdef EISCONN - case EISCONN: - return "EISCONN"; - #endif - case EISDIR: - return "EISDIR"; - #ifdef ELOOP - case ELOOP: - return "ELOOP"; - #endif - case EMFILE: - return "EMFILE"; - case EMLINK: - return "EMLINK"; - case EMSGSIZE: - return "EMSGSIZE"; - case ENAMETOOLONG: - return "ENAMETOOLONG"; - case ENFILE: - return "ENFILE"; - case ENOBUFS: - return "ENOBUFS"; - case ENODEV: - return "ENODEV"; - case ENOENT: - return "ENOENT"; - case ENOEXEC: - return "ENOEXEC"; - case ENOMEM: - return "ENOMEM"; - case ENOSPC: - return "ENOSPC"; - case ENOSYS: - return "ENOSYS"; - #ifdef ENOTCONN - case ENOTCONN: - return "ENOTCONN"; - #endif - case ENOTDIR: - return "ENOTDIR"; - #if defined(ENOTEMPTY) && (ENOTEMPTY !=3D EEXIST) /* same code on AIX */ - case ENOTEMPTY: - return "ENOTEMPTY"; - #endif - #ifdef ENOTSOCK - case ENOTSOCK: - return "ENOTSOCK"; - #endif - #ifdef ENOTSUP - case ENOTSUP: - return "ENOTSUP"; - #endif - case ENOTTY: - return "ENOTTY"; - case ENXIO: - return "ENXIO"; - #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP !=3D ENOTSU= P)) - case EOPNOTSUPP: - return "EOPNOTSUPP"; - #endif - #ifdef EOVERFLOW - case EOVERFLOW: - return "EOVERFLOW"; - #endif - case EPERM: - return "EPERM"; - case EPIPE: - return "EPIPE"; - case EPROTONOSUPPORT: - return "EPROTONOSUPPORT"; - case ERANGE: - return "ERANGE"; - #ifdef EROFS - case EROFS: - return "EROFS"; - #endif - case ESRCH: - return "ESRCH"; - #ifdef ETIMEDOUT - case ETIMEDOUT: - return "ETIMEDOUT"; - #endif - #ifdef ETXTBSY - case ETXTBSY: - return "ETXTBSY"; - #endif - #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK !=3D EAGAI= N)) - case EWOULDBLOCK: - return "EWOULDBLOCK"; - #endif - case EXDEV: - return "EXDEV"; - } - = - return NULL; - } - = - = - /* * error_severity --- get string representing elevel * * The string is not localized here, but we mark the strings for transla= tion --- 3382,3387 ---- diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 4094e22..705c52b 100644 *** a/src/include/pg_config.h.in --- b/src/include/pg_config.h.in *************** *** 531,539 **** /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H = - /* Define to 1 if you have the `strerror' function. */ - #undef HAVE_STRERROR - = /* Define to 1 if you have the `strerror_r' function. */ #undef HAVE_STRERROR_R = --- 531,536 ---- diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32 index 6618b43..eafe377 100644 *** a/src/include/pg_config.h.win32 --- b/src/include/pg_config.h.win32 *************** *** 402,412 **** /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 = - /* Define to 1 if you have the `strerror' function. */ - #ifndef HAVE_STRERROR - #define HAVE_STRERROR 1 - #endif - = /* Define to 1 if you have the `strerror_r' function. */ /* #undef HAVE_STRERROR_R */ = --- 402,407 ---- diff --git a/src/include/port.h b/src/include/port.h index d927561..bffc773 100644 *** a/src/include/port.h --- b/src/include/port.h *************** extern int pg_printf(const char *fmt,... *** 189,194 **** --- 189,198 ---- #endif #endif /* USE_REPL_SNPRINTF */ = + /* Replace strerror() with our own, somewhat more robust wrapper */ + extern char *pg_strerror(int errnum); + #define strerror pg_strerror + = /* Portable prompt handling */ extern void simple_prompt(const char *prompt, char *destination, size_t = destlen, bool echo); diff --git a/src/include/port/win32_port.h b/src/include/port/win32_port.h index b398cd3..360dbdf 100644 *** a/src/include/port/win32_port.h --- b/src/include/port/win32_port.h *************** extern int pgwin32_safestat(const char * *** 322,329 **** * Supplement to . * * We redefine network-related Berkeley error symbols as the correspondi= ng WSA ! * constants. This allows elog.c to recognize them as being in the Wins= ock ! * error code range and pass them off to pgwin32_socket_strerror(), sinc= e * Windows' version of plain strerror() won't cope. Note that this will= break * if these names are used for anything else besides Windows Sockets err= ors. * See TranslateSocketError() when changing this list. --- 322,329 ---- * Supplement to . * * We redefine network-related Berkeley error symbols as the correspondi= ng WSA ! * constants. This allows strerror.c to recognize them as being in the W= insock ! * error code range and pass them off to win32_socket_strerror(), since * Windows' version of plain strerror() won't cope. Note that this will= break * if these names are used for anything else besides Windows Sockets err= ors. * See TranslateSocketError() when changing this list. *************** int pgwin32_connect(SOCKET s, const st *** 456,463 **** int pgwin32_select(int nfds, fd_set *readfs, fd_set *writefds, fd_set = *exceptfds, const struct timeval *timeout); int pgwin32_recv(SOCKET s, char *buf, int len, int flags); int pgwin32_send(SOCKET s, const void *buf, int len, int flags); - = - const char *pgwin32_socket_strerror(int err); int pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout); = extern int pgwin32_noblock; --- 456,461 ---- diff --git a/src/interfaces/ecpg/compatlib/.gitignore b/src/interfaces/ecp= g/compatlib/.gitignore index ad5ba13..8b9aa95 100644 *** a/src/interfaces/ecpg/compatlib/.gitignore --- b/src/interfaces/ecpg/compatlib/.gitignore *************** *** 2,5 **** --- 2,6 ---- /blibecpg_compatdll.def /exports.list /snprintf.c + /strerror.c /strnlen.c diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/= compatlib/Makefile index ebfd895..b7bd162 100644 *** a/src/interfaces/ecpg/compatlib/Makefile --- b/src/interfaces/ecpg/compatlib/Makefile *************** SHLIB_EXPORTS =3D exports.txt *** 31,37 **** # Need to recompile any libpgport object files LIBS :=3D $(filter-out -lpgport, $(LIBS)) = ! OBJS=3D informix.o $(filter snprintf.o strnlen.o, $(LIBOBJS)) $(WIN32RES= ) = PKG_CONFIG_REQUIRES_PRIVATE =3D libecpg libpgtypes = --- 31,37 ---- # Need to recompile any libpgport object files LIBS :=3D $(filter-out -lpgport, $(LIBS)) = ! OBJS=3D informix.o strerror.o $(filter snprintf.o strnlen.o, $(LIBOBJS))= $(WIN32RES) = PKG_CONFIG_REQUIRES_PRIVATE =3D libecpg libpgtypes = *************** submake-pgtypeslib: *** 48,54 **** # Shared library stuff include $(top_srcdir)/src/Makefile.shlib = ! snprintf.c strnlen.c: % : $(top_srcdir)/src/port/% rm -f $@ && $(LN_S) $< . = install: all installdirs install-lib --- 48,54 ---- # Shared library stuff include $(top_srcdir)/src/Makefile.shlib = ! snprintf.c strerror.c strnlen.c: % : $(top_srcdir)/src/port/% rm -f $@ && $(LN_S) $< . = install: all installdirs install-lib *************** installdirs: installdirs-lib *** 58,63 **** uninstall: uninstall-lib = clean distclean: clean-lib ! rm -f $(OBJS) snprintf.c strnlen.c = maintainer-clean: distclean maintainer-clean-lib --- 58,63 ---- uninstall: uninstall-lib = clean distclean: clean-lib ! rm -f $(OBJS) snprintf.c strerror.c strnlen.c = maintainer-clean: distclean maintainer-clean-lib diff --git a/src/interfaces/ecpg/ecpglib/.gitignore b/src/interfaces/ecpg/= ecpglib/.gitignore index 1619e97..545c106 100644 *** a/src/interfaces/ecpg/ecpglib/.gitignore --- b/src/interfaces/ecpg/ecpglib/.gitignore *************** *** 4,9 **** --- 4,10 ---- /path.c /pgstrcasecmp.c /snprintf.c + /strerror.c /strlcpy.c /strnlen.c /thread.c diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ec= pglib/Makefile index d25d248..005d25a 100644 *** a/src/interfaces/ecpg/ecpglib/Makefile --- b/src/interfaces/ecpg/ecpglib/Makefile *************** override CFLAGS +=3D $(PTHREAD_CFLAGS) *** 26,32 **** LIBS :=3D $(filter-out -lpgport, $(LIBS)) = OBJS=3D execute.o typename.o descriptor.o sqlda.o data.o error.o prepare= .o memory.o \ ! connect.o misc.o path.o pgstrcasecmp.o \ $(filter snprintf.o strlcpy.o strnlen.o win32setlocale.o isinf.o, $(LIB= OBJS)) \ $(WIN32RES) = --- 26,32 ---- LIBS :=3D $(filter-out -lpgport, $(LIBS)) = OBJS=3D execute.o typename.o descriptor.o sqlda.o data.o error.o prepare= .o memory.o \ ! connect.o misc.o path.o pgstrcasecmp.o strerror.o \ $(filter snprintf.o strlcpy.o strnlen.o win32setlocale.o isinf.o, $(LIB= OBJS)) \ $(WIN32RES) = *************** include $(top_srcdir)/src/Makefile.shlib *** 57,63 **** # necessarily use the same object files as the backend uses. Instead, # symlink the source files in here and build our own object file. = ! path.c pgstrcasecmp.c snprintf.c strlcpy.c strnlen.c thread.c win32setlo= cale.c isinf.c: % : $(top_srcdir)/src/port/% rm -f $@ && $(LN_S) $< . = misc.o: misc.c $(top_builddir)/src/port/pg_config_paths.h --- 57,63 ---- # necessarily use the same object files as the backend uses. Instead, # symlink the source files in here and build our own object file. = ! path.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c strnlen.c thread.c= win32setlocale.c isinf.c: % : $(top_srcdir)/src/port/% rm -f $@ && $(LN_S) $< . = misc.o: misc.c $(top_builddir)/src/port/pg_config_paths.h *************** uninstall: uninstall-lib *** 74,79 **** = clean distclean: clean-lib rm -f $(OBJS) ! rm -f path.c pgstrcasecmp.c snprintf.c strlcpy.c strnlen.c thread.c win= 32setlocale.c isinf.c = maintainer-clean: distclean maintainer-clean-lib --- 74,79 ---- = clean distclean: clean-lib rm -f $(OBJS) ! rm -f path.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c strnlen.c t= hread.c win32setlocale.c isinf.c = maintainer-clean: distclean maintainer-clean-lib diff --git a/src/interfaces/ecpg/pgtypeslib/.gitignore b/src/interfaces/ec= pg/pgtypeslib/.gitignore index d5f0fae..b3fae08 100644 *** a/src/interfaces/ecpg/pgtypeslib/.gitignore --- b/src/interfaces/ecpg/pgtypeslib/.gitignore *************** *** 4,8 **** --- 4,9 ---- /pgstrcasecmp.c /rint.c /snprintf.c + /strerror.c /string.c /strnlen.c diff --git a/src/interfaces/ecpg/pgtypeslib/Makefile b/src/interfaces/ecpg= /pgtypeslib/Makefile index 29264ce..18b2402 100644 *** a/src/interfaces/ecpg/pgtypeslib/Makefile --- b/src/interfaces/ecpg/pgtypeslib/Makefile *************** SHLIB_LINK +=3D $(filter -lm, $(LIBS)) *** 30,36 **** SHLIB_EXPORTS =3D exports.txt = OBJS=3D numeric.o datetime.o common.o dt_common.o timestamp.o interval.o= \ ! pgstrcasecmp.o \ $(filter rint.o snprintf.o strnlen.o, $(LIBOBJS)) \ string.o \ $(WIN32RES) --- 30,36 ---- SHLIB_EXPORTS =3D exports.txt = OBJS=3D numeric.o datetime.o common.o dt_common.o timestamp.o interval.o= \ ! pgstrcasecmp.o strerror.o \ $(filter rint.o snprintf.o strnlen.o, $(LIBOBJS)) \ string.o \ $(WIN32RES) *************** include $(top_srcdir)/src/Makefile.shlib *** 45,51 **** # necessarily use the same object files as the backend uses. Instead, # symlink the source files in here and build our own object file. = ! pgstrcasecmp.c rint.c snprintf.c strnlen.c: % : $(top_srcdir)/src/port/% rm -f $@ && $(LN_S) $< . = string.c: % : $(top_srcdir)/src/common/% --- 45,51 ---- # necessarily use the same object files as the backend uses. Instead, # symlink the source files in here and build our own object file. = ! pgstrcasecmp.c rint.c snprintf.c strerror.c strnlen.c: % : $(top_srcdir)= /src/port/% rm -f $@ && $(LN_S) $< . = string.c: % : $(top_srcdir)/src/common/% *************** installdirs: installdirs-lib *** 58,63 **** uninstall: uninstall-lib = clean distclean: clean-lib ! rm -f $(OBJS) pgstrcasecmp.c rint.c snprintf.c strnlen.c string.c = maintainer-clean: distclean maintainer-clean-lib --- 58,63 ---- uninstall: uninstall-lib = clean distclean: clean-lib ! rm -f $(OBJS) pgstrcasecmp.c rint.c snprintf.c strerror.c strnlen.c str= ing.c = maintainer-clean: distclean maintainer-clean-lib diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index ec0122a..8324f4f 100644 *** a/src/interfaces/libpq/Makefile --- b/src/interfaces/libpq/Makefile *************** OBJS=3D fe-auth.o fe-auth-scram.o fe-conne *** 36,44 **** libpq-events.o # libpgport C files we always use OBJS +=3D chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.= o \ ! thread.o # libpgport C files that are needed if identified by configure ! OBJS +=3D $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o= system.o snprintf.o strerror.o strlcpy.o strnlen.o win32error.o win32setl= ocale.o, $(LIBOBJS)) = ifeq ($(enable_strong_random), yes) OBJS +=3D pg_strong_random.o --- 36,44 ---- libpq-events.o # libpgport C files we always use OBJS +=3D chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.= o \ ! strerror.o thread.o # libpgport C files that are needed if identified by configure ! OBJS +=3D $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o= system.o snprintf.o strlcpy.o strnlen.o win32error.o win32setlocale.o, $(= LIBOBJS)) = ifeq ($(enable_strong_random), yes) OBJS +=3D pg_strong_random.o diff --git a/src/pl/plpython/plpython.h b/src/pl/plpython/plpython.h index 5c2e6a8..6cc323a 100644 *** a/src/pl/plpython/plpython.h --- b/src/pl/plpython/plpython.h *************** *** 27,33 **** */ #undef _POSIX_C_SOURCE #undef _XOPEN_SOURCE - #undef HAVE_STRERROR #undef HAVE_TZNAME = /* --- 27,32 ---- diff --git a/src/port/Makefile b/src/port/Makefile index d7467fb..b3a10ba 100644 *** a/src/port/Makefile --- b/src/port/Makefile *************** LIBS +=3D $(PTHREAD_LIBS) *** 33,39 **** OBJS =3D $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_nto= p.o \ noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \ pgstrcasecmp.o pqsignal.o \ ! qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o = ifeq ($(enable_strong_random), yes) OBJS +=3D pg_strong_random.o --- 33,39 ---- OBJS =3D $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_nto= p.o \ noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \ pgstrcasecmp.o pqsignal.o \ ! qsort.o qsort_arg.o quotes.o sprompt.o strerror.o tar.o thread.o = ifeq ($(enable_strong_random), yes) OBJS +=3D pg_strong_random.o diff --git a/src/port/strerror.c b/src/port/strerror.c index e92ebc9..e3393eb 100644 *** a/src/port/strerror.c --- b/src/port/strerror.c *************** *** 1,30 **** ! /* src/port/strerror.c */ ! = ! /* ! * strerror - map error number to descriptive string * ! * This version is obviously somewhat Unix-specific. * ! * based on code by Henry Spencer ! * modified for ANSI by D'Arcy J.M. Cain */ - = #include "c.h" = = ! extern const char *const sys_errlist[]; ! extern int sys_nerr; = ! const char * ! strerror(int errnum) { ! static char buf[24]; = ! if (errnum < 0 || errnum > sys_nerr) { ! sprintf(buf, _("unrecognized error %d"), errnum); ! return buf; } = ! return sys_errlist[errnum]; } --- 1,285 ---- ! /*----------------------------------------------------------------------= --- * ! * strerror.c ! * Replacement for standard strerror() function * ! * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group ! * Portions Copyright (c) 1994, Regents of the University of California ! * ! * ! * IDENTIFICATION ! * src/port/strerror.c ! * ! *----------------------------------------------------------------------= --- */ #include "c.h" = + /* + * Within this file, "strerror" means the platform's function not pg_str= error + */ + #undef strerror = ! static char *get_errno_symbol(int errnum); ! #ifdef WIN32 ! static char *win32_socket_strerror(int errnum); ! #endif = ! = ! /* ! * A slightly cleaned-up version of strerror() ! */ ! char * ! pg_strerror(int errnum) { ! /* this buffer is only used if strerror() and get_errno_symbol() fail *= / ! static char errorstr_buf[48]; ! char *str; = ! /* If it's a Windows Winsock error, that needs special handling */ ! #ifdef WIN32 ! /* Winsock error code range, per WinError.h */ ! if (errnum >=3D 10000 && errnum <=3D 11999) ! return win32_socket_strerror(errnum); ! #endif ! = ! /* Try the platform's strerror() */ ! str =3D strerror(errnum); ! = ! /* ! * Some strerror()s return an empty string for out-of-range errno. Thi= s ! * is ANSI C spec compliant, but not exactly useful. Also, we may get ! * back strings of question marks if libc cannot transcode the message = to ! * the codeset specified by LC_CTYPE. If we get nothing useful, first = try ! * get_errno_symbol(), and if that fails, print the numeric errno. ! */ ! if (str =3D=3D NULL || *str =3D=3D '\0' || *str =3D=3D '?') ! str =3D get_errno_symbol(errnum); ! = ! if (str =3D=3D NULL) { ! snprintf(errorstr_buf, sizeof(errorstr_buf), ! /*------ ! translator: This string will be truncated at 47 ! characters expanded. */ ! _("operating system error %d"), errnum); ! str =3D errorstr_buf; } = ! return str; } + = + /* + * Returns a symbol (e.g. "ENOENT") for an errno code. + * Returns NULL if the code is unrecognized. + */ + static char * + get_errno_symbol(int errnum) + { + switch (errnum) + { + case E2BIG: + return "E2BIG"; + case EACCES: + return "EACCES"; + #ifdef EADDRINUSE + case EADDRINUSE: + return "EADDRINUSE"; + #endif + #ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: + return "EADDRNOTAVAIL"; + #endif + case EAFNOSUPPORT: + return "EAFNOSUPPORT"; + #ifdef EAGAIN + case EAGAIN: + return "EAGAIN"; + #endif + #ifdef EALREADY + case EALREADY: + return "EALREADY"; + #endif + case EBADF: + return "EBADF"; + #ifdef EBADMSG + case EBADMSG: + return "EBADMSG"; + #endif + case EBUSY: + return "EBUSY"; + case ECHILD: + return "ECHILD"; + #ifdef ECONNABORTED + case ECONNABORTED: + return "ECONNABORTED"; + #endif + case ECONNREFUSED: + return "ECONNREFUSED"; + #ifdef ECONNRESET + case ECONNRESET: + return "ECONNRESET"; + #endif + case EDEADLK: + return "EDEADLK"; + case EDOM: + return "EDOM"; + case EEXIST: + return "EEXIST"; + case EFAULT: + return "EFAULT"; + case EFBIG: + return "EFBIG"; + #ifdef EHOSTUNREACH + case EHOSTUNREACH: + return "EHOSTUNREACH"; + #endif + case EIDRM: + return "EIDRM"; + case EINPROGRESS: + return "EINPROGRESS"; + case EINTR: + return "EINTR"; + case EINVAL: + return "EINVAL"; + case EIO: + return "EIO"; + #ifdef EISCONN + case EISCONN: + return "EISCONN"; + #endif + case EISDIR: + return "EISDIR"; + #ifdef ELOOP + case ELOOP: + return "ELOOP"; + #endif + case EMFILE: + return "EMFILE"; + case EMLINK: + return "EMLINK"; + case EMSGSIZE: + return "EMSGSIZE"; + case ENAMETOOLONG: + return "ENAMETOOLONG"; + case ENFILE: + return "ENFILE"; + case ENOBUFS: + return "ENOBUFS"; + case ENODEV: + return "ENODEV"; + case ENOENT: + return "ENOENT"; + case ENOEXEC: + return "ENOEXEC"; + case ENOMEM: + return "ENOMEM"; + case ENOSPC: + return "ENOSPC"; + case ENOSYS: + return "ENOSYS"; + #ifdef ENOTCONN + case ENOTCONN: + return "ENOTCONN"; + #endif + case ENOTDIR: + return "ENOTDIR"; + #if defined(ENOTEMPTY) && (ENOTEMPTY !=3D EEXIST) /* same code on AIX */ + case ENOTEMPTY: + return "ENOTEMPTY"; + #endif + #ifdef ENOTSOCK + case ENOTSOCK: + return "ENOTSOCK"; + #endif + #ifdef ENOTSUP + case ENOTSUP: + return "ENOTSUP"; + #endif + case ENOTTY: + return "ENOTTY"; + case ENXIO: + return "ENXIO"; + #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (EOPNOTSUPP !=3D ENOTSU= P)) + case EOPNOTSUPP: + return "EOPNOTSUPP"; + #endif + #ifdef EOVERFLOW + case EOVERFLOW: + return "EOVERFLOW"; + #endif + case EPERM: + return "EPERM"; + case EPIPE: + return "EPIPE"; + case EPROTONOSUPPORT: + return "EPROTONOSUPPORT"; + case ERANGE: + return "ERANGE"; + #ifdef EROFS + case EROFS: + return "EROFS"; + #endif + case ESRCH: + return "ESRCH"; + #ifdef ETIMEDOUT + case ETIMEDOUT: + return "ETIMEDOUT"; + #endif + #ifdef ETXTBSY + case ETXTBSY: + return "ETXTBSY"; + #endif + #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK !=3D EAGAI= N)) + case EWOULDBLOCK: + return "EWOULDBLOCK"; + #endif + case EXDEV: + return "EXDEV"; + } + = + return NULL; + } + = + = + #ifdef WIN32 + = + /* + * Windows' strerror() doesn't know the Winsock codes, so handle them th= is way + */ + static char * + win32_socket_strerror(int errnum) + { + static char wserrbuf[256]; + static HANDLE handleDLL =3D INVALID_HANDLE_VALUE; + = + if (handleDLL =3D=3D INVALID_HANDLE_VALUE) + { + handleDLL =3D LoadLibraryEx("netmsg.dll", NULL, + DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); + if (handleDLL =3D=3D NULL) + { + /* just treat this as an unrecognized error ... */ + sprintf(wserrbuf, "unrecognized winsock error %d", errnum); + return wserrbuf; + } + } + = + ZeroMemory(&wserrbuf, sizeof(wserrbuf)); + if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_FROM_HMODULE, + handleDLL, + errnum, + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), + wserrbuf, + sizeof(wserrbuf) - 1, + NULL) =3D=3D 0) + { + /* Failed to get id */ + sprintf(wserrbuf, "unrecognized winsock error %d", errnum); + } + = + return wserrbuf; + } + = + #endif /* WIN32 */ diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 9ce03ce..2be72f8 100644 *** a/src/tools/msvc/Mkvcbuild.pm --- b/src/tools/msvc/Mkvcbuild.pm *************** sub mkvcbuild *** 96,104 **** chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c ! sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c dlopen.c win32env.c win32error.c win32security.c win32setlocale.c); = push(@pgportfiles, 'rint.c') if ($vsVersion < '12.00'); --- 96,105 ---- chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c + dirent.c dlopen.c getopt.c getopt_long.c pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c ! sprompt.c strerror.c tar.c thread.c win32env.c win32error.c win32security.c win32setlocale.c); = push(@pgportfiles, 'rint.c') if ($vsVersion < '12.00'); ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="0002-migrate-percent-m-implementation-2.patch"; charset="us-ascii" Content-ID: <1267.1536773973.3@sss.pgh.pa.us> Content-Description: 0002-migrate-percent-m-implementation-2.patch Content-Transfer-Encoding: quoted-printable diff --git a/config/c-compiler.m4 b/config/c-compiler.m4 index eedaf12..fb58c94 100644 *** a/config/c-compiler.m4 --- b/config/c-compiler.m4 *************** fi])# PGAC_C_SIGNED *** 20,34 **** # PGAC_C_PRINTF_ARCHETYPE # ----------------------- # Select the format archetype to be used by gcc to check printf-type fun= ctions. ! # We prefer "gnu_printf", which matches the features glibc supports, not= ably ! # %m, 'z' and 'll' width modifiers ('ll' only matters if int64 requires = it), ! # and argument order control if we're doing --enable-nls. On platforms = where ! # the native printf doesn't have 'z'/'ll' or arg control, we replace it = with ! # src/port/snprintf.c which does, so that the only potential mismatch he= re is ! # whether or not %m is supported. We need that for elog/ereport, so we = live ! # with the fact that erroneous use of %m in plain printf calls won't be ! # detected. (It appears that many versions of gcc/clang wouldn't report= it ! # even if told to check according to plain printf archetype, anyway.) AC_DEFUN([PGAC_PRINTF_ARCHETYPE], [AC_CACHE_CHECK([for printf format archetype], pgac_cv_printf_archetype, [ac_save_c_werror_flag=3D$ac_c_werror_flag --- 20,27 ---- # PGAC_C_PRINTF_ARCHETYPE # ----------------------- # Select the format archetype to be used by gcc to check printf-type fun= ctions. ! # We prefer "gnu_printf", as that most closely matches the features supp= orted ! # by src/port/snprintf.c (particularly the %m conversion spec). AC_DEFUN([PGAC_PRINTF_ARCHETYPE], [AC_CACHE_CHECK([for printf format archetype], pgac_cv_printf_archetype, [ac_save_c_werror_flag=3D$ac_c_werror_flag diff --git a/config/c-library.m4 b/config/c-library.m4 index da7fa77..d371f1b 100644 *** a/config/c-library.m4 --- b/config/c-library.m4 *************** AC_DEFUN([PGAC_STRUCT_ADDRINFO], *** 171,276 **** ])])# PGAC_STRUCT_ADDRINFO = = - # PGAC_FUNC_SNPRINTF_ARG_CONTROL - # --------------------------------------- - # Determine if snprintf supports %1$ argument selection, e.g. %5$ select= s - # the fifth argument after the printf format string. - # This is not in the C99 standard, but in the Single Unix Specification = (SUS). - # It is used in our language translation strings. - # - AC_DEFUN([PGAC_FUNC_SNPRINTF_ARG_CONTROL], - [AC_MSG_CHECKING([whether snprintf supports argument control]) - AC_CACHE_VAL(pgac_cv_snprintf_arg_control, - [AC_RUN_IFELSE([AC_LANG_SOURCE([[#include - #include - = - int main() - { - char buf[100]; - = - /* can it swap arguments? */ - snprintf(buf, 100, "%2\$d %1\$d", 3, 4); - if (strcmp(buf, "4 3") !=3D 0) - return 1; - return 0; - }]])], - [pgac_cv_snprintf_arg_control=3Dyes], - [pgac_cv_snprintf_arg_control=3Dno], - [pgac_cv_snprintf_arg_control=3Dcross]) - ])dnl AC_CACHE_VAL - AC_MSG_RESULT([$pgac_cv_snprintf_arg_control]) - ])# PGAC_FUNC_SNPRINTF_ARG_CONTROL - = - # PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT - # --------------------------------- - # Determine if snprintf supports the z length modifier for printing - # size_t-sized variables. That's supported by C99 and POSIX but not - # all platforms play ball, so we must test whether it's working. - # - AC_DEFUN([PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT], - [AC_MSG_CHECKING([whether snprintf supports the %z modifier]) - AC_CACHE_VAL(pgac_cv_snprintf_size_t_support, - [AC_RUN_IFELSE([AC_LANG_SOURCE([[#include - #include - = - int main() - { - char bufz[100]; - char buf64[100]; - = - /* - * Print the largest unsigned number fitting in a size_t using both %z= u - * and the previously-determined format for 64-bit integers. Note tha= t - * we don't run this code unless we know snprintf handles 64-bit ints. - */ - bufz[0] =3D '\0'; /* in case snprintf fails to emit anything */ - snprintf(bufz, sizeof(bufz), "%zu", ~((size_t) 0)); - snprintf(buf64, sizeof(buf64), "%" INT64_MODIFIER "u", - (unsigned PG_INT64_TYPE) ~((size_t) 0)); - if (strcmp(bufz, buf64) !=3D 0) - return 1; - return 0; - }]])], - [pgac_cv_snprintf_size_t_support=3Dyes], - [pgac_cv_snprintf_size_t_support=3Dno], - [pgac_cv_snprintf_size_t_support=3Dcross]) - ])dnl AC_CACHE_VAL - AC_MSG_RESULT([$pgac_cv_snprintf_size_t_support]) - ])# PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT - = - # PGAC_FUNC_SNPRINTF_C99_RESULT - # ----------------------------- - # Determine whether snprintf returns the desired buffer length when - # it overruns the actual buffer length. That's required by C99 and POSI= X - # but ancient platforms don't behave that way, so we must test. - # While we're at it, let's just verify that it doesn't physically overru= n - # the buffer. - # - AC_DEFUN([PGAC_FUNC_SNPRINTF_C99_RESULT], - [AC_MSG_CHECKING([whether snprintf handles buffer overrun per C99]) - AC_CACHE_VAL(pgac_cv_snprintf_c99_result, - [AC_RUN_IFELSE([AC_LANG_SOURCE([[#include - #include - = - int main() - { - char buf[10]; - = - strcpy(buf, "abcdefghi"); - if (snprintf(buf, 4, "%d", 123456) !=3D 6) - return 1; - if (strcmp(buf, "123") !=3D 0 || buf[4] !=3D 'e') - return 1; - return 0; - }]])], - [pgac_cv_snprintf_c99_result=3Dyes], - [pgac_cv_snprintf_c99_result=3Dno], - [pgac_cv_snprintf_c99_result=3Dcross]) - ])dnl AC_CACHE_VAL - AC_MSG_RESULT([$pgac_cv_snprintf_c99_result]) - ])# PGAC_FUNC_SNPRINTF_C99_RESULT - = - = # PGAC_TYPE_LOCALE_T # ------------------ # Check for the locale_t type and find the right header file. macOS --- 171,176 ---- diff --git a/configure b/configure index 1aefc57..4eed2f4 100755 *** a/configure --- b/configure *************** $as_echo "#define HAVE_PS_STRINGS 1" >>c *** 15325,15421 **** fi = = - # We use our snprintf.c emulation if either snprintf() or vsnprintf() - # is missing. Yes, there are machines that have only one. We may - # also decide to use snprintf.c if snprintf() is present but does not - # have all the features we need --- see below. - = - if test "$PORTNAME" =3D "win32"; then - # Win32 gets snprintf.c built unconditionally. - # - # To properly translate all NLS languages strings, we must support the - # *printf() %$ format, which allows *printf() arguments to be selected - # by position in the translated string. - # - # libintl versions < 0.13 use the native *printf() functions, and Win3= 2 - # *printf() doesn't understand %$, so we must use our /port versions, - # which do understand %$. libintl versions >=3D 0.13 include their own - # *printf versions on Win32. The libintl 0.13 release note text is: - # - # C format strings with positions, as they arise when a translator - # needs to reorder a sentence, are now supported on all platforms. - # On those few platforms (NetBSD and Woe32) for which the native - # printf()/fprintf()/... functions don't support such format - # strings, replacements are provided through . - # - # We could use libintl >=3D 0.13's *printf() if we were sure that we h= ad - # a libintl >=3D 0.13 at runtime, but seeing that there is no clean wa= y - # to guarantee that, it is best to just use our own, so we are sure to - # get %$ support. In include/port.h we disable the *printf() macros - # that might have been defined by libintl. - # - # We do this unconditionally whether NLS is used or not so we are sure - # that all Win32 libraries and binaries behave the same. - pgac_need_repl_snprintf=3Dyes - else - pgac_need_repl_snprintf=3Dno - for ac_func in snprintf - do : - ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" - if test "x$ac_cv_func_snprintf" =3D xyes; then : - cat >>confdefs.h <<_ACEOF - #define HAVE_SNPRINTF 1 - _ACEOF - = - else - pgac_need_repl_snprintf=3Dyes - fi - done - = - for ac_func in vsnprintf - do : - ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf" - if test "x$ac_cv_func_vsnprintf" =3D xyes; then : - cat >>confdefs.h <<_ACEOF - #define HAVE_VSNPRINTF 1 - _ACEOF - = - else - pgac_need_repl_snprintf=3Dyes - fi - done - = - fi - = - = - # Check whether declares snprintf() and vsnprintf(); if not, - # include/c.h will provide declarations. Note this is a separate test - # from whether the functions exist in the C library --- there are - # systems that have the functions but don't bother to declare them :-( - = - ac_fn_c_check_decl "$LINENO" "snprintf" "ac_cv_have_decl_snprintf" "$ac_= includes_default" - if test "x$ac_cv_have_decl_snprintf" =3D xyes; then : - ac_have_decl=3D1 - else - ac_have_decl=3D0 - fi - = - cat >>confdefs.h <<_ACEOF - #define HAVE_DECL_SNPRINTF $ac_have_decl - _ACEOF - ac_fn_c_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$a= c_includes_default" - if test "x$ac_cv_have_decl_vsnprintf" =3D xyes; then : - ac_have_decl=3D1 - else - ac_have_decl=3D0 - fi - = - cat >>confdefs.h <<_ACEOF - #define HAVE_DECL_VSNPRINTF $ac_have_decl - _ACEOF - = - = - = { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isinf" >&5 $as_echo_n "checking for isinf... " >&6; } if ${ac_cv_func_isinf+:} false; then : --- 15325,15330 ---- *************** fi *** 16133,16185 **** # Run tests below here # -------------------- = - # For NLS, force use of our snprintf if system's doesn't do arg control. - # See comment above at snprintf test for details. - if test "$enable_nls" =3D yes -a "$pgac_need_repl_snprintf" =3D no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf sup= ports argument control" >&5 - $as_echo_n "checking whether snprintf supports argument control... " >&6= ; } - if ${pgac_cv_snprintf_arg_control+:} false; then : - $as_echo_n "(cached) " >&6 - else - if test "$cross_compiling" =3D yes; then : - pgac_cv_snprintf_arg_control=3Dcross - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - #include - = - int main() - { - char buf[100]; - = - /* can it swap arguments? */ - snprintf(buf, 100, "%2\$d %1\$d", 3, 4); - if (strcmp(buf, "4 3") !=3D 0) - return 1; - return 0; - } - _ACEOF - if ac_fn_c_try_run "$LINENO"; then : - pgac_cv_snprintf_arg_control=3Dyes - else - pgac_cv_snprintf_arg_control=3Dno - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext - fi - = - = - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_arg_c= ontrol" >&5 - $as_echo "$pgac_cv_snprintf_arg_control" >&6; } - = - if test $pgac_cv_snprintf_arg_control !=3D yes ; then - pgac_need_repl_snprintf=3Dyes - fi - fi - = - = = { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether long int is 64= bits" >&5 $as_echo_n "checking whether long int is 64 bits... " >&6; } --- 16042,16047 ---- *************** _ACEOF *** 16359,16366 **** = = # Select the printf length modifier that goes with that, too. - # (This used to be bound up with replacement-snprintf selection, but now - # we assume that the native *printf functions use standard length modifi= ers.) if test x"$pg_int64_type" =3D x"long long int" ; then INT64_MODIFIER=3D'"ll"' else --- 16221,16226 ---- *************** cat >>confdefs.h <<_ACEOF *** 16373,16492 **** _ACEOF = = - # Force use of our snprintf if the system's doesn't support the %z flag. - # (Note this test uses PG_INT64_TYPE and INT64_MODIFIER.) - if test "$pgac_need_repl_snprintf" =3D no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf sup= ports the %z modifier" >&5 - $as_echo_n "checking whether snprintf supports the %z modifier... " >&6;= } - if ${pgac_cv_snprintf_size_t_support+:} false; then : - $as_echo_n "(cached) " >&6 - else - if test "$cross_compiling" =3D yes; then : - pgac_cv_snprintf_size_t_support=3Dcross - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - #include - = - int main() - { - char bufz[100]; - char buf64[100]; - = - /* - * Print the largest unsigned number fitting in a size_t using both %z= u - * and the previously-determined format for 64-bit integers. Note tha= t - * we don't run this code unless we know snprintf handles 64-bit ints. - */ - bufz[0] =3D '\0'; /* in case snprintf fails to emit anything */ - snprintf(bufz, sizeof(bufz), "%zu", ~((size_t) 0)); - snprintf(buf64, sizeof(buf64), "%" INT64_MODIFIER "u", - (unsigned PG_INT64_TYPE) ~((size_t) 0)); - if (strcmp(bufz, buf64) !=3D 0) - return 1; - return 0; - } - _ACEOF - if ac_fn_c_try_run "$LINENO"; then : - pgac_cv_snprintf_size_t_support=3Dyes - else - pgac_cv_snprintf_size_t_support=3Dno - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext - fi - = - = - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_size_= t_support" >&5 - $as_echo "$pgac_cv_snprintf_size_t_support" >&6; } - = - if test "$pgac_cv_snprintf_size_t_support" !=3D yes; then - pgac_need_repl_snprintf=3Dyes - fi - fi - = - # Force use of our snprintf if the system's doesn't handle buffer overru= n - # as specified by C99. - if test "$pgac_need_repl_snprintf" =3D no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf han= dles buffer overrun per C99" >&5 - $as_echo_n "checking whether snprintf handles buffer overrun per C99... = " >&6; } - if ${pgac_cv_snprintf_c99_result+:} false; then : - $as_echo_n "(cached) " >&6 - else - if test "$cross_compiling" =3D yes; then : - pgac_cv_snprintf_c99_result=3Dcross - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include - #include - = - int main() - { - char buf[10]; - = - strcpy(buf, "abcdefghi"); - if (snprintf(buf, 4, "%d", 123456) !=3D 6) - return 1; - if (strcmp(buf, "123") !=3D 0 || buf[4] !=3D 'e') - return 1; - return 0; - } - _ACEOF - if ac_fn_c_try_run "$LINENO"; then : - pgac_cv_snprintf_c99_result=3Dyes - else - pgac_cv_snprintf_c99_result=3Dno - fi - rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext - fi - = - = - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_c99_r= esult" >&5 - $as_echo "$pgac_cv_snprintf_c99_result" >&6; } - = - if test "$pgac_cv_snprintf_c99_result" !=3D yes; then - pgac_need_repl_snprintf=3Dyes - fi - fi - = - # Now we have checked all the reasons to replace snprintf - if test $pgac_need_repl_snprintf =3D yes; then - = - $as_echo "#define USE_REPL_SNPRINTF 1" >>confdefs.h - = - case " $LIBOBJS " in - *" snprintf.$ac_objext "* ) ;; - *) LIBOBJS=3D"$LIBOBJS snprintf.$ac_objext" - ;; - esac - = - fi - = # has to be down here, rather than with the other builtins, because # the test uses PG_INT64_TYPE. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_mul_over= flow" >&5 --- 16233,16238 ---- diff --git a/configure.in b/configure.in index 3a23913..f4e0b07 100644 *** a/configure.in --- b/configure.in *************** if test "$pgac_cv_var_PS_STRINGS" =3D yes = *** 1595,1647 **** fi = = - # We use our snprintf.c emulation if either snprintf() or vsnprintf() - # is missing. Yes, there are machines that have only one. We may - # also decide to use snprintf.c if snprintf() is present but does not - # have all the features we need --- see below. - = - if test "$PORTNAME" =3D "win32"; then - # Win32 gets snprintf.c built unconditionally. - # - # To properly translate all NLS languages strings, we must support the - # *printf() %$ format, which allows *printf() arguments to be selected - # by position in the translated string. - # - # libintl versions < 0.13 use the native *printf() functions, and Win3= 2 - # *printf() doesn't understand %$, so we must use our /port versions, - # which do understand %$. libintl versions >=3D 0.13 include their own - # *printf versions on Win32. The libintl 0.13 release note text is: - # - # C format strings with positions, as they arise when a translator - # needs to reorder a sentence, are now supported on all platforms. - # On those few platforms (NetBSD and Woe32) for which the native - # printf()/fprintf()/... functions don't support such format - # strings, replacements are provided through . - # - # We could use libintl >=3D 0.13's *printf() if we were sure that we h= ad - # a libintl >=3D 0.13 at runtime, but seeing that there is no clean wa= y - # to guarantee that, it is best to just use our own, so we are sure to - # get %$ support. In include/port.h we disable the *printf() macros - # that might have been defined by libintl. - # - # We do this unconditionally whether NLS is used or not so we are sure - # that all Win32 libraries and binaries behave the same. - pgac_need_repl_snprintf=3Dyes - else - pgac_need_repl_snprintf=3Dno - AC_CHECK_FUNCS(snprintf, [], pgac_need_repl_snprintf=3Dyes) - AC_CHECK_FUNCS(vsnprintf, [], pgac_need_repl_snprintf=3Dyes) - fi - = - = - # Check whether declares snprintf() and vsnprintf(); if not, - # include/c.h will provide declarations. Note this is a separate test - # from whether the functions exist in the C library --- there are - # systems that have the functions but don't bother to declare them :-( - = - AC_CHECK_DECLS([snprintf, vsnprintf]) - = - = dnl Cannot use AC_CHECK_FUNC because isinf may be a macro AC_CACHE_CHECK([for isinf], ac_cv_func_isinf, [AC_LINK_IFELSE([AC_LANG_PROGRAM([ --- 1595,1600 ---- *************** for the exact reason.]])], *** 1811,1826 **** # Run tests below here # -------------------- = - # For NLS, force use of our snprintf if system's doesn't do arg control. - # See comment above at snprintf test for details. - if test "$enable_nls" =3D yes -a "$pgac_need_repl_snprintf" =3D no; then - PGAC_FUNC_SNPRINTF_ARG_CONTROL - if test $pgac_cv_snprintf_arg_control !=3D yes ; then - pgac_need_repl_snprintf=3Dyes - fi - fi - = - = dnl Check to see if we have a working 64-bit integer type. dnl Since Postgres 8.4, we no longer support compilers without a working dnl 64-bit type; but we have to determine whether that type is called --- 1764,1769 ---- *************** AC_DEFINE_UNQUOTED(PG_INT64_TYPE, $pg_in *** 1843,1850 **** [Define to the name of a signed 64-bit integer type.]) = # Select the printf length modifier that goes with that, too. - # (This used to be bound up with replacement-snprintf selection, but now - # we assume that the native *printf functions use standard length modifi= ers.) if test x"$pg_int64_type" =3D x"long long int" ; then INT64_MODIFIER=3D'"ll"' else --- 1786,1791 ---- *************** fi *** 1854,1883 **** AC_DEFINE_UNQUOTED(INT64_MODIFIER, $INT64_MODIFIER, [Define to the appropriate printf length modifier for= 64-bit ints.]) = - # Force use of our snprintf if the system's doesn't support the %z flag. - # (Note this test uses PG_INT64_TYPE and INT64_MODIFIER.) - if test "$pgac_need_repl_snprintf" =3D no; then - PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT - if test "$pgac_cv_snprintf_size_t_support" !=3D yes; then - pgac_need_repl_snprintf=3Dyes - fi - fi - = - # Force use of our snprintf if the system's doesn't handle buffer overru= n - # as specified by C99. - if test "$pgac_need_repl_snprintf" =3D no; then - PGAC_FUNC_SNPRINTF_C99_RESULT - if test "$pgac_cv_snprintf_c99_result" !=3D yes; then - pgac_need_repl_snprintf=3Dyes - fi - fi - = - # Now we have checked all the reasons to replace snprintf - if test $pgac_need_repl_snprintf =3D yes; then - AC_DEFINE(USE_REPL_SNPRINTF, 1, [Use replacement snprintf() functions.= ]) - AC_LIBOBJ(snprintf) - fi - = # has to be down here, rather than with the other builtins, because # the test uses PG_INT64_TYPE. PGAC_C_BUILTIN_OP_OVERFLOW --- 1795,1800 ---- diff --git a/src/backend/lib/stringinfo.c b/src/backend/lib/stringinfo.c index 798a823..df7e01f 100644 *** a/src/backend/lib/stringinfo.c --- b/src/backend/lib/stringinfo.c *************** resetStringInfo(StringInfo str) *** 77,88 **** --- 77,91 ---- void appendStringInfo(StringInfo str, const char *fmt,...) { + int save_errno =3D errno; + = for (;;) { va_list args; int needed; = /* Try to format the data. */ + errno =3D save_errno; va_start(args, fmt); needed =3D appendStringInfoVA(str, fmt, args); va_end(args); *************** appendStringInfo(StringInfo str, const c *** 105,110 **** --- 108,116 ---- * pass the return value to enlargeStringInfo() before trying again; see * appendStringInfo for standard usage pattern. * + * Caution: callers must be sure to preserve their entry-time errno + * when looping, in case the fmt contains "%m". + * * XXX This API is ugly, but there seems no alternative given the C spec= 's * restrictions on what can portably be done with va_list arguments: you= have * to redo va_start before you can rescan the argument list, and we can'= t do diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog= .c index 22e5d87..b9c1130 100644 *** a/src/backend/utils/error/elog.c --- b/src/backend/utils/error/elog.c *************** static void write_csvlog(ErrorData *edat *** 177,183 **** static void send_message_to_server_log(ErrorData *edata); static void write_pipe_chunks(char *data, int len, int dest); static void send_message_to_frontend(ErrorData *edata); - static char *expand_fmt_string(const char *fmt, ErrorData *edata); static const char *error_severity(int elevel); static void append_with_tabs(StringInfo buf, const char *str); static bool is_log_level_output(int elevel, int log_min_level); --- 177,182 ---- *************** errcode_for_socket_access(void) *** 705,717 **** */ #define EVALUATE_MESSAGE(domain, targetfield, appendval, translateit) \ { \ - char *fmtbuf; \ StringInfoData buf; \ /* Internationalize the error format string */ \ if ((translateit) && !in_error_recursion_trouble()) \ fmt =3D dgettext((domain), fmt); \ - /* Expand %m in format string */ \ - fmtbuf =3D expand_fmt_string(fmt, edata); \ initStringInfo(&buf); \ if ((appendval) && edata->targetfield) { \ appendStringInfoString(&buf, edata->targetfield); \ --- 704,713 ---- *************** errcode_for_socket_access(void) *** 722,736 **** { \ va_list args; \ int needed; \ va_start(args, fmt); \ ! needed =3D appendStringInfoVA(&buf, fmtbuf, args); \ va_end(args); \ if (needed =3D=3D 0) \ break; \ enlargeStringInfo(&buf, needed); \ } \ - /* Done with expanded fmt */ \ - pfree(fmtbuf); \ /* Save the completed message into the stack item */ \ if (edata->targetfield) \ pfree(edata->targetfield); \ --- 718,731 ---- { \ va_list args; \ int needed; \ + errno =3D edata->saved_errno; \ va_start(args, fmt); \ ! needed =3D appendStringInfoVA(&buf, fmt, args); \ va_end(args); \ if (needed =3D=3D 0) \ break; \ enlargeStringInfo(&buf, needed); \ } \ /* Save the completed message into the stack item */ \ if (edata->targetfield) \ pfree(edata->targetfield); \ *************** errcode_for_socket_access(void) *** 746,760 **** #define EVALUATE_MESSAGE_PLURAL(domain, targetfield, appendval) \ { \ const char *fmt; \ - char *fmtbuf; \ StringInfoData buf; \ /* Internationalize the error format string */ \ if (!in_error_recursion_trouble()) \ fmt =3D dngettext((domain), fmt_singular, fmt_plural, n); \ else \ fmt =3D (n =3D=3D 1 ? fmt_singular : fmt_plural); \ - /* Expand %m in format string */ \ - fmtbuf =3D expand_fmt_string(fmt, edata); \ initStringInfo(&buf); \ if ((appendval) && edata->targetfield) { \ appendStringInfoString(&buf, edata->targetfield); \ --- 741,752 ---- *************** errcode_for_socket_access(void) *** 765,779 **** { \ va_list args; \ int needed; \ va_start(args, n); \ ! needed =3D appendStringInfoVA(&buf, fmtbuf, args); \ va_end(args); \ if (needed =3D=3D 0) \ break; \ enlargeStringInfo(&buf, needed); \ } \ - /* Done with expanded fmt */ \ - pfree(fmtbuf); \ /* Save the completed message into the stack item */ \ if (edata->targetfield) \ pfree(edata->targetfield); \ --- 757,770 ---- { \ va_list args; \ int needed; \ + errno =3D edata->saved_errno; \ va_start(args, n); \ ! needed =3D appendStringInfoVA(&buf, fmt, args); \ va_end(args); \ if (needed =3D=3D 0) \ break; \ enlargeStringInfo(&buf, needed); \ } \ /* Save the completed message into the stack item */ \ if (edata->targetfield) \ pfree(edata->targetfield); \ *************** send_message_to_frontend(ErrorData *edat *** 3329,3387 **** = = /* - * expand_fmt_string --- process special format codes in a format string - * - * We must replace %m with the appropriate strerror string, since vsnpri= ntf - * won't know what to do with it. - * - * The result is a palloc'd string. - */ - static char * - expand_fmt_string(const char *fmt, ErrorData *edata) - { - StringInfoData buf; - const char *cp; - = - initStringInfo(&buf); - = - for (cp =3D fmt; *cp; cp++) - { - if (cp[0] =3D=3D '%' && cp[1] !=3D '\0') - { - cp++; - if (*cp =3D=3D 'm') - { - /* - * Replace %m by system error string. If there are any %'s in - * the string, we'd better double them so that vsnprintf won't - * misinterpret. - */ - const char *cp2; - = - cp2 =3D strerror(edata->saved_errno); - for (; *cp2; cp2++) - { - if (*cp2 =3D=3D '%') - appendStringInfoCharMacro(&buf, '%'); - appendStringInfoCharMacro(&buf, *cp2); - } - } - else - { - /* copy % and next char --- this avoids trouble with %%m */ - appendStringInfoCharMacro(&buf, '%'); - appendStringInfoCharMacro(&buf, *cp); - } - } - else - appendStringInfoCharMacro(&buf, *cp); - } - = - return buf.data; - } - = - = - /* * error_severity --- get string representing elevel * * The string is not localized here, but we mark the strings for transla= tion --- 3320,3325 ---- diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_bac= kup_archiver.c index 36e3383..267d86a 100644 *** a/src/bin/pg_dump/pg_backup_archiver.c --- b/src/bin/pg_dump/pg_backup_archiver.c *************** archputs(const char *s, Archive *AH) *** 1471,1476 **** --- 1471,1477 ---- int archprintf(Archive *AH, const char *fmt,...) { + int save_errno =3D errno; char *p; size_t len =3D 128; /* initial assumption about buffer size */ size_t cnt; *************** archprintf(Archive *AH, const char *fmt, *** 1483,1488 **** --- 1484,1490 ---- p =3D (char *) pg_malloc(len); = /* Try to format the data. */ + errno =3D save_errno; va_start(args, fmt); cnt =3D pvsnprintf(p, len, fmt, args); va_end(args); *************** RestoreOutput(ArchiveHandle *AH, OutputC *** 1604,1609 **** --- 1606,1612 ---- int ahprintf(ArchiveHandle *AH, const char *fmt,...) { + int save_errno =3D errno; char *p; size_t len =3D 128; /* initial assumption about buffer size */ size_t cnt; *************** ahprintf(ArchiveHandle *AH, const char * *** 1616,1621 **** --- 1619,1625 ---- p =3D (char *) pg_malloc(len); = /* Try to format the data. */ + errno =3D save_errno; va_start(args, fmt); cnt =3D pvsnprintf(p, len, fmt, args); va_end(args); diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_t= ar.c index 007be12..407a56d 100644 *** a/src/bin/pg_dump/pg_backup_tar.c --- b/src/bin/pg_dump/pg_backup_tar.c *************** _EndBlobs(ArchiveHandle *AH, TocEntry *t *** 1026,1031 **** --- 1026,1032 ---- static int tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...) { + int save_errno =3D errno; char *p; size_t len =3D 128; /* initial assumption about buffer size */ size_t cnt; *************** tarPrintf(ArchiveHandle *AH, TAR_MEMBER = *** 1038,1043 **** --- 1039,1045 ---- p =3D (char *) pg_malloc(len); = /* Try to format the data. */ + errno =3D save_errno; va_start(args, fmt); cnt =3D pvsnprintf(p, len, fmt, args); va_end(args); diff --git a/src/common/psprintf.c b/src/common/psprintf.c index 04465a1..2cf100f 100644 *** a/src/common/psprintf.c --- b/src/common/psprintf.c *************** *** 45,50 **** --- 45,51 ---- char * psprintf(const char *fmt,...) { + int save_errno =3D errno; size_t len =3D 128; /* initial assumption about buffer size */ = for (;;) *************** psprintf(const char *fmt,...) *** 60,65 **** --- 61,67 ---- result =3D (char *) palloc(len); = /* Try to format the data. */ + errno =3D save_errno; va_start(args, fmt); newlen =3D pvsnprintf(result, len, fmt, args); va_end(args); *************** psprintf(const char *fmt,...) *** 89,94 **** --- 91,99 ---- * Other error cases do not return, but exit via elog(ERROR) or exit(). * Hence, this shouldn't be used inside libpq. * + * Caution: callers must be sure to preserve their entry-time errno + * when looping, in case the fmt contains "%m". + * * Note that the semantics of the return value are not exactly C99's. * First, we don't promise that the estimated buffer size is exactly rig= ht; * callers must be prepared to loop multiple times to get the right size= . diff --git a/src/include/c.h b/src/include/c.h index 901d791..b255da6 100644 *** a/src/include/c.h --- b/src/include/c.h *************** typedef union PGAlignedXLogBlock *** 1114,1127 **** * standard C library. */ = - #if !HAVE_DECL_SNPRINTF - extern int snprintf(char *str, size_t count, const char *fmt,...) pg_att= ribute_printf(3, 4); - #endif - = - #if !HAVE_DECL_VSNPRINTF - extern int vsnprintf(char *str, size_t count, const char *fmt, va_list a= rgs); - #endif - = #if defined(HAVE_FDATASYNC) && !HAVE_DECL_FDATASYNC extern int fdatasync(int fildes); #endif --- 1114,1119 ---- diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 705c52b..254fa80 100644 *** a/src/include/pg_config.h.in --- b/src/include/pg_config.h.in *************** *** 166,175 **** don't. */ #undef HAVE_DECL_RTLD_NOW = - /* Define to 1 if you have the declaration of `snprintf', and to 0 if yo= u - don't. */ - #undef HAVE_DECL_SNPRINTF - = /* Define to 1 if you have the declaration of `strlcat', and to 0 if you don't. */ #undef HAVE_DECL_STRLCAT --- 166,171 ---- *************** *** 194,203 **** don't. */ #undef HAVE_DECL_SYS_SIGLIST = - /* Define to 1 if you have the declaration of `vsnprintf', and to 0 if y= ou - don't. */ - #undef HAVE_DECL_VSNPRINTF - = /* Define to 1 if you have the `dlopen' function. */ #undef HAVE_DLOPEN = --- 190,195 ---- *************** *** 507,515 **** /* Define to 1 if you have the `shm_open' function. */ #undef HAVE_SHM_OPEN = - /* Define to 1 if you have the `snprintf' function. */ - #undef HAVE_SNPRINTF - = /* Define to 1 if you have spinlocks. */ #undef HAVE_SPINLOCKS = --- 499,504 ---- *************** *** 712,720 **** /* Define to 1 if you have the header file. */ #undef HAVE_UUID_UUID_H = - /* Define to 1 if you have the `vsnprintf' function. */ - #undef HAVE_VSNPRINTF - = /* Define to 1 if you have the header file. */ #undef HAVE_WCHAR_H = --- 701,706 ---- *************** *** 923,931 **** /* Define to 1 to build with PAM support. (--with-pam) */ #undef USE_PAM = - /* Use replacement snprintf() functions. */ - #undef USE_REPL_SNPRINTF - = /* Define to 1 to use software CRC-32C implementation (slicing-by-8). */ #undef USE_SLICING_BY_8_CRC32C = --- 909,914 ---- diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32 index eafe377..92d648e 100644 *** a/src/include/pg_config.h.win32 --- b/src/include/pg_config.h.win32 *************** *** 135,144 **** don't. */ #define HAVE_DECL_RTLD_NOW 0 = - /* Define to 1 if you have the declaration of `snprintf', and to 0 if yo= u - don't. */ - #define HAVE_DECL_SNPRINTF 1 - = /* Define to 1 if you have the declaration of `strnlen', and to 0 if you don't. */ #define HAVE_DECL_STRNLEN 1 --- 135,140 ---- *************** *** 151,160 **** don't. */ #define HAVE_DECL_STRTOULL 1 = - /* Define to 1 if you have the declaration of `vsnprintf', and to 0 if y= ou - don't. */ - #define HAVE_DECL_VSNPRINTF 1 - = /* Define to 1 if you have the `dlopen' function. */ /* #undef HAVE_DLOPEN */ = --- 147,152 ---- *************** *** 373,381 **** /* Define to 1 if you have the `setsid' function. */ /* #undef HAVE_SETSID */ = - /* Define to 1 if you have the `snprintf' function. */ - /* #undef HAVE_SNPRINTF */ - = /* Define to 1 if you have spinlocks. */ #define HAVE_SPINLOCKS 1 = --- 365,370 ---- *************** *** 553,561 **** /* Define to 1 if you have the header file. */ #define HAVE_UTIME_H 1 = - /* Define to 1 if you have the `vsnprintf' function. */ - #define HAVE_VSNPRINTF 1 - = /* Define to 1 if you have the header file. */ #define HAVE_WCHAR_H 1 = --- 542,547 ---- *************** *** 712,720 **** /* Define to 1 to build with PAM support. (--with-pam) */ /* #undef USE_PAM */ = - /* Use replacement snprintf() functions. */ - #define USE_REPL_SNPRINTF 1 - = /* Define to 1 to use software CRC-32C implementation (slicing-by-8). */ #if (_MSC_VER < 1500) #define USE_SLICING_BY_8_CRC32C 1 --- 698,703 ---- diff --git a/src/include/port.h b/src/include/port.h index bffc773..0f0cd28 100644 *** a/src/include/port.h --- b/src/include/port.h *************** extern unsigned char pg_tolower(unsigned *** 134,140 **** extern unsigned char pg_ascii_toupper(unsigned char ch); extern unsigned char pg_ascii_tolower(unsigned char ch); = ! #ifdef USE_REPL_SNPRINTF = /* * Versions of libintl >=3D 0.13 try to replace printf() and friends wit= h --- 134,145 ---- extern unsigned char pg_ascii_toupper(unsigned char ch); extern unsigned char pg_ascii_tolower(unsigned char ch); = ! /* ! * Beginning in v12, we always replace snprintf() and friends with our o= wn ! * implementation. This symbol is no longer consulted by the core code, ! * but keep it defined anyway in case any extensions are looking at it. ! */ ! #define USE_REPL_SNPRINTF 1 = /* * Versions of libintl >=3D 0.13 try to replace printf() and friends wit= h *************** extern int pg_printf(const char *fmt,... *** 187,193 **** #define fprintf pg_fprintf #define printf pg_printf #endif - #endif /* USE_REPL_SNPRINTF */ = /* Replace strerror() with our own, somewhat more robust wrapper */ extern char *pg_strerror(int errnum); --- 192,197 ---- diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/= compatlib/Makefile index b7bd162..e07a7fa 100644 *** a/src/interfaces/ecpg/compatlib/Makefile --- b/src/interfaces/ecpg/compatlib/Makefile *************** SHLIB_EXPORTS =3D exports.txt *** 31,37 **** # Need to recompile any libpgport object files LIBS :=3D $(filter-out -lpgport, $(LIBS)) = ! OBJS=3D informix.o strerror.o $(filter snprintf.o strnlen.o, $(LIBOBJS))= $(WIN32RES) = PKG_CONFIG_REQUIRES_PRIVATE =3D libecpg libpgtypes = --- 31,38 ---- # Need to recompile any libpgport object files LIBS :=3D $(filter-out -lpgport, $(LIBS)) = ! OBJS=3D informix.o snprintf.o strerror.o \ ! $(filter strnlen.o, $(LIBOBJS)) $(WIN32RES) = PKG_CONFIG_REQUIRES_PRIVATE =3D libecpg libpgtypes = diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ec= pglib/Makefile index 005d25a..b381623 100644 *** a/src/interfaces/ecpg/ecpglib/Makefile --- b/src/interfaces/ecpg/ecpglib/Makefile *************** override CFLAGS +=3D $(PTHREAD_CFLAGS) *** 26,33 **** LIBS :=3D $(filter-out -lpgport, $(LIBS)) = OBJS=3D execute.o typename.o descriptor.o sqlda.o data.o error.o prepare= .o memory.o \ ! connect.o misc.o path.o pgstrcasecmp.o strerror.o \ ! $(filter snprintf.o strlcpy.o strnlen.o win32setlocale.o isinf.o, $(LIB= OBJS)) \ $(WIN32RES) = # thread.c is needed only for non-WIN32 implementation of path.c --- 26,33 ---- LIBS :=3D $(filter-out -lpgport, $(LIBS)) = OBJS=3D execute.o typename.o descriptor.o sqlda.o data.o error.o prepare= .o memory.o \ ! connect.o misc.o path.o pgstrcasecmp.o snprintf.o strerror.o \ ! $(filter strlcpy.o strnlen.o win32setlocale.o isinf.o, $(LIBOBJS)) \ $(WIN32RES) = # thread.c is needed only for non-WIN32 implementation of path.c diff --git a/src/interfaces/ecpg/pgtypeslib/Makefile b/src/interfaces/ecpg= /pgtypeslib/Makefile index 18b2402..15d7f33 100644 *** a/src/interfaces/ecpg/pgtypeslib/Makefile --- b/src/interfaces/ecpg/pgtypeslib/Makefile *************** SHLIB_LINK +=3D $(filter -lm, $(LIBS)) *** 30,37 **** SHLIB_EXPORTS =3D exports.txt = OBJS=3D numeric.o datetime.o common.o dt_common.o timestamp.o interval.o= \ ! pgstrcasecmp.o strerror.o \ ! $(filter rint.o snprintf.o strnlen.o, $(LIBOBJS)) \ string.o \ $(WIN32RES) = --- 30,37 ---- SHLIB_EXPORTS =3D exports.txt = OBJS=3D numeric.o datetime.o common.o dt_common.o timestamp.o interval.o= \ ! pgstrcasecmp.o snprintf.o strerror.o \ ! $(filter rint.o strnlen.o, $(LIBOBJS)) \ string.o \ $(WIN32RES) = diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index 8324f4f..a106088 100644 *** a/src/interfaces/libpq/Makefile --- b/src/interfaces/libpq/Makefile *************** OBJS=3D fe-auth.o fe-auth-scram.o fe-conne *** 36,44 **** libpq-events.o # libpgport C files we always use OBJS +=3D chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.= o \ ! strerror.o thread.o # libpgport C files that are needed if identified by configure ! OBJS +=3D $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o= system.o snprintf.o strlcpy.o strnlen.o win32error.o win32setlocale.o, $(= LIBOBJS)) = ifeq ($(enable_strong_random), yes) OBJS +=3D pg_strong_random.o --- 36,44 ---- libpq-events.o # libpgport C files we always use OBJS +=3D chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.= o \ ! snprintf.o strerror.o thread.o # libpgport C files that are needed if identified by configure ! OBJS +=3D $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o= system.o strlcpy.o strnlen.o win32error.o win32setlocale.o, $(LIBOBJS)) = ifeq ($(enable_strong_random), yes) OBJS +=3D pg_strong_random.o diff --git a/src/interfaces/libpq/pqexpbuffer.c b/src/interfaces/libpq/pqe= xpbuffer.c index 0814ec6..43c36c3 100644 *** a/src/interfaces/libpq/pqexpbuffer.c --- b/src/interfaces/libpq/pqexpbuffer.c *************** enlargePQExpBuffer(PQExpBuffer str, size *** 233,238 **** --- 233,239 ---- void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) { + int save_errno =3D errno; va_list args; bool done; = *************** printfPQExpBuffer(PQExpBuffer str, const *** 244,249 **** --- 245,251 ---- /* Loop in case we have to retry after enlarging the buffer. */ do { + errno =3D save_errno; va_start(args, fmt); done =3D appendPQExpBufferVA(str, fmt, args); va_end(args); *************** printfPQExpBuffer(PQExpBuffer str, const *** 261,266 **** --- 263,269 ---- void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) { + int save_errno =3D errno; va_list args; bool done; = *************** appendPQExpBuffer(PQExpBuffer str, const *** 270,275 **** --- 273,279 ---- /* Loop in case we have to retry after enlarging the buffer. */ do { + errno =3D save_errno; va_start(args, fmt); done =3D appendPQExpBufferVA(str, fmt, args); va_end(args); *************** appendPQExpBuffer(PQExpBuffer str, const *** 281,286 **** --- 285,293 ---- * Shared guts of printfPQExpBuffer/appendPQExpBuffer. * Attempt to format data and append it to str. Returns true if done * (either successful or hard failure), false if need to retry. + * + * Caution: callers must be sure to preserve their entry-time errno + * when looping, in case the fmt contains "%m". */ static bool appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) diff --git a/src/pl/plperl/plperl.h b/src/pl/plperl/plperl.h index e6241f0..f8888a4 100644 *** a/src/pl/plperl/plperl.h --- b/src/pl/plperl/plperl.h *************** *** 29,39 **** * Sometimes perl carefully scribbles on our *printf macros. * So we undefine them here and redefine them after it's done its dirty = deed. */ - = - #ifdef USE_REPL_SNPRINTF #undef snprintf #undef vsnprintf - #endif = /* * ActivePerl 5.18 and later are MinGW-built, and their headers use GCC'= s --- 29,36 ---- *************** *** 99,105 **** #endif = /* put back our snprintf and vsnprintf */ - #ifdef USE_REPL_SNPRINTF #ifdef snprintf #undef snprintf #endif --- 96,101 ---- *************** *** 113,119 **** #define vsnprintf pg_vsnprintf #define snprintf pg_snprintf #endif /* __GNUC__ */ - #endif /* USE_REPL_SNPRINTF */ = /* perl version and platform portability */ #define NEED_eval_pv --- 109,114 ---- diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c index e244104..3814a6c 100644 *** a/src/pl/plpython/plpy_elog.c --- b/src/pl/plpython/plpy_elog.c *************** static bool set_string_attr(PyObject *ob *** 46,51 **** --- 46,52 ---- void PLy_elog_impl(int elevel, const char *fmt,...) { + int save_errno =3D errno; char *xmsg; char *tbmsg; int tb_depth; *************** PLy_elog_impl(int elevel, const char *fm *** 96,101 **** --- 97,103 ---- va_list ap; int needed; = + errno =3D save_errno; va_start(ap, fmt); needed =3D appendStringInfoVA(&emsg, dgettext(TEXTDOMAIN, fmt), ap); va_end(ap); diff --git a/src/pl/plpython/plpython.h b/src/pl/plpython/plpython.h index 6cc323a..aefbfc2 100644 *** a/src/pl/plpython/plpython.h --- b/src/pl/plpython/plpython.h *************** *** 33,43 **** * Sometimes python carefully scribbles on our *printf macros. * So we undefine them here and redefine them after it's done its dirty = deed. */ - = - #ifdef USE_REPL_SNPRINTF #undef snprintf #undef vsnprintf - #endif = #if defined(_MSC_VER) && defined(_DEBUG) /* Python uses #pragma to bring in a non-default libpython on VC++ if --- 33,40 ---- *************** typedef int Py_ssize_t; *** 124,130 **** #include = /* put back our snprintf and vsnprintf */ - #ifdef USE_REPL_SNPRINTF #ifdef snprintf #undef snprintf #endif --- 121,126 ---- *************** typedef int Py_ssize_t; *** 138,144 **** #define vsnprintf pg_vsnprintf #define snprintf pg_snprintf #endif /* __GNUC__ */ - #endif /* USE_REPL_SNPRINTF */ = /* * Used throughout, and also by the Python 2/3 porting layer, so it's ea= sier to --- 134,139 ---- diff --git a/src/port/Makefile b/src/port/Makefile index b3a10ba..a2ee8e2 100644 *** a/src/port/Makefile --- b/src/port/Makefile *************** LIBS +=3D $(PTHREAD_LIBS) *** 33,39 **** OBJS =3D $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_nto= p.o \ noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \ pgstrcasecmp.o pqsignal.o \ ! qsort.o qsort_arg.o quotes.o sprompt.o strerror.o tar.o thread.o = ifeq ($(enable_strong_random), yes) OBJS +=3D pg_strong_random.o --- 33,40 ---- OBJS =3D $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_nto= p.o \ noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \ pgstrcasecmp.o pqsignal.o \ ! qsort.o qsort_arg.o quotes.o snprintf.o sprompt.o strerror.o \ ! tar.o thread.o = ifeq ($(enable_strong_random), yes) OBJS +=3D pg_strong_random.o diff --git a/src/port/README b/src/port/README index 4ae96da..c446b46 100644 *** a/src/port/README --- b/src/port/README *************** and adding infrastructure to recompile t *** 18,24 **** = OBJS=3D execute.o typename.o descriptor.o data.o error.o prepare= .o memory.o \ connect.o misc.o path.o exec.o \ ! $(filter snprintf.o, $(LIBOBJS)) = The problem is that there is no testing of which object files need to be added, but missing functions usually show up when linking user --- 18,24 ---- = OBJS=3D execute.o typename.o descriptor.o data.o error.o prepare= .o memory.o \ connect.o misc.o path.o exec.o \ ! $(filter strlcat.o, $(LIBOBJS)) = The problem is that there is no testing of which object files need to be added, but missing functions usually show up when linking user diff --git a/src/port/snprintf.c b/src/port/snprintf.c index 851e2ae..63cec5d 100644 *** a/src/port/snprintf.c --- b/src/port/snprintf.c *************** *** 64,69 **** --- 64,77 ---- * * 5. Space and '#' flags are not implemented. * + * In addition, we support some extensions over C99: + * + * 1. Argument order control through "%n$" and "*n$", as required by POS= IX. + * + * 2. "%m" expands to the value of strerror(errno), where errno is the + * value that variable had at the start of the call. This is a glibc + * extension, but a very useful one. + * * * Historically the result values of sprintf/snprintf varied across plat= forms. * This implementation now follows the C99 standard: *************** static void flushbuffer(PrintfTarget *ta *** 155,160 **** --- 163,175 ---- static void dopr(PrintfTarget *target, const char *format, va_list args)= ; = = + /* + * Externally visible entry points. + * + * All of these are just wrappers around dopr(). Note it's essential th= at + * they not change the value of "errno" before reaching dopr(). + */ + = int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) { *************** static void trailing_pad(int *padlen, Pr *** 315,325 **** = = /* ! * dopr(): poor man's version of doprintf */ static void dopr(PrintfTarget *target, const char *format, va_list args) { const char *format_start =3D format; int ch; bool have_dollar; --- 330,341 ---- = = /* ! * dopr(): the guts of *printf for all cases. */ static void dopr(PrintfTarget *target, const char *format, va_list args) { + int save_errno =3D errno; const char *format_start =3D format; int ch; bool have_dollar; *************** nextch1: *** 497,502 **** --- 513,519 ---- else have_non_dollar =3D true; break; + case 'm': case '%': break; } *************** nextch2: *** 802,807 **** --- 819,831 ---- precision, pointflag, target); break; + case 'm': + { + const char *errm =3D strerror(save_errno); + = + dostr(errm, strlen(errm), target); + } + break; case '%': dopr_outch('%', target); break; ------- =_aaaaaaaaaa0--