Issue Details (XML | Word | Printable)

Key: GROOVY-1863
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Blocker Blocker
Assignee: Jochen Theodorou
Reporter: Aaron Digulla
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
groovy

Groovy compiler executes code it is compiling

Created: 30/Apr/07 03:37 AM   Updated: 14/Oct/07 01:30 PM   Resolved: 10/Oct/07 05:23 AM
Return to search
Component/s: command line processing
Affects Version/s: 1.0
Fix Version/s: 1.1-rc-1

Time Tracking:
Not Specified

File Attachments: 1. File ClassExaminer.groovy (3 kB)
2. File patch (6 kB)
3. HTML File StaticInitBug.zip (0.6 kB)

Issue Links:
dependent
 


 Description  « Hide

Unpack the attached example and compile it. The compiler will crash with a RuntimeException like this:


{



Aaron Digulla added a comment - 30/Apr/07 03:43 AM

Unpack the attached example and compile it. The compiler will crash with a RuntimeException like this:

java.lang.ExceptionInInitializerError
	at sun.misc.Unsafe.ensureClassInitialized(Native Method)
	at sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(UnsafeFieldAccessorFactory.java:25)
	at sun.reflect.ReflectionFactory.newFieldAccessor(ReflectionFactory.java:122)
	at java.lang.reflect.Field.acquireFieldAccessor(Field.java:918)
	at java.lang.reflect.Field.getFieldAccessor(Field.java:899)
	at java.lang.reflect.Field.get(Field.java:358)
	at org.codehaus.groovy.control.ResolveVisitor.getTimeStamp(ResolveVisitor.java:275)
	at org.codehaus.groovy.control.ResolveVisitor.isSourceNewer(ResolveVisitor.java:298)
	at org.codehaus.groovy.control.ResolveVisitor.resolveToScript(ResolveVisitor.java:327)
	at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:248)
	at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:226)
	at org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ResolveVisitor.java:211)
	at org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ResolveVisitor.java:221)
	at org.codehaus.groovy.control.ResolveVisitor.transformVariableExpression(ResolveVisitor.java:675)
	at org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:538)
	at org.codehaus.groovy.control.ResolveVisitor.transformDeclarationExpression(ResolveVisitor.java:741)
	at org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:542)
	at org.codehaus.groovy.control.ResolveVisitor.visitExpressionStatement(ResolveVisitor.java:839)
	at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:70)
	at org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:83)
	at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitBlockStatement(ClassCodeVisitorSupport.java:102)
	at org.codehaus.groovy.control.ResolveVisitor.visitBlockStatement(ResolveVisitor.java:845)
	at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:82)
	at org.codehaus.groovy.control.ResolveVisitor.visitMethod(ResolveVisitor.java:181)
	at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:838)
	at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:36)
	at org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:787)
	at org.codehaus.groovy.control.ResolveVisitor.startResolving(ResolveVisitor.java:128)
	at org.codehaus.groovy.control.CompilationUnit$5.call(CompilationUnit.java:595)
	at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:833)
	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:480)
	at org.codehaus.groovy.eclipse.core.compiler.GroovyCompiler.compile(GroovyCompiler.java:158)
	at org.codehaus.groovy.eclipse.core.compiler.GroovyCompiler.compile(GroovyCompiler.java:89)
	at org.codehaus.groovy.eclipse.core.model.GroovyProject.compileGroovyFile(GroovyProject.java:496)
	at org.codehaus.groovy.eclipse.core.GroovyCore.sourceChanged(GroovyCore.java:106)
	at org.codehaus.groovy.eclipse.editor.GroovyReconcilingStrategy.reconcile(GroovyReconcilingStrategy.java:78)
	at org.eclipse.jface.text.reconciler.MonoReconciler.process(MonoReconciler.java:71)
	at org.eclipse.jface.text.reconciler.AbstractReconciler$BackgroundThread.run(AbstractReconciler.java:204)
