eclipse-jdt / eclipse-jdt/eclipse.jdt.core

NullPointerException when listing a missing package in a system module

Open
#5,381 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
237
Forks
195
Avg merge
1d 12h
Merged PRs (30d)
47

Description

## Description

`EclipseFileManager.list()` throws when asked to list a package that does not exist in a system module.

`JrtFileSystem.list()` initializes its intermediate `files` variable to `null`. When `Files.list(resolve)` throws `NoSuchFileException`, the default error path logs the exception and continues. The subsequent iteration over `files` then throws a secondary `NullPointerException`.

Source: https://github.com/eclipse-jdt/eclipse.jdt.core/blob/80fa9fa3e994d5f7b8d97ff1fcc88179efbe59f9/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/JrtFileSystem.java#L73-L100

## Reproducer

```java
JavaCompiler compiler = new EclipseCompiler();

try (StandardJavaFileManager fileManager =
compiler.getStandardFileManager(null, null, null)) {

JavaFileManager.Location javaBase =
fileManager.getLocationForModule(
StandardLocation.SYSTEM_MODULES,
"java.base");

boolean found = fileManager.list(
javaBase,
"org.eclipse.jdt.__missing_package__",
Set.of(JavaFileObject.Kind.CLASS),
false)
.iterator()
.hasNext();

System.out.println(found);
}
```

## Expected behavior

The lookup returns an empty iterable and prints `false`.

A nonexistent package is an ordinary negative lookup. The directory-backed implementation returns when its package directory does not exist, and the archive-backed implementation returns when the archive contains no types for the requested package.

## Actual behavior

With the default value of `org.eclipse.jdt.propagate_io_errors` (`false`), ECJ logs `NoSuchFileException` and then throws `NullPointerException` while iterating over the null `files` variable.

With `-Dorg.eclipse.jdt.propagate_io_errors=true`, the missing package instead produces `IllegalStateException`.

## Suggested fix

- Catch `NoSuchFileException` and `NotDirectoryException` before the general `IOException` handler.
- Treat those two exceptions as negative lookups and return an empty list without writing to `System.err`.
- Preserve the existing propagation policy for other checked `IOException`s.
- When propagation is disabled, return an empty list after logging the original checked I/O failure instead of producing a secondary NPE.
- Avoid a nullable intermediate list so every normal return path produces a valid result.

This intentionally changes the behavior for missing packages when `org.eclipse.jdt.propagate_io_errors=true`: these lookups would return an empty list instead of throwing `IllegalStateException`.

## Scope

Kind filtering remains in `EclipseFileManager.collectAllMatchingFiles()`. `JrtFileSystem.list()` does not currently use its `kinds` parameter, and this issue does not propose changing that behavior.

Recursive enumeration is also separate. The current implementation does not use the `recurse` parameter, but a missing package should produce an empty result for either value. Correct recursive traversal has different enumeration and performance implications and can be addressed independently.

An `UncheckedIOException` raised during lazy stream traversal currently propagates past the checked `IOException` handler and is outside the scope of this issue.

## Version

Reproduced from current master at `80fa9fa3e994d5f7b8d97ff1fcc88179efbe59f9`.

Contributor guide

Open the contributing guide

Research direction

Start in org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/JrtFileSystem.java at JrtFileSystem.list(), then review EclipseFileManager.collectAllMatchingFiles() for the existing filtering boundary. Run the provided EclipseCompiler reproducer against a missing package in java.base; done means both recurse values return an empty iterable without a secondary NPE, while other I/O errors retain the stated propagation behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
compilers
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.