jakarta-bcel-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dick Eimers <dweim...@cs.uu.nl>
Subject Relying on local variable slot 0
Date Wed, 14 Jul 2004 11:07:44 GMT
This problem was brought to our attention by Toby Reyelts in October
2002, but was not really examined as much as I'd like :)

Many rewriting of existing methods rely on the *this* reference to be
in slot 0. When a method is invoked a new stack frame is created by
the virtual machine where the object reference to the object on which
the method is invoked, i.e. in Java programming language is referred to
as *this*, is placed in the first local variable slot indexed by 0. 

The object initialization method (<init>) is special, because slot 0
contains the uninitialized *this*, as explained in the VM Section
4.9.4 on how code is verified:

"When doing dataflow analysis on instance methods, the verifier
initializes local variable 0 to contain an object of the current
class, or, for instance initialization methods, local variable 0
contains a special type indicating an uninitialized object. After an
appropriate instance initialization method is invoked (from the
current class or the current superclass) on this object, all
occurrences of this special type on the verifier's model of the
operand stack and in the local variable array are replaced by the
current class type. The verifier rejects code that uses the new object
before it has been initialized or that initializes the object more
than once. In addition, it ensures that every normal return of the
method has invoked an instance initialization method either in the
class of this method or in the direct superclass."

Reyelts said he'd seen bytecode which overwrites slot 0, so the "this"
reference that's placed there when the method begins execution is
lost, and thus cannot be relied on!  He proposed a solutions where the
*this* is stored in the first free local variable slot, which seems
valid, BUT.. 

I created the following method that implements his proposal: 

public Initializer(); // javap lies, this is actually called "<init>"
Signature: ()V
0: aload_0            ; load unitialized object from locvar slot 0
1: dup                ; duplicate
2: astore N           ; store the unitialized object in locvar slot 1
3: aconst_null
4: astore_0           ; store special null value in locvar slot 0	
5: invokespecial #x; //Method java/lang/Object."<init>":()V
8: return

which does nothing but load the slot, duplicate it, store it in the
next free slot N and override the 0th slot with null. The object is
eventually initialized, so local var slot N refers a initialized
object that can be relied on to do whatever with.

Now the problem, different verifiers yield different results, that is,
the native verifier by sun accepts this class and sun's vm executes it
perfectly, but JustIce returns this: 

Pass 3b, method number 0 ['public void <init>()']:

Constraint violated in method 'public void <init>()':
Instruction ASTORE constraint violated: Working on an uninitialized
object '<UNINITIALIZED OBJECT OF TYPE 'Initializer'>'.
InstructionHandle:    2: astore_1[76](1)
Execution Frame:
Local Variables:
1: <unknown object>
2: <unknown object>
Slots used: 2 MaxStack: 2.
<UNINITIALIZED OBJECT OF TYPE 'Initializer'> (Size: 1)
<UNINITIALIZED OBJECT OF TYPE 'Initializer'> (Size: 1)
Execution flow:
   0: aload_0   [InstructionContext]
   1: dup       [InstructionContext]
   2: astore_1  [InstructionContext]

I think the source of the problem is the definition of _use_ as in "The
verifier rejects code that uses the new object before it has been
initialized or that initializes the object more than once." 

Anyone who can shed some light on this case?? What is correct? Is this a
bug in JustIce or is Sun not obeying their own spec?

To unsubscribe, e-mail: bcel-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: bcel-user-help@jakarta.apache.org

View raw message