Bug 545605 - Adjust ecj to change in JVMS 4.7.18./19.
Summary: Adjust ecj to change in JVMS 4.7.18./19.
Status: REOPENED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.10   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard: stalebug bulk move
Keywords:
Depends on:
Blocks:
 
Reported: 2019-03-20 23:36 EDT by larry CLA
Modified: 2022-06-30 19:41 EDT (History)
4 users (show)

See Also:


Attachments
e.class (25.12 KB, application/octet-stream)
2019-03-21 04:12 EDT, larry CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description larry CLA 2019-03-20 23:36:56 EDT
I got an error when I selecting it in package explorer.

java.lang.IllegalStateException: Mismatching number of parameter annotations, 2>1 in a(Ljava/util/function/Function;Ljava/lang/Object;J)Z in =
	at org.eclipse.jdt.internal.compiler.classfmt.MethodInfoWithParameterAnnotations.getParameterAnnotations(MethodInfoWithParameterAnnotations.java:46)
	at org.eclipse.jdt.internal.core.ClassFileInfo.generateMethodInfos(ClassFileInfo.java:364)
	at org.eclipse.jdt.internal.core.ClassFileInfo.readBinaryChildren(ClassFileInfo.java:432)
	at org.eclipse.jdt.internal.core.ClassFile.buildStructure(ClassFile.java:91)
	at org.eclipse.jdt.internal.core.Openable.generateInfos(Openable.java:268)
	at org.eclipse.jdt.internal.core.JavaElement.openWhenClosed(JavaElement.java:596)
	at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:326)
	at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:312)
	at org.eclipse.jdt.internal.core.Openable.getBuffer(Openable.java:298)
	at org.eclipse.jdt.internal.core.AbstractClassFile.getBuffer(AbstractClassFile.java:221)
	at org.eclipse.jdt.internal.core.AbstractClassFile.getSourceRange(AbstractClassFile.java:347)
	at org.eclipse.jdt.internal.ui.javaeditor.EditorUtility.getEditorID(EditorUtility.java:424)
	at org.eclipse.jdt.internal.ui.javaeditor.EditorUtility.openInEditor(EditorUtility.java:182)
	at org.eclipse.jdt.ui.actions.OpenAction.run(OpenAction.java:287)
	at org.eclipse.jdt.ui.actions.OpenAction.run(OpenAction.java:252)
	at org.eclipse.jdt.ui.actions.SelectionDispatchAction.dispatchRun(SelectionDispatchAction.java:274)
	at org.eclipse.jdt.ui.actions.SelectionDispatchAction.run(SelectionDispatchAction.java:252)
	at org.eclipse.jdt.internal.ui.packageview.PackageExplorerActionGroup.handleOpen(PackageExplorerActionGroup.java:382)
	at org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart$4.open(PackageExplorerPart.java:545)
	at org.eclipse.ui.OpenAndLinkWithEditorHelper$InternalListener.open(OpenAndLinkWithEditorHelper.java:49)
	at org.eclipse.jface.viewers.StructuredViewer$2.run(StructuredViewer.java:853)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.ui.internal.JFaceUtil.lambda$0(JFaceUtil.java:47)
	at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:176)
	at org.eclipse.jface.viewers.StructuredViewer.fireOpen(StructuredViewer.java:850)
	at org.eclipse.jface.viewers.StructuredViewer.handleOpen(StructuredViewer.java:1165)
	at org.eclipse.jface.util.OpenStrategy.fireOpenEvent(OpenStrategy.java:276)
	at org.eclipse.jface.util.OpenStrategy.access$2(OpenStrategy.java:271)
	at org.eclipse.jface.util.OpenStrategy$1.handleEvent(OpenStrategy.java:311)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4131)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1055)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3944)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3547)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1173)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1062)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:156)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:636)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:339)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:563)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:151)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:155)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:203)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:137)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:107)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:400)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:255)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:659)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:595)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1501)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 2
	at org.eclipse.jdt.internal.compiler.classfmt.MethodInfoWithParameterAnnotations.getParameterAnnotations(MethodInfoWithParameterAnnotations.java:30)
	... 54 more
Comment 1 Andrey Loskutov CLA 2019-03-21 02:23:03 EDT
Larry, I assume this happens only with one file? If yes, could you attach it? If not, which Eclipse version do you have?
Comment 2 larry CLA 2019-03-21 04:12:42 EDT
Created attachment 277943 [details]
e.class
Comment 3 larry CLA 2019-03-21 04:16:49 EDT
(In reply to Andrey Loskutov from comment #1)
> Larry, I assume this happens only with one file? If yes, could you attach
> it? If not, which Eclipse version do you have?

4.10 and 4.11 are same, see attachment.
Comment 4 Andrey Loskutov CLA 2019-03-21 05:33:46 EDT
Larry, who has generated e.class? It looks like it reports only 2 parameters but the signature shows 3:

  // access flags 0xA
  private static a(Ljava/util/function/Function;Ljava/lang/Object;J)Z
    // annotable parameter count: 2 (invisible)
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 1


The similar code below shows this bytecode:

  // access flags 0xA
  private static a(Ljava/util/function/Function;Ljava/lang/Object;J)Z
    // annotable parameter count: 3 (invisible)
    @LNotNull;() // invisible, parameter 1

If we remove the "long" parameter, we will get:

  // access flags 0xA
  private static a(Ljava/util/function/Function;Ljava/lang/Object;)Z
    // annotable parameter count: 2 (invisible)
    @LNotNull;() // invisible, parameter 1


So for me this looks like an error in the obfuscator who generated e.class, which doesn't properly record parameters count for annotations. This is exact what Stephan commented on bug 474081 comment 1.

Below similar code trying to match the related part of the broken class file.

-----------------------------------------------------------

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.function.Function;


public class X {

	private static boolean a(Function f, @NotNull Object o, long l) {
		return false;
	}
}

@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})
@interface NotNull {
}
Comment 5 larry CLA 2019-03-21 07:50:42 EDT
(In reply to Andrey Loskutov from comment #4)
> Larry, who has generated e.class? It looks like it reports only 2 parameters

Yes, exactly, this class generated by an obfuscator. I don't know who is.
In fact this file is part of IDEA, Maybe nobody might call this method, but it works fine.
This file parsed well in Structure of IDEA. In eclipse, package explorer, outline, debug view and so on couldn’t work. So can eclipse ignore this error method?
Comment 6 Stephan Herrmann CLA 2019-03-21 08:10:49 EDT
Thanks larry and Andrey for details and analysis. So the detailed error message from bug 474081 indeed helps to identify the offending method. It can be confirmed that the class file violates JVMS. Ergo the bug should primarily be reported against the tool that created the class file.

I'm closing this bug as WORKSFORME.

If anyone feels inclined to provide a clean workaround on JDT side, I will tentatively welcome this, but in that case my expectation would be: the illegal class file must be reported in some suitable why rather than silently be swallowed. The code location that currently raises the exception does not have enough context to raise a regular compile error, so it would be tricky to say the least to find a way how to turn the exception into a normal compile error.
Comment 7 larry CLA 2019-03-21 08:27:19 EDT
(In reply to Stephan Herrmann from comment #6)
> Thanks larry and Andrey for details and analysis. So the detailed error
> message from bug 474081 indeed helps to identify the offending method. It
> can be confirmed that the class file violates JVMS. Ergo the bug should
> primarily be reported against the tool that created the class file.
> 
> I'm closing this bug as WORKSFORME.
> 
> If anyone feels inclined to provide a clean workaround on JDT side, I will
> tentatively welcome this, but in that case my expectation would be: the
> illegal class file must be reported in some suitable why rather than
> silently be swallowed. The code location that currently raises the exception
> does not have enough context to raise a regular compile error, so it would
> be tricky to say the least to find a way how to turn the exception into a
> normal compile error.

This class can be reflected, so it is a LEGAL class file and NOT violates JVMS.
Comment 8 larry CLA 2019-03-21 08:36:47 EDT
This class can be reflected, so it is a LEGAL class file and NOT violates JVMS.
Comment 9 Andrey Loskutov CLA 2019-03-21 08:43:14 EDT
(In reply to larry from comment #8)
> This class can be reflected, so it is a LEGAL class file and NOT violates
> JVMS.

Not sure what do you mean by reflected, but the bytecode of this class violates specs.

@Stephan, I have a patch that will avoid error dialogs and only report errors to the log and also will show the "error" editor part. I will push it in a second.
Comment 10 Stephan Herrmann CLA 2019-03-21 08:50:42 EDT
(In reply to larry from comment #8)
> This class can be reflected, so it is a LEGAL class file and NOT violates
> JVMS.

This is unsound reasoning.

To prove that the class is legal you'd have to argue how it conforms to the following from JVMS (§4.7.18/19):

"The value of the num_parameters item gives the number of formal parameters of the method represented by the method_info structure on which the annotation occurs.

This duplicates information that could be extracted from the method descriptor."

Interestingly, the last sentence was changed in version 10:

There is no assurance that this number is the same as the number of parameter descriptors in the method descriptor.
Comment 11 larry CLA 2019-03-21 08:58:25 EDT
(In reply to Andrey Loskutov from comment #9)
> (In reply to larry from comment #8)
> > This class can be reflected, so it is a LEGAL class file and NOT violates
> > JVMS.
> 
> Not sure what do you mean by reflected, but the bytecode of this class
> violates specs.
> 
> @Stephan, I have a patch that will avoid error dialogs and only report
> errors to the log and also will show the "error" editor part. I will push it
> in a second.

This class can load by Class.forName().
I can call  getDeclaredMethods().
It seems that JVM thought is a legal class.
Comment 12 Andrey Loskutov CLA 2019-03-21 09:00:49 EDT
(In reply to Stephan Herrmann from comment #10)
> Interestingly, the last sentence was changed in version 10:
> 
> There is no assurance that this number is the same as the number of
> parameter descriptors in the method descriptor.

Does it mean, we should be able to parse this class file now?
Comment 13 Stephan Herrmann CLA 2019-03-21 09:02:53 EDT
Apparently, the spec change was driven by https://bugs.openjdk.java.net/browse/JDK-8067975 (which has several links to related bugs). 

I'm not a aware of any JSR/JEP that covers this. In particular the comment "However, javac has never emitted Runtime[In]VisibleParameterAnnotations attributes that follow the method descriptor." seems to indicate that they silently adjusted the spec to javac's behavior. This style of changing the spec underfoot is dangerous for any effort to keep ecj in line with the spec.

Anyway, the solution to the bug at hand is given further down in latest JVMS (12):


"The i'th entry in the parameter_annotations table may, but is not required to, correspond to the i'th parameter descriptor in the method descriptor (§4.3.3).

For example, a compiler may choose to create entries in the table corresponding only to those parameter descriptors which represent explicitly declared parameters in source code. In the Java programming language, a constructor of an inner class is specified to have an implicitly declared parameter before its explicitly declared parameters (JLS §8.8.1), so the corresponding <init> method in a class file has a parameter descriptor representing the implicitly declared parameter before any parameter descriptors representing explicitly declared parameters. If the first explicitly declared parameter is annotated in source code, then a compiler may create parameter_annotations[0] to store annotations corresponding to the second parameter descriptor."

This needs to be implemented in ecj.
Comment 14 Stephan Herrmann CLA 2019-03-21 09:04:17 EDT
(In reply to larry from comment #11)
> It seems that JVM thought is a legal class.

Also JVM is just a piece of software which may have bugs.

(In reply to Andrey Loskutov from comment #12)
> Does it mean, we should be able to parse this class file now?

Yep, that's how I read the latest JVMS.
Comment 15 Manoj N Palat CLA 2019-08-27 01:14:22 EDT
Bulk move to 4.14
Comment 16 Manoj N Palat CLA 2019-08-27 02:06:27 EDT
Bulk move out of 4.13
Comment 17 larry CLA 2020-01-09 20:41:44 EST
A year has passed, how about this?
Comment 18 Andrey Loskutov CLA 2020-01-10 04:17:25 EST
(In reply to larry from comment #17)
> A year has passed, how about this?

https://wiki.eclipse.org/Platform/How_to_Contribute ?
Comment 19 Olivier Thomann CLA 2020-01-10 10:40:17 EST
It looks like you can have less parameter annotations than the number of parameters. Instead of adding lots of check, we could simply handle the AIOOBE by returning null which would be equivalent to no annotation on the last parameters.
Comment 20 Olivier Thomann CLA 2020-06-26 11:55:12 EDT
I will prepare a patch for this one.
Comment 21 Eclipse Genie CLA 2022-06-30 19:41:43 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.