There are (at least) two race conditions in GroovyCategorySupport.java that 
would explain the intermittent and hard to reproduce bugs.

I was hoping to submit this as my first official pull request to the Groovy 
project, but gradle has different ideas…

However, the offending code is in on lines 75-76 and 99-100 where 
atomicCategoryUsageCounter is used non-atomically. If no one beats me to it I 
will submit a PR once I puzzle out why ./gradlew test is failing for me.

Cheers,
Keith

> On Oct 28, 2015, at 3:03 PM, Pascal Schumacher <[email protected]> 
> wrote:
> 
> Hi James,
> 
> thanks for reporting this. :)
> 
> Sadly I could not replicate the problem with groovy 2.4.5 (on windows) and 
> your testcase (tried different times and different amounts of threads).
> 
> I guess that's just caused by platform differences as I do not remember any 
> changes in 2.4.5 related to this problem and 
> https://github.com/apache/incubator-groovy/blob/d3bc07e5c2af7f5fbd344a961d549772de0680c7/src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java
>  
> <https://github.com/apache/incubator-groovy/blob/d3bc07e5c2af7f5fbd344a961d549772de0680c7/src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java>
>  looks like it could have concurrency issues.
> 
> - Pascal
> 
> Am 27.10.2015 um 23:10 schrieb James Oswald:
>> For the below email I have create a ticket and attached examples to this 
>> ticket: https://issues.apache.org/jira/browse/GROOVY-7535 
>> <https://issues.apache.org/jira/browse/GROOVY-7535>
>> When using groovy use block, we randomly get 
>> groovy.lang.MissingPropertyException when trying to access a property off a 
>> category.
>> 
>> index 76
>> Exception in thread "Thread-77" groovy.lang.MissingPropertyException: No 
>> such property: millisecond for class: java.lang.Integer
>> at 
>> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:51)
>> at 
>> org.codehaus.groovy.runtime.callsite.PojoMetaClassGetPropertySite.callGetProperty(PojoMetaClassGetPropertySite.java:43)
>> at 
>> TimeCategoryTest$__spock_initializeFields_closure1$_closure4$_closure5.doCall(TimeCategoryTest.groovy:23)
>> at 
>> TimeCategoryTest$__spock_initializeFields_closure1$_closure4$_closure5.doCall(TimeCategoryTest.groovy)
>> at sun.reflect.GeneratedMethodAccessor12.invoke(Unknown Source)
>> at 
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>> at java.lang.reflect.Method.invoke(Method.java:497)
>> at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
>> at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
>> at 
>> org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
>> at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
>> at groovy.lang.Closure.call(Closure.java:423)
>> at groovy.lang.Closure.call(Closure.java:417)
>> at 
>> org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:109)
>> at 
>> org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.access$400(GroovyCategorySupport.java:65)
>> at 
>> org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:249)
>> at 
>> org.codehaus.groovy.runtime.DefaultGroovyMethods.use(DefaultGroovyMethods.java:403)
>> 
>> or groovy.lang.MissingMethodException when trying to access a method from a 
>> category.
>> 
>> index 82
>> Exception in thread "Thread-207" groovy.lang.MissingMethodException: No 
>> signature of method: java.lang.String.test() is applicable for argument 
>> types: (java.lang.String) values: [ bar]
>> Possible solutions: next(), toSet(), getAt(java.lang.String), wait(). 
>> trim(), toList()
>> at 
>> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:56)
>> at 
>> org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:46)
>> at 
>> org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:122)
>> at 
>> CategoryTest$__spock_initializeFields_closure1$_closure5.doCall(CategoryTest.groovy:24)
>> at 
>> CategoryTest$__spock_initializeFields_closure1$_closure5.doCall(CategoryTest.groovy)
>> at sun.reflect.GeneratedMethodAccessor12.invoke(Unknown Source)
>> at 
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>> at java.lang.reflect.Method.invoke(Method.java:497)
>> at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
>> at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
>> at 
>> org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
>> at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
>> at groovy.lang.Closure.call(Closure.java:423)
>> at groovy.lang.Closure.call(Closure.java:417)
>> at 
>> org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:109)
>> at 
>> org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.access$400(GroovyCategorySupport.java:65)
>> at 
>> org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:249)
>> at 
>> org.codehaus.groovy.runtime.DefaultGroovyMethods.use(DefaultGroovyMethods.java:403)
>> 
>> On the server, either one of these exceptions to appear every few days or 
>> weeks.
>> 
>> The code below will reproduce this error:
>> 
>> class TestCategory {
>>     def static String test(String self, String foo) {
>>         return self + foo
>>     }
>> }
>> 
>> def test = {
>>     100.times {
>>         sleep( 10 )
>>         use(TestCategory) {
>>             println "foo".test(' bar')
>>         }
>>         sleep( 20 )
>>     }
>> }
>> 
>> 100.times {
>>     Thread.start test
>> }
>> I found a similar issue GROOVY-2105 
>> <https://issues.apache.org/jira/browse/GROOVY-2105> which contains a test 
>> that reproduces this problem on Linux. Looking back the fix that was 
>> implemented for this ticket was to add synchronized to 3 methods. These 
>> changes were late removed in a refactor of GroovyCategorySupport.
>> NOTE: problem does not happen 100% of the time.  You may have to play with 
>> the number of threads to generate the exception. What I have attached 
>> generates the exception on my linux box most of the time.
>> 
>> I have reproduced these exceptions on Cent O/S version 6.4 with 64 Bit JDK 
>> 1.8 and groovy 2.4.4
>> 
>> 
>> -- 
>> 
>> James 
> 

Reply via email to