]> granicus.if.org Git - postgresql/commitdiff
Incorporate strerror_r() into src/port/snprintf.c, too.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 26 Sep 2018 16:35:57 +0000 (12:35 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 26 Sep 2018 16:35:57 +0000 (12:35 -0400)
This provides the features that used to exist in useful_strerror()
for users of strerror_r(), too.  Also, standardize on the GNU convention
that strerror_r returns a char pointer that may not be NULL.

I notice that libpq's win32.c contains a variant version of strerror_r
that probably ought to be folded into strerror.c.  But lacking a
Windows environment, I should leave that to somebody else.

Discussion: https://postgr.es/m/2975.1526862605@sss.pgh.pa.us

src/include/port.h
src/interfaces/libpq/fe-auth.c
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/fe-lobj.c
src/interfaces/libpq/fe-misc.c
src/interfaces/libpq/fe-secure-openssl.c
src/interfaces/libpq/fe-secure.c
src/interfaces/libpq/libpq-int.h
src/port/strerror.c
src/port/thread.c
src/test/thread/thread_test.c

index acf8d5fefd742c4642f5d155a0ebf95e9ad9a831..abbe1ad9a1a6db87bf44c4ff0f32501be384cc44 100644 (file)
@@ -193,6 +193,11 @@ extern int pg_printf(const char *fmt,...) pg_attribute_printf(1, 2);
 extern char *pg_strerror(int errnum);
 #define strerror pg_strerror
 
+/* Likewise for strerror_r(); note we prefer the GNU API for that */
+extern char *pg_strerror_r(int errnum, char *buf, size_t buflen);
+#define strerror_r pg_strerror_r
+#define PG_STRERROR_R_BUFLEN 256       /* Recommended buffer size for strerror_r */
+
 /* Portable prompt handling */
 extern void simple_prompt(const char *prompt, char *destination, size_t destlen,
                          bool echo);
@@ -428,8 +433,6 @@ extern char *dlerror(void);
 #endif
 
 /* thread.h */
-extern char *pqStrerror(int errnum, char *strerrbuf, size_t buflen);
-
 #ifndef WIN32
 extern int pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
                   size_t buflen, struct passwd **result);
index 540aba98b37119fb9f841f7c13d02e22e53abbfe..92641fe5e9acc37f6301fb5c89f06e49fe46ef71 100644 (file)
@@ -756,11 +756,11 @@ pg_local_sendauth(PGconn *conn)
 
        if (sendmsg(conn->sock, &msg, 0) == -1)
        {
-               char            sebuf[256];
+               char            sebuf[PG_STRERROR_R_BUFLEN];
 
                printfPQExpBuffer(&conn->errorMessage,
                                                  "pg_local_sendauth: sendmsg: %s\n",
-                                                 pqStrerror(errno, sebuf, sizeof(sebuf)));
+                                                 strerror_r(errno, sebuf, sizeof(sebuf)));
                return STATUS_ERROR;
        }
        return STATUS_OK;
@@ -1098,7 +1098,7 @@ pg_fe_getauthname(PQExpBuffer errorMessage)
                        printfPQExpBuffer(errorMessage,
                                                          libpq_gettext("could not look up local user ID %d: %s\n"),
                                                          (int) user_id,
-                                                         pqStrerror(pwerr, pwdbuf, sizeof(pwdbuf)));
+                                                         strerror_r(pwerr, pwdbuf, sizeof(pwdbuf)));
                else
                        printfPQExpBuffer(errorMessage,
                                                          libpq_gettext("local user with ID %d does not exist\n"),
index 45bc067921c807aa1a9abb3895ee5e9795351324..d001bc513d30ba855bec068e9a2c598c12641ba7 100644 (file)
@@ -1459,7 +1459,7 @@ connectNoDelay(PGconn *conn)
                                   (char *) &on,
                                   sizeof(on)) < 0)
        {
-               char            sebuf[256];
+               char            sebuf[PG_STRERROR_R_BUFLEN];
 
                appendPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("could not set socket to TCP no delay mode: %s\n"),
@@ -1480,7 +1480,7 @@ connectNoDelay(PGconn *conn)
 static void
 connectFailureMessage(PGconn *conn, int errorno)
 {
-       char            sebuf[256];
+       char            sebuf[PG_STRERROR_R_BUFLEN];
 
 #ifdef HAVE_UNIX_SOCKETS
        if (IS_AF_UNIX(conn->raddr.addr.ss_family))
@@ -1637,7 +1637,7 @@ setKeepalivesIdle(PGconn *conn)
        if (setsockopt(conn->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE,
                                   (char *) &idle, sizeof(idle)) < 0)
        {
-               char            sebuf[256];
+               char            sebuf[PG_STRERROR_R_BUFLEN];
 
                appendPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("setsockopt(%s) failed: %s\n"),
@@ -1671,7 +1671,7 @@ setKeepalivesInterval(PGconn *conn)
        if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPINTVL,
                                   (char *) &interval, sizeof(interval)) < 0)
        {
-               char            sebuf[256];
+               char            sebuf[PG_STRERROR_R_BUFLEN];
 
                appendPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("setsockopt(%s) failed: %s\n"),
@@ -1706,7 +1706,7 @@ setKeepalivesCount(PGconn *conn)
        if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPCNT,
                                   (char *) &count, sizeof(count)) < 0)
        {
-               char            sebuf[256];
+               char            sebuf[PG_STRERROR_R_BUFLEN];
 
                appendPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("setsockopt(%s) failed: %s\n"),
@@ -2036,7 +2036,7 @@ PQconnectPoll(PGconn *conn)
        bool            reset_connection_state_machine = false;
        bool            need_new_connection = false;
        PGresult   *res;
-       char            sebuf[256];
+       char            sebuf[PG_STRERROR_R_BUFLEN];
        int                     optval;
        PQExpBufferData savedMessage;
 
@@ -2580,7 +2580,7 @@ keep_going:                                               /* We will come back to here until there is
                                                else
                                                        appendPQExpBuffer(&conn->errorMessage,
                                                                                          libpq_gettext("could not get peer credentials: %s\n"),
-                                                                                         pqStrerror(errno, sebuf, sizeof(sebuf)));
+                                                                                         strerror_r(errno, sebuf, sizeof(sebuf)));
                                                goto error_return;
                                        }
 
@@ -2591,7 +2591,7 @@ keep_going:                                               /* We will come back to here until there is
                                                        appendPQExpBuffer(&conn->errorMessage,
                                                                                          libpq_gettext("could not look up local user ID %d: %s\n"),
                                                                                          (int) uid,
-                                                                                         pqStrerror(passerr, sebuf, sizeof(sebuf)));
+                                                                                         strerror_r(passerr, sebuf, sizeof(sebuf)));
                                                else
                                                        appendPQExpBuffer(&conn->errorMessage,
                                                                                          libpq_gettext("local user with ID %d does not exist\n"),
@@ -3953,7 +3953,7 @@ internal_cancel(SockAddr *raddr, int be_pid, int be_key,
 {
        int                     save_errno = SOCK_ERRNO;
        pgsocket        tmpsock = PGINVALID_SOCKET;
-       char            sebuf[256];
+       char            sebuf[PG_STRERROR_R_BUFLEN];
        int                     maxlen;
        struct
        {
index a5ad3af2580bbfb61f6dec3a4edcf65911f79df9..b9caa229669abe825eff2d5b739355e815d92442 100644 (file)
@@ -694,7 +694,7 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid)
        char            buf[LO_BUFSIZE];
        Oid                     lobjOid;
        int                     lobj;
-       char            sebuf[256];
+       char            sebuf[PG_STRERROR_R_BUFLEN];
 
        /*
         * open the file to be read in
@@ -704,7 +704,7 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid)
        {                                                       /* error */
                printfPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("could not open file \"%s\": %s\n"),
-                                                 filename, pqStrerror(errno, sebuf, sizeof(sebuf)));
+                                                 filename, strerror_r(errno, sebuf, sizeof(sebuf)));
                return InvalidOid;
        }
 
@@ -760,7 +760,7 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid)
                printfPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("could not read from file \"%s\": %s\n"),
                                                  filename,
-                                                 pqStrerror(save_errno, sebuf, sizeof(sebuf)));
+                                                 strerror_r(save_errno, sebuf, sizeof(sebuf)));
                return InvalidOid;
        }
 
@@ -789,7 +789,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
                                tmp;
        char            buf[LO_BUFSIZE];
        int                     lobj;
-       char            sebuf[256];
+       char            sebuf[PG_STRERROR_R_BUFLEN];
 
        /*
         * open the large object.
@@ -814,7 +814,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
                printfPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("could not open file \"%s\": %s\n"),
                                                  filename,
-                                                 pqStrerror(save_errno, sebuf, sizeof(sebuf)));
+                                                 strerror_r(save_errno, sebuf, sizeof(sebuf)));
                return -1;
        }
 
@@ -834,7 +834,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
                        printfPQExpBuffer(&conn->errorMessage,
                                                          libpq_gettext("could not write to file \"%s\": %s\n"),
                                                          filename,
-                                                         pqStrerror(save_errno, sebuf, sizeof(sebuf)));
+                                                         strerror_r(save_errno, sebuf, sizeof(sebuf)));
                        return -1;
                }
        }
@@ -857,7 +857,7 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename)
        {
                printfPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("could not write to file \"%s\": %s\n"),
-                                                 filename, pqStrerror(errno, sebuf, sizeof(sebuf)));
+                                                 filename, strerror_r(errno, sebuf, sizeof(sebuf)));
                result = -1;
        }
 
index 2a6637fdda398f0b3d4b1719322bf3fa3ef54672..46ece1a14c8d31692544491bb8dc1edc084d3c93 100644 (file)
@@ -1071,7 +1071,7 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
 
        if (result < 0)
        {
-               char            sebuf[256];
+               char            sebuf[PG_STRERROR_R_BUFLEN];
 
                printfPQExpBuffer(&conn->errorMessage,
                                                  libpq_gettext("select() failed: %s\n"),
index bbae8eff813906cc97b751677153ee6891e9e4bd..beca3492e8dcf1a2ba18f8ddaf2569d57bbaed8f 100644 (file)
@@ -142,7 +142,7 @@ pgtls_read(PGconn *conn, void *ptr, size_t len)
 {
        ssize_t         n;
        int                     result_errno = 0;
-       char            sebuf[256];
+       char            sebuf[PG_STRERROR_R_BUFLEN];
        int                     err;
        unsigned long ecode;
 
@@ -272,7 +272,7 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len)
 {
        ssize_t         n;
        int                     result_errno = 0;
-       char            sebuf[256];
+       char            sebuf[PG_STRERROR_R_BUFLEN];
        int                     err;
        unsigned long ecode;
 
@@ -443,7 +443,7 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
 
        return cert_hash;
 }
-#endif /* HAVE_X509_GET_SIGNATURE_NID */
+#endif                                                 /* HAVE_X509_GET_SIGNATURE_NID */
 
 /* ------------------------------------------------------------ */
 /*                                             OpenSSL specific code                                   */
@@ -780,7 +780,7 @@ initialize_SSL(PGconn *conn)
        struct stat buf;
        char            homedir[MAXPGPATH];
        char            fnbuf[MAXPGPATH];
-       char            sebuf[256];
+       char            sebuf[PG_STRERROR_R_BUFLEN];
        bool            have_homedir;
        bool            have_cert;
        bool            have_rootcert;
@@ -941,7 +941,7 @@ initialize_SSL(PGconn *conn)
                {
                        printfPQExpBuffer(&conn->errorMessage,
                                                          libpq_gettext("could not open certificate file \"%s\": %s\n"),
-                                                         fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
+                                                         fnbuf, strerror_r(errno, sebuf, sizeof(sebuf)));
                        SSL_CTX_free(SSL_context);
                        return -1;
                }
