Bug 264816 - [search] AIOOBE in StringOperation.getPatternMatchingRegions(..) with pattern "?*"
Summary: [search] AIOOBE in StringOperation.getPatternMatchingRegions(..) with pattern...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.5   Edit
Hardware: PC Windows XP
: P3 major (vote)
Target Milestone: 3.5 M6   Edit
Assignee: Frederic Fusier CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-02-13 04:23 EST by Markus Keller CLA
Modified: 2009-02-13 10:35 EST (History)
1 user (show)

See Also:


Attachments
Proposed patch (4.52 KB, patch)
2009-02-13 07:27 EST, Frederic Fusier CLA
no flags Details | Diff
Proposed patch+tests (4.52 KB, patch)
2009-02-13 07:53 EST, Frederic Fusier CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Keller CLA 2009-02-13 04:23:56 EST
HEAD (N20090212-2000)

- Open Type dialog
- enter pattern ".HMap"
-> AIOOBE

We call SearchPattern.getMatchingRegions(String, String, int) with arguments:
pattern= "?*" (id=475)	
name= "java.util - [jdk1.4.2]" (id=476)	
matchRule= 2 [0x2] [^B]	


!ENTRY org.eclipse.jface 4 2 2009-02-13 10:17:19.906
!MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.jface".
!STACK 0
java.lang.ArrayIndexOutOfBoundsException: 0
	at org.eclipse.jdt.internal.core.search.StringOperation.getPatternMatchingRegions(StringOperation.java:372)
	at org.eclipse.jdt.core.search.SearchPattern.getMatchingRegions(SearchPattern.java:828)
	at org.eclipse.jdt.internal.ui.dialogs.FilteredTypesSelectionDialog$TypeItemLabelProvider.getStyledText(FilteredTypesSelectionDialog.java:874)
	at org.eclipse.ui.dialogs.FilteredItemsSelectionDialog$ItemsListLabelProvider.getStyledText(FilteredItemsSelectionDialog.java:1703)
	at org.eclipse.ui.dialogs.FilteredItemsSelectionDialog$ItemsListLabelProvider.update(FilteredItemsSelectionDialog.java:1720)
	at org.eclipse.jface.viewers.ViewerColumn.refresh(ViewerColumn.java:145)
	at org.eclipse.jface.viewers.AbstractTableViewer.doUpdateItem(AbstractTableViewer.java:393)
	at org.eclipse.jface.viewers.StructuredViewer$UpdateItemSafeRunnable.run(StructuredViewer.java:475)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37)
	at org.eclipse.core.runtime.Platform.run(Platform.java:874)
	at org.eclipse.ui.internal.JFaceUtil$1.run(JFaceUtil.java:48)
	at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:175)
	at org.eclipse.jface.viewers.StructuredViewer.refreshItem(StructuredViewer.java:1492)
	at org.eclipse.jface.viewers.AbstractTableViewer.replace(AbstractTableViewer.java:1053)
	at org.eclipse.ui.dialogs.FilteredItemsSelectionDialog$ContentProvider.updateElement(FilteredItemsSelectionDialog.java:2935)
	at org.eclipse.jface.viewers.AbstractTableViewer$1.handleEvent(AbstractTableViewer.java:85)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:87)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1003)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1027)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1012)
	at org.eclipse.swt.widgets.Table.checkData(Table.java:933)
	at org.eclipse.swt.widgets.Table.wmNotifyChild(Table.java:6343)
	at org.eclipse.swt.widgets.Control.wmNotify(Control.java:4843)
	at org.eclipse.swt.widgets.Composite.wmNotify(Composite.java:1755)
	at org.eclipse.swt.widgets.Control.WM_NOTIFY(Control.java:4473)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:3966)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4601)
	at org.eclipse.swt.internal.win32.OS.$$YJP$$CallWindowProcW(Native Method)
	at org.eclipse.swt.internal.win32.OS.CallWindowProcW(OS.java)
	at org.eclipse.swt.internal.win32.OS.CallWindowProc(OS.java:2297)
	at org.eclipse.swt.widgets.Table.callWindowProc(Table.java:333)
	at org.eclipse.swt.widgets.Table.callWindowProc(Table.java:199)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:4002)
	at org.eclipse.swt.widgets.Table.windowProc(Table.java:5520)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4601)
	at org.eclipse.swt.internal.win32.OS.$$YJP$$DispatchMessageW(Native Method)
	at org.eclipse.swt.internal.win32.OS.DispatchMessageW(OS.java)
	at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2394)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3470)
	at org.eclipse.jface.window.Window.runEventLoop(Window.java:825)
	at org.eclipse.jface.window.Window.open(Window.java:801)
	at org.eclipse.jdt.internal.ui.dialogs.FilteredTypesSelectionDialog.open(FilteredTypesSelectionDialog.java:504)
	at org.eclipse.jdt.internal.ui.actions.OpenTypeAction.runWithEvent(OpenTypeAction.java:71)
	at org.eclipse.jdt.internal.ui.actions.OpenTypeAction.runWithEvent(OpenTypeAction.java:132)
	at org.eclipse.ui.internal.handlers.ActionDelegateHandlerProxy.execute(ActionDelegateHandlerProxy.java:281)
	at org.eclipse.core.commands.Command.executeWithChecks(Command.java:476)
	at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:508)
	at org.eclipse.ui.internal.handlers.HandlerService.executeCommand(HandlerService.java:169)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.executeCommand(WorkbenchKeyboard.java:471)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.press(WorkbenchKeyboard.java:823)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.processKeyEvent(WorkbenchKeyboard.java:879)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.filterKeySequenceBindings(WorkbenchKeyboard.java:570)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.access$3(WorkbenchKeyboard.java:511)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard$KeyDownFilter.handleEvent(WorkbenchKeyboard.java:126)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:87)
	at org.eclipse.swt.widgets.Display.filterEvent(Display.java:1190)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1002)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1027)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1012)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1040)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1036)
	at org.eclipse.swt.widgets.Widget.wmChar(Widget.java:1358)
	at org.eclipse.swt.widgets.Control.WM_CHAR(Control.java:4019)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:3912)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4588)
	at org.eclipse.swt.internal.win32.OS.$$YJP$$DispatchMessageW(Native Method)
	at org.eclipse.swt.internal.win32.OS.DispatchMessageW(OS.java)
	at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2394)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3470)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2388)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2352)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2204)
	at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:499)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:333)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:492)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:113)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:556)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:511)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1284)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1260)
