The launcher doesn't have full zip64 support, and in particular can't open jar files where the offset of the manifest from the central directory is >4 GB in size.
Most zip implementations in the JDK have been updated to support the zip64 extension. See https://bugs.openjdk.org/browse/JDK-4681995 for java.util.jar changes, and https://bugs.openjdk.org/browse/JDK-7194005 for previous changes to the launcher for zip64 support.
References are from https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT.
From 4.5.3:
> If one of the size or offset fields in the Local or Central directory record is too small to hold the required data, a Zip64 extended information record is created.
When parse_manifest.c reads 'central directory header' entries (4.3.12), it assumes the values are present directly in the header, and does not inspect the 'Zip64 Extended Information Extra Field' (4.5.3).
When reading a zip64 file >4GB in size, it will read the 'relative offset of local header' from the central directory and assume it is a valid offset. It should check if that value is set to 0xFFFFFFFF and then look for a Zip64 extended information record:
https://github.com/openjdk/jdk/blob/fb8f2a0a929ebe7f65c69741712b89bbb403ade9/src/java.base/share/native/libjli/parse_manifest.c#L164-L165
---
Repro:
```
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class Zip64 {
public static class Main {
public static void main(String[] args) {
System.out.print("Main");
}
}
public static void main(String[] args) throws IOException {
try (OutputStream fos = Files.newOutputStream(Paths.get(args[0]));
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos)) {
byte[] gb = new byte[1 << 30];
for (int i = 1; i <= 5; i++) {
writeEntry(zos, Integer.toString(i), gb);
}
for (Class<?> clazz : List.of(Zip64.class, Main.class)) {
String baseName = clazz.getName() + ".class";
writeEntry(zos, baseName, Zip64.class.getResourceAsStream(baseName).readAllBytes());
}
writeEntry(
zos,
"META-INF/MANIFEST.MF",
("Manifest-Version: 1.0\nMain-Class: " + Main.class.getName() + "\n").getBytes(UTF_8));
}
}
private static void writeEntry(ZipOutputStream zos, String name, byte[] bytes)
throws IOException {
ZipEntry ze = new ZipEntry(name);
ze.setMethod(ZipEntry.STORED);
ze.setSize(bytes.length);
CRC32 crc = new CRC32();
crc.update(bytes);
ze.setCrc(crc.getValue());
zos.putNextEntry(ze);
zos.write(bytes);
zos.closeEntry();
}
}
```
$ java -fullversion
openjdk full version "22-ea+30-2287"
$ javac Zip64.java
$ java Zip64 zip64.jar
The expected behaviour is:
$ java -jar zip64.jar
Main
The actual behaviour is that the launcher fails to open the jar:
$ java -jar zip64.jar
Error: Invalid or corrupt jarfile zip64.jar