diff --git a/src/include/port.h b/src/include/port.h index f9b4a16c0af647d028fb240ff14cbcc2773b8440..3f187159cb3421b0f0e13a27cf9394a498a44078 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -126,12 +126,11 @@ extern unsigned char pg_tolower(unsigned char ch); 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 - * macros to their own versions that understand the %$ format. We do the - * same, so disable their macros, if they exist. + * Capture macro-compatible calls to printf() and friends, and redirect them + * to wrappers that throw errors in lieu of reporting failure in a return + * value. Versions of libintl >= 0.13 similarly redirect to versions that + * understand the %$ format, so disable libintl macros first. */ #ifdef vsnprintf #undef vsnprintf @@ -155,36 +154,63 @@ extern unsigned char pg_ascii_tolower(unsigned char ch); #undef printf #endif -extern int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args); -extern int pg_snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3, 4); -extern int pg_vsprintf(char *str, const char *fmt, va_list args); -extern int pg_sprintf(char *str, const char *fmt,...) pg_attribute_printf(2, 3); -extern int pg_vfprintf(FILE *stream, const char *fmt, va_list args); -extern int pg_fprintf(FILE *stream, const char *fmt,...) pg_attribute_printf(2, 3); -extern int pg_printf(const char *fmt,...) pg_attribute_printf(1, 2); +extern int +vsnprintf_throw_on_fail(char *str, size_t count, const char *fmt, va_list args) +pg_attribute_printf(3, 0); +extern int +snprintf_throw_on_fail(char *str, size_t count, const char *fmt,...) +pg_attribute_printf(3, 4); +extern int +vsprintf_throw_on_fail(char *str, const char *fmt, va_list args) +pg_attribute_printf(2, 0); +extern int +sprintf_throw_on_fail(char *str, const char *fmt,...) +pg_attribute_printf(2, 3); +extern int +vfprintf_throw_on_fail(FILE *stream, const char *fmt, va_list args) +pg_attribute_printf(2, 0); +extern int +fprintf_throw_on_fail(FILE *stream, const char *fmt,...) +pg_attribute_printf(2, 3); +extern int +printf_throw_on_fail(const char *fmt,...) +pg_attribute_printf(1, 2); /* * The GCC-specific code below prevents the pg_attribute_printf above from * being replaced, and this is required because gcc doesn't know anything - * about pg_printf. + * about printf_throw_on_fail. */ #ifdef __GNUC__ -#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__) -#define snprintf(...) pg_snprintf(__VA_ARGS__) -#define vsprintf(...) pg_vsprintf(__VA_ARGS__) -#define sprintf(...) pg_sprintf(__VA_ARGS__) -#define vfprintf(...) pg_vfprintf(__VA_ARGS__) -#define fprintf(...) pg_fprintf(__VA_ARGS__) -#define printf(...) pg_printf(__VA_ARGS__) +#define vsnprintf(...) vsnprintf_throw_on_fail(__VA_ARGS__) +#define snprintf(...) snprintf_throw_on_fail(__VA_ARGS__) +#define vsprintf(...) vsprintf_throw_on_fail(__VA_ARGS__) +#define sprintf(...) sprintf_throw_on_fail(__VA_ARGS__) +#define vfprintf(...) vfprintf_throw_on_fail(__VA_ARGS__) +#define fprintf(...) fprintf_throw_on_fail(__VA_ARGS__) +#define printf(...) printf_throw_on_fail(__VA_ARGS__) #else -#define vsnprintf pg_vsnprintf -#define snprintf pg_snprintf -#define vsprintf pg_vsprintf -#define sprintf pg_sprintf -#define vfprintf pg_vfprintf -#define fprintf pg_fprintf -#define printf pg_printf +#define vsnprintf vsnprintf_throw_on_fail +#define snprintf snprintf_throw_on_fail +#define vsprintf vsprintf_throw_on_fail +#define sprintf sprintf_throw_on_fail +#define vfprintf vfprintf_throw_on_fail +#define fprintf fprintf_throw_on_fail +#define printf printf_throw_on_fail #endif + +#ifdef USE_REPL_SNPRINTF + +/* Code outside syswrap.c should not call these. */ + +extern int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args); +extern int pg_snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3, 4); +extern int pg_vsprintf(char *str, const char *fmt, va_list args); +extern int pg_sprintf(char *str, const char *fmt,...) pg_attribute_printf(2, 3); +extern int pg_vfprintf(FILE *stream, const char *fmt, va_list args); +extern int pg_fprintf(FILE *stream, const char *fmt,...) pg_attribute_printf(2, 3); +extern int pg_printf(const char *fmt,...) pg_attribute_printf(1, 2); + #endif /* USE_REPL_SNPRINTF */ #if defined(WIN32) diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/compatlib/Makefile index ed52bff01ed229954c0de032f51476cfd8cb3dd0..fcbddbf5812f8fab01b6332874af70fe88e32a24 100644 --- a/src/interfaces/ecpg/compatlib/Makefile +++ b/src/interfaces/ecpg/compatlib/Makefile @@ -48,6 +48,7 @@ submake-pgtypeslib: # Shared library stuff include $(top_srcdir)/src/Makefile.shlib +# XXX This library uses no symbols from snprintf.c. snprintf.c: % : $(top_srcdir)/src/port/% rm -f $@ && $(LN_S) $< . diff --git a/src/interfaces/ecpg/ecpglib/.gitignore b/src/interfaces/ecpg/ecpglib/.gitignore index 8ef6401dd0ebc31acc061303cc2f1f11d99f04f3..c28ac74fa9aa50424aa7259a721b3a96a9865f20 100644 --- a/src/interfaces/ecpg/ecpglib/.gitignore +++ b/src/interfaces/ecpg/ecpglib/.gitignore @@ -5,6 +5,7 @@ /pgstrcasecmp.c /snprintf.c /strlcpy.c +/syswrap.c /thread.c /win32setlocale.c /isinf.c diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ecpglib/Makefile index a4ec8c80e6a5d0c66a914c06d89d521fa161a010..35791168d91a8a4d31292c71bc2eb261cef2dd13 100644 --- a/src/interfaces/ecpg/ecpglib/Makefile +++ b/src/interfaces/ecpg/ecpglib/Makefile @@ -26,7 +26,7 @@ override CFLAGS += $(PTHREAD_CFLAGS) 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 \ + connect.o misc.o path.o pgstrcasecmp.o syswrap.o \ $(filter snprintf.o strlcpy.o win32setlocale.o isinf.o, $(LIBOBJS)) $(WIN32RES) # thread.c is needed only for non-WIN32 implementation of path.c @@ -55,7 +55,7 @@ include $(top_srcdir)/src/Makefile.shlib # 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 thread.c win32setlocale.c isinf.c: % : $(top_srcdir)/src/port/% +path.c pgstrcasecmp.c snprintf.c strlcpy.c syswrap.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 @@ -72,6 +72,6 @@ uninstall: uninstall-lib clean distclean: clean-lib rm -f $(OBJS) - rm -f path.c pgstrcasecmp.c snprintf.c strlcpy.c thread.c win32setlocale.c isinf.c + rm -f path.c pgstrcasecmp.c snprintf.c strlcpy.c syswrap.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 fbcd68d7d3efd22a7116cc8e3bf31d119a3a7fa8..e33c94d81f6bd66742030f6ce385e18431a3f9c7 100644 --- a/src/interfaces/ecpg/pgtypeslib/.gitignore +++ b/src/interfaces/ecpg/pgtypeslib/.gitignore @@ -4,3 +4,4 @@ /pgstrcasecmp.c /rint.c /snprintf.c +/syswrap.c diff --git a/src/interfaces/ecpg/pgtypeslib/Makefile b/src/interfaces/ecpg/pgtypeslib/Makefile index 6c7ae63d4e2f6b2a601e2643f80d68e577c45734..830f47074f53abfd89933a6280a6014208e49a13 100644 --- a/src/interfaces/ecpg/pgtypeslib/Makefile +++ b/src/interfaces/ecpg/pgtypeslib/Makefile @@ -30,7 +30,7 @@ SHLIB_LINK += -lm SHLIB_EXPORTS = exports.txt OBJS= numeric.o datetime.o common.o dt_common.o timestamp.o interval.o \ - pgstrcasecmp.o \ + pgstrcasecmp.o syswrap.o \ $(filter rint.o snprintf.o, $(LIBOBJS)) $(WIN32RES) all: all-lib @@ -43,7 +43,7 @@ include $(top_srcdir)/src/Makefile.shlib # 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: % : $(top_srcdir)/src/port/% +pgstrcasecmp.c rint.c snprintf.c syswrap.c: % : $(top_srcdir)/src/port/% rm -f $@ && $(LN_S) $< . install: all installdirs install-lib @@ -53,6 +53,6 @@ installdirs: installdirs-lib uninstall: uninstall-lib clean distclean: clean-lib - rm -f $(OBJS) pgstrcasecmp.c rint.c snprintf.c + rm -f $(OBJS) pgstrcasecmp.c rint.c snprintf.c syswrap.c maintainer-clean: distclean maintainer-clean-lib diff --git a/src/interfaces/libpq/.gitignore b/src/interfaces/libpq/.gitignore index cb96af717665e776bb4c5d06f86263a9abcae895..5e672f1ae1fdd764f11fdb4e3774d516955c5f6f 100644 --- a/src/interfaces/libpq/.gitignore +++ b/src/interfaces/libpq/.gitignore @@ -13,6 +13,7 @@ /strerror.c /strlcpy.c /system.c +/syswrap.c /thread.c /win32error.c /win32setlocale.c diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index 6973a204840745a2e08806b7a43902ff2c7e003b..c0afa89161cd83e910ad37310326bba39a41b47f 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -36,7 +36,7 @@ OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \ libpq-events.o # libpgport C files we always use OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.o \ - thread.o + syswrap.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 win32error.o win32setlocale.o, $(LIBOBJS)) # backend/libpq @@ -93,7 +93,7 @@ backend_src = $(top_srcdir)/src/backend # For some libpgport modules, this only happens if configure decides # the module is needed (see filter hack in OBJS, above). -chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c inet_net_ntop.c noblock.c open.c system.c pgsleep.c pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c thread.c win32error.c win32setlocale.c: % : $(top_srcdir)/src/port/% +chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c inet_net_ntop.c noblock.c open.c system.c pgsleep.c pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c syswrap.c thread.c win32error.c win32setlocale.c: % : $(top_srcdir)/src/port/% rm -f $@ && $(LN_S) $< . ip.c md5.c: % : $(backend_src)/libpq/% @@ -145,7 +145,7 @@ clean distclean: clean-lib # Might be left over from a Win32 client-only build rm -f pg_config_paths.h rm -f inet_net_ntop.c noblock.c pgstrcasecmp.c pqsignal.c thread.c - rm -f chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c open.c system.c snprintf.c strerror.c strlcpy.c win32error.c win32setlocale.c + rm -f chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c open.c system.c snprintf.c strerror.c strlcpy.c syswrap.c win32error.c win32setlocale.c rm -f pgsleep.c rm -f md5.c ip.c rm -f encnames.c wchar.c diff --git a/src/interfaces/libpq/bcc32.mak b/src/interfaces/libpq/bcc32.mak index 78102fafd45c948a93bff59100677ddd728fdf53..9bb577a0ed3d4fa2e1fddb81c85995b17444353c 100644 --- a/src/interfaces/libpq/bcc32.mak +++ b/src/interfaces/libpq/bcc32.mak @@ -107,6 +107,7 @@ CLEAN : -@erase "$(INTDIR)\pgsleep.obj" -@erase "$(INTDIR)\open.obj" -@erase "$(INTDIR)\system.obj" + -@erase "$(INTDIR)\syswrap.obj" -@erase "$(INTDIR)\win32error.obj" -@erase "$(OUTDIR)\$(OUTFILENAME).lib" -@erase "$(OUTDIR)\$(OUTFILENAME)dll.lib" @@ -151,6 +152,7 @@ LIB32_OBJS= \ "$(INTDIR)\pgsleep.obj" \ "$(INTDIR)\open.obj" \ "$(INTDIR)\system.obj" \ + "$(INTDIR)\syswrap.obj" \ "$(INTDIR)\win32error.obj" \ "$(INTDIR)\pthread-win32.obj" @@ -302,6 +304,11 @@ LINK32_FLAGS = -Gn -L$(BCB)\lib;$(INTDIR); -x -Tpd -v $(CPP_PROJ) /I"." ..\..\port\system.c << +"$(INTDIR)\syswrap.obj" : ..\..\port\syswrap.c + $(CPP) @<< + $(CPP_PROJ) ..\..\port\syswrap.c +<< + "$(INTDIR)\win32error.obj" : ..\..\port\win32error.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\win32error.c diff --git a/src/interfaces/libpq/win32.mak b/src/interfaces/libpq/win32.mak index 1b71ebd387072bb4f59aa27592fb9f7a8cbf54b5..b05fce82ccd8c6431bdfdcccf86c3185f5d7748e 100644 --- a/src/interfaces/libpq/win32.mak +++ b/src/interfaces/libpq/win32.mak @@ -114,6 +114,7 @@ CLEAN : -@erase "$(INTDIR)\pgsleep.obj" -@erase "$(INTDIR)\open.obj" -@erase "$(INTDIR)\system.obj" + -@erase "$(INTDIR)\syswrap.obj" -@erase "$(INTDIR)\win32error.obj" -@erase "$(INTDIR)\win32setlocale.obj" -@erase "$(OUTDIR)\$(OUTFILENAME).lib" @@ -164,6 +165,7 @@ LIB32_OBJS= \ "$(INTDIR)\pgsleep.obj" \ "$(INTDIR)\open.obj" \ "$(INTDIR)\system.obj" \ + "$(INTDIR)\syswrap.obj" \ "$(INTDIR)\win32error.obj" \ "$(INTDIR)\win32setlocale.obj" \ "$(INTDIR)\pthread-win32.obj" @@ -348,6 +350,11 @@ LINK32_OBJS= \ $(CPP_PROJ) /I"." ..\..\port\system.c << +"$(INTDIR)\syswrap.obj" : ..\..\port\syswrap.c + $(CPP) @<< + $(CPP_PROJ) ..\..\port\syswrap.c +<< + "$(INTDIR)\win32error.obj" : ..\..\port\win32error.c $(CPP) @<< $(CPP_PROJ) /I"." ..\..\port\win32error.c diff --git a/src/pl/plperl/plperl.h b/src/pl/plperl/plperl.h index 813d4401bbbf7b56bbeab552c273a3346afc5a7b..cc748ec3c0e8062fdee8ee3ec16cf29f2fa55517 100644 --- a/src/pl/plperl/plperl.h +++ b/src/pl/plperl/plperl.h @@ -37,10 +37,8 @@ * So we undefine them here and redefine them after it's done its dirty deed. */ -#ifdef USE_REPL_SNPRINTF #undef snprintf #undef vsnprintf -#endif /* required for perl API */ @@ -49,7 +47,6 @@ #include "XSUB.h" /* put back our snprintf and vsnprintf */ -#ifdef USE_REPL_SNPRINTF #ifdef snprintf #undef snprintf #endif @@ -57,13 +54,12 @@ #undef vsnprintf #endif #ifdef __GNUC__ -#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__) -#define snprintf(...) pg_snprintf(__VA_ARGS__) +#define vsnprintf(...) vsnprintf_throw_on_fail(__VA_ARGS__) +#define snprintf(...) snprintf_throw_on_fail(__VA_ARGS__) #else -#define vsnprintf pg_vsnprintf -#define snprintf pg_snprintf +#define vsnprintf vsnprintf_throw_on_fail +#define snprintf snprintf_throw_on_fail #endif /* __GNUC__ */ -#endif /* USE_REPL_SNPRINTF */ /* perl version and platform portability */ #define NEED_eval_pv diff --git a/src/pl/plpython/plpython.h b/src/pl/plpython/plpython.h index ea540af39e38666d15f1f98a46b567500c25f770..0f60af68363867ca34842b810dfde1831511c6c1 100644 --- a/src/pl/plpython/plpython.h +++ b/src/pl/plpython/plpython.h @@ -35,10 +35,8 @@ * 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 @@ -125,7 +123,6 @@ typedef int Py_ssize_t; #include <eval.h> /* put back our snprintf and vsnprintf */ -#ifdef USE_REPL_SNPRINTF #ifdef snprintf #undef snprintf #endif @@ -133,13 +130,12 @@ typedef int Py_ssize_t; #undef vsnprintf #endif #ifdef __GNUC__ -#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__) -#define snprintf(...) pg_snprintf(__VA_ARGS__) +#define vsnprintf(...) vsnprintf_throw_on_fail(__VA_ARGS__) +#define snprintf(...) snprintf_throw_on_fail(__VA_ARGS__) #else -#define vsnprintf pg_vsnprintf -#define snprintf pg_snprintf +#define vsnprintf vsnprintf_throw_on_fail +#define snprintf snprintf_throw_on_fail #endif /* __GNUC__ */ -#endif /* USE_REPL_SNPRINTF */ /* * Used throughout, and also by the Python 2/3 porting layer, so it's easier to diff --git a/src/port/Makefile b/src/port/Makefile index bc9b63add0479459d146550c0338e1a22a478400..b0fc56ac455bbb5b8858397a79daff8f476f03c1 100644 --- a/src/port/Makefile +++ b/src/port/Makefile @@ -33,7 +33,7 @@ LIBS += $(PTHREAD_LIBS) 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 + qsort.o qsort_arg.o quotes.o sprompt.o syswrap.o tar.o thread.o # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND OBJS_SRV = $(OBJS:%.o=%_srv.o) diff --git a/src/port/snprintf.c b/src/port/snprintf.c index 0c779a601fcfc93b723f1a696adce8923565fde3..91c97d487cdb388129b4831f75e60cce319ad131 100644 --- a/src/port/snprintf.c +++ b/src/port/snprintf.c @@ -114,6 +114,7 @@ typedef struct /* bufend == NULL is for sprintf, where we assume buf is big enough */ FILE *stream; /* eventual output destination, or NULL */ int nchars; /* # chars already sent to stream */ + bool failed; /* call is a failure; errno is set */ } PrintfTarget; /* @@ -143,7 +144,7 @@ typedef union static void flushbuffer(PrintfTarget *target); -static int dopr(PrintfTarget *target, const char *format, va_list args); +static void dopr(PrintfTarget *target, const char *format, va_list args); int @@ -157,14 +158,10 @@ pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) target.bufend = str + count - 1; target.stream = NULL; /* target.nchars is unused in this case */ - if (dopr(&target, fmt, args)) - { - *(target.bufptr) = '\0'; - errno = EINVAL; /* bad format */ - return -1; - } + target.failed = false; + dopr(&target, fmt, args); *(target.bufptr) = '\0'; - return target.bufptr - target.bufstart; + return target.failed ? -1 : (target.bufptr - target.bufstart); } int @@ -190,14 +187,10 @@ pg_vsprintf(char *str, const char *fmt, va_list args) target.bufend = NULL; target.stream = NULL; /* target.nchars is unused in this case */ - if (dopr(&target, fmt, args)) - { - *(target.bufptr) = '\0'; - errno = EINVAL; /* bad format */ - return -1; - } + target.failed = false; + dopr(&target, fmt, args); *(target.bufptr) = '\0'; - return target.bufptr - target.bufstart; + return target.failed ? -1 : (target.bufptr - target.bufstart); } int @@ -227,14 +220,11 @@ pg_vfprintf(FILE *stream, const char *fmt, va_list args) target.bufend = buffer + sizeof(buffer) - 1; target.stream = stream; target.nchars = 0; - if (dopr(&target, fmt, args)) - { - errno = EINVAL; /* bad format */ - return -1; - } + target.failed = false; + dopr(&target, fmt, args); /* dump any remaining buffer contents */ flushbuffer(&target); - return target.nchars; + return target.failed ? -1 : target.nchars; } int @@ -261,14 +251,24 @@ pg_printf(const char *fmt,...) return len; } -/* call this only when stream is defined */ +/* + * Attempt to write the entire buffer to target->stream; discard the entire + * buffer in any case. Call this only when target->stream is defined. + */ static void flushbuffer(PrintfTarget *target) { size_t nc = target->bufptr - target->bufstart; - if (nc > 0) - target->nchars += fwrite(target->bufstart, 1, nc, target->stream); + if (!target->failed && nc > 0) + { + size_t written; + + written = fwrite(target->bufstart, 1, nc, target->stream); + target->nchars += written; + if (written != nc) + target->failed = true; + } target->bufptr = target->bufstart; } @@ -295,7 +295,7 @@ static void trailing_pad(int *padlen, PrintfTarget *target); /* * dopr(): poor man's version of doprintf */ -static int +static void dopr(PrintfTarget *target, const char *format, va_list args) { const char *format_start = format; @@ -372,12 +372,12 @@ nextch1: case '$': have_dollar = true; if (accum <= 0 || accum > NL_ARGMAX) - return -1; + goto bad_format; if (afterstar) { if (argtypes[accum] && argtypes[accum] != ATYPE_INT) - return -1; + goto bad_format; argtypes[accum] = ATYPE_INT; last_dollar = Max(last_dollar, accum); afterstar = false; @@ -427,7 +427,7 @@ nextch1: atype = ATYPE_INT; if (argtypes[fmtpos] && argtypes[fmtpos] != atype) - return -1; + goto bad_format; argtypes[fmtpos] = atype; last_dollar = Max(last_dollar, fmtpos); } @@ -439,7 +439,7 @@ nextch1: { if (argtypes[fmtpos] && argtypes[fmtpos] != ATYPE_INT) - return -1; + goto bad_format; argtypes[fmtpos] = ATYPE_INT; last_dollar = Max(last_dollar, fmtpos); } @@ -452,7 +452,7 @@ nextch1: { if (argtypes[fmtpos] && argtypes[fmtpos] != ATYPE_CHARPTR) - return -1; + goto bad_format; argtypes[fmtpos] = ATYPE_CHARPTR; last_dollar = Max(last_dollar, fmtpos); } @@ -468,7 +468,7 @@ nextch1: { if (argtypes[fmtpos] && argtypes[fmtpos] != ATYPE_DOUBLE) - return -1; + goto bad_format; argtypes[fmtpos] = ATYPE_DOUBLE; last_dollar = Max(last_dollar, fmtpos); } @@ -489,7 +489,7 @@ nextch1: /* Per spec, you use either all dollar or all not. */ if (have_dollar && have_non_dollar) - return -1; + goto bad_format; /* * In dollar mode, collect the arguments in physical order. @@ -499,7 +499,7 @@ nextch1: switch (argtypes[i]) { case ATYPE_NONE: - return -1; /* invalid format */ + goto bad_format; case ATYPE_INT: argvalues[i].i = va_arg(args, int); break; @@ -524,6 +524,9 @@ nextch1: format = format_start; while ((ch = *format++) != '\0') { + if (target->failed) + break; + if (ch != '%') { dopr_outch(ch, target); @@ -781,7 +784,11 @@ nextch2: } } - return 0; + return; + +bad_format: + errno = EINVAL; + target->failed = true; } static size_t @@ -831,8 +838,10 @@ fmtptr(void *value, PrintfTarget *target) /* we rely on regular C library's sprintf to do the basic conversion */ vallen = sprintf(convert, "%p", value); - - dostr(convert, vallen, target); + if (vallen < 0) + target->failed = true; + else + dostr(convert, vallen, target); } static void @@ -965,16 +974,19 @@ fmtfloat(double value, char type, int forcesign, int leftjust, if (pointflag) { - sprintf(fmt, "%%.%d%c", prec, type); + if (sprintf(fmt, "%%.%d%c", prec, type) < 0) + goto fail; zeropadlen = precision - prec; } - else - sprintf(fmt, "%%%c", type); + else if (sprintf(fmt, "%%%c", type) < 0) + goto fail; if (!isnan(value) && adjust_sign((value < 0), forcesign, &signvalue)) value = -value; vallen = sprintf(convert, fmt, value); + if (vallen < 0) + goto fail; /* If it's infinity or NaN, forget about doing any zero-padding */ if (zeropadlen > 0 && !isdigit((unsigned char) convert[vallen - 1])) @@ -1014,6 +1026,10 @@ fmtfloat(double value, char type, int forcesign, int leftjust, } trailing_pad(&padlen, target); + return; + +fail: + target->failed = true; } static void diff --git a/src/port/syswrap.c b/src/port/syswrap.c new file mode 100644 index 0000000000000000000000000000000000000000..8415a336303699eed799bf34ec44c18f0633a9be --- /dev/null +++ b/src/port/syswrap.c @@ -0,0 +1,155 @@ +/*------------------------------------------------------------------------- + * + * syswrap.c + * error-throwing wrappers around POSIX functions that rarely fail + * + * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group + * + * + * IDENTIFICATION + * src/port/syswrap.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +/* Prevent recursion */ +#undef vsnprintf +#undef snprintf +#undef vsprintf +#undef sprintf +#undef vfprintf +#undef fprintf +#undef printf + +/* When the libc primitives are lacking, use our own. */ +#ifdef USE_REPL_SNPRINTF +#ifdef __GNUC__ +#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__) +#define snprintf(...) pg_snprintf(__VA_ARGS__) +#define vsprintf(...) pg_vsprintf(__VA_ARGS__) +#define sprintf(...) pg_sprintf(__VA_ARGS__) +#define vfprintf(...) pg_vfprintf(__VA_ARGS__) +#define fprintf(...) pg_fprintf(__VA_ARGS__) +#define printf(...) pg_printf(__VA_ARGS__) +#else +#define vsnprintf pg_vsnprintf +#define snprintf pg_snprintf +#define vsprintf pg_vsprintf +#define sprintf pg_sprintf +#define vfprintf pg_vfprintf +#define fprintf pg_fprintf +#define printf pg_printf +#endif +#endif /* USE_REPL_SNPRINTF */ + +/* + * We abort() in the frontend, rather than exit(), because libpq in particular + * has no business calling exit(). These failures had better be rare. + */ +#ifdef FRONTEND +#define LIB_ERR(func) \ +do { \ + int discard = fprintf(stderr, "%s failed: %s\n", func, strerror(errno)); \ + (void) discard; \ + abort(); \ +} while (0) +#else +#define LIB_ERR(func) elog(ERROR, "%s failed: %m", func) +#endif + +int +vsnprintf_throw_on_fail(char *str, size_t count, const char *fmt, va_list args) +{ + int save_errno; + int ret; + + /* + * On HP-UX B.11.31, a call that truncates output returns -1 without + * setting errno. (SUSv2 allowed this until the approval of Base Working + * Group Resolution BWG98-006.) We could avoid the save and restore of + * errno on most platforms. + */ + save_errno = errno; + errno = 0; + ret = vsnprintf(str, count, fmt, args); + if (ret < 0 && errno != 0) + LIB_ERR("vsnprintf"); + errno = save_errno; + return ret; +} + +int +snprintf_throw_on_fail(char *str, size_t count, const char *fmt,...) +{ + int ret; + va_list args; + + va_start(args, fmt); + ret = vsnprintf_throw_on_fail(str, count, fmt, args); + va_end(args); + return ret; +} + +int +vsprintf_throw_on_fail(char *str, const char *fmt, va_list args) +{ + int ret; + + ret = vsprintf(str, fmt, args); + if (ret < 0) + LIB_ERR("vsprintf"); + return ret; +} + +int +sprintf_throw_on_fail(char *str, const char *fmt,...) +{ + int ret; + va_list args; + + va_start(args, fmt); + ret = vsprintf_throw_on_fail(str, fmt, args); + va_end(args); + return ret; +} + +int +vfprintf_throw_on_fail(FILE *stream, const char *fmt, va_list args) +{ + int ret; + + ret = vfprintf(stream, fmt, args); + if (ret < 0) + LIB_ERR("vfprintf"); + return ret; +} + +int +fprintf_throw_on_fail(FILE *stream, const char *fmt,...) +{ + int ret; + va_list args; + + va_start(args, fmt); + ret = vfprintf_throw_on_fail(stream, fmt, args); + va_end(args); + return ret; +} + +int +printf_throw_on_fail(const char *fmt,...) +{ + int ret; + va_list args; + + va_start(args, fmt); + ret = vfprintf_throw_on_fail(stdout, fmt, args); + va_end(args); + return ret; +} diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index be06898d1ae8599d3ede12ed31a6d8cfb2bdcd70..35acb52d5829a8643c2f99fb6e03e14860cec332 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -91,7 +91,7 @@ sub mkvcbuild erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.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 + sprompt.c syswrap.c tar.c thread.c getopt.c getopt_long.c dirent.c win32env.c win32error.c win32setlocale.c); push(@pgportfiles, 'rint.c') if ($vsVersion < '12.00');