Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-9103

CLONE - CLONE - Fix warning "An illegal reflective access operation has occurred"

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 2.4.11, 2.4.15
    • 3.0.0-beta-2
    • groovy-jdk

    Description

      This cloned issue is to cover the rest part of GROOVY-9081.

      Case 2, 8, 9 are illegal access and have to be fixed by changing user's code(including the implementation of some AST Transformations)

      2) Sub-class derives the protected members from public class,

      2.1) Clone array via clone method of java.lang.Object , use Arrays.copyOf instead ( Note: the method is protected, truely illegal access, we should fix our code), e.g.
      https://github.com/apache/groovy/blob/master/src/test/org/codehaus/groovy/transform/ImmutableTransformTest.groovy#L163-L180
      As we can see, groovy.transform.Immutable will generate the code to invoke clone on array object:

          @groovy.transform.Generated
          public HasList(java.util.Map args) {
              metaClass = /*BytecodeExpression*/
              if ( args == null) {
                  args = [:]
              }
              org.codehaus.groovy.transform.ImmutableASTTransformation.checkPropNames(this, args)
              if ( args .letters == null) {
                  this .letters = null
              } else {
                  this .letters = ((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .letters, 'clone', new java.lang.Object[][])) as java.lang.String[])
              }
              if ( args .nums == null) {
                  this .nums = null
              } else {
                  if ( args .nums instanceof java.lang.Cloneable) {
                      this .nums = ((((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object) instanceof java.util.SortedSet ? org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable((((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object)) as java.util.SortedSet<E extends java.lang.Object>) : ((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object) instanceof java.util.SortedMap ? org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable((((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object)) as java.util.SortedMap<K extends java.lang.Object, V extends java.lang.Object>) : ((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object) instanceof java.util.Set ? org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable((((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object)) as java.util.Set<E extends java.lang.Object>) : ((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object) instanceof java.util.Map ? org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable((((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object)) as java.util.Map<K extends java.lang.Object, V extends java.lang.Object>) : ((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object) instanceof java.util.List ? org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable((((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object)) as java.util.List<E extends java.lang.Object>) : org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable((((org.codehaus.groovy.runtime.ReflectionMethodInvoker.invoke( args .nums, 'clone', new java.lang.Object[][])) as java.lang.Object)) as java.util.Collection)) as java.lang.Object)
                  } else {
                      this .nums = (( args .nums instanceof java.util.SortedSet ? org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable(( args .nums) as java.util.SortedSet<E extends java.lang.Object>) : args .nums instanceof java.util.SortedMap ? org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable(( args .nums) as java.util.SortedMap<K extends java.lang.Object, V extends java.lang.Object>) : args .nums instanceof java.util.Set ? org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable(( args .nums) as java.util.Set<E extends java.lang.Object>) : args .nums instanceof java.util.Map ? org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable(( args .nums) as java.util.Map<K extends java.lang.Object, V extends java.lang.Object>) : args .nums instanceof java.util.List ? org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable(( args .nums) as java.util.List<E extends java.lang.Object>) : org.codehaus.groovy.runtime.DefaultGroovyMethods.asImmutable(( args .nums) as java.util.Collection)) as java.lang.Object)
                  }
              }
          }
      

      2.2) Access the overrided protected method of sub-class(Truely illegal access, we should fix our code), e.g.
      https://github.com/apache/groovy/blob/master/src/test/org/codehaus/groovy/transform/classloading/TransformsAndCustomClassLoadersTest.groovy#L124
      AppClassLoader derives ClassLoader, but Class<?> loadClass(String cn, boolean resolve) of AppClassLoader is still protected, we should not access it if we do not want warnings.
      2.3) Access the protected final method(Truely illegal access, we should fix our code), e.g.
      https://github.com/apache/groovy/blob/master/src/test/org/codehaus/groovy/reflection/SecurityTest.java#L243-L258
      protected final Class<?> defineClass(String name, java.nio.ByteBuffer b, ProtectionDomain protectionDomain) of ClassLoader

      6) ?Get properties of objects(including private methods)

      https://github.com/apache/groovy/blob/master/src/test/org/codehaus/groovy/classgen/asm/sc/ArraysAndCollectionsStaticCompileTest.groovy#L68
      ''.properties will access java.lang.String.isLatin1, which is private

      We fix the case by filtering non-properties and allow illegal access properties for backward compatibility via switching on JVM option -Dgroovy.allow.illegal.access.properties=true(Note: false is the default value)

      8) Access invisible members or explicitly invoke setAccessible (Truely illegal access, we should fix our code), e.g.

      https://github.com/apache/groovy/blob/master/src/test/groovy/transform/ThreadInterruptTest.groovy#L65

      9) Avoid use java.math.BigInteger.multiply(long), and use BigInteger.multiply(BigInteger) instead*(Truely illegal access)*, e.g.

      https://github.com/apache/groovy/blob/master/src/test/groovy/transform/stc/STCAssignmentTest.groovy#L692
      More examples:

      1G * 2 // emits illegal access warnings
      1G * 2G // Recommend to append "G" to the number to represent BigInteger, no illegal access warnings
      

       We make Groovy a bit smarter by find the proper method, i.e. BigInteger.multiply(BigInteger)

      Attachments

        Issue Links

          Activity

            People

              daniel_sun Daniel Sun
              benrobot Benjamin Roedell
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 1h 50m
                  1h 50m