JDK-8299258 : Launching ksh (shell) from within Java through ProcessBuilder causes ksh process to crash with EXC_BAD_ACCESS (SIGSEGV)
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 20
  • Priority: P2
  • Status: Resolved
  • Resolution: Duplicate
  • OS: os_x
  • Submitted: 2022-12-22
  • Updated: 2024-01-24
  • Resolved: 2023-01-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 20
20Resolved
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Consider the trivial program below which uses the ProcessBuiler API to launch the "/bin/ksh" binary. The command it uses to launch is /bin/ksh --version and is expected to write out the version of ksh. However, running that Java program which launches ksh causes ksh to crash with EXC_BAD_ACCESS (SIGSEGV). 

This issue has been observed on macosx system and happens only on Java 20 and JDK mainline. The same program works fine on Java 19 and previous versions.

The reproducing code follows (the same is attached to this JBS issue):

------
import java.io.*;
import java.nio.file.Path;
import java.util.*;

public class Test {
	public static void main(final String[] args) throws Exception {
		System.out.println("Using Java version " + System.getProperty("java.specification.version"));
		final String[] cmd = new String[] {"/bin/ksh", "--version"};
		final ProcessBuilder pb = new ProcessBuilder(cmd);
        System.out.println("Running command: " + Arrays.toString(cmd));
        final Process p = pb.start();
        final String s = waitAndCapture(p);
        System.out.println("Process id: " + p.pid() + " Exit code " + p.exitValue());
        System.out.println("Command result: ");
        System.out.println(s);
	}


	private static String waitAndCapture(Process p) throws IOException, InterruptedException {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        InputStream in = null;
        InputStream err = null;
        OutputStream out = null;
        try {
            int c;
            in = p.getInputStream();
            while ((c = in.read()) != -1) {
                bout.write(c);
            }
            err = p.getErrorStream();
            while ((c = err.read()) != -1) {
                bout.write(c);
            }
            out = p.getOutputStream();
            p.waitFor();
        } finally {
            close(in, out, err);
        }

        return bout.toString();
    }

    private static void close(final Closeable... closeables) {
        for (Closeable c : closeables) {
            if (c != null) {
                try {
                    c.close();
                } catch (Exception e) {
                    // Ignore
                }
            }
        }
    }
}
------
Running the following command:

java Test.java

results in:

Using Java version 21
Running command: [/bin/ksh, --version]
Process id: 58578 Exit code 139
Command result: 

That exit code 139 for ksh implies the SIGSEGV crash. The crash logs will be available on system specific location and I collected it from my local setup. Here's the relevant parts including stack backtrace which shows the exception happens within ksh binary:

Process:               ksh [58536]
Path:                  /bin/ksh
Identifier:            ksh
Version:               ???
Code Type:             ARM-64 (Native)
Parent Process:        java [58534]
Responsible:           Terminal [636]
User ID:               xxx

Date/Time:             2022-12-22 13:40:16.0739 +0530
OS Version:            macOS 13.0.1 (22A400)
Report Version:        12
...

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Codes:       0x0000000000000001, 0x0000000000000000

Termination Reason:    Namespace SIGNAL, Code 11 Segmentation fault: 11
Terminating Process:   exc handler [58536]

...

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   ksh                           	       0x104321dac sh_ioinit + 76
1   ksh                           	       0x104321d94 sh_ioinit + 52
2   ksh                           	       0x10431e898 sh_init + 524
3   ksh                           	       0x104308798 sh_main + 72
4   dyld                          	       0x191aebe50 start + 2544


Thread 0 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000000   x1: 0x0000000000000000   x2: 0x000000000000000b   x3: 0x0000000000000000
    x4: 0x0000000000000000   x5: 0x0000600002a10474   x6: 0x000000000000000a   x7: 0x0000000000000001
    x8: 0x00000001043fb680   x9: 0x0000000000000000  x10: 0x0000600001d10000  x11: 0x00000000000000c0
   x12: 0x0000000000000055  x13: 0x00000000000007fb  x14: 0x000000008002a7fb  x15: 0x000000008002a7fb
   x16: 0x0000000191dd77cc  x17: 0x00000001f2328c98  x18: 0x0000000000000000  x19: 0x00000001043fb878
   x20: 0x00000001043f8da0  x21: 0x000000016bb07480  x22: 0x0000000104401de8  x23: 0x0000000000000002
   x24: 0x00000001ed9e83c0  x25: 0x0000000000000000  x26: 0x0000000000000000  x27: 0x0000000000000000
   x28: 0x0000000000000000   fp: 0x000000016bb06b40   lr: 0x0000000104321d94
    sp: 0x000000016bb06b20   pc: 0x0000000104321dac cpsr: 0x20001000
   far: 0x0000000000000000  esr: 0x92000046 (Data Abort) byte write Translation fault

Running the same program against Java 19 returns the expected result:

$> <path-to-jdk-19>/bin/java Test.java
results in:

Using Java version 19
Running command: [/bin/ksh, --version]
Process id: 58682 Exit code 2
Command result: 
  version         sh (AT&T Research) 93u+ 2012-08-01

Comments
Fixed by JDK-8300055
17-01-2023

The PR for the backout is out https://github.com/openjdk/jdk20/pull/102
12-01-2023

I suggest reassigning this back to hotspot->runtime for mitigation.
23-12-2022

We can't have a bug that crashes all exec's of ksh. I agree with Roger that we need to revisit this change to JDK 20 so that the crash is avoided.
23-12-2022

Please take another look at the knock effects of this change. It seems desirable use a smaller value that does not trigger the ksh bug causing an apparent compatibility problem. Thanks
22-12-2022

After investigating this, it has been established that this issue started showing up in Java 20 after the change in https://bugs.openjdk.org/browse/JDK-8291060. Previously, up until Java 19, the value being set for RLIMIT_NOFILE, by the JDK, appears to be 10240. Now, with the change in JDK-8291060, it's being set to 9223372036854775807 (which represents RLIM_INFINITY). This value gets imposed on the current Java process as well as its children processes. That change has exposed a bug in ksh binary where it can't handle a value for RLIMIT_NOFILE which exceeds INT_MAX value on the system. Essentially, the code in ksh tries to cast that RLIMIT_NOFILE value to an integer which results in an negative number when the value is more than INT_MAX. That then leads it down a code path within ksh where it ends up trying to write to a data structure that hasn't been initialized. So the real bug resides in ksh. This JBS issue is to record this detail and decide whether any other considerations need to be taken into account for the change in JDK-8291060 and/or whether it deserves a release note.
22-12-2022

A workaround exists to get past this issue. When launching Java, one can set the -XX:-MaxFDLimit option. Doing so, prevents the JDK from setting any explicit RLIMIT_NOFILE on the Java process (and as a result its child processes). Running the following command with Java 20 (and mainline) gets the same program to pass: java -XX:-MaxFDLimit Test.java results in the expected output: Using Java version 21 Running command: [/bin/ksh, --version] Process id: 59029 Exit code 2 Command result: version sh (AT&T Research) 93u+ 2012-08-01
22-12-2022