Caused by: java.lang.RuntimeException: This must not be executed during compile!
	at Foo.init(Foo.java:13)
	at Foo.<init>(Foo.java:8)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at org.codehaus.groovy.runtime.MetaClassHelper.doConstructorInvoke(MetaClassHelper.java:562)
	at groovy.lang.MetaClassImpl.doConstructorInvoke(MetaClassImpl.java:1756)
	at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:758)
	at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:688)
	at org.codehaus.groovy.runtime.Invoker.invokeConstructorOf(Invoker.java:163)
	at org.codehaus.groovy.runtime.InvokerHelper.invokeConstructorOf(InvokerHelper.java:140)
	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeNewN(ScriptBytecodeAdapter.java:243)
	at StaticInitBug.<clinit>(StaticInitBug.groovy:4)
	... 38 more

The problem is this: Foo does some strange stuff in its constructor.

StaticInitBug has a static initializer of type Foo.

Bar uses StaticInitBug. While the compiler compiles Bar, it tries to find out the lastModificationTime of the class StaticInitBug. This code resolves the class using reflection. The net result is that StaticInitBug is loaded and initialized which leads to the execution of the code in Foo.

This should not happen. I guess using reflection in the Groovy compiler is a "must not". Some other means to analyze a class without actually executing any code in it must be found.


Aaron Digulla added a comment - 03/May/07 07:25 AM

A small example how to read the lastModified date from a groovy class file without Reflection.


Aaron Digulla made changes - 03/May/07 07:25 AM
Field Original Value New Value
Attachment ClassExaminer.groovy [ 27124 ]
Aaron Digulla added a comment - 03/May/07 10:37 AM

Attached the original testcase for the bug again.


Aaron Digulla made changes - 03/May/07 10:37 AM
Attachment StaticInitBug.zip [ 27126 ]
Robert Stroud added a comment - 08/May/07 03:17 AM

See discussion on groovy-dev mailing list - the difficulty is that the compiler uses Field.get to access a timestamp that was added to the compiled class. However, this causes the class to be initialized, which in turn causes static initializers to be executed.

http://www.nabble.com/Groovy-runs-code-in-static-initializers-during-compile-tf3607689.html

I don't think there's anything wrong with using Class objects to access type information about classes, so I don't think it's necessary to find an alternative way of reading a class file - however, care must be taken not to initialize the class file during compilation.

An alternative approach to solving this problem is to check for the existence of a source file and object file, and compare the file modification times - this avoids the need to store a modification time in the class file.

I've attached a patch that uses this approach - it runs the attached example without triggering the runtime exception from the compiler:

http://www.nabble.com/Groovy-runs-code-in-static-initializers-during-compile-tf3607689.html

This is just a "proof of concept", but I think it suggests another way of tackling this issue.


Robert Stroud made changes - 08/May/07 03:18 AM
Attachment patch [ 27191 ]
Guillaume Laforge made changes - 17/May/07 08:49 AM
Assignee Jochen Theodorou [ blackdrag ]
Fix Version/s 1.1-beta-2 [ 10436 ]
Jochen Theodorou made changes - 01/Jul/07 01:35 PM
Fix Version/s 1.1-beta-3 [ 13590 ]
Fix Version/s 1.1-beta-2 [ 10436 ]
Jochen Theodorou made changes - 01/Jul/07 01:36 PM
Link This issue depends upon GROOVY-1962 [ GROOVY-1962 ]
Guillaume Laforge made changes - 20/Sep/07 03:11 PM
Fix Version/s 1.1-beta-3 [ 13590 ]
Fix Version/s 1.1-rc-1 [ 13165 ]
Guillaume Laforge made changes - 06/Oct/07 05:17 PM
Priority Critical [ 2 ] Blocker [ 1 ]
Guillaume Laforge made changes - 10/Oct/07 05:23 AM
Resolution Fixed [ 1 ]
Status Open [ 1 ] Closed [ 6 ]
Aaron Digulla added a comment - 10/Oct/07 08:17 AM

In which revision has it been fixed?


Guillaume Laforge added a comment - 10/Oct/07 08:19 AM

in trunk


Aaron Digulla added a comment - 10/Oct/07 08:26 AM

In which revision in trunk?

I'd like to review the fix.



Aaron Digulla added a comment - 14/Oct/07 01:30 PM

The fix looks good to me, thanks!