Menu ▾ ▴

#4153 NPE in TextAreaMouseHandler.doSingleClick when offsetToXY(dragStart) returns null (jEdit 5.7.0)

normal bug
open
nobody
5
2026-09-13
2026-09-13
tvojeho
No

jEdit 5.7.0 can throw a repeated NullPointerException from TextAreaMouseHandler.doSingleClick() when an ordinary mouse click is processed while the clicked/caret offset is temporarily not represented as a visible point in the text area.

The exception is logged silently in activity.log; no normal error dialog is shown.

The immediate failure is:

java.lang.NullPointerException: Cannot read field "x" because "<local4>" is null
    at org.gjt.sp.jedit.textarea.TextAreaMouseHandler.doSingleClick(TextAreaMouseHandler.java:224)
    at org.gjt.sp.jedit.textarea.TextAreaMouseHandler.mousePressed(TextAreaMouseHandler.java:132)
    at org.gjt.sp.jedit.textarea.MouseHandler.mousePressed(MouseHandler.java:64)

The problem appears to be a missing null check in the core mouse handler.

In the jEdit 5.7.0 source, TextAreaMouseHandler.doSingleClick() does approximately:

Point p = textArea.offsetToXY(dragStart);
textArea.moveCaretPosition(dragStart,
    (p.x < 0) ? TextArea.NO_SCROLL : TextArea.NORMAL_SCROLL);

However, the documented contract of TextArea.offsetToXY(...) explicitly allows it to return null when the requested offset is not currently visible.

Therefore p.x can legitimately dereference null.

This is not only a macro-side exception: the uncaught NPE occurs inside jEdit's core mouse-event handler on the AWT Event Dispatch Thread.

Environment

jEdit version: 5.7.0
Build: 2025-08-08

Java runtime version: 17.0.20

OS:

  • Linux
  • Kernel/version: 6.8.0-138-generic
  • Architecture: amd64

Active plugins

ActionHooks 0.6
BufferTabs 1.2.5
CandyFolds 1.2.3
Character Map 1.3.3
Common Controls 1.7.4
Console 5.1.4
Context Menu 0.4
DirtyGutter 0.3b
Editor Scheme 1.8
ErrorList 2.4.0
FTP 1.4
Finish Him! 0.9
FoldViewer 1.1
GnuRegexp 1.0.1
Image Viewer 1.4
Info Viewer 1.6.3
JDiff Plugin 3.4.0
Jakarta Commons 0.9
Menu Editor 0.5
MetalColor 1.1.0
Mouse Snap 0.1
OpenIt 1.6.0
Project Viewer 3.6
QuickNotepad 5.0
RecentBufferSwitcher 0.2
Reopen 0.6
Scala Plugin 1.1.0
TaskList 2.7
Templates 5.1.0
TextTools 1.16
Undo Repair 1.0
WhiteSpace 1.0.3
XSearch 1.9

Known triggering sequence

I currently encounter the problem after a BeanShell text-editing macro performs a multiline edit followed by caret/scroll updates.

A representative sequence is:

  1. Open a normal writable text buffer.
  2. Perform a multiline replacement around the caret.
  3. Move/restore the caret and update its visibility/scroll position.
  4. Immediately left-click in the jEdit text area.
  5. PositionChanging is emitted.
  6. TextAreaMouseHandler.doSingleClick() throws the NPE shown below.
  7. Additional clicks may generate the same exception repeatedly.

In my specific case, immediately before the failure the activity log contains:

14:48:21 [AWT-EventQueue-0] [message] BeanShell: Running script .../+ [NumPadAdd].bsh
14:48:21 [AWT-EventQueue-0] [debug] EditBus: PositionChanging[what=POSITION_CHANGING,source=org.gjt.sp.jedit.EditPane[active]]
14:48:21 [AWT-EventQueue-0] [notice] String: [METHOD] Function::: ensureCaretVisible; Timestamp::: 20260913144821
14:48:21 [AWT-EventQueue-0] [notice] String: [METHOD] Function::: ensureCaretVisible; Timestamp::: 20260913144821
14:48:22 [AWT-EventQueue-0] [debug] EditBus: PositionChanging[what=POSITION_CHANGING,source=org.gjt.sp.jedit.EditPane[active]]
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0: Exception in thread "AWT-EventQueue-0"
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0: java.lang.NullPointerException: Cannot read field "x" because "<local4>" is null
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at org.gjt.sp.jedit.textarea.TextAreaMouseHandler.doSingleClick(TextAreaMouseHandler.java:224)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at org.gjt.sp.jedit.textarea.TextAreaMouseHandler.mousePressed(TextAreaMouseHandler.java:132)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at org.gjt.sp.jedit.textarea.MouseHandler.mousePressed(MouseHandler.java:64)

