6

The problem

I need to use JDK10 to compile a legacy project I have to work on. I know it is a short-term support release whose lifetime has ended. But before the project is updated to a newer Java version I need to be able to build and run it on my development machine.

Note: The project does build correctly on its CI pipeline and does run on the production environment. The problem is not related to the project but to my machine.

The problem I am running into is I cannot compile any java code with JDK10, but other JDKs such as 8, 9, 11, 12 and 17 do work.

Reproduce the problem

To showcase my problem, I am trying to compile a simple hello world program Test.java:

public class Test {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

I am using the prebuilt JDK from OpenJDK, but I have also tried and reproduced this problem with the Zulu distribution.

I can consistently reproduce the problem with:

$ wget https://download.java.net/java/GA/jdk10/10.0.2/19aef61b38124481863b1413dce1855f/13/openjdk-10.0.2_linux-x64_bin.tar.gz
...
2022-10-24 14:10:31 (11,1 MB/s) - ‘openjdk-10.0.2_linux-x64_bin.tar.gz’ saved [204892533/204892533]
$ tar -xzf openjdk-10.0.2_linux-x64_bin.tar.gz
$ jdk-10.0.2/bin/java -version 
openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment 18.3 (build 10.0.2+13)
OpenJDK 64-Bit Server VM 18.3 (build 10.0.2+13, mixed mode)
$ jdk-10.0.2/bin/javac -version                             
javac 10.0.2
$ jdk-10.0.2/bin/javac Test.java
Exception in thread "main" java.lang.ClassFormatError: Ille in class file <Unknown>
    at java.base/jdk.internal.misc.Unsafe.defineAnonymousClass0(Native Method)
    at java.base/jdk.internal.misc.Unsafe.defineAnonymousClass(Unsafe.java:1223)
    at java.base/java.lang.invoke.InnerClassLambdaMetafactory.spinInnerClass(InnerClassLambdaMetafactory.java:320)
    at java.base/java.lang.invoke.InnerClassLambdaMetafactory.buildCallSite(InnerClassLambdaMetafactory.java:188)
    at java.base/java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:317)
    at java.base/java.lang.invoke.CallSite.makeSite(CallSite.java:330)
    at java.base/java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:250)
    at java.base/java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:240)
    at jdk.compiler/com.sun.tools.javac.code.Symtab.doEnterClass(Symtab.java:700)
    at jdk.compiler/com.sun.tools.javac.code.Symtab.enterClass(Symtab.java:714)
    at jdk.compiler/com.sun.tools.javac.code.Symtab.enterClass(Symtab.java:275)
    at jdk.compiler/com.sun.tools.javac.code.Symtab.<init>(Symtab.java:485)
    at jdk.compiler/com.sun.tools.javac.code.Symtab.instance(Symtab.java:89)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.<init>(Attr.java:128)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.instance(Attr.java:119)
    at jdk.compiler/com.sun.tools.javac.comp.Annotate.<init>(Annotate.java:109)
    at jdk.compiler/com.sun.tools.javac.comp.Annotate.instance(Annotate.java:84)
    at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.<init>(ClassReader.java:235)
    at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.instance(ClassReader.java:228)
    at jdk.compiler/com.sun.tools.javac.code.ClassFinder.<init>(ClassFinder.java:180)
    at jdk.compiler/com.sun.tools.javac.code.ClassFinder.instance(ClassFinder.java:173)
    at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.<init>(JavaCompiler.java:386)
    at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.instance(JavaCompiler.java:115)
    at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:291)
    at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:165)
    at jdk.compiler/com.sun.tools.javac.Main.compile(Main.java:57)
    at jdk.compiler/com.sun.tools.javac.Main.main(Main.java:43)

Already checked

Other JDKs

With java 11 it works:

$ wget https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_linux-x64_bin.tar.gz
...
2022-10-24 14:08:42 (10,6 MB/s) - ‘openjdk-11.0.2_linux-x64_bin.tar.gz’ saved [187513052/187513052]

