A case was found where ITEM_NewObject entries are not being created correctly because the INVOKESPECIAL handler in StackMapGen.updateFrame method was updating a StackMapType that it should have been replacing.
Solved. Not a problem any more. Also have a test case in place to for regression testing.
None required
Package | Class | Method | Method # | Effect | Source |
---|---|---|---|---|---|
example.http | HttpView | run() | 6 | Would fail without fix | Wireless Toolkit 1.04 |
com.markcrocker.purifier.testcases | SpecialCases | newObjectOnStack() | 11 | Purifier1 |
When a StackMap includes NewObjects on the operand stack and an invokespecial that initializes those items is encountered, the Purifier1 has to be careful to update the type of any resulting StackMapTypes, but avoid disturbing any references to those types that might be in a stored frame.
com.markcrocker.purifier.testcases.SpecialCases.newObjectOnStack() provides an example of this issue and is shown below.
1 public void newObjectOnStack() { 2 long len = 17L; 3 StringBuffer b = null; 4 b = new StringBuffer(len >= 0 ? (int)len : 1000); 5: }
The following byte code is from the compiled and preverified class file created from the source in the previous section. The StackMap has been reformatted for readability.
public void newObjectOnStack() Code(max_stack = 6, max_locals = 4, code_length = 29) 0: ldc2_w 17 (37) 3: lstore_1 4: aconst_null 5: astore_3 6: new <java.lang.StringBuffer> (32) 9: dup 10: lload_1 11: lconst_0 12: lcmp 13: iflt #21 16: lload_1 17: l2i 18: goto #24 21: sipush 1000 24: invokespecial java.lang.StringBuffer.<init> (I)V (39) 27: astore_3 28: return Attribute(s) = StackMap( ( offset = 21, locals = { (type=Object, (40)class=com.markcrocker.purifier.testcases.SpecialCases), (type=Long), (type=Null) }, stack items = { (type=NewObject, offset=6), (type=NewObject, offset=6) } ) ( offset = 24, locals = { (type=Object, (40)class=com.markcrocker.purifier.testcases.SpecialCases), (type=Long), (type=Null) }, stack items = { (type=NewObject, offset=6), (type=NewObject, offset=6), (type=Integer) } ) )
The new instruction at offset 6 puts an ITEM_NewObject on the stack as it should and the following dup instruction adds another.
When the Purifier1's DFA gets to the invokespecial instruction at offset 24, The Purifier1's type resolution code for invokespecial recognizes that the ITEM_NewObject is supposed to become an ITEM_Object with an index pointing to a StringBuffer Classref. However, there are other references to the StackMapType that the original NewObject was held in, such as in the frame stored in the BranchStack by the iflt instruction at offset 13. When the invokespecial converts the ITEM_NewObject into an ITEM_Object pointing to StringBuffer, it must create a new instance of StackMapType to store on the Stack. If, instead of creating a new instance of StackMapType, it were to simply modify the existing instance, then the frame that is popped off of the BranchStack when investigating the branch target starting at offset 17 will have StringBuffer entries in the OperandStack, which would be an error.
Code in the INVOKESPECIAL case of updateFrame now handles this case correctly.