Skip to content

Commit

Permalink
#262 For-looping a Map does not work (#263)
Browse files Browse the repository at this point in the history
  • Loading branch information
mirkosertic authored Nov 4, 2019
1 parent 23c374c commit eb6d2ed
Show file tree
Hide file tree
Showing 14 changed files with 240 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public class BytecodeLinkedClass extends Node<Node, EdgeType> {
private Boolean callback;
private Boolean event;
private Set<BytecodeVirtualMethodIdentifier> implementedIdentifiersCache;
private BytecodeLinkedClass superClass;
private final BytecodeLinkedClass superClass;

public BytecodeLinkedClass(final BytecodeLinkedClass aSuperclass, final int aUniqueId, final BytecodeLinkerContext aLinkerContext, final BytecodeObjectTypeRef aClassName, final BytecodeClass aBytecodeClass) {
uniqueId = aUniqueId;
Expand Down Expand Up @@ -278,13 +278,13 @@ public boolean resolveVirtualMethod(final String aMethodName, final BytecodeMeth
return true;
}

boolean foundByInterface = false;
boolean somethingFound = false;

// Try to find default methods and also mark usage
// of interface methods
for (final BytecodeLinkedClass theImplementedInterface : getImplementingTypes(false, false)) {
if (theImplementedInterface.resolveVirtualMethod(aMethodName, aSignature)) {
foundByInterface = true;
somethingFound = true;
}
}

Expand All @@ -301,14 +301,14 @@ public boolean resolveVirtualMethod(final String aMethodName, final BytecodeMeth
return true;
}

if (!foundByInterface) {
final BytecodeLinkedClass theSuperClass = getSuperClass();
if (theSuperClass != null) {
return theSuperClass.resolveVirtualMethod(aMethodName, aSignature);
final BytecodeLinkedClass theSuperClass = getSuperClass();
if (theSuperClass != null) {
if (theSuperClass.resolveVirtualMethod(aMethodName, aSignature)) {
return true;
}
}

return foundByInterface;
return somethingFound;
}

public boolean resolveConstructorInvocation(final BytecodeMethodSignature aSignature) {
Expand Down Expand Up @@ -465,7 +465,9 @@ public void resolveInheritedOverriddenMethods() {
final BytecodeResolvedMethods theResolvedMethods = theClass.resolvedMethods();
final List<BytecodeMethod> theInstanceMethods = theResolvedMethods.stream().filter(t -> !t.getValue().getAccessFlags().isPrivate() && !t.getValue().getAccessFlags().isStatic()).map(BytecodeResolvedMethods.MethodEntry::getValue).collect(Collectors.toList());
for (final BytecodeMethod theMethod : theInstanceMethods) {
BytecodeLinkedClass.this.resolveVirtualMethod(theMethod.getName().stringValue(), theMethod.getSignature());
if (!BytecodeLinkedClass.this.resolveVirtualMethod(theMethod.getName().stringValue(), theMethod.getSignature())) {
throw new IllegalStateException("Cannot find method " + theMethod.getName() + " with signature " + theMethod.getSignature() + " in class " + theClass.getClassName().name());
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,21 @@
*/
package de.mirkosertic.bytecoder.intrinsics;

import de.mirkosertic.bytecoder.core.*;
import de.mirkosertic.bytecoder.ssa.*;

import java.util.ArrayList;
import java.util.List;

import de.mirkosertic.bytecoder.core.BytecodeInstructionGETSTATIC;
import de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKESPECIAL;
import de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKESTATIC;
import de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKEVIRTUAL;
import de.mirkosertic.bytecoder.core.BytecodeInstructionPUTSTATIC;
import de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef;
import de.mirkosertic.bytecoder.ssa.ParsingHelper;
import de.mirkosertic.bytecoder.ssa.Program;
import de.mirkosertic.bytecoder.ssa.RegionNode;
import de.mirkosertic.bytecoder.ssa.Value;
import de.mirkosertic.bytecoder.ssa.Variable;

public class Intrinsics {

private final List<Intrinsic> intrinsics;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,27 @@
*/
package de.mirkosertic.bytecoder.intrinsics;

import de.mirkosertic.bytecoder.core.*;
import de.mirkosertic.bytecoder.ssa.*;

import java.util.List;

import de.mirkosertic.bytecoder.core.BytecodeInstructionGETSTATIC;
import de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKESPECIAL;
import de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKESTATIC;
import de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKEVIRTUAL;
import de.mirkosertic.bytecoder.core.BytecodeInstructionPUTSTATIC;
import de.mirkosertic.bytecoder.core.BytecodeLinkedClass;
import de.mirkosertic.bytecoder.core.BytecodeMethodSignature;
import de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef;
import de.mirkosertic.bytecoder.ssa.IntegerValue;
import de.mirkosertic.bytecoder.ssa.NewInstanceFromDefaultConstructorExpression;
import de.mirkosertic.bytecoder.ssa.ParsingHelper;
import de.mirkosertic.bytecoder.ssa.Program;
import de.mirkosertic.bytecoder.ssa.RegionNode;
import de.mirkosertic.bytecoder.ssa.StringValue;
import de.mirkosertic.bytecoder.ssa.TypeOfExpression;
import de.mirkosertic.bytecoder.ssa.TypeRef;
import de.mirkosertic.bytecoder.ssa.Value;
import de.mirkosertic.bytecoder.ssa.Variable;

public class JavaLangClassIntrinsic extends Intrinsic {

@Override
Expand Down Expand Up @@ -52,6 +68,55 @@ public boolean intrinsify(final Program aProgram, final BytecodeInstructionINVOK
return false;
}

@Override
public boolean intrinsify(final Program aProgram, final BytecodeInstructionINVOKESTATIC aInstruction,
final String aMethodName, final List<Value> aArguments, final BytecodeObjectTypeRef aTargetClass,
final RegionNode aTargetBlock, final ParsingHelper aHelper) {
final BytecodeMethodSignature theSignature = aInstruction.getMethodReference().getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature();
final BytecodeObjectTypeRef theCalledClass = BytecodeObjectTypeRef.fromUtf8Constant(aInstruction.getMethodReference().getClassIndex().getClassConstant().getConstant());

if (theCalledClass.name().equals(Class.class.getName())) {
if ("forName".equals(aMethodName)) {
for (int i=0;i<theSignature.getArguments().length;i++) {
if (theSignature.getArguments()[i].equals(BytecodeObjectTypeRef.fromRuntimeClass(String.class))) {
final Value theArgumentValue = aArguments.get(i);
checkblock:
{
if (theArgumentValue instanceof StringValue) {
// We found something directly
final String theClassName = ((StringValue) theArgumentValue).getStringValue();
if (aProgram.getLinkerContext() != null) {
aProgram.getLinkerContext().getLogger().warn("Class {} is used by reflection!", theClassName);
}

break checkblock;
} else {
final List<Value> theIncomingFlows = theArgumentValue.incomingDataFlows();
for (final Value theValue : theIncomingFlows) {
if (theValue instanceof StringValue) {
// We found something as a variable
final String theClassName = ((StringValue) theValue).getStringValue();
if (aProgram.getLinkerContext() != null) {
aProgram.getLinkerContext().getLogger().warn("Class {} is used by reflection!", theClassName);
}

break checkblock;
}
}
}

if (aProgram.getLinkerContext() != null) {
aProgram.getLinkerContext().getLogger().warn("Class.forName usage detected with unknown class name");
}
}
}
}
}
}

return super.intrinsify(aProgram, aInstruction, aMethodName, aArguments, aTargetClass, aTargetBlock, aHelper);
}

@Override
public boolean intrinsify(final Program aProgram, final BytecodeInstructionINVOKEVIRTUAL aInstruction, final String aMethodName, final List<Value> aArguments, final Value aTarget, final RegionNode aTargetBlock, final ParsingHelper aHelper) {
final BytecodeMethodSignature theSignature = aInstruction.getMethodReference().getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ public Program generateFrom(final BytecodeClass aOwningClass, final BytecodeMeth
BytecodeLocalVariableTableAttributeInfo theDebugInfos = null;
if (theCode != null) {
theDebugInfos = theCode.attributeByType(BytecodeLocalVariableTableAttributeInfo.class);
theProgram = new Program(debugInformationFor(aOwningClass, theCode));
theProgram = new Program(debugInformationFor(aOwningClass, theCode), linkerContext);
} else {
theProgram = new Program(DebugInformation.empty());
theProgram = new Program(DebugInformation.empty(), linkerContext);
}

int theCurrentIndex = 0;
Expand Down Expand Up @@ -1143,7 +1143,7 @@ theTarget, new NewObjectAndConstructExpression(
final BytecodeMethodHandleConstant theMethodRef = theBootstrapMethod.getMethodRef();
final BytecodeMethodRefConstant theBootstrapMethodToInvoke = (BytecodeMethodRefConstant) theMethodRef.getReferenceIndex().getConstant();

final Program theProgram = new Program(DebugInformation.empty());
final Program theProgram = new Program(DebugInformation.empty(), linkerContext);
final RegionNode theInitNode = theProgram.getControlFlowGraph().createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);

// Don't forget to calculate reachability and dominators here
Expand Down
9 changes: 8 additions & 1 deletion core/src/main/java/de/mirkosertic/bytecoder/ssa/Program.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package de.mirkosertic.bytecoder.ssa;

import de.mirkosertic.bytecoder.core.BytecodeLinkerContext;
import de.mirkosertic.bytecoder.core.BytecodeProgram;

import java.util.ArrayList;
Expand All @@ -28,13 +29,19 @@ public class Program {
private final List<Variable> arguments;
private BytecodeProgram.FlowInformation flowInformation;
private long analysisTime;
private final BytecodeLinkerContext linkerContext;

public Program(final DebugInformation aDebugInformation) {
public Program(final DebugInformation aDebugInformation, final BytecodeLinkerContext aLinkerContext) {
controlFlowGraph = new ControlFlowGraph(this);
variables = new ArrayList<>();
arguments = new ArrayList<>();
debugInformation = aDebugInformation;
analysisTime = 0;
linkerContext = aLinkerContext;
}

public BytecodeLinkerContext getLinkerContext() {
return linkerContext;
}

public DebugInformation getDebugInformation() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.junit.runner.RunWith;

import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
Expand All @@ -31,16 +32,27 @@ public class HashMapTest {

@Test
public void containsGetPutUpdate() throws Exception {
HashMap<Integer, Integer> theMap = new HashMap<>();
final HashMap<Integer, Integer> theMap = new HashMap<>();
assertFalse(theMap.containsKey(new Integer(10)));
assertNull(theMap.get(new Integer(1024)));
Integer theOldValue = theMap.put(new Integer(255), new Integer(3000));
final Integer theOldValue = theMap.put(new Integer(255), new Integer(3000));
assertNull(theOldValue);
assertTrue(theMap.containsKey(new Integer(255)));
assertEquals(new Integer(3000), theMap.get(new Integer(255)));

Integer theOldValue2 = theMap.put(new Integer(255), new Integer(4000));
final Integer theOldValue2 = theMap.put(new Integer(255), new Integer(4000));
assertEquals(new Integer(3000), theOldValue2);
assertEquals(new Integer(4000), theMap.get(new Integer(255)));
}

@Test
public void testKeySetIterator() {
final Map<Integer, String> map = new HashMap<>();
map.put(1, "1");
map.put(2, "2");
map.put(3, "3");
for (final Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class GraphDFSOrderTest {

@Test
public void testSimpleNode() {
final Program p = new Program(DebugInformation.empty());
final Program p = new Program(DebugInformation.empty(), null);
final ControlFlowGraph graph = new ControlFlowGraph(p);
final RegionNode startNode = graph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
graph.calculateReachabilityAndMarkBackEdges();
Expand All @@ -52,7 +52,7 @@ public void testSimpleNode() {

@Test
public void testSimpleFlow() {
final Program p = new Program(DebugInformation.empty());
final Program p = new Program(DebugInformation.empty(), null);
final ControlFlowGraph graph = new ControlFlowGraph(p);
final RegionNode startNode = graph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
final RegionNode node2 = graph.createAt(new BytecodeOpcodeAddress(20), RegionNode.BlockType.NORMAL);
Expand All @@ -76,7 +76,7 @@ public void testSimpleFlow() {

@Test
public void testJoiningFlow() {
final Program p = new Program(DebugInformation.empty());
final Program p = new Program(DebugInformation.empty(), null);
final ControlFlowGraph graph = new ControlFlowGraph(p);
final RegionNode startNode = graph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
final RegionNode node2 = graph.createAt(new BytecodeOpcodeAddress(20), RegionNode.BlockType.NORMAL);
Expand Down Expand Up @@ -104,7 +104,7 @@ public void testJoiningFlow() {

@Test
public void testJoiningFlowWithLoop() {
final Program p = new Program(DebugInformation.empty());
final Program p = new Program(DebugInformation.empty(), null);
final ControlFlowGraph graph = new ControlFlowGraph(p);
final RegionNode startNode = graph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
final RegionNode node2 = graph.createAt(new BytecodeOpcodeAddress(20), RegionNode.BlockType.NORMAL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class ControlFlowGraphSCCTest {

@Test
public void testSimpleNode() {
final Program p = new Program(DebugInformation.empty());
final Program p = new Program(DebugInformation.empty(), null);
final ControlFlowGraph graph = new ControlFlowGraph(p);
final RegionNode startNode = graph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
graph.calculateReachabilityAndMarkBackEdges();
Expand All @@ -45,7 +45,7 @@ public void testSimpleNode() {

@Test
public void testSimpleFlow() {
final Program p = new Program(DebugInformation.empty());
final Program p = new Program(DebugInformation.empty(), null);
final ControlFlowGraph graph = new ControlFlowGraph(p);
final RegionNode startNode = graph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
final RegionNode node2 = graph.createAt(new BytecodeOpcodeAddress(20), RegionNode.BlockType.NORMAL);
Expand All @@ -67,7 +67,7 @@ public void testSimpleFlow() {

@Test
public void testJoiningFlow() {
final Program p = new Program(DebugInformation.empty());
final Program p = new Program(DebugInformation.empty(), null);
final ControlFlowGraph graph = new ControlFlowGraph(p);
final RegionNode startNode = graph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
final RegionNode node2 = graph.createAt(new BytecodeOpcodeAddress(20), RegionNode.BlockType.NORMAL);
Expand Down Expand Up @@ -95,7 +95,7 @@ public void testJoiningFlow() {

@Test
public void testLoop1() {
final Program p = new Program(DebugInformation.empty());
final Program p = new Program(DebugInformation.empty(), null);
final ControlFlowGraph graph = new ControlFlowGraph(p);
final RegionNode startNode = graph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
final RegionNode node2 = graph.createAt(new BytecodeOpcodeAddress(20), RegionNode.BlockType.NORMAL);
Expand All @@ -116,7 +116,7 @@ public void testLoop1() {

@Test
public void testLoop2() {
final Program p = new Program(DebugInformation.empty());
final Program p = new Program(DebugInformation.empty(), null);
final ControlFlowGraph graph = new ControlFlowGraph(p);
final RegionNode startNode = graph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
final RegionNode node2 = graph.createAt(new BytecodeOpcodeAddress(20), RegionNode.BlockType.NORMAL);
Expand All @@ -138,7 +138,7 @@ public void testLoop2() {

@Test
public void testLoop3Joining() {
final Program p = new Program(DebugInformation.empty());
final Program p = new Program(DebugInformation.empty(), null);
final ControlFlowGraph graph = new ControlFlowGraph(p);
final RegionNode startNode = graph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
final RegionNode node1 = graph.createAt(new BytecodeOpcodeAddress(10), RegionNode.BlockType.NORMAL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class DominanceTest {

@Test
public void testDirectFlow() {
final Program theProgram = new Program(DebugInformation.empty());
final Program theProgram = new Program(DebugInformation.empty(), null);
final ControlFlowGraph theGraph = new ControlFlowGraph(theProgram);

final RegionNode theNode1 = theGraph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
Expand Down Expand Up @@ -66,7 +66,7 @@ public void testDirectFlow() {

@Test
public void testEndlessLoop() {
final Program theProgram = new Program(DebugInformation.empty());
final Program theProgram = new Program(DebugInformation.empty(), null);
final ControlFlowGraph theGraph = new ControlFlowGraph(theProgram);

final RegionNode theNode1 = theGraph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
Expand All @@ -85,7 +85,7 @@ public void testEndlessLoop() {

@Test
public void testIFElseWithJoining() {
final Program theProgram = new Program(DebugInformation.empty());
final Program theProgram = new Program(DebugInformation.empty(), null);
final ControlFlowGraph theGraph = new ControlFlowGraph(theProgram);

final RegionNode theNode1 = theGraph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
Expand Down
Loading

0 comments on commit eb6d2ed

Please sign in to comment.