@@ -318,29 +318,46 @@ releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr)
318318 (* env )-> ReleaseByteArrayElements (env , arr , (jbyte * ) parr , JNI_ABORT );
319319}
320320
321- #define IOE_FORMAT "error=%d, %s"
321+ #define IOE_FORMAT "%s, error: %d (%s) %s"
322+
323+ #define SPAWN_HELPER_INTERNAL_ERROR_MSG "\n" \
324+ "Possible reasons:\n" \
325+ " - Spawn helper ran into JDK version mismatch\n" \
326+ " - Spawn helper ran into unexpected internal error\n" \
327+ " - Spawn helper was terminated by another process\n" \
328+ "Possible solutions:\n" \
329+ " - Restart JVM, especially after in-place JDK updates\n" \
330+ " - Check system logs for JDK-related errors\n" \
331+ " - Re-install JDK to fix permission/versioning problems\n" \
332+ " - Switch to legacy launch mechanism with -Djdk.lang.Process.launchMechanism=VFORK\n"
322333
323334static void
324- throwIOException (JNIEnv * env , int errnum , const char * defaultDetail )
335+ throwIOExceptionImpl (JNIEnv * env , int errnum , const char * externalDetail , const char * internalDetail )
325336{
326- const char * detail = defaultDetail ;
337+ const char * errorDetail ;
327338 char * errmsg ;
328339 size_t fmtsize ;
329340 char tmpbuf [1024 ];
330341 jstring s ;
331342
332343 if (errnum != 0 ) {
333344 int ret = getErrorString (errnum , tmpbuf , sizeof (tmpbuf ));
334- if (ret != EINVAL )
335- detail = tmpbuf ;
345+ if (ret != EINVAL ) {
346+ errorDetail = tmpbuf ;
347+ } else {
348+ errorDetail = "unknown" ;
349+ }
350+ } else {
351+ errorDetail = "none" ;
336352 }
353+
337354 /* ASCII Decimal representation uses 2.4 times as many bits as binary. */
338- fmtsize = sizeof (IOE_FORMAT ) + strlen (detail ) + 3 * sizeof (errnum );
355+ fmtsize = sizeof (IOE_FORMAT ) + strlen (externalDetail ) + 3 * sizeof (errnum ) + strlen ( errorDetail ) + strlen ( internalDetail ) + 1 ;
339356 errmsg = NEW (char , fmtsize );
340357 if (errmsg == NULL )
341358 return ;
342359
343- snprintf (errmsg , fmtsize , IOE_FORMAT , errnum , detail );
360+ snprintf (errmsg , fmtsize , IOE_FORMAT , externalDetail , errnum , errorDetail , internalDetail );
344361 s = JNU_NewStringPlatform (env , errmsg );
345362 if (s != NULL ) {
346363 jobject x = JNU_NewObjectByName (env , "java/io/IOException" ,
@@ -351,14 +368,38 @@ throwIOException(JNIEnv *env, int errnum, const char *defaultDetail)
351368 free (errmsg );
352369}
353370
371+ /**
372+ * Throws IOException that signifies an internal error, e.g. spawn helper failure.
373+ */
374+ static void
375+ throwInternalIOException (JNIEnv * env , int errnum , const char * externalDetail , int mode )
376+ {
377+ switch (mode ) {
378+ case MODE_POSIX_SPAWN :
379+ throwIOExceptionImpl (env , errnum , externalDetail , SPAWN_HELPER_INTERNAL_ERROR_MSG );
380+ break ;
381+ default :
382+ throwIOExceptionImpl (env , errnum , externalDetail , "" );
383+ }
384+ }
385+
386+ /**
387+ * Throws IOException that signifies a normal error.
388+ */
389+ static void
390+ throwIOException (JNIEnv * env , int errnum , const char * externalDetail )
391+ {
392+ throwIOExceptionImpl (env , errnum , externalDetail , "" );
393+ }
394+
354395/**
355396 * Throws an IOException with a message composed from the result of waitpid status.
356397 */
357- static void throwExitCause (JNIEnv * env , int pid , int status ) {
398+ static void throwExitCause (JNIEnv * env , int pid , int status , int mode ) {
358399 char ebuf [128 ];
359400 if (WIFEXITED (status )) {
360401 snprintf (ebuf , sizeof ebuf ,
361- "Failed to exec spawn helper: pid: %d, exit value : %d" ,
402+ "Failed to exec spawn helper: pid: %d, exit code : %d" ,
362403 pid , WEXITSTATUS (status ));
363404 } else if (WIFSIGNALED (status )) {
364405 snprintf (ebuf , sizeof ebuf ,
@@ -369,7 +410,7 @@ static void throwExitCause(JNIEnv *env, int pid, int status) {
369410 "Failed to exec spawn helper: pid: %d, status: 0x%08x" ,
370411 pid , status );
371412 }
372- throwIOException (env , 0 , ebuf );
413+ throwInternalIOException (env , 0 , ebuf , mode );
373414}
374415
375416#ifdef DEBUG_PROCESS
@@ -692,7 +733,7 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
692733 (fds [2 ] == -1 && pipe (err ) < 0 ) ||
693734 (pipe (childenv ) < 0 ) ||
694735 (pipe (fail ) < 0 )) {
695- throwIOException (env , errno , "Bad file descriptor" );
736+ throwInternalIOException (env , errno , "Bad file descriptor" , c -> mode );
696737 goto Catch ;
697738 }
698739 c -> fds [0 ] = fds [0 ];
@@ -726,13 +767,13 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
726767 if (resultPid < 0 ) {
727768 switch (c -> mode ) {
728769 case MODE_VFORK :
729- throwIOException (env , errno , "vfork failed" );
770+ throwInternalIOException (env , errno , "vfork failed" , c -> mode );
730771 break ;
731772 case MODE_FORK :
732- throwIOException (env , errno , "fork failed" );
773+ throwInternalIOException (env , errno , "fork failed" , c -> mode );
733774 break ;
734775 case MODE_POSIX_SPAWN :
735- throwIOException (env , errno , "posix_spawn failed" );
776+ throwInternalIOException (env , errno , "posix_spawn failed" , c -> mode );
736777 break ;
737778 }
738779 goto Catch ;
@@ -746,20 +787,21 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
746787 {
747788 int tmpStatus = 0 ;
748789 int p = waitpid (resultPid , & tmpStatus , 0 );
749- throwExitCause (env , p , tmpStatus );
790+ throwExitCause (env , p , tmpStatus , c -> mode );
750791 goto Catch ;
751792 }
752793 case sizeof (errnum ):
753794 if (errnum != CHILD_IS_ALIVE ) {
754795 /* This can happen if the spawn helper encounters an error
755796 * before or during the handshake with the parent. */
756- throwIOException (env , 0 , "Bad code from spawn helper "
757- "(Failed to exec spawn helper)" );
797+ throwInternalIOException (env , 0 ,
798+ "Bad code from spawn helper (Failed to exec spawn helper)" ,
799+ c -> mode );
758800 goto Catch ;
759801 }
760802 break ;
761803 default :
762- throwIOException (env , errno , "Read failed" );
804+ throwInternalIOException (env , errno , "Read failed" , c -> mode );
763805 goto Catch ;
764806 }
765807 }
@@ -771,7 +813,7 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
771813 throwIOException (env , errnum , "Exec failed" );
772814 goto Catch ;
773815 default :
774- throwIOException (env , errno , "Read failed" );
816+ throwInternalIOException (env , errno , "Read failed" , c -> mode );
775817 goto Catch ;
776818 }
777819
0 commit comments