$ tar -xzf openjdk-11.0.2_linux-x64_bin.tar.gz
$ jdk-11.0.2/bin/java -version 
openjdk version "11.0.2" 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)
$ jdk-11.0.2/bin/javac -version                             
javac 11.0.2
$ jdk-11.0.2/bin/javac Test.java
$ jdk-11.0.2/bin/java Test
Hello, world!

It also works with java 9:

$ wget https://download.java.net/java/GA/jdk9/9.0.4/binaries/openjdk-9.0.4_linux-x64_bin.tar.gz
...
2022-10-24 14:31:05 (11,0 MB/s) - ‘openjdk-9.0.4_linux-x64_bin.tar.gz’ saved [206018615/206018615]
$ tar -xzf openjdk-9.0.4_linux-x64_bin.tar.gz
$ jdk-9.0.4/bin/java -version 
openjdk version "9.0.4"
OpenJDK Runtime Environment (build 9.0.4+11)
OpenJDK 64-Bit Server VM (build 9.0.4+11, mixed mode)
$ jdk-9.0.4/bin/javac -version
javac 9.0.4
$ jdk-9.0.4/bin/javac Test.java
$ jdk-9.0.4/bin/java Test     
Hello, world!

Same goes with java 8, 12 and 17.

I have also tried the Zulu distributions.

Fresh install

I have tried installing a fresh Ubuntu 22.04 Desktop image on a VirtualBox. The problem cannot be reproduced. When downloading openjdk 10 and compiling/running the simple Test.java file, it does work as expected. It has to be related to my machine configuration.

OS information

Here are some details about my OS:

