From: Tom Lane <tgl@sss.pgh.pa.us>
To: Michael Paquier <michael@paquier.xyz>
Cc: Thomas Munro <thomas.munro@enterprisedb.com>
Cc: Alvaro Herrera <alvherre@2ndquadrant.com>
Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Subject: Re: Allowing printf("%m") only where it actually works
Date: Wed, 12 Sep 2018 13:40:01 -0400
Message-ID: <1304.1536774001@sss.pgh.pa.us> (raw)
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>
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
Attachments:download all (2 files, .tar.gz)0001-create-strerror-wrapper-2.patch (text/x-diff, 28.6K) downloaddiff --git a/configure b/configureindex 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.inindex 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.cindex 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.cindex 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.inindex 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.win32index 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.hindex 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.hindex 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/.gitignoreindex 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/Makefileindex 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/.gitignoreindex 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/Makefileindex 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/.gitignoreindex 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/Makefileindex 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/Makefileindex 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.o win32error.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.o win32setlocale.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.hindex 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/Makefileindex 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.cindex 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.pmindex 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');
0002-migrate-percent-m-implementation-2.patch (text/x-diff, 45.5K) downloaddiff --git a/config/c-compiler.m4 b/config/c-compiler.m4index 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.m4index 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/configureindex 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.inindex 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.cindex 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.cindex 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.cindex 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.cindex 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.cindex 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.hindex 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.inindex 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.win32index 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.hindex 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/Makefileindex 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/Makefileindex 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/Makefileindex 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/Makefileindex 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.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 \
! 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.cindex 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.hindex 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.cindex 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.hindex 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/Makefileindex 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/READMEindex 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.cindex 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;
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: tgl@sss.pgh.pa.us, michael@paquier.xyz, thomas.munro@enterprisedb.com, alvherre@2ndquadrant.com, pgsql-hackers@lists.postgresql.org
Subject: Re: Allowing printf("%m") only where it actually works
In-Reply-To: <1304.1536774001@sss.pgh.pa.us>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox