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
Class Signature attribute inconsistent with interfaces #8931
Comments
Imported From: https://issues.scala-lang.org/browse/SI-8931?orig=1 |
@soc said: |
@gourlaysama said: As in: ==> A.java <==
import java.io.Serializable;
public class A<T> implements Product1<T>, Product, Serializable {}
==> Product.java <==
public interface Product {}
==> Product1.java <==
public interface Product1<T> extends Product {} % javap -v A.class
[...]
#12 = Utf8 <T:Ljava/lang/Object;>Ljava/lang/Object;LProduct1<TT;>;LProduct;Ljava/io/Serializable; Note that case class Tuple1[+T](_1: T) extends Product1[T] is syntactic sugar for this: class Tuple1[+T] extends AnyRef with Product1[T] with Product with Serializable { <autogenerated members> } |
Eric Lafortune (lafortune) said: With a lower-level tool, you should see the actual interfaces. E.g. with ProGuard's java -jar proguard5.0/lib/proguard.jar \
-dontshrink \
-dontoptimize \
-dontobfuscate \
-dontpreverify \
-dump \
-injars lib/scala-library.jar'(scala/Tuple1.class)' \
| less You'll then see - Program class: scala/Tuple1
Superclass: java/lang/Object
.....
Interfaces (count = 2):
- Class [scala/Product1]
- Class [scala/Serializable]
.....
- Signature attribute:
- Utf8 [<T1:Ljava/lang/Object;>Ljava/lang/Object;Lscala/Product1<TT1;>;Lscala/Product;Lscala/Serializable;] Tools like asm or jad may provide the same information. Other tell-tale sign: |
@gourlaysama said: trait Foo
trait Foo1 extends Foo
class A extends Foo1 with Foo % javap -v A.class | grep '= Class.*Foo' # where is Foo...
#6 = Class #5 // Foo1 This seems to have regressed in Scala 2.9.2: % java -jar ~/Downloads/proguard5.0/lib/proguard.jar \
-dontshrink \
-dontoptimize \
-dontobfuscate \
-dontpreverify \
-dump \
-injars ~/scaladev/packs/scala-v2.9.1-1/pack/lib/scala-library.jar'(scala/Tuple1.class)' \
| grep 'Interfaces' -A 4
Interfaces (count = 4):
- Class [scala/Product1]
- Class [scala/ScalaObject]
- Class [scala/Product]
- Class [scala/Serializable]
% java -jar ~/Downloads/proguard5.0/lib/proguard.jar \
-dontshrink \
-dontoptimize \
-dontobfuscate \
-dontpreverify \
-dump \
-injars ~/scaladev/packs/scala-v2.9.2/pack/lib/scala-library.jar'(scala/Tuple1.class)' \
| grep 'Interfaces' -A 4
Interfaces (count = 2):
- Class [scala/Product1]
- Class [scala/Serializable]
Constant Pool (count = 184): |
@gourlaysama said: bq. Oracle's Java Virtual Machine implementation does not check the well-formedness of Signature attributes during class loading or linking. Instead, Signature attributes are checked by methods of the Java SE platform class libraries which expose generic signatures of classes, interfaces, constructors, methods, and fields. Examples include getGenericSuperclass in Class and toGenericString in java.lang.reflect.Executable. But even java reflection seems fine with it: scala> val c = classOf[Tuple1[String]]
c: Class[(String,)] = class scala.Tuple1
scala> c.getInterfaces
res0: Array[Class[_]] = Array(interface scala.Product1, interface scala.Serializable)
scala> c.getGenericInterfaces
res1: Array[java.lang.reflect.Type] = Array(scala.Product1<T1>, interface scala.Product, interface scala.Serializable) |
@gourlaysama said: So either it shouldn't do it at all, or it should do it properly (for both the signature and the interface list). |
@gourlaysama said: |
In scala-library.jar of Scala 2.11.2, a number of classes (165 to be precise) have Signature attributes that are inconsistent with their interfaces.
For instance, scala.Tuple1 has one superclass
java/lang/Object
and 2 direct interfaces:
scala/Product1
scala/Serializable
At the same time, it has this signature (adding whitespace for clarity):
T1:Ljava/lang/Object;
Ljava/lang/Object;
Lscala/Product1<TT1;>;
Lscala/Product;
Lscala/Serializable;
Note the 3 interface types, including the spurious "Lscala/Product;". The tool javap incorrectly lists it as a direct interface.
This seems to go against The Java Virtual Machine Specification, section 4.7.9.1: "A class signature encodes type information about a (possibly generic) class declaration. It describes any type parameters of the class, and lists its (possibly parameterized) direct superclass and direct superinterfaces, if any."
In practice, the problem triggers a crash in ProGuard 5.0, with an ArrayIndexOutOfBoundsException.
My apologies if this is a known issue; I haven't found it anywhere.
Eric Lafortune -- developer of ProGuard
The text was updated successfully, but these errors were encountered: