Bug 319425 - [compiler] JDT outputs corrupt .class file for problem type
Summary: [compiler] JDT outputs corrupt .class file for problem type
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.7   Edit
Hardware: PC Windows 7
: P3 major (vote)
Target Milestone: 3.7 M1   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-07-09 14:38 EDT by Fernando Colombo CLA
Modified: 2010-08-04 07:01 EDT (History)
3 users (show)

See Also:


Attachments
Error showing on Eclipse (157.39 KB, image/png)
2010-07-09 14:40 EDT, Fernando Colombo CLA
no flags Details
.java that produces incorrect .class file. (654.17 KB, text/plain)
2010-07-09 14:42 EDT, Fernando Colombo CLA
no flags Details
Zip containing the corrupt RtSql$TRtDBConnection.class file. (386.76 KB, application/x-zip-compressed)
2010-07-09 14:47 EDT, Fernando Colombo CLA
no flags Details
Bogus.java (654 bytes, text/plain)
2010-07-26 14:00 EDT, Fernando Colombo CLA
no flags Details
Proposed fix + regression test (3.50 KB, patch)
2010-07-26 14:48 EDT, Olivier Thomann CLA
no flags Details | Diff
Proposed fix + regression test (3.47 KB, patch)
2010-07-26 22:39 EDT, Olivier Thomann CLA
no flags Details | Diff
tiny improvement for the test (983 bytes, patch)
2010-07-29 09:34 EDT, Stephan Herrmann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Fernando Colombo CLA 2010-07-09 14:38:47 EDT
Build Identifier: Version: 3.5.2 Build id: M20100211-1343

We ported an application from Object Pascal to Java, and that generated a huge but valid .java file with many inner classes and dozens of methods. One of those inner classes is compiled to a corrupt .class file, as displayed in the image.

For legal reasons I can't send you the whole project. I'm sending you an image that shows the problem, the .java file and the corrupt .class file, but there are many dependecies and hence it won't simply compile.

I spent 4 hours trying to isolate it, but wasn't very successfull. Every change I made to the TRtDBConnection inner class produced either the same error or a completely unusable .class. For instance, if you add two new methods with the same name (which causes a semantic error), the .class is correctly generated, but any invocation would produce the standard "Unresolved compilation problem" error.

I found that if I create a new "sister" class, with empty implementations for the interface methods, I can instantiate and invoke methods normally. I'm in the process of gradually moving implementation from the bad class to the sister class, until the error shows up, but this is very painfull and time-consuming, since I have to resolve dependencies.

Additional information:

-Eclipse error log shows nothing for the cleanup-rebuild operation that generates a bad .class.

-This error happens in other machines and there are no bytecode modification tools in place, such as AOP. It's just a plain Java project.

java -version:

java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)

-Java compiler is set to 1.6 with default compliance settings. We are linking to a normal Java SE 6 library.

Reproducible: Always

Steps to Reproduce:
Just compile.
Comment 1 Fernando Colombo CLA 2010-07-09 14:40:10 EDT
Created attachment 173893 [details]
Error showing on Eclipse
Comment 2 Fernando Colombo CLA 2010-07-09 14:42:52 EDT
Created attachment 173895 [details]
.java that produces incorrect .class file.
Comment 3 Fernando Colombo CLA 2010-07-09 14:47:04 EDT
Created attachment 173896 [details]
Zip containing the corrupt RtSql$TRtDBConnection.class file.
Comment 4 Stephan Herrmann CLA 2010-07-09 18:20:57 EDT
That's strange, inspecting the class file attached to comment 3
I see the access flags to be 0x31, which is "public final"
plus the internal flag ACC_SUPER. Nothing wrong with that,
and this looks different from what the screenshot in comment 1
shows (0x419). Also the other files in the zip have reasonable
access flags, too.

