JDK-8212102 : [TextField] IOOBE on paste/replace text with control characters
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: 8u40,openjfx11
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: x86_64
  • Submitted: 2018-10-11
  • Updated: 2020-12-15
  • Resolved: 2019-01-30
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
openjfx11.0.10Fixed
Description
ADDITIONAL SYSTEM INFORMATION :
CPU: x64
OS: Windows 10 Enterprise
Java: openjdk-11+28

A DESCRIPTION OF THE PROBLEM :
When a single tab or newline symbol or an arbitrary combination of those is pasted from the clipboard into a javafx.scene.control.TextField, an exception is thrown and the textfield seems not to be usable afterwards.

In contrast, pasting a string that contains regular alphabetic characters interspersed with tabs and newlines like this:
"\r\n123\t456\r\n789\t"
will behave well, and when pasted into the textfield will be trimmed to:
"123456789"

So I would expect that:
"\r\n"
to be trimmed to the empty string:
""

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Copy a single tab or newline symbol from any text editor to the clipboard.
2. Start the test case application provided with this bug report.
3. Type something into the first textfield, e.g. "12345".
4. `Tab` away to the second textfield.
5. `Tab`back to the first textfield. Make sure that the whole text is selected.
6. Now paste the tab or newline symbol from the clipboard into the first textfield.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No exception is thrown and the textfield is still usable. The texfield is empty after pasting just tab or newline symbols.
ACTUAL -
A StringIndexOutOfBoundsException is thrown and the textfield is no longer usable.

---------- BEGIN STACKTRACE ----------
Exception in thread "JavaFX Application Thread" java.lang.StringIndexOutOfBoundsException: start 0, end 5, length 0
	at java.base/java.lang.AbstractStringBuilder.checkRangeSIOOBE(AbstractStringBuilder.java:1721)
	at java.base/java.lang.AbstractStringBuilder.substring(AbstractStringBuilder.java:1014)
	at java.base/java.lang.StringBuilder.substring(StringBuilder.java:85)
	at javafx.controls/javafx.scene.control.TextField$TextFieldContent.get(TextField.java:79)
	at javafx.controls/javafx.scene.control.TextInputControl.getText(TextInputControl.java:464)
	at javafx.controls/javafx.scene.control.TextInputControl.updateContent(TextInputControl.java:567)
	at javafx.controls/javafx.scene.control.TextInputControl.replaceText(TextInputControl.java:558)
	at javafx.controls/javafx.scene.control.TextInputControl.replaceText(TextInputControl.java:520)
	at javafx.controls/javafx.scene.control.TextInputControl.replaceSelection(TextInputControl.java:1124)
	at javafx.controls/javafx.scene.control.TextInputControl.paste(TextInputControl.java:658)
	at javafx.controls/com.sun.javafx.scene.control.behavior.TextInputControlBehavior.paste(TextInputControlBehavior.java:528)
	at javafx.controls/com.sun.javafx.scene.control.behavior.TextInputControlBehavior.lambda$new$20(TextInputControlBehavior.java:159)
	at javafx.controls/com.sun.javafx.scene.control.behavior.TextInputControlBehavior.lambda$keyMapping$62(TextInputControlBehavior.java:330)
	at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
	at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
	at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
	at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
	at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
	at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
	at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
	at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
	at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
	at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
	at javafx.graphics/javafx.scene.Scene$KeyHandler.process(Scene.java:4058)
	at javafx.graphics/javafx.scene.Scene$KeyHandler.access$1500(Scene.java:4004)
	at javafx.graphics/javafx.scene.Scene.processKeyEvent(Scene.java:2121)
	at javafx.graphics/javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2595)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:217)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:149)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent$1(GlassViewEventHandler.java:248)
	at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:390)
	at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:247)
	at javafx.graphics/com.sun.glass.ui.View.handleKeyEvent(View.java:547)
	at javafx.graphics/com.sun.glass.ui.View.notifyKey(View.java:971)
	at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
	at java.base/java.lang.Thread.run(Thread.java:834)
---------- END STACKTRACE ----------

---------- BEGIN SOURCE ----------
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class DebuggingJavaFXTextField extends Application {

  @Override
  public void start(final Stage primaryStage) {
    final Pane root = new VBox();
    root.getChildren().addAll(new TextField(), new TextField());
    primaryStage.setScene(new Scene(root, 600, 400));
    primaryStage.show();
  }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I found a workaround on Stackoverflow, that is setting a TextFormatter which simply filters all tabs and newlines to:
https://stackoverflow.com/questions/36009368/breaking-javafx-when-tab-character-is-pasted-into-textfield/36021504

However, for a Windows machine I had to filter out "\r" as well, so I had to change the code with the actual text manipulation to:
text.replaceAll("[\t\r\n]", "")

FREQUENCY : always



Comments
+1
30-01-2019

I ran it again and can confirm this. So the fix in the .00 webrev looks fine. +1
28-01-2019

Hello Kevin, The issue with TextFormatter. The issue can also be observed when all of the content of first text field, (Loan amount) is made empty string and moving the focus to any next field. The NPE occurs in test code and not in the FX source. Exception in thread "JavaFX Application Thread" java.lang.NullPointerException at hello.HelloTextFieldWithTextFormatter.lambda$start$0(HelloTextFieldWithTextFormatter.java:90) amountFormatter.getValue() on line #90 causes the exception. I think this is expected behavior, the TextFormatter.getValue() can be null when content are empty.
22-01-2019

This does fix the problem, although I note that there is a similar problem in TextField when using a TextFormatter that has a filter, which this fix doesn't address (and it doesn't seem to be sufficient to just call filterInput(text) in that case). To see this problem, run hello.HelloTextFieldWithTextFormatter and paste a newline or tab and then click and type in one of the text fields.
16-01-2019

Hi Kevin, Ajit, Please review this fix: http://cr.openjdk.java.net/~arapte/fx/8212102/webrev.00/ Issue: The issue occurs when a text containing control characters is pasted or is used to replace the current content of TextField. Cause: 1. When text containing control characters ("\r\n") is used to paste or replace. 2. The TextInputControl.replaceText(), TextInputControl.updateContent() creates TextFormatter.Change using the string which contains control characters and performs further operations. 3. But when the text is actually updated in method TextField.TextFieldContent.insert(), the control characters are filtered using TextInputControl.filterInput(). So a input text "\r\n" would become an empty string "". 4. This causes an inconsistency in the in TextField member variables, which leads to exception. 5. Similar issue can be observed with PasswordField (is extended from TextField) Fix: The input text should be filtered before performing any computations. Added a package method in TextInputControl and overridden it for TextField and TextArea. Verification: Added a test in TextInputControlTest, which will be executed for all child classes of TextInputControl. Verified all test run on Windows7, Mac, Ubuntu16.04. No existing test fails due to this change.
16-01-2019

Issue is reproducible in JDK 8u181 and latest openjfx. Its a regression in JDK 8u40. Windows 10, 64-bit JDK results: ----------------------------- 8u33-b05 : Pass 8u40-02 : Fail < -- Regression 8u181 : Fail latest openjfx : Fail -----------------------------
12-10-2018