Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Erasure and inheritance collude: compiler attempts cast to an inaccessible class #4283

Closed
scabug opened this issue Feb 23, 2011 · 13 comments
Closed
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Feb 23, 2011

Because of erasure, the compiler needs to insert casts to get the expected type. The "expected type" logic seems to depend on the use of the type, rather than the statically-known type.

In this example, since the class AbstractFoo is the one that defines the field t, the compiler thinks it needs to cast the result of ScalaBipp.make.get to AbstractFoo in order to access t. This is incorrect behavior, since AbstractFoo might in fact be inaccessible in the scope in which the cast is applied.

=== What steps will reproduce the problem (please be specific and use wikiformatting)? ===
test/AbstractFoo.java

package test;

/* package private */ class AbstractFoo {
  public int t;
}

ScalaBipp.scala

package test

class ScalaBipp extends AbstractFoo {
  def make: Option[ScalaBipp] = Option(this)
}

test.scala

package other

object IllegalAccess {
    val x = (new test.ScalaBipp).make.get.t // java.lang.IllegalAccessError: tried to access class test.AbstractFoo from class other.IllegalAccess$$
}

=== What is the expected behavior? ===
No runtime failure.

=== What do you see instead? ===
Runtime exception accessing class test.AbstractFoo and the following bytecode:

javap -c other.IllegalAccess$$

   0:	new	SI-16; //class test/ScalaBipp
   3:	dup
   4:	invokespecial	SI-18; //Method test/ScalaBipp."<init>":()V
   7:	invokevirtual	SI-22; //Method test/ScalaBipp.make:()Lscala/Option;
   10:	invokevirtual	SI-28; //Method scala/Option.get:()Ljava/lang/Object;
   13:	checkcast	SI-30; //class test/AbstractFoo
   16:	getfield	SI-34; //Field test/AbstractFoo.t:I
   19:	istore_2
   20:	return

=== Additional information ===
The checkcast on line 13 is wrong. It should cast to ScalaBipp rather than AbstractFoo.

test

=== Scala version ===
trunk r24156

@scabug
Copy link
Author

scabug commented Feb 23, 2011

Imported From: https://issues.scala-lang.org/browse/SI-4283?orig=1
Reporter: Josh Suereth (joshua.suereth)
Other Milestones: 2.12.0-M5
See #18, #22, #28, #30, #34, #16

@scabug
Copy link
Author

scabug commented Feb 28, 2011

@axel22 said:
Fails with trunk as well.

@scabug
Copy link
Author

scabug commented Mar 2, 2011

@lindydonna said:
I have cut down the test case substantially.

@scabug
Copy link
Author

scabug commented Mar 2, 2011

@lindydonna said:
Note: I strongly suspect this is a typer bug, rather than a code gen bug.

@scabug
Copy link
Author

scabug commented Mar 17, 2011

@paulp said:
Still some free riders in the test case not pulling their bug weight. This is all you need.

// Ab.java
package test;

class Aa { public int t; }
public class Ab extends Aa { }

// a.scala
object Test extends App { (new test.Ab).t }

@scabug
Copy link
Author

scabug commented Apr 11, 2011

@odersky said:
This will be very hard to get right. The info is no longer available at the point where it is needed. All type info is are deleted and then things are re-typechecked from the ground up with casts inserted. There's no room here for "what was the type before?".

@scabug
Copy link
Author

scabug commented Apr 13, 2011

@odersky said (edited by @lrytz on Mar 22, 2017 8:46:32 AM UTC):
I fixed now my part of this in scala/scala@514d01c1ce by inserting another cast pre-emptively when an IllegalAccess error is possible in an erasure-inserted cast. There's still a problem in that emitted getField and putField instructions get the owner of the accessed field as prefix, instead of the static type of the qualifier. invoke operations are OK. All of these are demonstrated in test t2383, which is in test/pending/run.

@scabug
Copy link
Author

scabug commented Apr 13, 2011

@dragos said:
(In r24751) Closes #4283. no review.

@scabug
Copy link
Author

scabug commented Apr 13, 2011

@dragos said:
(In r24758) Revert "Closes #4283. no review." because of failing tests.

@scabug
Copy link
Author

scabug commented Apr 14, 2011

@dragos said (edited by @lrytz on Mar 22, 2017 8:46:48 AM UTC):
(In scala/scala@8707c9ecb3) This time, fixed #4283. no review.

@scabug
Copy link
Author

scabug commented Nov 24, 2011

@paulp said:
Note that r24749 caused #5162.

@scabug
Copy link
Author

scabug commented Apr 11, 2016

@lrytz said (edited on Apr 11, 2016 8:36:12 AM UTC):
this one still fails for field writes (2.12.0-M4):

A.java

package a;
/*package private*/ abstract class A { public int t; }

B.java

package a;
public class B extends A { }

Test.scala

package b
object Test {
  def main(args: Array[String]): Unit = {
    val b = new a.B
    b.t = 10
  }
}
$ javac A.java B.java -d .
$ scalac12 Test.scala
$ scala12 b.Test
java.lang.IllegalAccessError: tried to access class a.A from class b.Test$

I'll push a fix.

@scabug
Copy link
Author

scabug commented Apr 12, 2016

@lrytz said:
Fix for field writes in scala/scala#5096

@scabug scabug closed this as completed Apr 25, 2016
@scabug scabug added this to the 2.10.0-M3 milestone Apr 7, 2017
lrytz added a commit to lrytz/scala that referenced this issue Jul 4, 2017
A super access to a protected member in a package-protected class is allowed through
an intermediate public class. The fix for scala/bug#5162 actually introduced an error
for this case, because the scala compiler would generate an INVOKESPECIAL with the
package-protected class as receiver, which is illegal. However, we can use the public
intermediate class in the invocation signature.

Fixes scala/bug#7936

This is very similar to scala/bug#4283
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants