8133249: Occasional SIGSEGV: non thread-safe use of strerr in getLastErrorString
authorrobm
Thu, 01 Oct 2015 00:13:09 +0100
changeset 32846 5383225ebd0d
parent 32845 e630c3008f2c
child 32847 9409488183a6
8133249: Occasional SIGSEGV: non thread-safe use of strerr in getLastErrorString Reviewed-by: igerasim, rriggs, christos
jdk/make/lib/CoreLibraries.gmk
jdk/make/mapfiles/libjava/mapfile-vers
jdk/src/java.base/share/native/libjava/jni_util.h
jdk/src/java.base/share/native/libzip/zip_util.c
jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c
jdk/src/java.base/unix/native/libjava/jni_util_md.c
jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c
jdk/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
jdk/src/java.base/windows/native/libjava/jni_util_md.c
jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c
--- a/jdk/make/lib/CoreLibraries.gmk	Thu Oct 01 00:09:51 2015 +0100
+++ b/jdk/make/lib/CoreLibraries.gmk	Thu Oct 01 00:13:09 2015 +0100
@@ -160,6 +160,7 @@
         -framework Security -framework SystemConfiguration, \
     LDFLAGS_SUFFIX_windows := -export:winFileHandleOpen -export:handleLseek \
         -export:getLastErrorString \
+        -export:getErrorString \
         jvm.lib $(BUILD_LIBFDLIBM) $(WIN_VERIFY_LIB) \
         shell32.lib delayimp.lib -DELAYLOAD:shell32.dll \
         advapi32.lib version.lib, \
--- a/jdk/make/mapfiles/libjava/mapfile-vers	Thu Oct 01 00:09:51 2015 +0100
+++ b/jdk/make/mapfiles/libjava/mapfile-vers	Thu Oct 01 00:13:09 2015 +0100
@@ -282,8 +282,9 @@
 
                 # ZipFile.c needs this one
 		throwFileNotFoundException;
-                # zip_util.c needs this one
+                # zip_util.c needs these
 		getLastErrorString;
+		getErrorString;
 
 	# Outcalls from libjvm done using dlsym().
 
--- a/jdk/src/java.base/share/native/libjava/jni_util.h	Thu Oct 01 00:09:51 2015 +0100
+++ b/jdk/src/java.base/share/native/libjava/jni_util.h	Thu Oct 01 00:13:09 2015 +0100
@@ -388,6 +388,7 @@
                           char *jniEntryName);
 
 extern size_t getLastErrorString(char *buf, size_t len);
+extern int getErrorString(int err, char *buf, size_t len);
 #ifdef __cplusplus
 } /* extern "C" */
 #endif /* __cplusplus */
--- a/jdk/src/java.base/share/native/libzip/zip_util.c	Thu Oct 01 00:09:51 2015 +0100
+++ b/jdk/src/java.base/share/native/libzip/zip_util.c	Thu Oct 01 00:13:09 2015 +0100
@@ -1438,6 +1438,7 @@
 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
 {
     char *msg;
+    char tmpbuf[1024];
 
     strcpy(entryname, entry->name);
     if (entry->csize == 0) {
@@ -1456,8 +1457,11 @@
             msg = zip->msg;
             ZIP_Unlock(zip);
             if (n == -1) {
-                jio_fprintf(stderr, "%s: %s\n", zip->name,
-                            msg != 0 ? msg : strerror(errno));
+                if (msg == 0) {
+                    getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+                    msg = tmpbuf;
+                }
+                jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
                 return JNI_FALSE;
             }
             buf += n;
@@ -1470,8 +1474,11 @@
             if ((msg == NULL) || (*msg == 0)) {
                 msg = zip->msg;
             }
-            jio_fprintf(stderr, "%s: %s\n", zip->name,
-                        msg != 0 ? msg : strerror(errno));
+            if (msg == 0) {
+                getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+                msg = tmpbuf;
+            }
+            jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
             return JNI_FALSE;
         }
     }
--- a/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c	Thu Oct 01 00:09:51 2015 +0100
+++ b/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c	Thu Oct 01 00:13:09 2015 +0100
@@ -248,12 +248,13 @@
     const char *detail = defaultDetail;
     char *errmsg;
     size_t fmtsize;
+    char tmpbuf[1024];
     jstring s;
 
     if (errnum != 0) {
-        const char *s = strerror(errnum);
-        if (strcmp(s, "Unknown error") != 0)
-            detail = s;
+        int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf));
+        if (ret != EINVAL)
+            detail = tmpbuf;
     }
     /* ASCII Decimal representation uses 2.4 times as many bits as binary. */
     fmtsize = sizeof(IOE_FORMAT) + strlen(detail) + 3 * sizeof(errnum);
--- a/jdk/src/java.base/unix/native/libjava/jni_util_md.c	Thu Oct 01 00:09:51 2015 +0100
+++ b/jdk/src/java.base/unix/native/libjava/jni_util_md.c	Thu Oct 01 00:13:09 2015 +0100
@@ -30,6 +30,13 @@
 #include "jni_util.h"
 #include "dlfcn.h"
 
+#if defined(LINUX) && (defined(_GNU_SOURCE) || \
+         (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE < 200112L \
+             && defined(_XOPEN_SOURCE) && _XOPEN_SOURCE < 600))
+extern int __xpg_strerror_r(int, char *, size_t);
+#define strerror_r(a, b, c) __xpg_strerror_r((a), (b), (c))
+#endif
+
 void* getProcessHandle() {
     static void *procHandle = NULL;
     if (procHandle != NULL) {
@@ -55,16 +62,14 @@
 size_t
 getLastErrorString(char *buf, size_t len)
 {
-    char *err;
-    size_t n;
     if (errno == 0 || len < 1) return 0;
+    getErrorString(errno, buf, len);
+    return strlen(buf);
+}
 
-    err = strerror(errno);
-    n = strlen(err);
-    if (n >= len)
-        n = len - 1;
-
-    strncpy(buf, err, n);
-    buf[n] = '\0';
-    return n;
+int
+getErrorString(int err, char *buf, size_t len)
+{
+    if (err == 0 || len < 1) return 0;
+    return strerror_r(err, buf, len);
 }
--- a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Thu Oct 01 00:09:51 2015 +0100
+++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Thu Oct 01 00:13:09 2015 +0100
@@ -918,6 +918,7 @@
                                                            jobject this) {
     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
     int arg, fd, t = 1;
+    char tmpbuf[1024];
 #ifdef AF_INET6
     int domain = ipv6_available() ? AF_INET6 : AF_INET;
 #else
@@ -953,22 +954,23 @@
     arg = 65507;
     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
                    (char *)&arg, sizeof(arg)) < 0) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                        strerror(errno));
+        getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", tmpbuf);
         close(fd);
         return;
     }
     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
                    (char *)&arg, sizeof(arg)) < 0) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                        strerror(errno));
+        getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", tmpbuf);
         close(fd);
         return;
     }
 #endif /* __APPLE__ */
 
     if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof (int)) < 0) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", strerror(errno));
+        getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", tmpbuf);
         close(fd);
         return;
     }
@@ -977,9 +979,10 @@
      arg = 0;
      int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
      if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
-         (errno != ENOPROTOOPT)) {
-         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                         strerror(errno));
+           (errno != ENOPROTOOPT))
+    {
+        getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", tmpbuf);
          close(fd);
          return;
      }
@@ -994,7 +997,8 @@
         int ttl = 1;
         if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttl,
                 sizeof (ttl)) < 0) {
-            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", strerror(errno));
+            getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", tmpbuf);
             close(fd);
             return;
         }
--- a/jdk/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c	Thu Oct 01 00:09:51 2015 +0100
+++ b/jdk/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c	Thu Oct 01 00:13:09 2015 +0100
@@ -315,21 +315,15 @@
 JNIEXPORT jbyteArray
 Java_sun_nio_fs_UnixNativeDispatcher_strerror(JNIEnv* env, jclass this, jint error)
 {
-    char* msg;
+    char tmpbuf[1024];
     jsize len;
     jbyteArray bytes;
 
-#ifdef _AIX
-    /* strerror() is not thread-safe on AIX so we have to use strerror_r() */
-    char buffer[256];
-    msg = (strerror_r((int)error, buffer, 256) == 0) ? buffer : "Error while calling strerror_r";
-#else
-    msg = strerror((int)error);
-#endif
-    len = strlen(msg);
+    getErrorString((int)errno, tmpbuf, sizeof(tmpbuf));
+    len = strlen(tmpbuf);
     bytes = (*env)->NewByteArray(env, len);
     if (bytes != NULL) {
-        (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)msg);
+        (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)tmpbuf);
     }
     return bytes;
 }
--- a/jdk/src/java.base/windows/native/libjava/jni_util_md.c	Thu Oct 01 00:09:51 2015 +0100
+++ b/jdk/src/java.base/windows/native/libjava/jni_util_md.c	Thu Oct 01 00:13:09 2015 +0100
@@ -108,13 +108,9 @@
                 }
             } else if (errno != 0) {
                 // C runtime error that has no corresponding WIN32 error code
-                const WCHAR *rtError = _wcserror(errno);
-                if (rtError != NULL) {
-                    wcsncpy(utf16_osErrorMsg, rtError, cbErrorMsg);
-                    // truncate if too long
-                    utf16_osErrorMsg[cbErrorMsg - 1] = L'\0';
+                int ret = _wcserror_s(utf16_osErrorMsg, cbErrorMsg, errno);
+                if (ret == 0)
                     n = wcslen(utf16_osErrorMsg);
-                }
             } else
                 noError = TRUE; //OS has no error to report
 
@@ -147,3 +143,12 @@
     }
     return n;
 }
+
+int
+getErrorString(int err, char *buf, size_t len)
+{
+    int ret = 0;
+    if (err == 0 || len < 1) return 0;
+    ret = strerror_s(buf, len, err);
+    return ret;
+}
--- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c	Thu Oct 01 00:09:51 2015 +0100
+++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c	Thu Oct 01 00:13:09 2015 +0100
@@ -2211,8 +2211,11 @@
 
     optlen = sizeof(optval.i);
     if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
-        char errmsg[255];
-        sprintf(errmsg, "error getting socket option: %s\n", strerror(errno));
+        char tmpbuf[255];
+        int size = 0;
+        char errmsg[255 + 31];
+        getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+        sprintf(errmsg, "error getting socket option: %s", tmpbuf);
         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
         return NULL;
     }