@Override protected void execute(VirtualMachine vm, Op op, MethodState mState) { // This is a virtual method, so register 0 contains a reference to an instance of Ljava/io/PrintStream; // Register 1 should have the string to print. HeapItem item = mState.peekParameter(1); Object value = item.getValue(); String valueStr = (String) value; System.out.println(valueStr); }
@SuppressWarnings({ "unchecked" }) private Object invokeEnumInit(MethodState mState, String name, ClassLoader classLoader) throws ClassNotFoundException { /* * Enums can't be instantiated by calling newInstance() on the constructor, * even with setAccessible(true). It fails with InstantiationException. * http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9 */ HeapItem instance = mState.peekParameter(mState.getParameterStart()); String enumType = ClassNameUtils.internalToSource(instance.getType()); Class<? extends Enum> enumClass = (Class<? extends Enum>) classLoader.loadClass(enumType); try { return Enum.valueOf(enumClass, name); } catch (IllegalArgumentException e) { enumAnalyzer.analyze(enumClass); name = enumAnalyzer.getObfuscatedName(name); return Enum.valueOf(enumClass, name); } }
private static HeapItem getMutableParameterConsensus(int[] addresses, ExecutionGraph graph, int parameterRegister) { ExecutionNode firstNode = graph.getNodePile(addresses[0]).get(0); HeapItem item = firstNode.getContext().getMethodState().peekParameter(parameterRegister); for (int address : addresses) { List<ExecutionNode> nodes = graph.getNodePile(address); for (ExecutionNode node : nodes) { HeapItem otherItem = node.getContext().getMethodState().peekParameter(parameterRegister); if (item.getValue() != otherItem.getValue()) { log.trace("No consensus value for r{}. Returning unknown.", parameterRegister); return HeapItem.newUnknown(item.getType()); } } } return item; }
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; }
@Override public void execute(VirtualMachine vm, Op op, ExecutionContext context) { MethodState mState = context.getMethodState(); String argumentType = mState.peekParameter(0).getType(); VirtualType virtualType = vm.getClassManager().getVirtualType(argumentType); try { Class<?> value = vm.getClassLoader().loadClass(virtualType.getBinaryName()); mState.assignReturnRegister(value, RETURN_TYPE); } catch (ClassNotFoundException e) { throw new RuntimeException("Class not found: " + argumentType, e); } }
@Override public void execute(VirtualMachine vm, Op op, ExecutionContext context) { MethodState mState = context.getMethodState(); HeapItem fieldItem = mState.peekParameter(0); HeapItem instanceItem = mState.peekParameter(1); Field field = (Field) fieldItem.getValue(); int accessFlags = field.getModifiers(); String fieldClassName = ClassNameUtils.toInternal(field.getDeclaringClass()); if (!field.isAccessible()) { VirtualType callingClass = context.getCallerContext().getMethod().getDefiningClass(); ClassManager classManager = vm.getClassManager(); VirtualClass fieldClass = classManager.getVirtualClass(fieldClassName); boolean hasAccess = checkAccess(callingClass, fieldClass, accessFlags, op, vm.getExceptionFactory()); if (!hasAccess) { return; } } Object instance = instanceItem.getValue(); HeapItem getItem = get(field, instance, fieldClassName, accessFlags, context, vm, op); mState.assignReturnRegister(getItem); }
@Test public void unsafeClassNameReturnsClassAndHasNoSideEffects() throws Exception { String className = "Lunsafe/Class;"; SideEffect.Level level = SideEffect.Level.NONE; VirtualClass virtualClass = setupClass(className, false, level); String binaryClassName = "unsafe.Class"; doReturn(OBJECT_CLASS).when(classLoader).loadClass(binaryClassName); HeapItem item = new HeapItem(binaryClassName, CommonTypes.STRING); when(mState.peekParameter(0)).thenReturn(item); method.execute(vm, op, context); verify(mState, times(1)).assignReturnRegister(eq(OBJECT_CLASS), eq(CommonTypes.CLASS)); verify(context, times(1)).staticallyInitializeClassIfNecessary(virtualClass); assertEquals(level, method.getSideEffectLevel()); }
@Test public void existentSafeClassNameReturnsRealClassAndHasNoSideEffects() throws Exception { String className = "Ljava/lang/String;"; // genuinely safe to load SideEffect.Level level = SideEffect.Level.NONE; setupClass(className, true, level); String binaryClassName = "java.lang.String"; HeapItem item = new HeapItem(binaryClassName, CommonTypes.STRING); when(mState.peekParameter(0)).thenReturn(item); method.execute(vm, op, context); verify(mState, times(1)).assignReturnRegister(eq(STRING_CLASS), eq(CommonTypes.CLASS)); assertEquals(level, method.getSideEffectLevel()); }
@Test public void strongSideEffectsClassNameReturnsClassAndHasStrongSideEffects() throws Exception { String className = "Lstrong/Class;"; SideEffect.Level level = SideEffect.Level.STRONG; VirtualClass virtualClass = setupClass(className, false, level); String binaryClassName = "strong.Class"; doReturn(OBJECT_CLASS).when(classLoader).loadClass(binaryClassName); HeapItem item = new HeapItem(binaryClassName, CommonTypes.STRING); when(mState.peekParameter(0)).thenReturn(item); method.execute(vm, op, context); verify(mState, times(1)).assignReturnRegister(eq(OBJECT_CLASS), eq(CommonTypes.CLASS)); verify(context, times(1)).staticallyInitializeClassIfNecessary(virtualClass); assertEquals(level, method.getSideEffectLevel()); }
private InvocationArguments getArguments(MethodState mState) throws ClassNotFoundException { int paramOffset = 0; if (!method.isStatic()) { // First parameter in method state for non-static methods is the virtual instance for that method // It's not needed to reflect the actual JVM method paramOffset = 1; } List<String> parameterTypeNames = method.getParameterTypeNames(); int size = parameterTypeNames.size() - paramOffset; Object[] args = new Object[size]; Class<?>[] parameterTypes = new Class<?>[size]; int registerCount = mState.getRegisterCount(); for (int i = paramOffset; i < registerCount; ) { HeapItem argItem = mState.peekParameter(i); args[i - paramOffset] = argItem.getValue(); String parameterTypeName = parameterTypeNames.get(i); Class<?> parameterType; if (argItem.isPrimitive()) { parameterType = ClassNameUtils.getPrimitiveClass(parameterTypeName); } else { // Shouldn't need a VM class loader since these are all safe to reflect on the JVM // Also, some classes are arrays and loadClass only works for non-array, non-primitive types parameterType = Class.forName(ClassNameUtils.internalToBinary(parameterTypeName)); } parameterTypes[i - paramOffset] = parameterType; // Long tried every diet but is still fat and takes 2 registers. Could be thyroid. i += Utils.getRegisterSize(parameterTypeName); } return new InvocationArguments(args, parameterTypes); }
@Test public void unknownClassNameThrowsExceptionAndAssignsNothing() throws Exception { String className = "Lunknown/Class;"; SideEffect.Level level = SideEffect.Level.NONE; VirtualClass virtualClass = setupClass(className, false, level); String binaryName = "unknown.Class"; HeapItem item = new HeapItem(binaryName, CommonTypes.STRING); when(mState.peekParameter(0)).thenReturn(item); when(classManager.getVirtualClass(className)).thenThrow(new RuntimeException()); Throwable exception = mock(Throwable.class); when(exceptionFactory.build(eq(op), eq(ClassNotFoundException.class), eq(binaryName))).thenReturn(exception); method.execute(vm, op, context); assertEquals(1, method.getExceptions().size()); Throwable actualException = method.getExceptions().iterator().next(); assertEquals(exception, actualException); verify(mState, times(0)).assignReturnRegister(any(UnknownValue.class), eq(CommonTypes.CLASS)); assertEquals(SideEffect.Level.NONE, method.getSideEffectLevel()); }
@Override public void execute(VirtualMachine vm, Op op, ExecutionContext context) { MethodState mState = context.getMethodState(); String binaryClassName = (String) mState.peekParameter(0).getValue(); String className = ClassNameUtils.binaryToInternal(binaryClassName);
HeapItem newInstanceItem = calleeContext.getMethodState().peekParameter(0); if (originalInstanceItem.getValue() != newInstanceItem.getValue()) {