I have not yet reduced the trigger to a plugin-free / stock-jEdit-only GUI sequence.

Nevertheless, the core failure itself does not appear to depend on a plugin API: TextAreaMouseHandler.doSingleClick() dereferences the result of an API method whose documented return value can be null.

A macro or plugin may make this state easier to reach, but it should not be able to cause an uncaught NPE merely by using normal text-area editing/caret APIs.

Complete stack trace for one occurrence

14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0: Exception in thread "AWT-EventQueue-0"
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0: java.lang.NullPointerException: Cannot read field "x" because "<local4>" is null
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at org.gjt.sp.jedit.textarea.TextAreaMouseHandler.doSingleClick(TextAreaMouseHandler.java:224)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at org.gjt.sp.jedit.textarea.TextAreaMouseHandler.mousePressed(TextAreaMouseHandler.java:132)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at org.gjt.sp.jedit.textarea.MouseHandler.mousePressed(MouseHandler.java:64)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.AWTEventMulticaster.mousePressed(AWTEventMulticaster.java:289)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.Component.processMouseEvent(Component.java:6623)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3389)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.Component.processEvent(Component.java:6391)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.Container.processEvent(Container.java:2266)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5001)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.Component.dispatchEvent(Component.java:4833)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4948)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4572)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4516)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.Component.dispatchEvent(Component.java:4833)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:775)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:747)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:744)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
14:48:22 [AWT-EventQueue-0] [error] AWT-EventQueue-0:  at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

The same exception occurred repeatedly on subsequent mouse presses at approximately 14:48:22–14:48:23.

Expected behavior

A normal single click in the text area should move the caret / update selection normally.

If the target offset cannot currently be converted to an on-screen point, the mouse handler should handle that condition without throwing.

No exception should escape onto the AWT Event Dispatch Thread.

Actual behavior

TextArea.offsetToXY(dragStart) returns null.

TextAreaMouseHandler.doSingleClick() then unconditionally accesses p.x, causing:

java.lang.NullPointerException: Cannot read field "x" because "<local4>" is null

The mouse event is aborted and the exception is written to activity.log.

Repeated clicks can cause repeated exceptions.

Source-level analysis

For jEdit 5.7.0, the relevant code is in:

org/gjt/sp/jedit/textarea/TextAreaMouseHandler.java
doSingleClick(MouseEvent evt)
approximately lines 220-225

The logic obtains:

Point p = textArea.offsetToXY(dragStart);

and immediately evaluates p.x.

However, TextArea.offsetToXY(...) documents null as a valid result when the requested offset is not visible.

Therefore doSingleClick() should not assume that the returned Point is non-null.

This also explains the Java 17 NPE message: local variable p is <local4>.

Suggested minimal defensive fix

A minimal fix would be to treat p == null like an off-screen result:

Point p = textArea.offsetToXY(dragStart);
int scrollMode = (p == null || p.x < 0)
    ? TextArea.NO_SCROLL
    : TextArea.NORMAL_SCROLL;
textArea.moveCaretPosition(dragStart, scrollMode);

This appears consistent with the existing comment:

defer scrolling until mouserelease if result is off-screen

because null from offsetToXY() means that the requested offset is not currently visible.

Alternatively, if another behavior is preferred when p == null, the important requirement is that the documented null return must be handled before dereferencing p.x.

Possible additional audit

There appear to be other places in TextAreaMouseHandler that also assume offsetToXY(...) cannot return null, for example direct .x use in the virtual-space calculations and similar logic in doSingleDrag().

It may be worth auditing all offsetToXY(...) calls in this class for the same documented-null condition rather than fixing only line 224.

The stack trace reported here specifically identifies the dereference in doSingleClick() line 224.

Relationship to older bug #3517

There is an older jEdit core issue:

#3517 - NPE when scrolling to top after multiline delete (soft wrap)

That issue involved text-area state after multiline deletion and was fixed in 2012.

It does not appear to be the same bug:

  • 3517 failed inside TextArea.scrollTo();

  • this report fails inside TextAreaMouseHandler.doSingleClick();
  • this report is reproducible on jEdit 5.7.0;
  • the immediate cause here is an unchecked null result from offsetToXY().

The older issue may nevertheless be useful historical context because both involve temporary text-area display/cache state after multiline editing.

Plugin involvement

The trigger was observed in a setup with the plugins listed above, but the actual exception occurs entirely in jEdit core mouse handling.

I have not identified a plugin frame in the exception stack.

The triggering BeanShell macro may expose a timing/display-state condition, but the core handler should still safely handle the documented null return from offsetToXY().

The immediate source-level null dereference should be independently verifiable from the jEdit 5.7.0 source.

Discussion


Log in to post a comment.