Comment 1 Frederic Fusier CLA 2009-02-13 05:52:51 EST
The problem comes when the pattern is only made of with '?' and/or '*'. The algorithm of the StringOperation.getPatternMatchingRegions(...) first counts the number of expected matching parts in the name and in this case gets 0, hence create a empty array. Of course trying to put anything in this kind of array leads to an AIOOBE!

So, I think the peculiar issue shows that the behavior needs to be changed when the pattern is either null or equals to '*'. Currently, it's specified that the returned regions will be the entire name. I missed the fact that any other pattern with only '?' and/or '*' characters should behave the same.

If we agree to change the API behavior to return in such case an empty array, then the problem could be easily fixed.

Furthermore, this would allow clients to distinguish the three following cases:
1) The name does not match the pattern: null is returned
2) The name matches the pattern and they have some characters in common:
   an array of the common characters is returned
3) The name matches the pattern but they have no common character:
   an empty array is returned

Of course not all clients would need to distinguish these 3 different cases (e.g. Open Type dialog do not care of case 1 as the styled text is applied in the acceptMatch method of the SearchRequestor, hence the name _always_ matches
the pattern), but I think it could be interesting for some clients calling this
API without having made a search request before...

Finally, the other advantage of modifying this behavior would be to make the returned array consistent when the given pattern has '?' and/or '*'. Currently, the API returns an array [0, length] when the pattern is only '*' and this can make the clients think that the characters matched by the '*' are included in the matching regions. However, this is not the case as soon as a character other than '?' or '*' is in the pattern; e.g. for 'H*M*' pattern and 'HashMap' name, the returned array is {0,1,4,1}, hence characters matched by the 2 stars are obviously not included in the array...

If everybody agrees on this change, I'll be back soon with a patch for it which, of course, will also fix the AIOOBE...
Comment 2 Markus Keller CLA 2009-02-13 06:08:14 EST
Sounds good.
Comment 3 Dani Megert CLA 2009-02-13 06:47:53 EST
+1
Comment 4 Frederic Fusier CLA 2009-02-13 07:27:11 EST
Created attachment 125623 [details]
Proposed patch
Comment 5 Frederic Fusier CLA 2009-02-13 07:53:18 EST
Created attachment 125631 [details]
Proposed patch+tests

It looks like I forgot to add tests I wrote to previous patch...
Comment 6 Frederic Fusier CLA 2009-02-13 07:53:40 EST
Released for 3.5M6 in HEAD stream.
Comment 7 Frederic Fusier CLA 2009-02-13 07:56:32 EST
When verifying this bug fix, please note that it won't be possible to reproduce the exception using any I-build as the problem has been fixed before the new functionality was present in such a build...

The only build exhibiting this issue would be the N20090212-2000 build, but I'm not sure it will be available.
Comment 8 Dani Megert CLA 2009-02-13 10:35:06 EST
Verified in HEAD.