I'm trying to run an old JDK (version 1.3 released in May 2000) in a relatively modern Linux box (Debian 10).
As far as binary compatibility is concerned, everything seems fine, since all the necessary 32-bit dependencies are still available in Debian Linux:
libbsd0
libc6
libgcc1
libice6
libnspr4
libodbc1
libsm6
libuuid1
libx11-6
libxau6
libxcb1
libxdmcp6
libxext6
libxi6
libxt6
libxtst6
unixodbc-dev
What's missing is libxp6:i386
which is luckily still available from Debian 8 "Jessie" and the ancient libstdc++
from gcc 2.96, which can be taken from early CentOS versions (CentOS 4, compat-libstdc++-296
package).
Using the above recipé, I used to successfully run Java 1.3 (incl. even the JDBC-ODBC bridge) up until Debian 9. Then, Debian 10 was released. Now, running java -version
instead of the usual
java version "1.3.1_20"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_20-b03)
Java HotSpot(TM) Client VM (build 1.3.1_20-b03, mixed mode)
prints out
Error occurred during initialization of VM
java/lang/NoClassDefFoundError: java/lang/Object
Indeed, it fails to unpack rt.jar
and load java/lang/Object.class
out of the JAR archive. When running strace -f
, the difference between Debian 9 and Debian 10 can be clearly seen. Here, the process opens rt.jar
and maps it (mmap()
) into the virtual memory:
stat64("/usr/lib/jvm/java-1.3.1_20-sun-i386/jre/lib/rt.jar", {st_mode=S_IFREG|0644, st_size=13904932, ...}) = 0
lstat64("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/usr/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/usr/lib/jvm", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/usr/lib/jvm/java-1.3.1_20-sun-i386", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
lstat64("/usr/lib/jvm/java-1.3.1_20-sun-i386/jre", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
lstat64("/usr/lib/jvm/java-1.3.1_20-sun-i386/jre/lib", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
lstat64("/usr/lib/jvm/java-1.3.1_20-sun-i386/jre/lib/rt.jar", {st_mode=S_IFREG|0664, st_size=13904932, ...}) = 0
open("/usr/lib/jvm/java-1.3.1_20-sun-i386/jre/lib/rt.jar", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0664, st_size=13904932, ...}) = 0
_llseek(3, 0, [13904932], SEEK_END) = 0
mmap2(NULL, 13904932, PROT_READ, MAP_SHARED, 3, 0) = 0xf6b9c000
close(3) = 0
And here's exactly the same scenario from Debian 10:
stat64("/usr/lib/jvm/java-1.3.1_20-sun-i386/jre/lib/rt.jar", {st_mode=S_IFREG|0644, st_size=13904932, ...}) = 0
openat(AT_FDCWD, "/usr/lib/jvm/java-1.3.1_20-sun-i386/jre", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
close(3) = 0
As you can see, instead of /usr/lib/jvm/java-1.3.1_20-sun-i386/jre/lib/rt.jar
being opened (open()
or openat()
), one of its parent directories (/usr/lib/jvm/java-1.3.1_20-sun-i386/jre
) is opened, quite expectedly resulting in the empty JVM classpath.
The cause of the problem is definitely not the kernel: I observe the same difference using i386/debian:10
vs i386/debian:9
Docker image with exactly the same kernel on exactly the same hardware.
The workarounds I'm considering are:
- using a VM with an earlier Linux version,
- using a Docker container with an earlier Linux userspace,
- substituting an earlier
glibc
version, - switching to any BSD UNIX (Free/Net/DragonFly), with a stable Linux ABI.
Still, are there any ways to further diagnose the problem?