aboutsummaryrefslogtreecommitdiff
path: root/src/port/strerror.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/port/strerror.c')
-rw-r--r--src/port/strerror.c85
1 files changed, 61 insertions, 24 deletions
diff --git a/src/port/strerror.c b/src/port/strerror.c
index ca6910d2e6c..ba93815c50a 100644
--- a/src/port/strerror.c
+++ b/src/port/strerror.c
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* strerror.c
- * Replacement for standard strerror() function
+ * Replacements for standard strerror() and strerror_r() functions
*
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
@@ -15,13 +15,16 @@
#include "c.h"
/*
- * Within this file, "strerror" means the platform's function not pg_strerror
+ * Within this file, "strerror" means the platform's function not pg_strerror,
+ * and likewise for "strerror_r"
*/
#undef strerror
+#undef strerror_r
+static char *gnuish_strerror_r(int errnum, char *buf, size_t buflen);
static char *get_errno_symbol(int errnum);
#ifdef WIN32
-static char *win32_socket_strerror(int errnum);
+static char *win32_socket_strerror(int errnum, char *buf, size_t buflen);
#endif
@@ -31,19 +34,28 @@ static char *win32_socket_strerror(int errnum);
char *
pg_strerror(int errnum)
{
- /* this buffer is only used if strerror() and get_errno_symbol() fail */
- static char errorstr_buf[48];
+ static char errorstr_buf[PG_STRERROR_R_BUFLEN];
+
+ return pg_strerror_r(errnum, errorstr_buf, sizeof(errorstr_buf));
+}
+
+/*
+ * A slightly cleaned-up version of strerror_r()
+ */
+char *
+pg_strerror_r(int errnum, char *buf, size_t buflen)
+{
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);
+ return win32_socket_strerror(errnum, buf, buflen);
#endif
- /* Try the platform's strerror() */
- str = strerror(errnum);
+ /* Try the platform's strerror_r(), or maybe just strerror() */
+ str = gnuish_strerror_r(errnum, buf, buflen);
/*
* Some strerror()s return an empty string for out-of-range errno. This
@@ -57,18 +69,43 @@ pg_strerror(int 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;
+ snprintf(buf, buflen, _("operating system error %d"), errnum);
+ str = buf;
}
return str;
}
/*
+ * Simple wrapper to emulate GNU strerror_r if what the platform provides is
+ * POSIX. Also, if platform lacks strerror_r altogether, fall back to plain
+ * strerror; it might not be very thread-safe, but tough luck.
+ */
+static char *
+gnuish_strerror_r(int errnum, char *buf, size_t buflen)
+{
+#ifdef HAVE_STRERROR_R
+#ifdef STRERROR_R_INT
+ /* POSIX API */
+ if (strerror_r(errnum, buf, buflen) == 0)
+ return buf;
+ return NULL; /* let caller deal with failure */
+#else
+ /* GNU API */
+ return strerror_r(errnum, buf, buflen);
+#endif
+#else /* !HAVE_STRERROR_R */
+ char *sbuf = strerror(errnum);
+
+ if (sbuf == NULL) /* can this still happen anywhere? */
+ return NULL;
+ /* To minimize thread-unsafety hazard, copy into caller's buffer */
+ strlcpy(buf, sbuf, buflen);
+ return buf;
+#endif
+}
+
+/*
* Returns a symbol (e.g. "ENOENT") for an errno code.
* Returns NULL if the code is unrecognized.
*/
@@ -247,9 +284,8 @@ get_errno_symbol(int errnum)
* Windows' strerror() doesn't know the Winsock codes, so handle them this way
*/
static char *
-win32_socket_strerror(int errnum)
+win32_socket_strerror(int errnum, char *buf, size_t buflen)
{
- static char wserrbuf[256];
static HANDLE handleDLL = INVALID_HANDLE_VALUE;
if (handleDLL == INVALID_HANDLE_VALUE)
@@ -258,28 +294,29 @@ win32_socket_strerror(int errnum)
DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
if (handleDLL == NULL)
{
- sprintf(wserrbuf, "winsock error %d (could not load netmsg.dll to translate: error code %lu)",
- errnum, GetLastError());
- return wserrbuf;
+ snprintf(buf, buflen,
+ "winsock error %d (could not load netmsg.dll to translate: error code %lu)",
+ errnum, GetLastError());
+ return buf;
}
}
- ZeroMemory(&wserrbuf, sizeof(wserrbuf));
+ ZeroMemory(buf, buflen);
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,
+ buf,
+ buflen - 1,
NULL) == 0)
{
/* Failed to get id */
- sprintf(wserrbuf, "unrecognized winsock error %d", errnum);
+ snprintf(buf, buflen, "unrecognized winsock error %d", errnum);
}
- return wserrbuf;
+ return buf;
}
#endif /* WIN32 */