Re: Allowing printf("%m") only where it actually works - Mailing list pgsql-hackers
From | Tom Lane |
---|---|
Subject | Re: Allowing printf("%m") only where it actually works |
Date | |
Msg-id | 1304.1536774001@sss.pgh.pa.us Whole thread Raw |
In response to | Re: Allowing printf("%m") only where it actually works (Michael Paquier <michael@paquier.xyz>) |
Responses |
Re: Allowing printf("%m") only where it actually works
|
List | pgsql-hackers |
Michael Paquier <michael@paquier.xyz> 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 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" = xyes; then : - $as_echo "#define HAVE_STRERROR 1" >>confdefs.h - - else - case " $LIBOBJS " in - *" strerror.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS strerror.$ac_objext" - ;; - esac - - fi - ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" if test "x$ac_cv_func_strlcat" = 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 random 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 random rint srandom strlcat strlcpy strnlen]) case $host_os in diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.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 = INVALID_HANDLE_VALUE; - - if (handleDLL == INVALID_HANDLE_VALUE) - { - handleDLL = LoadLibraryEx("netmsg.dll", NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); - if (handleDLL == NULL) - ereport(FATAL, - (errmsg_internal("could not load netmsg.dll: error code %lu", GetLastError()))); - } - - 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) == 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 = useful_strerror(edata->saved_errno); for (; *cp2; cp2++) { if (*cp2 == '%') --- 3358,3364 ---- */ const char *cp2; ! cp2 = strerror(edata->saved_errno); for (; *cp2; cp2++) { if (*cp2 == '%') *************** 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 >= 10000 && errnum <= 11999) - return pgwin32_socket_strerror(errnum); - #endif - str = strerror(errnum); - - /* - * Some strerror()s return an empty string for out-of-range errno. This - * 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 == NULL || *str == '\0' || *str == '?') - str = get_errno_symbol(errnum); - - if (str == NULL) - { - snprintf(errorstr_buf, sizeof(errorstr_buf), - /*------ - translator: This string will be truncated at 47 - characters expanded. */ - _("operating system error %d"), errnum); - str = 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 != 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 != ENOTSUP)) - 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 != EAGAIN)) - 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 translation --- 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 <stdlib.h> 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 <stdlib.h> 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 <errno.h>. * * We redefine network-related Berkeley error symbols as the corresponding WSA ! * constants. This allows elog.c to recognize them as being in the Winsock ! * error code range and pass them off to pgwin32_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 errors. * See TranslateSocketError() when changing this list. --- 322,329 ---- * Supplement to <errno.h>. * * We redefine network-related Berkeley error symbols as the corresponding WSA ! * constants. This allows strerror.c to recognize them as being in the Winsock ! * 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 errors. * 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/ecpg/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 = exports.txt *** 31,37 **** # Need to recompile any libpgport object files LIBS := $(filter-out -lpgport, $(LIBS)) ! OBJS= informix.o $(filter snprintf.o strnlen.o, $(LIBOBJS)) $(WIN32RES) PKG_CONFIG_REQUIRES_PRIVATE = libecpg libpgtypes --- 31,37 ---- # Need to recompile any libpgport object files LIBS := $(filter-out -lpgport, $(LIBS)) ! OBJS= informix.o strerror.o $(filter snprintf.o strnlen.o, $(LIBOBJS)) $(WIN32RES) PKG_CONFIG_REQUIRES_PRIVATE = 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/ecpglib/Makefile index d25d248..005d25a 100644 *** a/src/interfaces/ecpg/ecpglib/Makefile --- b/src/interfaces/ecpg/ecpglib/Makefile *************** override CFLAGS += $(PTHREAD_CFLAGS) *** 26,32 **** LIBS := $(filter-out -lpgport, $(LIBS)) OBJS= 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, $(LIBOBJS)) \ $(WIN32RES) --- 26,32 ---- LIBS := $(filter-out -lpgport, $(LIBS)) OBJS= 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, $(LIBOBJS)) \ $(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 win32setlocale.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 win32setlocale.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 thread.c win32setlocale.c isinf.c maintainer-clean: distclean maintainer-clean-lib diff --git a/src/interfaces/ecpg/pgtypeslib/.gitignore b/src/interfaces/ecpg/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 += $(filter -lm, $(LIBS)) *** 30,36 **** SHLIB_EXPORTS = exports.txt OBJS= 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 = exports.txt OBJS= 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 string.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= fe-auth.o fe-auth-scram.o fe-conne *** 36,44 **** libpq-events.o # libpgport C files we always use OBJS += 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 += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o system.o snprintf.o strerror.o strlcpy.o strnlen.owin32error.o win32setlocale.o, $(LIBOBJS)) ifeq ($(enable_strong_random), yes) OBJS += pg_strong_random.o --- 36,44 ---- libpq-events.o # libpgport C files we always use OBJS += 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 += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o system.o snprintf.o strlcpy.o strnlen.o win32error.owin32setlocale.o, $(LIBOBJS)) ifeq ($(enable_strong_random), yes) OBJS += 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 += $(PTHREAD_LIBS) *** 33,39 **** OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.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 += pg_strong_random.o --- 33,39 ---- OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.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 += 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_strerror + */ + #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 >= 10000 && errnum <= 11999) ! return win32_socket_strerror(errnum); ! #endif ! ! /* Try the platform's strerror() */ ! str = strerror(errnum); ! ! /* ! * Some strerror()s return an empty string for out-of-range errno. This ! * 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 == NULL || *str == '\0' || *str == '?') ! str = get_errno_symbol(errnum); ! ! if (str == NULL) { ! snprintf(errorstr_buf, sizeof(errorstr_buf), ! /*------ ! translator: This string will be truncated at 47 ! characters expanded. */ ! _("operating system error %d"), errnum); ! str = 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 != 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 != ENOTSUP)) + 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 != EAGAIN)) + case EWOULDBLOCK: + return "EWOULDBLOCK"; + #endif + case EXDEV: + return "EXDEV"; + } + + return NULL; + } + + + #ifdef WIN32 + + /* + * Windows' strerror() doesn't know the Winsock codes, so handle them this way + */ + static char * + win32_socket_strerror(int errnum) + { + static char wserrbuf[256]; + static HANDLE handleDLL = INVALID_HANDLE_VALUE; + + if (handleDLL == INVALID_HANDLE_VALUE) + { + handleDLL = LoadLibraryEx("netmsg.dll", NULL, + DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); + if (handleDLL == 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) == 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'); 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 functions. ! # We prefer "gnu_printf", which matches the features glibc supports, notably ! # %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 here 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=$ac_c_werror_flag --- 20,27 ---- # PGAC_C_PRINTF_ARCHETYPE # ----------------------- # Select the format archetype to be used by gcc to check printf-type functions. ! # We prefer "gnu_printf", as that most closely matches the features supported ! # 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=$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$ selects - # 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 <stdio.h> - #include <string.h> - - int main() - { - char buf[100]; - - /* can it swap arguments? */ - snprintf(buf, 100, "%2\$d %1\$d", 3, 4); - if (strcmp(buf, "4 3") != 0) - return 1; - return 0; - }]])], - [pgac_cv_snprintf_arg_control=yes], - [pgac_cv_snprintf_arg_control=no], - [pgac_cv_snprintf_arg_control=cross]) - ])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 <stdio.h> - #include <string.h> - - int main() - { - char bufz[100]; - char buf64[100]; - - /* - * Print the largest unsigned number fitting in a size_t using both %zu - * and the previously-determined format for 64-bit integers. Note that - * we don't run this code unless we know snprintf handles 64-bit ints. - */ - bufz[0] = '\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) != 0) - return 1; - return 0; - }]])], - [pgac_cv_snprintf_size_t_support=yes], - [pgac_cv_snprintf_size_t_support=no], - [pgac_cv_snprintf_size_t_support=cross]) - ])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 POSIX - # 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 overrun - # 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 <stdio.h> - #include <string.h> - - int main() - { - char buf[10]; - - strcpy(buf, "abcdefghi"); - if (snprintf(buf, 4, "%d", 123456) != 6) - return 1; - if (strcmp(buf, "123") != 0 || buf[4] != 'e') - return 1; - return 0; - }]])], - [pgac_cv_snprintf_c99_result=yes], - [pgac_cv_snprintf_c99_result=no], - [pgac_cv_snprintf_c99_result=cross]) - ])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" = "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 Win32 - # *printf() doesn't understand %$, so we must use our /port versions, - # which do understand %$. libintl versions >= 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 <libintl.h>. - # - # We could use libintl >= 0.13's *printf() if we were sure that we had - # a libintl >= 0.13 at runtime, but seeing that there is no clean way - # 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=yes - else - pgac_need_repl_snprintf=no - for ac_func in snprintf - do : - ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" - if test "x$ac_cv_func_snprintf" = xyes; then : - cat >>confdefs.h <<_ACEOF - #define HAVE_SNPRINTF 1 - _ACEOF - - else - pgac_need_repl_snprintf=yes - 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" = xyes; then : - cat >>confdefs.h <<_ACEOF - #define HAVE_VSNPRINTF 1 - _ACEOF - - else - pgac_need_repl_snprintf=yes - fi - done - - fi - - - # Check whether <stdio.h> 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" = xyes; then : - ac_have_decl=1 - else - ac_have_decl=0 - 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" "$ac_includes_default" - if test "x$ac_cv_have_decl_vsnprintf" = xyes; then : - ac_have_decl=1 - else - ac_have_decl=0 - 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" = yes -a "$pgac_need_repl_snprintf" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf supports 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" = yes; then : - pgac_cv_snprintf_arg_control=cross - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include <stdio.h> - #include <string.h> - - int main() - { - char buf[100]; - - /* can it swap arguments? */ - snprintf(buf, 100, "%2\$d %1\$d", 3, 4); - if (strcmp(buf, "4 3") != 0) - return 1; - return 0; - } - _ACEOF - if ac_fn_c_try_run "$LINENO"; then : - pgac_cv_snprintf_arg_control=yes - else - pgac_cv_snprintf_arg_control=no - 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_control" >&5 - $as_echo "$pgac_cv_snprintf_arg_control" >&6; } - - if test $pgac_cv_snprintf_arg_control != yes ; then - pgac_need_repl_snprintf=yes - 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 modifiers.) if test x"$pg_int64_type" = x"long long int" ; then INT64_MODIFIER='"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" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf supports 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" = yes; then : - pgac_cv_snprintf_size_t_support=cross - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include <stdio.h> - #include <string.h> - - int main() - { - char bufz[100]; - char buf64[100]; - - /* - * Print the largest unsigned number fitting in a size_t using both %zu - * and the previously-determined format for 64-bit integers. Note that - * we don't run this code unless we know snprintf handles 64-bit ints. - */ - bufz[0] = '\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) != 0) - return 1; - return 0; - } - _ACEOF - if ac_fn_c_try_run "$LINENO"; then : - pgac_cv_snprintf_size_t_support=yes - else - pgac_cv_snprintf_size_t_support=no - 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" != yes; then - pgac_need_repl_snprintf=yes - fi - fi - - # Force use of our snprintf if the system's doesn't handle buffer overrun - # as specified by C99. - if test "$pgac_need_repl_snprintf" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf handles 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" = yes; then : - pgac_cv_snprintf_c99_result=cross - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - #include <stdio.h> - #include <string.h> - - int main() - { - char buf[10]; - - strcpy(buf, "abcdefghi"); - if (snprintf(buf, 4, "%d", 123456) != 6) - return 1; - if (strcmp(buf, "123") != 0 || buf[4] != 'e') - return 1; - return 0; - } - _ACEOF - if ac_fn_c_try_run "$LINENO"; then : - pgac_cv_snprintf_c99_result=yes - else - pgac_cv_snprintf_c99_result=no - 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_result" >&5 - $as_echo "$pgac_cv_snprintf_c99_result" >&6; } - - if test "$pgac_cv_snprintf_c99_result" != yes; then - pgac_need_repl_snprintf=yes - fi - fi - - # Now we have checked all the reasons to replace snprintf - if test $pgac_need_repl_snprintf = yes; then - - $as_echo "#define USE_REPL_SNPRINTF 1" >>confdefs.h - - case " $LIBOBJS " in - *" snprintf.$ac_objext "* ) ;; - *) LIBOBJS="$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_overflow" >&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" = 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" = "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 Win32 - # *printf() doesn't understand %$, so we must use our /port versions, - # which do understand %$. libintl versions >= 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 <libintl.h>. - # - # We could use libintl >= 0.13's *printf() if we were sure that we had - # a libintl >= 0.13 at runtime, but seeing that there is no clean way - # 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=yes - else - pgac_need_repl_snprintf=no - AC_CHECK_FUNCS(snprintf, [], pgac_need_repl_snprintf=yes) - AC_CHECK_FUNCS(vsnprintf, [], pgac_need_repl_snprintf=yes) - fi - - - # Check whether <stdio.h> 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" = yes -a "$pgac_need_repl_snprintf" = no; then - PGAC_FUNC_SNPRINTF_ARG_CONTROL - if test $pgac_cv_snprintf_arg_control != yes ; then - pgac_need_repl_snprintf=yes - 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 modifiers.) if test x"$pg_int64_type" = x"long long int" ; then INT64_MODIFIER='"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" = no; then - PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT - if test "$pgac_cv_snprintf_size_t_support" != yes; then - pgac_need_repl_snprintf=yes - fi - fi - - # Force use of our snprintf if the system's doesn't handle buffer overrun - # as specified by C99. - if test "$pgac_need_repl_snprintf" = no; then - PGAC_FUNC_SNPRINTF_C99_RESULT - if test "$pgac_cv_snprintf_c99_result" != yes; then - pgac_need_repl_snprintf=yes - fi - fi - - # Now we have checked all the reasons to replace snprintf - if test $pgac_need_repl_snprintf = 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 = errno; + for (;;) { va_list args; int needed; /* Try to format the data. */ + errno = save_errno; va_start(args, fmt); needed = 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 = dgettext((domain), fmt); \ - /* Expand %m in format string */ \ - fmtbuf = 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 = appendStringInfoVA(&buf, fmtbuf, args); \ va_end(args); \ if (needed == 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 = edata->saved_errno; \ va_start(args, fmt); \ ! needed = appendStringInfoVA(&buf, fmt, args); \ va_end(args); \ if (needed == 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 = dngettext((domain), fmt_singular, fmt_plural, n); \ else \ fmt = (n == 1 ? fmt_singular : fmt_plural); \ - /* Expand %m in format string */ \ - fmtbuf = 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 = appendStringInfoVA(&buf, fmtbuf, args); \ va_end(args); \ if (needed == 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 = edata->saved_errno; \ va_start(args, n); \ ! needed = appendStringInfoVA(&buf, fmt, args); \ va_end(args); \ if (needed == 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 vsnprintf - * 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 = fmt; *cp; cp++) - { - if (cp[0] == '%' && cp[1] != '\0') - { - cp++; - if (*cp == '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 = strerror(edata->saved_errno); - for (; *cp2; cp2++) - { - if (*cp2 == '%') - 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 translation --- 3320,3325 ---- diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_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 = errno; char *p; size_t len = 128; /* initial assumption about buffer size */ size_t cnt; *************** archprintf(Archive *AH, const char *fmt, *** 1483,1488 **** --- 1484,1490 ---- p = (char *) pg_malloc(len); /* Try to format the data. */ + errno = save_errno; va_start(args, fmt); cnt = 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 = errno; char *p; size_t len = 128; /* initial assumption about buffer size */ size_t cnt; *************** ahprintf(ArchiveHandle *AH, const char * *** 1616,1621 **** --- 1619,1625 ---- p = (char *) pg_malloc(len); /* Try to format the data. */ + errno = save_errno; va_start(args, fmt); cnt = 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_tar.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 = errno; char *p; size_t len = 128; /* initial assumption about buffer size */ size_t cnt; *************** tarPrintf(ArchiveHandle *AH, TAR_MEMBER *** 1038,1043 **** --- 1039,1045 ---- p = (char *) pg_malloc(len); /* Try to format the data. */ + errno = save_errno; va_start(args, fmt); cnt = 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 = errno; size_t len = 128; /* initial assumption about buffer size */ for (;;) *************** psprintf(const char *fmt,...) *** 60,65 **** --- 61,67 ---- result = (char *) palloc(len); /* Try to format the data. */ + errno = save_errno; va_start(args, fmt); newlen = 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 right; * 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_attribute_printf(3, 4); - #endif - - #if !HAVE_DECL_VSNPRINTF - extern int vsnprintf(char *str, size_t count, const char *fmt, va_list args); - #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 you - 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 you - 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 <uuid/uuid.h> 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 <wchar.h> 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 you - 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 you - 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 <utime.h> 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 <wchar.h> 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 >= 0.13 try to replace printf() and friends with --- 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 own ! * 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 >= 0.13 try to replace printf() and friends with *************** 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 = exports.txt *** 31,37 **** # Need to recompile any libpgport object files LIBS := $(filter-out -lpgport, $(LIBS)) ! OBJS= informix.o strerror.o $(filter snprintf.o strnlen.o, $(LIBOBJS)) $(WIN32RES) PKG_CONFIG_REQUIRES_PRIVATE = libecpg libpgtypes --- 31,38 ---- # Need to recompile any libpgport object files LIBS := $(filter-out -lpgport, $(LIBS)) ! OBJS= informix.o snprintf.o strerror.o \ ! $(filter strnlen.o, $(LIBOBJS)) $(WIN32RES) PKG_CONFIG_REQUIRES_PRIVATE = libecpg libpgtypes diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ecpglib/Makefile index 005d25a..b381623 100644 *** a/src/interfaces/ecpg/ecpglib/Makefile --- b/src/interfaces/ecpg/ecpglib/Makefile *************** override CFLAGS += $(PTHREAD_CFLAGS) *** 26,33 **** LIBS := $(filter-out -lpgport, $(LIBS)) OBJS= 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, $(LIBOBJS)) \ $(WIN32RES) # thread.c is needed only for non-WIN32 implementation of path.c --- 26,33 ---- LIBS := $(filter-out -lpgport, $(LIBS)) OBJS= 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 += $(filter -lm, $(LIBS)) *** 30,37 **** SHLIB_EXPORTS = exports.txt OBJS= 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 = exports.txt OBJS= 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= fe-auth.o fe-auth-scram.o fe-conne *** 36,44 **** libpq-events.o # libpgport C files we always use OBJS += 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 += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o system.o snprintf.o strlcpy.o strnlen.o win32error.owin32setlocale.o, $(LIBOBJS)) ifeq ($(enable_strong_random), yes) OBJS += pg_strong_random.o --- 36,44 ---- libpq-events.o # libpgport C files we always use OBJS += 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 += $(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 += pg_strong_random.o diff --git a/src/interfaces/libpq/pqexpbuffer.c b/src/interfaces/libpq/pqexpbuffer.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 = 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 = save_errno; va_start(args, fmt); done = 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 = 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 = save_errno; va_start(args, fmt); done = 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 = 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 = save_errno; va_start(ap, fmt); needed = 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 <eval.h> /* 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 easier 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 += $(PTHREAD_LIBS) *** 33,39 **** OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.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 += pg_strong_random.o --- 33,40 ---- OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.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 += 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= 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= 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 POSIX. + * + * 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 platforms. * 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 that + * 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 = 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 = errno; const char *format_start = format; int ch; bool have_dollar; *************** nextch1: *** 497,502 **** --- 513,519 ---- else have_non_dollar = true; break; + case 'm': case '%': break; } *************** nextch2: *** 802,807 **** --- 819,831 ---- precision, pointflag, target); break; + case 'm': + { + const char *errm = strerror(save_errno); + + dostr(errm, strlen(errm), target); + } + break; case '%': dopr_outch('%', target); break;
pgsql-hackers by date: