Всем здравствуйте.
С целью опытов над умершими пытаюсь завести старую версию JDK (1.3) на умеренно современной операционке (Debian 10). И да, я не оговорился – это именно JDK 1.3, выпущенный в мае 2000 года н. э., а не JDK 13, выпущенный в 2019.
И всё бы хорошо с бинарной совместимостью в том смысле, что, на первый взгляд, достаточно установить 32-разрядные зависимости, которые до сих пор есть в Debian:
libbsd0
libc6
libgcc1
libice6
libnspr4
libodbc1
libsm6
libuuid1
libx11-6
libxau6
libxcb1
libxdmcp6
libxext6
libxi6
libxt6
libxtst6
unixodbc-dev
Из нестандартного нужно доустановить лишь libxp6
, которая без проблем достаётся из почти свежего Debian 8, да libstdc++
от gcc 2.96 (пакет compat-libstdc++-296
из ранних версий CentOS).
И вот такой набор (вплоть до моста JDBC-ODBC) прекрасно работал у меня вплоть до Debian 9 включительно.
В Debian 10 что-то случилось, и команда java -version
вместо привычного
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)
выдаёт
Error occurred during initialization of VM
java/lang/NoClassDefFoundError: java/lang/Object
И, если присмотреться, она таки действительно не может распаковать rt.jar
и достать оттуда java/lang/Object.class
. При запуске strace -f
видно, что на Debian 9 процесс открывает rt.jar
и отображает (mmap
) его содержимое в виртуальную память. Это java
здорового некрофила:
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
А вот ровно то же самое, но на Debian 10. Так сказать, java
некрофила-курильщика:
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
Как видно, мы вместо того, чтобы выполнить open()
/openat()
для файла /usr/lib/jvm/java-1.3.1_20-sun-i386/jre/lib/rt.jar
, выполняем то же самое действие для каталога /usr/lib/jvm/java-1.3.1_20-sun-i386/jre
– с предсказуемым исходом.
Проблема совершенно точно не в ядре – её можно воспроизвести на чистом Docker-контейнере i386/debian:10
, а на i386/debian:9
всё работает. Ну, т. е., на худой конец, можно гонять старый софт в Docker’е и этим удовлетвориться.
Тем не менее, если у кого-л. будут идеи, как диагностировать, – предлагайте, буду признателен.