@@ -1212,7 +1212,7 @@ open_client_SSL(PGconn *conn)
 
                        case SSL_ERROR_SYSCALL:
                                {
-                                       char            sebuf[256];
+                                       char            sebuf[PG_STRERROR_R_BUFLEN];
 
                                        if (r == -1)
                                                printfPQExpBuffer(&conn->errorMessage,
index f7dc249bf0c4cd4563c4ec8b1dc9a208c680271e..a06fc7dc824231215a256c275a619f77da08ed9f 100644 (file)
@@ -233,7 +233,7 @@ pqsecure_raw_read(PGconn *conn, void *ptr, size_t len)
 {
        ssize_t         n;
        int                     result_errno = 0;
-       char            sebuf[256];
+       char            sebuf[PG_STRERROR_R_BUFLEN];
 
        n = recv(conn->sock, ptr, len, 0);
 
@@ -311,7 +311,7 @@ pqsecure_raw_write(PGconn *conn, const void *ptr, size_t len)
        ssize_t         n;
        int                     flags = 0;
        int                     result_errno = 0;
-       char            sebuf[256];
+       char            sebuf[PG_STRERROR_R_BUFLEN];
 
        DECLARE_SIGPIPE_INFO(spinfo);
 
index bdd8f9d9b29f64405a33218dac7baa90bde0c553..975ab33d025396ec77d19c7852b06a3986ea5eee 100644 (file)
@@ -773,7 +773,7 @@ extern char *libpq_ngettext(const char *msgid, const char *msgid_plural, unsigne
 #define SOCK_ERRNO_SET(e) WSASetLastError(e)
 #else
 #define SOCK_ERRNO errno
-#define SOCK_STRERROR pqStrerror
+#define SOCK_STRERROR strerror_r
 #define SOCK_ERRNO_SET(e) (errno = (e))
 #endif
 
index ca6910d2e6c2e43488398ca9a56744721b8e0fe9..ba93815c50a2329716ea8a4802d4aada6af39f78 100644 (file)
@@ -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
 #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,17 +69,42 @@ 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 */
index da2df1f80876f62dc4a2e12bbcc446fe2ab5141f..8e0c7df73a896a7ec1063c90d9ff96ae422afc0b 100644 (file)
  */
 
 
-/*
- * Wrapper around strerror and strerror_r to use the former if it is
- * available and also return a more useful value (the error string).
- */
-char *
-pqStrerror(int errnum, char *strerrbuf, size_t buflen)
-{
-#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_STRERROR_R)
-       /* reentrant strerror_r is available */
-#ifdef STRERROR_R_INT
-       /* SUSv3 version */
-       if (strerror_r(errnum, strerrbuf, buflen) == 0)
-               return strerrbuf;
-       else
-               return "Unknown error";
-#else
-       /* GNU libc */
-       return strerror_r(errnum, strerrbuf, buflen);
-#endif
-#else
-       /* no strerror_r() available, just use strerror */
-       strlcpy(strerrbuf, strerror(errnum), buflen);
-
-       return strerrbuf;
-#endif
-}
-
 /*
  * Wrapper around getpwuid() or getpwuid_r() to mimic POSIX getpwuid_r()
  * behaviour, if that function is not available or required.
index 381607324d3c07bee15f5adc80f23cfac4ca1f05..31452317a6ec668c545e00f1aaff4e1c66cb009c 100644 (file)
@@ -22,6 +22,9 @@
 
 #if !defined(IN_CONFIGURE) && !defined(WIN32)
 #include "postgres.h"
+
+/* we want to know what the native strerror does, not pg_strerror */
+#undef strerror
 #endif
 
 #include <stdio.h>
@@ -197,7 +200,7 @@ main(int argc, char *argv[])
        /* report results */
 
 #ifdef HAVE_STRERROR_R
-       printf("Your system has sterror_r();  it does not need strerror().\n");
+       printf("Your system has strerror_r(); it does not need strerror().\n");
 #else
        printf("Your system uses strerror() which is ");
        if (strerror_threadsafe)