Scala Programming Language
  1. Scala Programming Language
  2. SI-6063

2.10 regression: broken static forwarders for non-public methods generated when extending class from different package

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: Scala 2.10.0-M6
    • Component/s: None
    • Labels:
      None

      Description

      As an example, take java.lang.Throwable as our superclass.

      % cat O.scala
      object O extends Throwable
      % scalac29 -version
      Scala compiler version 2.9.2 -- Copyright 2002-2011, LAMP/EPFL
      % scalac29 O.scala
      % cat J.java
      public class J {
        public static void main(String[] args) {
          O.getStackTraceDepth();
        }
      }
      % javac -version
      javac 1.6.0_33
      % javac -classpath .:/usr/local/scala-2.9.2/lib/scala-library.jar J.java
      J.java:3: cannot find symbol
      symbol  : method getStackTraceDepth()
      location: class O
          O.getStackTraceDepth();
           ^
      1 error
      

      2.10.0-M4 does generate a forwarder, but woe to she who attempts to actually use it:

      % rm *.class
      % scalac210 -version
      Scala compiler version 2.10.0-M4 -- Copyright 2002-2011, LAMP/EPFL
      % scalac210 O.scala
      % javac -classpath .:/usr/local/scala-2.9.2/lib/scala-library.jar J.java
      % java -classpath .:/usr/local/scala-2.9.2/lib/scala-library.jar J
      Exception in thread "main" java.lang.IllegalAccessError: tried to access method java.lang.Throwable.getStackTraceDepth()I from class O
      	at O.getStackTraceDepth(O.scala)
      	at J.main(J.java:3)
      

      A quick look with javap shows that the body of the forwarder is confused about the static-ness of the method it's trying to forward to:

      % javap -c -classpath .:/usr/local/scala-2.9.2/lib/scala-library.jar O
      ...
      public static int getStackTraceDepth();
        Code:
         0:	getstatic	; //Field O$.MODULE$:LO$;
         3:	invokevirtual	; //Method O$.getStackTraceDepth:()I
         6:	ireturn
      ...
      

      My examples don't have package declarations, but I don't think that matters because I hit this in real code and in the real code everything was in packages.

      It's true you can avoid the runtime error by simply not attempting to use the broken static forwarder, but I'm afraid that doesn't really solve it because the invalid forwarders may confuse tools. For example, they cause ProGuard to abort and exit when processing my real code.

      This appears related to SI-3452 (which itself has many related tickets).

        Activity

        Hide
        Seth Tisue added a comment -

        Ugh, I can't edit the description of my own ticket. Please replace "the body of the forwarder is confused about the static-ness of the method it's trying to forward to" with "the body of the forwarder is attempting to call a non-public method".

        The forwarder should not be generated at all, since O isn't in the java.lang package so the method is inaccessible.

        Show
        Seth Tisue added a comment - Ugh, I can't edit the description of my own ticket. Please replace "the body of the forwarder is confused about the static-ness of the method it's trying to forward to" with "the body of the forwarder is attempting to call a non-public method". The forwarder should not be generated at all, since O isn't in the java.lang package so the method is inaccessible.
        Hide
        Seth Tisue added a comment -

        I checked and the same thing still happens on master as of two days ago:

        % rm *.class                                                          
        % ~/scala/dists/latest/bin/scalac -version
        Scala compiler version 2.10.0-20120709-094806-e9afc228fd -- Copyright 2002-2011, LAMP/EPFL
        % ~/scala/dists/latest/bin/scalac O.scala
        % javac -classpath ~/scala/dists/latest/lib/scala-library.jar:. J.java
        % java -classpath ~/scala/dists/latest/lib/scala-library.jar:. J      
        Exception in thread "main" java.lang.IllegalAccessError: tried to access method java.lang.Throwable.getStackTraceDepth()I from class O
        	at O.getStackTraceDepth(O.scala)
        	at J.main(J.java:3)
        
        Show
        Seth Tisue added a comment - I checked and the same thing still happens on master as of two days ago: % rm *.class % ~/scala/dists/latest/bin/scalac -version Scala compiler version 2.10.0-20120709-094806-e9afc228fd -- Copyright 2002-2011, LAMP/EPFL % ~/scala/dists/latest/bin/scalac O.scala % javac -classpath ~/scala/dists/latest/lib/scala-library.jar:. J.java % java -classpath ~/scala/dists/latest/lib/scala-library.jar:. J Exception in thread "main" java.lang.IllegalAccessError: tried to access method java.lang.Throwable.getStackTraceDepth()I from class O at O.getStackTraceDepth(O.scala) at J.main(J.java:3)
        Hide
        Miguel Garcia added a comment -

        The thing is that j.l.Throwable.getStackTraceDepth() is package-protected, and the following program doesn't compile:

        object O extends Throwable
        
        object Test {
          def main(args: Array[String]) {
            O.getStackTraceDepth()
          }
        }
        

        The error reads

        error: method getStackTraceDepth in class Throwable cannot be accessed in object O
            O.getStackTraceDepth()
              ^
        one error found
        
        Show
        Miguel Garcia added a comment - The thing is that j.l.Throwable.getStackTraceDepth() is package-protected, and the following program doesn't compile: object O extends Throwable object Test { def main(args: Array[String]) { O.getStackTraceDepth() } } The error reads error: method getStackTraceDepth in class Throwable cannot be accessed in object O O.getStackTraceDepth() ^ one error found
        Hide
        Seth Tisue added a comment -

        right. so no static forwarder should be generated.

        Show
        Seth Tisue added a comment - right. so no static forwarder should be generated.
        Hide
        Paul Phillips added a comment -

        Protected symbols are already excluded from getting forwarders; I can only guess that the symbol isn't marked protected anymore for some reason. Or possibly that we're getting wrong flags due to it not being initialized (a tragic possibility.)

        Show
        Paul Phillips added a comment - Protected symbols are already excluded from getting forwarders; I can only guess that the symbol isn't marked protected anymore for some reason. Or possibly that we're getting wrong flags due to it not being initialized (a tragic possibility.)
        Hide
        Paul Phillips added a comment -

        No, I see the problem; due to the confusing encoding of access, checking for PRIVATE and PROTECTED is still not enough. Also have to check !m.hasAccessBoundary.

        Show
        Paul Phillips added a comment - No, I see the problem; due to the confusing encoding of access, checking for PRIVATE and PROTECTED is still not enough. Also have to check !m.hasAccessBoundary.
        Hide
        Seth Tisue added a comment -

        may I suggest this be marked critical for 2.10 since it's a regression?

        Show
        Seth Tisue added a comment - may I suggest this be marked critical for 2.10 since it's a regression?
        Show
        Adriaan Moors added a comment - https://github.com/scala/scala/pull/1070
        Hide
        Seth Tisue added a comment -

        awesome — thank you

        Show
        Seth Tisue added a comment - awesome — thank you

          People

          • Assignee:
            Paul Phillips
            Reporter:
            Seth Tisue
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development