Are you sure you uploaded the right (buggy) class file / zip?
Comment 5 Fernando Colombo CLA 2010-07-10 00:44:57 EDT
(In reply to comment #4)
> That's strange, inspecting the class file attached to comment 3
> I see the access flags to be 0x31, which is "public final"
> plus the internal flag ACC_SUPER. Nothing wrong with that,
> and this looks different from what the screenshot in comment 1
> shows (0x419). Also the other files in the zip have reasonable
> access flags, too.
> 
> Are you sure you uploaded the right (buggy) class file / zip?

I checked again and the zip is correct. I got myself some .class dumps using javap and to be sure, I wrote a small .class parser (just to skip the constant pool) and you are right: the access flags are 0x31 (javap report as public final).

If the .class files are correctly generated, then I guess it's a JVM bug. I will fill a hotspot bug at Sun and link here. I think you can close this bug.

Thanks for your help and forgive me to bother you.
Comment 6 Olivier Thomann CLA 2010-07-13 10:10:03 EDT
Closing as WORKSFORME for now.
If you reproduce it repeatedly, then I might worth being reopened. But in this case I doubt I can do anything without getting the complete projects and steps to reproduce.
Comment 7 Fernando Colombo CLA 2010-07-26 13:40:20 EDT
Update:

The project contains a Java class, say C1, that was automatically (and incorrectly) written as both abstract and final. This compiler error doesn't prevent the .class file from being generated. When corrected, the JVM error disappears and all classes are normally loaded and executed.

When C1 is loaded because of a static method call, JVM reports same exception class, but displays access flag 0x418, which corresponds to ACC_ABSTRACT|ACC_FINAL|0x8 (don't know what that 0x8 means, but I guess Eclipse is generating the class with ACC_ABSTRACT|ACC_FINAL, which is consistent with the compiler error).

When C1 is loaded due to another reason (which I couldn't find exactly - see below) then JVM reports the original code (0x419) and on the wrong class (say C2).

I suspected that the well-formed .class of C2 has some sort of reference to C1. To find this thing, I made C2 reference C1 in a field type, a method argument, a return value, and the base class. On small sources, the error was always reported on C1, which was very easy to find and correct. Only in the huge source the error is reported on C2 which gives no clue that C1 is the offending .class.

Suggestion: If a Java source says that a class is both abstract and final, the generated .class should be neither, and missing abstract entries should become methods that just throw the "unresolved compiler error" exception. This is not barely important as most people run Java programs only after all compiler errors are fixed, but may remove some pain of developers that intentionally let errors during experiments.
Comment 8 Olivier Thomann CLA 2010-07-26 13:50:54 EDT
I'll investigate. So your class C1 is written as abstract final.
You do have a compile error reported, but you run your code anyway, right ?
This means that the "problem" type that we generate is bogus.
Comment 9 Fernando Colombo CLA 2010-07-26 14:00:08 EDT
Created attachment 175251 [details]
Bogus.java
Comment 10 Fernando Colombo CLA 2010-07-26 14:01:00 EDT
(In reply to comment #8)
> I'll investigate. So your class C1 is written as abstract final.
> You do have a compile error reported, but you run your code anyway, right ?
> This means that the "problem" type that we generate is bogus.

Yes, and that's very easy to reproduce. Since you reopened, I added the test case.
Comment 11 Olivier Thomann CLA 2010-07-26 14:09:47 EDT
(In reply to comment #10)
> Yes, and that's very easy to reproduce. Since you reopened, I added the test
> case.
I should be able to fix it quickly. It was not obvious from the original description that this was the problem.
Comment 12 Olivier Thomann CLA 2010-07-26 14:48:46 EDT
Created attachment 175258 [details]
Proposed fix + regression test

Will release for tomorrow's I-build. Are you able to test this I-build ?
Comment 13 Fernando Colombo CLA 2010-07-26 15:19:24 EDT
(In reply to comment #12)
> Created an attachment (id=175258) [details]
> Proposed fix + regression test
> 
> Will release for tomorrow's I-build. Are you able to test this I-build ?

I can't test, sorry. But I'm sure that if Eclipse generates valid access flags for the problem type, it will work.

Please, consider my suggestion. The .class for the "problem type" must be neither abstract nor public, so JVM will allow instantiation. Missing abstract methods should be stubs that only throws "unresolved compilation error".

Nevermind about interpreting the problem from the first report. JVM didn't told the correct story. The important thing is attitude to make things right.

Thanks!
Comment 14 Fernando Colombo CLA 2010-07-26 15:20:54 EDT
Please, consider:
> neither abstract nor public

As:
> neither abstract nor final
Comment 15 Olivier Thomann CLA 2010-07-26 22:39:21 EDT
Created attachment 175288 [details]
Proposed fix + regression test

Patch that clears both bits (AccFinal and AccAbstract) when both are set.
Comment 16 Olivier Thomann CLA 2010-07-26 22:40:09 EDT
Released for 3.7M1.
Regression test added in:
org.eclipse.jdt.core.tests.compiler.regression.ProblemTypeAndMethodTest#test107
Comment 17 Stephan Herrmann CLA 2010-07-29 09:34:55 EDT
Created attachment 175495 [details]
tiny improvement for the test

(In reply to comment #16)
> Released for 3.7M1.
> Regression test added in:
> org.eclipse.jdt.core.tests.compiler.regression.ProblemTypeAndMethodTest#test107

That test actually doesn't detect the bug :)
("catch (Error)" also catches the bogus ClassFormatError).
The attached patch improves the patch to discriminate the two potential
Errors thrown at runtime.
Comment 18 Satyam Kandula CLA 2010-08-04 07:00:45 EDT
Filed bug 321695 to address the problem Stephan mentioned in comment 17.
Comment 19 Satyam Kandula CLA 2010-08-04 07:01:11 EDT
Verified for 3.7M1 using build I20100802-1800