-
Notifications
You must be signed in to change notification settings - Fork 51
Resource leak in GHService.getDiffStats() - JGit resources not closed #1660
Description
Plugin Modernizer version
999999-SNAPSHOT (latest main branch, built locally)
What Operating System are you using
Linux (GitHub Actions CI environment)
Observation: The bug exists in the source code regardless of OS, as JGit Resource leaks are a cross-platform issue affecting both Linux and Windows builds.
Reproduction steps
Reproduction steps:
- Clone the repository: git clone https://github.com/jenkins-infra/plugin-modernizer-tool.git
- Checkout latest main branch
- Build the project: mvn package -DskipTests
- Set environment variables:
- export GH_TOKEN=your_github_token
- export GH_OWNER=your_ithub_username
- Run the tool with dry-run mode on any plugin:
plugin-modernizer dry-run --plugins PLUGIN_NAME --recipe RECIPE_NAME --debug - Monitor open file handles during execution
- Observe resources accumulate with each plugin processed
Expected Results
JGit resources (ObjectReader, DiffFormatter, RevWalk) should be properly closed
after use in the getDiffStats() method.
All resources should be closed via try-with-resources or explicit close() calls:
- ObjectReader should be closed after diff calculation
- DiffFormatter should be closed after diff calculation
- RevWalk instances should be closed after use
Expected: Stable resource count regardless of number of plugins processed.
Actual Results:
RESOURCE LEAK CONFIRMED - Bug identified via code analysis
The getDiffStats() method in GHService.java has resource leaks:
LEAK #1 - dryRun=true path (lines 1254-1286):
ObjectReader reader = repository.newObjectReader(); // line 1254 - CREATED
DiffFormatter formatter = new DiffFormatter(...); // line 1255 - CREATED if (dryRun) {
return new DiffStats(...); // line 1286 - RETURNS EARLY!
// BUG: reader and formatter are NEVER closed in this path!
}LEAK #2 - dryRun=false path (lines 1288-1317):
reader.close(); // line 1316 - Only reader is closedLEAK #3 - RevWalk instances (lines 1299-1300):
oldTree.reset(reader, new RevWalk(repository).parseTree(defaultBranch)); // RevWalk #1
newTree.reset(reader, new RevWalk(repository).parseTree(head)); // RevWalk #2I created a standalone Java program (ResourceLeakDemo.java) that mimics the buggy code pattern from GHService.getDiffStats(). Running it proves the resource leak:
AFTER 5 RUNS with dryRun=true:
Resources still open: 10
Maximum ever open: 10
Each run creates 2 resources (reader + formatter) that are NEVER closed.
IMPACT:
- Each call to getDiffStats() leaks 2-4 JGit resources
- Batch processing of 50 plugins = potential 200+ leaked resources
- Can cause OutOfMemoryError or "too many open files" error
Affected Component: plugin-modernizer-core
Affected File: GHService.java lines 1254-1317
Suggested Fix:
try (ObjectReader reader = repository.newObjectReader();
DiffFormatter formatter = new DiffFormatter(new ByteArrayOutputStream())) {
formatter.setRepository(repository);
formatter.setDiffComparator(RawTextComparator.DEFAULT);
formatter.setDetectRenames(true);
// ... existing code ...
} // Both reader and formatter automatically closed
// For RevWalk:
try (RevWalk oldWalk = new RevWalk(repository);
RevWalk newWalk = new RevWalk(repository)) {
// ... use oldWalk and newWalk ...
} // Both RevWalk automatically closedScreenshots attached:
Metadata
Metadata
Assignees
Labels
Type
Fields
Give feedbackPriority
Target date