@Override public void execute(ExecutionNode node, MethodState mState) { HeapItem lhsItem = mState.readRegister(lhsRegister); HeapItem rhsItem = mState.readRegister(rhsRegister); HeapItem item; if (lhsItem.isUnknown() || rhsItem.isUnknown()) { item = HeapItem.newUnknown("I"); } else { Number lhs = (Number) lhsItem.getValue(); Number rhs = (Number) rhsItem.getValue(); assert lhs.getClass() == rhs.getClass(); assert lhsItem.getType().equals(rhsItem.getType()); int cmp = cmp(lhs, rhs); item = new HeapItem(cmp, "I"); } mState.assignRegister(destRegister, item); }
private void assignCalleeMethodArguments(MethodState callerState, MethodState calleeState) { int parameterRegister = calleeState.getParameterStart(); for (int i = 0; i < parameterRegisters.length; i++) { int callerRegister = parameterRegisters[i]; HeapItem item = callerState.readRegister(callerRegister); String parameterType = analyzedParameterTypes[i]; Object value = item.getValue(); if (item.isPrimitive() && !item.isUnknown()) { boolean hasNullByteValue = item.getType().equals("I") && value instanceof Number && item.asInteger() == 0; if (hasNullByteValue && ClassNameUtils.isObject(parameterType)) { value = null; } else { // The "I" type may actually be "S", "B", "C", etc. Cast to the given parameter type. value = Utils.castToPrimitive(value, parameterType); } } HeapItem parameterItem = new HeapItem(value, parameterType); calleeState.assignParameter(parameterRegister, parameterItem); parameterRegister += Utils.getRegisterSize(parameterType); } }
public static void setRegisterMock(MethodState mState, int register, Object value, String type) { HeapItem item = mock(HeapItem.class); when(item.getValue()).thenReturn(value); if (CommonTypes.INTEGER.equals(type) && value instanceof Number) { when(item.asInteger()).thenReturn((Integer) value); } else if (value instanceof UnknownValue) { when(item.isUnknown()).thenReturn(true); } when(item.getComponentBase()).thenReturn(ClassNameUtils.getComponentBase(type)); when(item.getType()).thenReturn(type); when(mState.readRegister(eq(register))).thenReturn(item); }
@Test public void canCreate2DLocalInstanceArray() throws ClassNotFoundException { int length = 5; initial.setRegisters(0, length, "I"); ExecutionGraph graph = VMTester.execute(CLASS_NAME, "create2DLocalInstanceArray()V", initial); HeapItem consensus = graph.getTerminatingRegisterConsensus(0); assertEquals("[[" + CLASS_NAME, consensus.getType()); assertEquals(length, Array.getLength(consensus.getValue())); Class<?> actualClass = consensus.getValue().getClass(); assertEquals("[[" + CLASS_NAME, actualClass.getName()); }
@Override public void execute(ExecutionNode node, MethodState mState) { HeapItem arrayItem = mState.readRegister(arrayRegister); Object array = arrayItem.getValue(); Object lengthValue = null; if (arrayItem.isUnknown()) { lengthValue = new UnknownValue(); } else if (array == null) { node.clearChildren(); return; } else if (array.getClass().isArray()) { lengthValue = Array.getLength(array); node.clearExceptions(); } else { // Won't pass DEX verifier if it's not an array class. Probably our fault, so error. if (log.isErrorEnabled()) { log.error("Unexpected non-array class: {}, {}", array.getClass(), array); } } mState.assignRegister(destRegister, lengthValue, CommonTypes.INTEGER); }
private void executeArrayClone(MethodState callerMethodState, ExecutionNode node) { int instanceRegister = parameterRegisters[0]; HeapItem arrayItem = callerMethodState.peekRegister(instanceRegister); if (arrayItem.isUnknown()) { callerMethodState.assignResultRegister(new UnknownValue(), arrayItem.getType()); } else if (arrayItem.isNull()) { // This operation would have thrown a null pointer exception, and nothing else. Throwable exception = new NullPointerException(); addException(exception); node.clearChildren(); } else { Method m = null; try { m = Object.class.getDeclaredMethod("clone"); m.setAccessible(true); Object clone = m.invoke(arrayItem.getValue()); callerMethodState.assignResultRegister(clone, arrayItem.getType()); } catch (Exception e) { // TODO: should handle exceptions here and bubble them up e.printStackTrace(); } } }
@Override public void execute(ExecutionNode node, MethodState mState) { HeapItem lhsItem = mState.readRegister(register1); HeapItem rhsItem = compareToZero ? new HeapItem(0, "I") : mState.readRegister(register2); if (lhsItem.isUnknown() || rhsItem.isUnknown()) { return; Object lhs = lhsItem.getValue(); Object rhs = rhsItem.getValue(); int cmp; if (compareToZero) {
public static BuilderInstruction buildConstant(int address, ExecutionGraphManipulator manipulator) { DexBuilder dexBuilder = manipulator.getDexBuilder(); OneRegisterInstruction instruction = (OneRegisterInstruction) manipulator.getInstruction(address); int register = instruction.getRegisterA(); HeapItem item = manipulator.getRegisterConsensus(address, register); Object value = item.getValue(); String type = item.isPrimitive() ? item.getType() : item.getUnboxedValueType(); BuilderInstruction constant = buildConstant(value, type, register, dexBuilder); return constant; }
/*** * {@see #set(String, int, HeapItem)} * * @param heapId * @param register * @param value * @param type */ void set(String heapId, int register, Object value, String type) { set(heapId, register, new HeapItem(value, type)); }
private static void testValueEquals(HeapItem expected, HeapItem consensus) { Object expectedValue = expected.getValue(); Object consensusValue = consensus.getValue(); } else if (expected.isUnknown()) { assertEquals(expected.toString(), consensus.toString()); } else if (expectedValue.getClass().isArray()) { assertEquals(expected.getType(), consensus.getType()); assertEquals(expectedValue.getClass(), consensusValue.getClass()); } else { assertEquals(expectedValue, consensusValue); assertEquals(expected.getType(), consensus.getType());
@Nonnull public boolean isNull() { return getValue() == null; }
private boolean canConstantizeAddress(int address) { if (!manipulator.wasAddressReached(address)) { return false; } Op op = manipulator.getOp(address); if (!constantBuilder.canConstantizeOp(op)) { return false; } OneRegisterInstruction instruction = (OneRegisterInstruction) manipulator.getInstruction(address); if (instruction == null) { return false; } int register = instruction.getRegisterA(); HeapItem consensus = manipulator.getRegisterConsensus(address, register); // Consensus may be null if we have correct syntax without legitimate values (fake code) if (consensus == null || consensus.isUnknown()) { return false; } String type = consensus.isPrimitive() ? consensus.getType() : consensus.getValueType(); if (!constantBuilder.canConstantizeType(type)) { return false; } return true; }
Object value = item.getValue(); if (value instanceof Number) { dimensions[i] = ((Number) value).intValue(); } else { if (!item.isUnknown()) { if (log.isWarnEnabled()) { log.warn("Unexpected value virtual for {}: {}", toString(), item); mState.assignResultRegister(HeapItem.newUnknown("[I")); } else { mState.assignResultRegister(dimensions, "[I");
private static boolean throwsArrayStoreException(HeapItem arrayItem, HeapItem valueItem, ClassManager classManager) { VirtualType valueType = classManager.getVirtualType(valueItem.getType()); VirtualType arrayTypeType = classManager.getVirtualType(arrayItem.getType()); if (arrayTypeType instanceof VirtualClass && arrayTypeType.getName().equals(CommonTypes.OBJECT)) { Exception e = new Exception("APutOp"); (!valueItem.isUnknown() && valueTypeName.equals(CommonTypes.INTEGER) && valueItem.asInteger() == 0 && !ClassNameUtils.isPrimitive(arrayComponentTypeName));
private void executeLocalObjectInit(MethodState callerMethodState) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { int instanceRegister = parameterRegisters[0]; HeapItem instanceItem = callerMethodState.peekRegister(instanceRegister); UninitializedInstance uninitializedInstance = (UninitializedInstance) instanceItem.getValue(); VirtualType instanceType = uninitializedInstance.getType(); // Create a Java class of the true type Class<?> klazz = vm.getClassLoader().loadClass(instanceType.getBinaryName()); Object newInstance = ObjectInstantiator.newInstance(klazz); HeapItem newInstanceItem = new HeapItem(newInstance, instanceType.getName()); callerMethodState.assignRegisterAndUpdateIdentities(instanceRegister, newInstanceItem); }
HeapItem item = context.getMethodState().peekRegister(targetRegister); String signature = method.getSignature(); if (signature.charAt(0) == '[' || (!item.isNull() && item.getValueType().charAt(0) == '[')) { int targetRegister = parameterRegisters[0]; HeapItem item = context.getMethodState().peekRegister(targetRegister); targetMethod = resolveTargetMethod(item.getValue());
private static String getUnknownArrayInnerType(HeapItem array) { String outerType = array.getType(); String result; if (CommonTypes.UNKNOWN.equals(outerType)) { result = CommonTypes.UNKNOWN; } else { result = outerType.replaceFirst("\\[", ""); } return result; }
private boolean allArgumentsKnown(MethodState mState) { for (int parameterRegister = mState.getParameterStart(); parameterRegister < mState.getRegisterCount(); ) { HeapItem item = mState.peekParameter(parameterRegister); if (item.isUnknown()) { return false; } String type = item.getType(); parameterRegister += Utils.getRegisterSize(type); } return true; }