Purifier1 Special Cases

Failed NewObject Creation

Brief Description

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.

Status

Solved. Not a problem any more. Also have a test case in place to for regression testing.

Action Items

None required

Test Cases Exhibiting NewObject Creation

Test Cases Exhibiting NewObject Creation
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

Details

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.

Example

com.markcrocker.purifier.testcases.SpecialCases.newObjectOnStack() provides an example of this issue and is shown below.

Source Code

1  public void newObjectOnStack() {
2    long len = 17L;
3    StringBuffer b = null;
4    b = new StringBuffer(len >= 0 ? (int)len : 1000);
5:  }

Bytecode

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)
		}
	)
)

Data Flow Analysis

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.

Solutions

Code in the INVOKESPECIAL case of updateFrame now handles this case correctly.

Back to Developer's Guide   Purifier1 Home Page

Valid HTML 4.01!