Bug 471192 - ArrayIndexOutOfBoundsException in StyledTextRenderer.calculateClientArea (230)
Summary: ArrayIndexOutOfBoundsException in StyledTextRenderer.calculateClientArea (230)
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 4.5   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 4.6 M1   Edit
Assignee: Niraj Modi CLA
QA Contact: Ed Merks CLA
URL:
Whiteboard:
Keywords:
: 264189 468295 468723 (view as bug list)
Depends on:
Blocks:
 
Reported: 2015-06-27 05:50 EDT by EPP Error Reports CLA
Modified: 2017-07-14 07:36 EDT (History)
8 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description EPP Error Reports CLA 2015-06-27 05:50:06 EDT
The following problem was reported against Oomph, but it appears to me to be an SWT bug.  In particular, the problem occurs in this code:

void calculateClientArea () {
	int index = styledText.getTopIndex();
	int lineCount = content.getLineCount();
	int height = styledText.getClientArea().height;
	int y = 0;
	while (height > y && lineCount > index) {
		calculate(index, 1);
		y += lineHeight[index++];
	}
}

It's not clear why content.getLineCount() is used instead of this.lineCount.   I'm not sure anything guarantees that the content's getLineCount can never change, but from the index out of bounds it appears the value being returned must be different from the value it had at the time setContent was called.  So to my thinking, it would be safer to use this.lineCount because the lineHeight array is definitely exactly that big. 


The following incident was reported via the automated error reporting:


    code:                   0
    plugin:                 org.eclipse.ui_3.107.0.v20150507-1945
    message:                Unhandled event loop exception
    fingerprint:            9a162245
    exception class:        org.eclipse.swt.SWTException
    exception message:      Failed to execute runnable (java.lang.ArrayIndexOutOfBoundsException: -12)
    number of children:     0
    
    org.eclipse.swt.SWTException: Failed to execute runnable (java.lang.ArrayIndexOutOfBoundsException: -12)
    at org.eclipse.swt.SWT.error(SWT.java:4491)
    at org.eclipse.swt.SWT.error(SWT.java:4406)
    at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:138)
    at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3794)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3433)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:1127)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:337)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1018)
    at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:156)
    at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:654)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:337)
    at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:598)
    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:150)
    at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:139)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:380)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:235)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:669)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:608)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1515)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1488)
caused by: java.lang.ArrayIndexOutOfBoundsException: -12
    at org.eclipse.swt.custom.StyledTextRenderer.calculateClientArea(StyledTextRenderer.java:230)
    at org.eclipse.swt.custom.StyledText.handleResize(StyledText.java:6204)
    at org.eclipse.swt.custom.StyledText$7.handleEvent(StyledText.java:5689)
    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
    at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4481)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1327)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1351)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1332)
    at org.eclipse.swt.widgets.Control.setBounds(Control.java:1053)
    at org.eclipse.swt.widgets.Composite.setBounds(Composite.java:1443)
    at org.eclipse.swt.widgets.Canvas.setBounds(Canvas.java:381)
    at org.eclipse.swt.widgets.Control.setBounds(Control.java:890)
    at org.eclipse.jface.text.source.SourceViewer$RulerLayout.layout(SourceViewer.java:155)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1660)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.updateLayout(Composite.java:1666)
    at org.eclipse.swt.widgets.Composite.layout(Composite.java:1012)
    at org.eclipse.oomph.internal.ui.UIPropertyTester$3$1.run(UIPropertyTester.java:121)
    at org.eclipse.oomph.ui.UIUtil$5.run(UIUtil.java:530)
    at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
    at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:135)
    at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3794)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3433)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:1127)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:337)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1018)
    at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:156)
    at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:654)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:337)
    at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:598)
    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:150)
    at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:139)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:380)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:235)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:669)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:608)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1515)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1488)
   
  

General Information:

    reported-by:      Stefan Taferner
    anonymous-id:     e7ac5435-9315-4272-84d0-19fd8b874a5a
    eclipse-build-id: 4.5.0.I20150603-2000
    eclipse-product:  org.eclipse.epp.package.java.product
    operating system: Linux 3.19.0 (x86_64) - gtk
    jre-version:      1.8.0_45-internal-b14

The following plug-ins were present on the execution stack (*):
    1. org.eclipse.core.databinding.observable_1.5.0.v20150422-0725
    2. org.eclipse.core.databinding_1.5.0.v20150422-0725
    3. org.eclipse.core.runtime_3.11.0.v20150405-1723
    4. org.eclipse.e4.ui.workbench_1.3.0.v20150531-1948
    5. org.eclipse.e4.ui.workbench.swt_0.13.0.v20150504-0621
    6. org.eclipse.equinox.app_1.3.300.v20150423-1356
    7. org.eclipse.equinox.launcher_1.3.100.v20150511-1540
    8. org.eclipse.jface.text_3.10.0.v20150603-1752
    9. org.eclipse.jface_3.11.0.v20150602-1400
    10. org.eclipse.oomph.ui_1.1.0.v20150610-0617
    11. org.eclipse.swt_3.104.0.v20150528-0211
    12. org.eclipse.ui_3.107.0.v20150507-1945
    13. org.eclipse.ui.ide.application_1.1.0.v20150422-0725
    14. org.eclipse.ui.ide_3.11.0.v20150510-1749

Please note that:
* Messages, stacktraces, and nested status objects may be shortened.
* Bug fields like status, resolution, and whiteboard are sent
  back to reporters.
* The list of present bundles and their respective versions was
  calculated by package naming heuristics. This may or may not reflect reality.

Other Resources:
* Report: https://dev.eclipse.org/recommenders/committers/confess/#/problems/558b9b91e4b08735226abae3  
* Manual: https://dev.eclipse.org/recommenders/community/confess/#/guide


Thank you for your assistance.
Your friendly error-reports-inbox.

This bug was created on behalf of ed.merks@gmail.com.
Comment 1 Ed Merks CLA 2015-06-28 02:36:54 EDT
I think this problem report is a similar case

https://dev.eclipse.org/recommenders/committers/confess/#/problems/558dc4b9e4b08735226aeb55/details
Comment 2 Niraj Modi CLA 2015-07-03 04:19:19 EDT

(In reply to EPP Error Reports from comment #0)
> The following problem was reported against Oomph, but it appears to me to be
> an SWT bug.  In particular, the problem occurs in this code:
> 
> void calculateClientArea () {
> 	int index = styledText.getTopIndex();
> 	int lineCount = content.getLineCount();
> 	int height = styledText.getClientArea().height;
> 	int y = 0;
> 	while (height > y && lineCount > index) {
> 		calculate(index, 1);
> 		y += lineHeight[index++];
> 	}
> }
> 
> It's not clear why content.getLineCount() is used instead of this.lineCount.
> I'm not sure anything guarantees that the content's getLineCount can never
> change, but from the index out of bounds it appears the value being returned
> must be different from the value it had at the time setContent was called. 
> So to my thinking, it would be safer to use this.lineCount because the
> lineHeight array is definitely exactly that big. 

Actually content.getLineCount() is used to initialize 'lineCount' and same is used to length of 'lineHeight' array, referring StyledTextRenderer#setContent(StyledTextContent content) method.

Not sure under what scenario/steps is leading to this exception.
Anyways, to avoid this exception, I am planning to add check for 'index' value should be less than length of 'lineHeight' array in StyledTextRenderer#calculateClientArea() method.
Comment 3 Eclipse Genie CLA 2015-07-03 04:30:41 EDT
New Gerrit change created: https://git.eclipse.org/r/51311
Comment 4 Niraj Modi CLA 2015-07-03 06:05:50 EDT
(In reply to Eclipse Genie from comment #3)
> New Gerrit change created: https://git.eclipse.org/r/51311
Some issue with gerrit builds(not sure if it's updated for 4.6 release)

Pushed the fix to master via below git commit:
http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=1fb20c85714d3b5e9b6b332141e562a3d751a115
Comment 5 Niraj Modi CLA 2015-07-03 06:13:30 EDT
(In reply to Ed Merks from comment #1)
> I think this problem report is a similar case
> 
> https://dev.eclipse.org/recommenders/committers/confess/#/problems/
> 558dc4b9e4b08735226aeb55/details

Above problem is unrelated to this bug.
SWT StyledText#getOffsetAtLine(int lineIndex) is public method which throws IllegalArgumentException only when 'lineIndex' argument is out of range, which happens to be the case here.
Please raise a separate bug on this, with Platform/UI component if none exists.
Comment 6 Niraj Modi CLA 2015-07-08 02:58:40 EDT
Reopening this bug to handle possibility of negative 'index' value in StyledTextRenderer.calculateClientArea() method.
Comment 7 Niraj Modi CLA 2015-07-08 03:23:31 EDT
*** Bug 468723 has been marked as a duplicate of this bug. ***
Comment 8 Niraj Modi CLA 2015-07-08 04:02:23 EDT
(In reply to Niraj Modi from comment #6)
> Reopening this bug to handle possibility of negative 'index' value in
> StyledTextRenderer.calculateClientArea() method.

Added check to avoid above problem, via below git commit:
http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=0793952a85f125d0adaba6ff8058e9d23f79ed57
Comment 9 Arun Thondapu CLA 2015-07-09 06:20:58 EDT
*** Bug 468295 has been marked as a duplicate of this bug. ***
Comment 10 Timo Kinnunen CLA 2015-07-09 06:33:46 EDT
(In reply to comment #2)
> Not sure under what scenario/steps is leading to this exception.

ConsoleDocumentAdapter has a synchronized documentAboutToBeChanged() method, suggesting that it's expected to be called from multiple threads. The documentAboutToBeChanged() method fires all registered textChangeListeners, leading to a call to StyledTextRenderer.textChanging() method. The textChanging() method can replace the lineHeight and lineWidth arrays in StyledTextRenderer with new arrays of smaller size. Meanwhile, the method StyledTextRenderer.calculateClientArea() which reads the lineHeight and lineWidth arrays can be called from the UI thread without going through ConsoleDocumentAdapter, leading to a race condition.

This theory is based on the code itself, I haven't verified this is the cause of the reported exceptions.
Comment 11 Stefan Xenos CLA 2015-07-30 00:42:11 EDT
This fix doesn't look very robust to me.

getTopIndex() is a public API that doesn't document the fact that it can have a negative return value.

With this patch, getClientArea() will no longer crash, but I see several other callers that don't seem to be prepared to deal with negatives. For example, AnnotationBarHoverManager looks as though it will return invalid line ranges in this scenario.

Perhaps the fix should go inside getTopIndex() to guarantee it doesn't return a negative value rather than in this particular caller?
Comment 12 Marc-André Laperle CLA 2015-09-13 16:09:49 EDT
(In reply to Stefan Xenos from comment #11)
> Perhaps the fix should go inside getTopIndex() to guarantee it doesn't
> return a negative value rather than in this particular caller?

I think this sounds better. A negative index doesn't make much sense and I think it's fair that the callers would not assume that it could be negative, even without being specified in the javadoc. Of course, it would be even better if it was explicitly mentioned in the javadoc.
Comment 13 Niraj Modi CLA 2017-07-14 07:36:19 EDT
*** Bug 264189 has been marked as a duplicate of this bug. ***