Running old JDK/JVM versions in a modern Linux environment

85 Views Asked by At

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?

0

There are 0 best solutions below