[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: maybe a semantic mistake?



Make Laurie's example more interesting. I add another method in B.java

class B extends A {
  public void f() {  // will be changed to private in jimple
    ...
  }
  public void invoke_f() {
    this.f();
  }
}


In Test.java, I added one extra line to invoke "invoke_f" method on an
instance of C. Guess what, the actual method selected by Sun's JVM
1.4.1_01 (and IBM's) to invoke is B.f().

If read the spec carefully, it says "Let C be the class of objectref ....
If C contains ... and the resolved method is *accessible* from C, ... the
lookup procedure terminates." But in this example, the class of objectref
is C, and B.f is not accessible from C. It should lookup further to A.f().


It might be caused by implication that private method is invoked by
"invokespecial" bytecode only. But no verification error in this case.


The installed version of SableVM 1.0.1 invokes B.f() in both case, it
might not check accessiblity.

JikesRVM throws null pointer exception because the virtual table
entry for f() of class C is interntionally set to null.

Cheers,
-- Feng

On Thu, 6 Mar 2003, Prof. Laurie HENDREN wrote:

> Yes, I agree with Ondrej.  Take a look at the example I have
> attached to this message.   There are four classes A,B,C and Test as
> in your example,
>
> I wrote a little Java program, compiled
> it to class files,  then produced Jimple using Soot,  edited the Jimple to put
> the private in class B and changed the signature of the virtualinvoke in
> class Test (see below) and then used Soot to produce class files from
> the Jimple.
>
> I also decompiled the new class files (files in dava/src).  This gives
> you a source code look at what I have.  Note that
> the decompiled source will not recompile because of the private f in
> class B.
>
> However, you can run the class file Test.
>
> Try,  java -verify Test
>
> and it will say that it is running the method in class A.
>
>
> Here is the jimple for Test.java,
>
>
> /*****************************************
>
> public class Test extends java.lang.Object
> {
>
>     public void <init>()
>     {
>         Test r0;
>
>         r0 := @this: Test;
>         specialinvoke r0.<java.lang.Object: void <init>()>();
>         return;
>     }
>
>     public static void main(java.lang.String[] )
>     {
>         java.lang.String[] r0;
>         C $r1, r2;
>
>         r0 := @parameter0: java.lang.String[];
>         $r1 = new C;
>         specialinvoke $r1.<C: void <init>()>();
>         r2 = $r1;
>         virtualinvoke r2.<A: void f()>();  <---------------
>         return;
>     }
> }
>
> *******************************************
>
> Look at the statement marked by the arrow.  This must use the
> signature A in the call to f.    If either B or C is used, then
> the bytecode fails when run with the verifier (and it writes out
> that it is running f in B if you turn the verifier off).
>
>
> Cheers, Laurie
> +-------------------------------------------------------------+
> | Laurie Hendren, Professor, School of Computer Science       |
> | McGill University                                           |
> | 318 McConnell Engineering Building      tel: (514) 398-7391 |
> | 3480 University Street                  fax: (514) 398-3883 |
> | Montreal, Quebec H3A 2A7               hendren@cs.mcgill.ca |
> | CANADA                  http://www.sable.mcgill.ca/~hendren |
> +-------------------------------------------------------------+
>
> On Thu, 6 Mar 2003, Ondrej LHOTAK wrote:
>
> > The lookup code implemented in Soot follows the description given in the
> > Java Virtual Machine Specification, under invokevirtual:
> > http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc6.html#invokevirtual
> >
> > According to this description, for the example you gave, the A.f() that
> > Soot returns would indeed be the correct method to invoke. Contrary to
> > your claim, it is *not* true that C cannot access any f(), neither from
> > A nor B.
> >
> > If you still think I have misunderstood the specification, please let me
> > know.
> >
> > Ondrej
> >
> > On Thu, Mar 06, 2003 at 11:17:21AM -0500, Weilei Zhang wrote:
> > > The following is from the method resolveConcreteDispatch in Hierarchy.java.
> > >  public SootMethod resolveConcreteDispatch(SootClass concreteType, SootMethod m)
> > >     {
> > >     ..........
> > >         while (it.hasNext())
> > >         {
> > >             SootClass c = (SootClass)it.next();
> > >             if (c.declaresMethod(methodSig)
> > >             && isVisible( c, m )
> > >             ) {
> > >                 return c.getMethod(methodSig);
> > >             }
> > >         }
> > >     ......
> > >     }
> > > I think the loop should be terminated once we find a SootClass c s.t. (c.declaresMethod(methodSig)&& ! isVisible( c, m )).
> > > The reason is as follows: think of a Class A ,which has public method f(), Class B which extends A and has a redefined private method f(), Class C extends B and doesn't redefine method f(). Then the instance of C can't access any f(), either in A() or in B(). But in your code, A.f() will be returned.
> > > However, the case I mentioned can't appear in normally compiled java code because B can't override f() in A with weaker access privileges. But maybe it will appear in maliciously/purposefully made bytecode.
> > > As a conclusion, there is no problem in general cases, but there is a mistake semantically, IMHO.
> > > Regards
> > > -Weilei
> > >
> > >
> > >
> > >
> >
>