-
Bug
-
Resolution: Unresolved
-
Major
-
None
Hi,
When migrating our docker agent image from a RHEL 9 using JDK 22 or 23 to a RHEL 10 image using JDK 21 we have found a regression for some `sh` invocation that may hang forever. Basically, we have one shell script called by `sh` which eventually calls something like:
```
RANDOM_STRING="$(tr -dc 'a-z0-9' < /dev/urandom | fold -w 4 | head -n1)"
```
This works only if SIGPIPE isn't blocked, as we definitely expect the `head` command to immediately send a SIGPIPE to the `fold` command after one line as been echoed. If you run this in a "normal" shell, it works fine, however if you run this with SIGPIPE ignored, then you will see it hang for ever. On a recent distro, you can emulate this way:
```
[amadeus@50ca067559e9]~% env --ignore-signal=SIGPIPE sh -c "tr -dc 'a-z0-9' < /dev/urandom | fold -w 4 | head -n1"
aa78
^C <--- here it hangs for ever until hitting control + C
```
It happens that some java implementation do hide the SIGPIPE signal by default. This is the case of the JDK 21 found on RHEL 9/10/Fedora. You can easily reproduce that in some docker images based on CentOS/Fedora and run this trivial java program that is just a wrapper for system commands passed as argument:
```
[amadeus@50ca067559e9]~% cat plop.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
class TestSystemCommand
{
public static void main(String[] args)
{
try
{
Process process = Runtime.getRuntime().exec(args);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
reader.close();
}
catch (IOException e)
}
}
```
Which you can run like this:
```
[amadeus@50ca067559e9]~% java plop.java sh -c "tr -dc 'a-z0-9' < /dev/urandom | fold -w 4 | head -n1"
7ow9
^C% <--- Hang for ever until hitting control + C
```
If you run a `quay.io/fedora/fedora` container and `dnf install -y java-latest-openjdk-headless java-21-openjdk-headless` then you can see that there is at least with openjdk some difference of behavior between JDK 21 and JDK 24:
```
[root@3711488feefd /]# /usr/lib/jvm/java-21-openjdk/bin/java plop.java sh -c "tr -dc 'a-z0-9' < /dev/urandom | fold -w 4 | head -n1"
5eco
^C[root@3711488feefd /]# <--- Hangs for ever here
[root@3711488feefd /]# /usr/lib/jvm/java-24-openjdk/bin/java plop.java sh -c "tr -dc 'a-z0-9' < /dev/urandom | fold -w 4 | head -n1"
o8qn
[root@3711488feefd /]#
```
When using a recent coreutils (coreutils >= 8.31, released in 2019), this issue can be fixed by wrapping the command with the `env` command like this:
```
[root@3711488feefd /]# /usr/lib/jvm/java-21-openjdk/bin/java plop.java env --default-signal=SIGPIPE sh -c "tr -dc 'a-z0-9' < /dev/urandom | fold -w 4 | head -n1"
x0jw
[root@3711488feefd /]# /usr/lib/jvm/java-24-openjdk/bin/java plop.java env --default-signal=SIGPIPE sh -c "tr -dc 'a-z0-9' < /dev/urandom | fold -w 4 | head -n1"
s864
```
In order to cope with both old and new OS, where `env` might know the `--default-signal` argument, this more complex wrapper can be used:
```
[root@3711488feefd /]# /usr/lib/jvm/java-21-openjdk/bin/java plop.java sh -c 'if env --default-signal=SIGPIPE true 1>/dev/null 2>&1; then exec env --default-signal=SIGPIPE "$@"; else exec "$@"; fi' – sh -c "tr -dc 'a-z0-9' < /dev/urandom | fold -w 4 | head -n1"
n3d7
[root@3711488feefd /]# /usr/lib/jvm/java-24-openjdk/bin/java plop.java sh -c 'if env --default-signal=SIGPIPE true 1>/dev/null 2>&1; then exec env --default-signal=SIGPIPE "$@"; else exec "$@"; fi' – sh -c "tr -dc 'a-z0-9' < /dev/urandom | fold -w 4 | head -n1"
ormg
```
I will submit a pull request in the Github repo to wrap the call to `nohup` with the above described workaround.
Cheers,
Romain