$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.1 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
$ uname --all                        
Linux Work-Miguel 5.15.0-52-generic #58-Ubuntu SMP Thu Oct 13 08:03:55 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Miguel Alorda
  • 623
  • 5
  • 13
  • 1
    Have you checked whether your `CLASSPATH` environment variable contains anything that points to a specific jdk? – Federico klez Culloca Oct 24 '22 at 12:55
  • Fredericos comment is a good point to start. The `ClassFormatError` indicates that some class (i.e. an already compiled code) cannot be read by the JVM. So there seems to be some mismatch on your machine, when the JDK 10 compiler wants to read some already compiled classes and fails. – Seelenvirtuose Oct 24 '22 at 13:23
  • I also directly tested the exact steps you have shown us. Works on my machine. Thumbs up (btw) for the well written question. – Seelenvirtuose Oct 24 '22 at 13:24
  • 1
    @FedericoklezCulloca Thank you for the comment, I did not know of that env variable. However, it is not set `env | grep CLASSPATH` prints empty output – Miguel Alorda Oct 24 '22 at 13:56
  • @Seelenvirtuose, I do not think the problem is reproducible in another machine. Its most likely a problem regarding my machine configuration that I do not know how to find. As I have tested it on another machine and a VM. – Miguel Alorda Oct 24 '22 at 14:00
  • What happens when you build with Java 11 and pass `-target 10` to `javac`? – Elliott Frisch Oct 24 '22 at 14:08
  • @ElliottFrisch good suggestions. It seems I can build and run the sample with java 11 providing the target (getting the warning `warning: target release 10 conflicts with default source release 11`). Though I am not sure how I could use that to build the actual legacy system I need to work on. It uses gradle – Miguel Alorda Oct 24 '22 at 14:16
  • 1
    @MiguelAlorda Like [this](https://stackoverflow.com/a/44263437/2970947). – Elliott Frisch Oct 24 '22 at 14:18
  • @ElliottFrisch I just realised we do have the `sourceCompatibility` and `targetCompatibility` set to java 10, but I cannot simply run with java 11 as [gradle version (4.x) is not compatible with java 11](https://stackoverflow.com/questions/54358107/gradle-could-not-determine-java-version-from-11-0-2). That is yet another migration that is needed on the legacy project – Miguel Alorda Oct 24 '22 at 14:32

3 Answers3

2

So the problem is clearly not in the code you are compiling. According to the stack trace, it is happening while loading and initializing the compiler. The compiler hasn't actually started compiling anything yet.

The only things that I can think of to explain this are:

  • Your (original) Java 10 download was corrupted1 resulting in an installation with a subtly corrupted Java compiler; e.g. a bit flip in one of the .class files in the compiler.

  • Some critical library on your system is subtly corrupted, or has a subtle bug in it.

  • It is a hardware (mother board, CPU, RAM) problem. Or a firmware problem.

  • It is some weird side-effect of a hacked system.

It might be worth trying to fetch a copy of the Java 10 installer another way and compare it with the installer that you have been installing. Also, it is worth checking that the checksums (MD5, SHA256) for the download match the checksums that Oracle says they should be.

If those don't help, it is going to be difficult to track this down. And IMO not worth the effort.

My advice would be to remove Java 10 from the list of platforms that you build and test for. (And "support" if you are still trying to do that.) And if you really need to build with Java 10, get hold of a different machine (with reliable hardware) and reinstall everything from scratch using known good downloads.


1 - Without getting too "tin foil hat" about it, such a corruption could be caused by an undetected network transmission error, faulty hardware, or the interference of a "deep packet inspection" appliance. Repeating the download may result in the same corruption. However, the fact that other people report that they cannot reproduce this suggests that this is not simply due to a corrupted copy on the download server.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Thank you for your answer. I have already checked the integrity of the java download, and checked with different java 10 installers (Also checked java `10.0`, `10.0.1` and `10.0.2`). I do not think its a hardware problem neither as all other programs seem to run just fine. I suspect it is a corrupted/incompatibility with a system library, but I don't know how to track it (already tried with `apt-get update && apt-get upgrade`). I may end up building inside a docker container (in which java 10 does work) – Miguel Alorda Oct 24 '22 at 14:06
  • 1
    A fresh / clean OS install may be the answer. But if it was me, I'd be dropping Java 10. It is (IMO) extremely doubtful that building with Java 10 is going to be of significant value to your efforts. You certainly shouldn't be running on Java 10. – Stephen C Oct 24 '22 at 14:10
  • The only thing I can think of that I have installed up to the kernel level is [Kaspersky](https://www.kaspersky.co.uk/home-security) an antivirus and monitoring program required by company policies. It does cause some issues with signed certificates, for example, as it proxies all internet connections. But I have been able to deal with that so far and have not noticed any other problems about it. Also, as long a integrity hashes match, that should not be an issue – Miguel Alorda Oct 24 '22 at 14:10
  • Kapersky could conceivably interfere with files as they are being extracted from a (non-corrupt) installer or written to disk. – Stephen C Oct 24 '22 at 14:12
  • That is true. But how come it only interferes with java 10 and does it reliably no matter the minor version or the installer/distributable used? – Miguel Alorda Oct 24 '22 at 14:17
  • It could be looking for a virus signature and be detecting a false positive in some .class file that happens to be unchanged across a few minor versions. (Though it is not distinct .class files. Rather it is ... whatever representation they now use for the standard libraries since Java 9.) But is is only one of a few theories. – Stephen C Oct 24 '22 at 16:07
1

I have reasons to believe that something related with security on your system is getting involved here and breaks the process.

Reason 1

$ jdk-10.0.2/bin/javac Test.java
Exception in thread "main" java.lang.ClassFormatError: Ille in class file <Unknown>

Ille is very weird and 99% the process tried to write a message in the form of Illegal some description but got interupted in the middle of it.

Reason 2

at java.base/jdk.internal.misc.Unsafe.defineAnonymousClass0(Native Method)
    at java.base/jdk.internal.misc.Unsafe.defineAnonymousClass(Unsafe.java:1223)

Why does it even mention Unsafe here, there should not be any reason for it.

Panagiotis Bougioukos
  • 15,955
  • 2
  • 30
  • 47
0

Self answer

For anyone who comes across a similar issue, I did not manage to fix it. I have tried all solutions suggested above.

Still, as a temporary solution until we migrate to a Java long term support version, I ended up using a development container.

From an alpine, I installed git, jdk 10 and some other development tools, mounted the source as volumes and ended up working inside the container.

Currently I just use it for building and running the software, as I am using IntelliJ as an IDE. Still, since it cannot build the software correctly, it's Intellisense suggestions are not good enough. I might end up moving into a full blown VSCode devcontainter.

Miguel Alorda
  • 623
  • 5
  • 13