Skip to content

Fix IllegalArgumentException when drawing unified diff code minings#2773

Merged
iloveeclipse merged 1 commit into
eclipse-platform:masterfrom
tobiasmelcher:fix_font_disposed_in_unified_diff
Jun 19, 2026
Merged

Fix IllegalArgumentException when drawing unified diff code minings#2773
iloveeclipse merged 1 commit into
eclipse-platform:masterfrom
tobiasmelcher:fix_font_disposed_in_unified_diff

Conversation

@tobiasmelcher

Copy link
Copy Markdown
Contributor

UnifiedDiffLineHeaderCodeMining.draw() caches Font references in its foregrounds list and in cachedFont. These fonts can be disposed under the cache when:

  1. The mining is disposed while a paint event for it is still in flight (e.g. "hide diff" recomputes the mining list and a pending paintControl still references the old annotations).
  2. The widget font is replaced by an instance with equal FontData. The previous invalidation used Font.equals(), which is a value compare and does not detect a disposed handle.

Once an exception was thrown, the stale cache was never refreshed, so every subsequent scroll repaint produced another error.

Fix:

  • dispose() nulls the cached state so a stray paint after disposal cannot enter the fast path.
  • Cache invalidation also checks cachedFont.isDisposed().
  • The fast-path loop validates f.font.isDisposed() before use; if stale, the cache is dropped and the slow path rebuilds it in the same paint.

Fixes #2772

@tobiasmelcher

Copy link
Copy Markdown
Contributor Author

@iloveeclipse Unfortunately, I was unable to reproduce the issue on a Linux machine.
Could you please provide some additional information?

Were there any exceptions in the error log besides the java.lang.IllegalArgumentException?
Did you change the text editor font settings while the unified diff was being rendered?

From the current behavior, it seems that cached fonts may have been disposed unexpectedly, but I’m not sure under which circumstances this could happen.
Is it possible that LineHeaderCodeMining#draw is being called after the instance has already been disposed via LineHeaderCodeMining#dispose?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes repeated IllegalArgumentException errors thrown while painting unified diff line-header code minings when cached Font instances become disposed (e.g., after “hide diff” triggers recomputation while a paint is still in flight). It also hardens unified diff navigation runnables against empty diff lists.

Changes:

  • Clear cached mining paint state on dispose() and invalidate caches when the cached widget font is disposed.
  • Detect disposed cached foreground fonts during the fast-path draw loop and fall back to rebuilding caches in the same paint.
  • Prevent NextRunnable / PreviousRunnable from indexing into empty unified diff lists.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
team/bundles/org.eclipse.compare/compare/org/eclipse/compare/unifieddiff/internal/UnifiedDiffCodeMiningProvider.java Improves cache invalidation and draw fast-path robustness when fonts are disposed; clears cached state on dispose.
team/bundles/org.eclipse.compare/compare/org/eclipse/compare/unifieddiff/internal/PreviousRunnable.java Adds a guard to return early when there are no diffs to navigate.
team/bundles/org.eclipse.compare/compare/org/eclipse/compare/unifieddiff/internal/NextRunnable.java Adds a guard to return early when there are no diffs to navigate.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@iloveeclipse

Copy link
Copy Markdown
Member

Not sure if it is related, I always use Eclipse with disabled themes. Beside this, RHEL 9.6 with X11, KDE5, nothing special. I believe all errors were same, but I will check tomorrow, they were literally flooding my error log.

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Test Results

    54 files  ±0      54 suites  ±0   56m 41s ⏱️ + 2m 40s
 4 677 tests ±0   4 655 ✅ ±0   22 💤 ±0  0 ❌ ±0 
11 925 runs  ±0  11 772 ✅ ±0  153 💤 ±0  0 ❌ ±0 

Results for commit 31a855b. ± Comparison against base commit 82c7987.

♻️ This comment has been updated with latest results.

@iloveeclipse

Copy link
Copy Markdown
Member

Just tested the patch. Looks OK now, I don't see exceptions anymore. Regarding exceptions: they were all identical, exact same stack.

@iloveeclipse iloveeclipse force-pushed the fix_font_disposed_in_unified_diff branch from 75b155e to 1b31813 Compare June 19, 2026 06:07

@iloveeclipse iloveeclipse left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed one commit on top, could you please check?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

@iloveeclipse iloveeclipse force-pushed the fix_font_disposed_in_unified_diff branch from 1b31813 to b506153 Compare June 19, 2026 07:43
UnifiedDiffLineHeaderCodeMining.draw() caches Font references in its
foregrounds list and in cachedFont. These fonts can be disposed under
the cache when:

1. The mining is disposed while a paint event for it is still in flight
     (e.g. "hide diff" recomputes the mining list and a pending
     paintControl still references the old annotations).
2. The widget font is replaced by an instance with equal FontData. The
     previous invalidation used Font.equals(), which is a value compare
     and does not detect a disposed handle.

Once an exception was thrown, the stale cache was never refreshed, so
every subsequent scroll repaint produced another error.

Fix:
- dispose() nulls the cached state so a stray paint after disposal
  cannot enter the fast path.
- Cache invalidation also checks cachedFont.isDisposed().
- The fast-path loop validates f.font.isDisposed() before use; if stale,
  the cache is dropped and the slow path rebuilds it in the same paint.

Fixes eclipse-platform#2772
@tobiasmelcher tobiasmelcher force-pushed the fix_font_disposed_in_unified_diff branch from b506153 to 31a855b Compare June 19, 2026 08:26

@iloveeclipse iloveeclipse left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Tested yet again, still works :-)

@iloveeclipse iloveeclipse merged commit c45a7a7 into eclipse-platform:master Jun 19, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lot of errors reported in unified diff after click on "hide diff" button

4 participants