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

Dynamic compilation exposes privileged constructors

    XMLWordPrintableJSON

    Details

    • Type: Bug
    • Status: Open
    • Priority: Major
    • Resolution: Unresolved
    • Affects Version/s: 2.5.4
    • Fix Version/s: None
    • Component/s: Compiler
    • Labels:
      None
    • Environment:
      OpenJDK 10

      Description

      BigInteger(long) is a privileged constructor that behaves incorrectly for zero. When CompileStatic is not used, this constructor is exposed. Thus, the following assertion:

      assert new BigInteger("0") == new BigInteger(0)

      fails.


      BigDecimal(BigInteger, long, int, int) is a privileged constructor that assumes well-formed arguments. When CompileStatic is not used, this constructor is exposed, allowing for this code:

      BigDecimal nullbomb = new BigDecimal(null, Long.MIN_VALUE, 10, 10)
      

      to produce a seemingly valid BigDecimal, which nevertheless throws a NullPointerException when touched.


      String(char[], boolean) is a privileged constructor that allows memory to be shared between two strings. When CompileStatic is not used, this constructor is exposed, allowing for the following code:

      class EvilStringProvider {
          char[] good = "Good"
          char[] evil = "Evil"
      
          def getGoodString() {
              new String(good, true)
          }
      
          def surprise() {
              for (int i = 0; i < good.length; i++) {
                  good[i] = evil[i]
              }
          }
      }
      
      def provider = new EvilStringProvider()
      
      def myGoodString = provider.goodString
      println myGoodString
      
      provider.surprise()
      println myGoodString
      

      An object produces a string that says "Good", but is then magically able to change it to say "Evil" later on, violating the immutability assumption of Strings.


      If CompileStatic is active, all three of these examples will either fail due to the constructor not being found, or, in the case of BigInteger, the constructor argument will be implicitly converted to match a public constructor.

      Of course, Java reflection can replicate all of these effects, and many more dangerous effects besides. But code that does not appear to contain dangerous reflection should not be able to produce such effects.

      Side note: I'm not an expert on Groovy source code, but I think org.codehaus.groovy.reflection.CachedClass might be the culprit here; it appears to expose the constructors of its argument class without considering their access level. org.codehaus.groovy.reflection.stdclasses contains a number of classes that apply CachedClass to a number of standard library classes, including BigInteger, BigDecimal, and String.

        Attachments

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              curtis.mackie Curtis Mackie
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated: