RFR: 8356645: Javac should utilize new ZIP file system read-only access mode

David Beaumont duke at openjdk.org
Wed Jun 4 13:19:54 UTC 2025


On Wed, 4 Jun 2025 12:08:38 GMT, David Beaumont <duke at openjdk.org> wrote:

> This PR seeks to integrate the new ZipFileSystem "accessMode" parameter to open internal ZIP/JAR files as read only, to act as defense in-depth against accidental modification.
> 
> Note that this currently also propagates the (currently undocumented) "zipinfo-time" parameter to several other places where ZIP/JAR files are opened, which is likely to improve performance. This was discussed and is expected to be safe (but it's something to be careful about).
> This will, of course, be thoroughly tested before integration.
> 
> It also unifies several places to use a common helper method to obtain the environment map, adds more comments, and changes a small number of affected tests.
> 
> I'm also happy to update the original bug description to include the timestamp related changes as necessary.

Some pre-review comments.

src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java line 183:

> 181:      *                       {@code null} to ignore release versioning).
> 182:      */
> 183:     public static Map<String, ?> readOnlyJarFSEnv(String releaseVersion) {

I named this after the getJarFSProvider() method above, since they are used in close proximity, but would be happy to consider other names.

src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java line 577:

> 575:                 // Less common case is possible if the file manager was not initialized in JavacTask,
> 576:                 // or if non "*.jar" files are on the classpath. If this is not a ZIP/JAR file then it
> 577:                 // will ignore ZIP specific parameters in env, and may not end up being read-only.

Added comment just to pull out the fact that we might not be able to promise that all ArchiveContainer instances are backed by a read-only file system, and the compiler still has a duty not to attempt any modification.

src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java line 1463:

> 1461:                                 return null;
> 1462:                             }
> 1463:                             fs = jarFSProvider.newFileSystem(p, FSInfo.readOnlyJarFSEnv(null));

Happy to consider either commenting the null here (e.g. `readOnlyJarFSEnv(/* releaseVersion */ null)`), or adding a no-arg version of the method in FSInfo.

src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java line 98:

> 96: 
> 97:     // These must match attributes defined in ZipFileSystem.java.
> 98:     private static final Map<String, ?> CT_SYM_ZIP_ENV = Map.of(

Didn't use FSInfo here, even though it's mostly the same logic, because the symbol file is a ZIP, not a JAR, so naming gets a little muddled, and in this case there's no runtime info, so I can just make a constant map.

src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java line 120:

> 118:         Path ctSymFile = findCtSym();
> 119:         if (Files.exists(ctSymFile)) {
> 120:             try (FileSystem fs = FileSystems.newFileSystem(ctSymFile, (ClassLoader)null);

Several places in existing code pass "(ClassLoader) null", which by inspection makes no difference compared to simply not passing the parameter, so I took the decision to remove it for neatness.

src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java line 261:

> 259:                         // If for any reason this was not opened from a ZIP file,
> 260:                         // then the resulting file system would not be read-only.
> 261:                         assert fs.isReadOnly();

Not sure if an assert is the right thing here or if this should be an always-on runtime check (it can be provoked by having a non-ZIP symbol file, but it's not sanctioned in any way).

test/langtools/tools/javac/api/file/SJFM_TestBase.java line 164:

> 162:         if (zipfs == null) {
> 163:             Path testZip = createSourceZip();
> 164:             zipfs = FileSystems.newFileSystem(testZip, Map.of("accessMode", "readOnly"));

Not strictly necessary, but seems like a good idea to use read-only for testing.

test/langtools/tools/javac/jvm/ClassRefDupInConstantPoolTest.java line 46:

> 44: 
> 45: public class ClassRefDupInConstantPoolTest {
> 46: 

This test was failing and needed to be compiling its own class file rather than reading the one in the test library.

test/langtools/tools/javac/platform/VerifyCTSymClassFiles.java line 68:

> 66:         // Expected to always be a ZIP filesystem.
> 67:         try (FileSystem fs = FileSystems.newFileSystem(ctSym, FSInfo.readOnlyJarFSEnv(null))) {
> 68:             // Check that the file system is read only (not true if not a zip file system).

Another case where I'm not 100% sure if it should be an assert, or a runtime exception/error.

-------------

PR Review: https://git.openjdk.org/jdk/pull/25639#pullrequestreview-2896486601
PR Review Comment: https://git.openjdk.org/jdk/pull/25639#discussion_r2126444200
PR Review Comment: https://git.openjdk.org/jdk/pull/25639#discussion_r2126446371
PR Review Comment: https://git.openjdk.org/jdk/pull/25639#discussion_r2126449539
PR Review Comment: https://git.openjdk.org/jdk/pull/25639#discussion_r2126452047
PR Review Comment: https://git.openjdk.org/jdk/pull/25639#discussion_r2126454461
PR Review Comment: https://git.openjdk.org/jdk/pull/25639#discussion_r2126457316
PR Review Comment: https://git.openjdk.org/jdk/pull/25639#discussion_r2126458265
PR Review Comment: https://git.openjdk.org/jdk/pull/25639#discussion_r2126461426
PR Review Comment: https://git.openjdk.org/jdk/pull/25639#discussion_r2126462843


More information about the compiler-dev mailing list