[Prev][Next][Index][Thread]
RE: Type soundness issues in Java
> I thought about this a little more, and while I think the principles I
> described are more or less right, I'm not sure about the details. For
> example, verification should have loaded I.class to verify the field access
> "i.c". Similarly, it looks like it's the loading of class I that causes the
> final failure, but you would have thought the binary compatibility checks
> would have failed when class A was loaded in line 1 of main(). If not, it
> may be that the assumption tracking in the loader/verifier a messy business
> indeed, which may leave plenty of room for implementation bugs...
>
> So perhaps the story could be cleaner, and a formalization or model
> implementation might help with this!
I looked at the bytecode produced by javac on the Main class. That
explained a lot to me and reminded me of something I had forgotten.
The thing I could not figure out was how the expression i.c was producing
a meaningful value.
public static void main(String args[]) {
A a = new A();
I i;
System.out.println("I've been started");
if(a instanceof I)
System.out.println("a is instance of I!");
else
System.out.println("a Is NOT instance of I");
i=a;
System.out.println("Cast succeeded!");
System.out.println(java.lang.Integer.toString(i.c,10));
i.m();
}
Well, it turns out the expression is "optimized" by javac.
public static void main(String args[]) {
A a = new A();
I i;
System.out.println("I've been started");
if(a instanceof I)
System.out.println("a is instance of I!");
else
System.out.println("a Is NOT instance of I");
i=a;
System.out.println("Cast succeeded!");
System.out.println(java.lang.Integer.toString(i.c,10));
i.m();
}
Method void main(java.lang.String[])
0 new #5 <Class A>
3 dup
4 invokespecial #12 <Method A()>
7 astore_1
8 getstatic #15 <Field java.io.PrintStream out>
11 ldc #2 <String "I've been started">
13 invokevirtual #16 <Method void println(java.lang.String)>
16 aload_1
17 instanceof #6 <Class I>
20 ifeq 34
23 getstatic #15 <Field java.io.PrintStream out>
26 ldc #4 <String "a is instance of I!">
28 invokevirtual #16 <Method void println(java.lang.String)>
31 goto 42
34 getstatic #15 <Field java.io.PrintStream out>
37 ldc #3 <String "a Is NOT instance of I">
39 invokevirtual #16 <Method void println(java.lang.String)>
42 aload_1
43 astore_2
44 getstatic #15 <Field java.io.PrintStream out>
47 ldc #1 <String "Cast succeeded!">
49 invokevirtual #16 <Method void println(java.lang.String)>
52 getstatic #15 <Field java.io.PrintStream out>
55 iconst_4 <-------------------------------- i.c
56 bipush 10
58 invokestatic #17 <Method java.lang.String toString(int, int)>
61 invokevirtual #16 <Method void println(java.lang.String)>
64 aload_2
65 invokeinterface (args 1) #14 <InterfaceMethod void m()>
70 return
I write "optimized" above because fields in interfaces actually have
the meaning of constants.
The above bytecode also shows where the first "active" use of I is:
at the invokeinterface instruction at PC 65. So, indeed, the principle
doing things as lazily as possible explains this case.
Sorry if this was obvious to everyone all the time. I thought it was
worth spelling out.
Ole