aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/port.h80
-rw-r--r--src/interfaces/ecpg/compatlib/Makefile1
-rw-r--r--src/interfaces/ecpg/ecpglib/.gitignore1
-rw-r--r--src/interfaces/ecpg/ecpglib/Makefile6
-rw-r--r--src/interfaces/ecpg/pgtypeslib/.gitignore1
-rw-r--r--src/interfaces/ecpg/pgtypeslib/Makefile6
-rw-r--r--src/interfaces/libpq/.gitignore1
-rw-r--r--src/interfaces/libpq/Makefile6
-rw-r--r--src/interfaces/libpq/bcc32.mak7
-rw-r--r--src/interfaces/libpq/win32.mak7
-rw-r--r--src/pl/plperl/plperl.h12
-rw-r--r--src/pl/plpython/plpython.h12
-rw-r--r--src/port/Makefile2
-rw-r--r--src/port/snprintf.c94
-rw-r--r--src/port/syswrap.c155
-rw-r--r--src/tools/msvc/Mkvcbuild.pm2
16 files changed, 300 insertions, 93 deletions
diff --git a/src/include/port.h b/src/include/port.h
index f9b4a16c0af..3f187159cb3 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 ed52bff01ed..fcbddbf5812 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 8ef6401dd0e..c28ac74fa9a 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 a4ec8c80e6a..35791168d91 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 fbcd68d7d3e..e33c94d81f6 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 6c7ae63d4e2..830f47074f5 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 cb96af71766..5e672f1ae1f 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 6973a204840..c0afa89161c 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 78102fafd45..9bb577a0ed3 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 1b71ebd3870..b05fce82ccd 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 813d4401bbb..cc748ec3c0e 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 ea540af39e3..0f60af68363 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 bc9b63add04..b0fc56ac455 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 0c779a601fc..91c97d487cd 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 00000000000..8415a336303
--- /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 be06898d1ae..35acb52d582 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');