Bug 574020 - Crash with ImportRewrite when dealing with names beginning with `n`
Summary: Crash with ImportRewrite when dealing with names beginning with `n`
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.20   Edit
Hardware: PC Mac OS X
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2021-06-04 08:48 EDT by Dimitriye Danilovic CLA
Modified: 2023-06-05 06:56 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dimitriye Danilovic CLA 2021-06-04 08:48:18 EDT
```
java.lang.StringIndexOutOfBoundsException: String index out of range: -2
	at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:48)
	at java.base/java.lang.String.charAt(String.java:712)
	at org.cadixdev.mercury.jdt.rewrite.imports.ImportRewrite.compareImport(ImportRewrite.java:611)
	at org.cadixdev.mercury.jdt.rewrite.imports.ImportRewrite.findInImports(ImportRewrite.java:630)
	at org.cadixdev.mercury.jdt.rewrite.imports.ImportRewrite$1.findInContext(ImportRewrite.java:448)
	at com.dimitriye.filigree.remapper.RemapperVisitor$ImportContext.findInContext(RemapperVisitor.java:469)
```

The class in question is in another library, but it's copied wholesale over from JDT by their build process and after debugging and (I think) identifying the line causing the problem, the line in question is in `compareImport` in `org.eclipse.jdt.core.dom.rewrite.ImportRewrite`.

I'm not well versed enough with JDT to write a minimal example depending directly on JDT, I'll try to do so as soon as I can.

The key thing is that it seems to be an issue when the `name` parameter begins with `n`, in this case the `name` parameter was `nx` due to working with obfuscated code.

This allows the flow of execution to escape the guard at the beginning
```
if (curr.charAt(0) != prefix || !curr.endsWith(name)) {
```
as according to the debugger, `prefix` in this case was `n` and `curr` was `nx` just like `name`. Thus the execution proceeded as follows:
```
// Start at line 596 in org.eclipse.jdt.core.dom.rewrite.ImportRewrite
// curr: nx, name: nx, prefix: n
// Guard not triggered as both if conditions evaluate to false
if (curr.charAt(0) != prefix || !curr.endsWith(name)) {
  return ImportRewriteContext.RES_NAME_UNKNOWN;
}

curr= curr.substring(1); // removes the prefix
// curr: x, name: nx, prefix: n

// if branch gets skipped, `curr.length(): 1 != name.length(): 2`
if (curr.length() == name.length()) {
  if (qualifier.length() == 0) {
    return ImportRewriteContext.RES_NAME_FOUND;
  }
  return ImportRewriteContext.RES_NAME_CONFLICT;
}
// at this place: curr.length > name.length
// !!!!!!! CONTRACT VIOLATED !!!!!!!

int dotPos= curr.length() - name.length() - 1; // dotPos: -1
if (curr.charAt(dotPos) != '.') { // Crash
```

The call in question also came internally from JDT at
```
// Start at line 624 in same file
boolean allowAmbiguity=  (kind == ImportRewriteContext.KIND_STATIC_METHOD) || (name.length() == 1 && name.charAt(0) == '*');
List imports= this.existingImports;
char prefix= (kind == ImportRewriteContext.KIND_TYPE) ? NORMAL_PREFIX : STATIC_PREFIX;

for (int i= imports.size() - 1; i >= 0 ; i--) {
  String curr= (String) imports.get(i);
  int res= compareImport(prefix, qualifier, name, curr);
```

As best as I can tell, what triggered the bug was a preexisting import named `x`.

I *think* that the solution is simply to change
```
if (curr.charAt(0) != prefix || !curr.endsWith(name)) {
```
to
```
if (curr.charAt(0) != prefix || !curr.substring(1).endsWith(name)) {
```
but I'd rather someone more well versed in the codebase look at the issue before I submit a pull request.
Comment 1 Vikas Chandra CLA 2021-06-08 04:03:08 EDT
Sarika, can you have a look. Please note that original stack is in some other plugin which has code from JDT.
Comment 2 Sarika Sinha CLA 2021-06-14 04:23:47 EDT
@Dimitriye ,
Can you provide a proper testCase ?

The line numbers of current code is not matching the stacktrace attached.

So, it is not clear right now.

Also,
!curr.substring(1).endsWith(name) is when prefix is of length 1, so ideally it should be substring(length of prefix) ???
Comment 3 Eclipse Genie CLA 2023-06-05 06:56:25 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.