@Nonnull public static RegisterType getWideRegisterType(@Nonnull CharSequence type, boolean firstRegister) { switch (type.charAt(0)) { case 'J': if (firstRegister) { return getRegisterType(LONG_LO, null); } else { return getRegisterType(LONG_HI, null); } case 'D': if (firstRegister) { return getRegisterType(DOUBLE_LO, null); } else { return getRegisterType(DOUBLE_HI, null); } default: throw new ExceptionWithContext("Cannot use this method for narrow register type: %s", type); } }
private void analyzeConstString(@Nonnull AnalyzedInstruction analyzedInstruction) { TypeProto stringClass = classPath.getClass("Ljava/lang/String;"); RegisterType stringType = RegisterType.getRegisterType(RegisterType.REFERENCE, stringClass); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, stringType); }
private void analyzeCheckCast(@Nonnull AnalyzedInstruction analyzedInstruction) { ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; TypeReference reference = (TypeReference)instruction.getReference(); RegisterType castRegisterType = RegisterType.getRegisterType(classPath, reference); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, castRegisterType); }
private void analyzeConstClass(@Nonnull AnalyzedInstruction analyzedInstruction) { TypeProto classClass = classPath.getClass("Ljava/lang/Class;"); RegisterType classType = RegisterType.getRegisterType(RegisterType.REFERENCE, classClass); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, classType); }
@Nonnull public static RegisterType getRegisterType(@Nonnull ClassPath classPath, @Nonnull CharSequence type) { switch (type.charAt(0)) { case 'Z': return BOOLEAN_TYPE; case 'B': return BYTE_TYPE; case 'S': return SHORT_TYPE; case 'C': return CHAR_TYPE; case 'I': return INTEGER_TYPE; case 'F': return FLOAT_TYPE; case 'J': return LONG_LO_TYPE; case 'D': return DOUBLE_LO_TYPE; case 'L': case '[': return getRegisterType(REFERENCE, classPath.getClass(type)); default: throw new AnalysisException("Invalid type: " + type); } }
private void analyzeNewInstance(@Nonnull AnalyzedInstruction analyzedInstruction) { ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; int register = ((OneRegisterInstruction)analyzedInstruction.instruction).getRegisterA(); RegisterType destRegisterType = analyzedInstruction.getPostInstructionRegisterType(register); if (destRegisterType.category != RegisterType.UNKNOWN) { //the post-instruction destination register will only be set if we have already analyzed this instruction //at least once. If this is the case, then the uninit reference has already been propagated to all //successors and nothing else needs to be done. assert destRegisterType.category == RegisterType.UNINIT_REF; return; } TypeReference typeReference = (TypeReference)instruction.getReference(); RegisterType classType = RegisterType.getRegisterType(classPath, typeReference); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.getRegisterType(RegisterType.UNINIT_REF, classType.type)); }
private void analyzeIgetSgetWideObject(@Nonnull AnalyzedInstruction analyzedInstruction) { ReferenceInstruction referenceInstruction = (ReferenceInstruction)analyzedInstruction.instruction; FieldReference fieldReference = (FieldReference)referenceInstruction.getReference(); RegisterType fieldType = RegisterType.getRegisterType(classPath, fieldReference.getType()); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType); }
private void analyzeNewArray(@Nonnull AnalyzedInstruction analyzedInstruction) { ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; TypeReference type = (TypeReference)instruction.getReference(); if (type.getType().charAt(0) != '[') { throw new AnalysisException("new-array used with non-array type"); } RegisterType arrayType = RegisterType.getRegisterType(classPath, type); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, arrayType); }
return RegisterType.getRegisterType(mergedCategory, mergedType);
private void analyzeMoveResult(@Nonnull AnalyzedInstruction analyzedInstruction) { AnalyzedInstruction previousInstruction = null; if (analyzedInstruction.instructionIndex > 0) { previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex-1); } if (previousInstruction == null || !previousInstruction.instruction.getOpcode().setsResult()) { throw new AnalysisException(analyzedInstruction.instruction.getOpcode().name + " must occur after an " + "invoke-*/fill-new-array instruction"); } RegisterType resultRegisterType; ReferenceInstruction invokeInstruction = (ReferenceInstruction)previousInstruction.instruction; Reference reference = invokeInstruction.getReference(); if (reference instanceof MethodReference) { resultRegisterType = RegisterType.getRegisterType(classPath, ((MethodReference)reference).getReturnType()); } else { resultRegisterType = RegisterType.getRegisterType(classPath, (TypeReference)reference); } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, resultRegisterType); }
private void analyzeMoveException(@Nonnull AnalyzedInstruction analyzedInstruction) { int instructionAddress = getInstructionAddress(analyzedInstruction); RegisterType exceptionType = RegisterType.UNKNOWN_TYPE; for (TryBlock<? extends ExceptionHandler> tryBlock: methodImpl.getTryBlocks()) { for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) { if (handler.getHandlerCodeAddress() == instructionAddress) { String type = handler.getExceptionType(); if (type == null) { exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass("Ljava/lang/Throwable;")); } else { exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(type)) .merge(exceptionType); } } } } if (exceptionType.category == RegisterType.UNKNOWN) { throw new AnalysisException("move-exception must be the first instruction in an exception handler block"); } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType); }
private void analyzeInvokeDirectCommon(@Nonnull AnalyzedInstruction analyzedInstruction, int objectRegister) { // This handles the case of invoking a constructor on an uninitialized reference. This propagates the // initialized type for the object register, and also any known aliased registers. // // In some cases, unrelated uninitialized references may not have been propagated past this instruction. This // happens when propagating those types and the type of object register of this instruction isn't known yet. // In this case, we can't determine if the uninitialized reference being propagated in an alias of the object // register, so we don't stop propagation. // // We check for any of these unpropagated uninitialized references here and propagate them. if (analyzedInstruction.isInvokeInit()) { RegisterType uninitRef = analyzedInstruction.getPreInstructionRegisterType(objectRegister); if (uninitRef.category != RegisterType.UNINIT_REF && uninitRef.category != RegisterType.UNINIT_THIS) { assert analyzedInstruction.getSetRegisters().isEmpty(); return; } RegisterType initRef = RegisterType.getRegisterType(RegisterType.REFERENCE, uninitRef.type); for (int register: analyzedInstruction.getSetRegisters()) { RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(register); if (registerType == uninitRef) { setPostRegisterTypeAndPropagateChanges(analyzedInstruction, register, initRef); } else { // This is unrelated uninitialized reference. propagate it as-is setPostRegisterTypeAndPropagateChanges(analyzedInstruction, register, registerType); } } } }
private void analyzeAgetObject(@Nonnull AnalyzedInstruction analyzedInstruction) { ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); if (arrayRegisterType.category != RegisterType.NULL) { if (arrayRegisterType.category != RegisterType.REFERENCE || !(arrayRegisterType.type instanceof ArrayProto)) { throw new AnalysisException("aget-object used with non-array register: %s", arrayRegisterType.toString()); } ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type; String elementType = arrayProto.getImmediateElementType(); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(elementType))); } else { // If the array register is null, we can assume that the destination register was meant to be a reference // type, so we set the destination to NULL. This is the same behavior as dalvik's verifier setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.NULL_TYPE); } }
private void propagateParameterTypes(int parameterStartRegister) { int i=0; for (MethodParameter parameter: method.getParameters()) { if (TypeUtils.isWideType(parameter)) { setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getWideRegisterType(parameter, true)); setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getWideRegisterType(parameter, false)); } else { setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getRegisterType(classPath, parameter)); } } }
RegisterType.getRegisterType(RegisterType.UNINIT_THIS, classPath.getClass(method.getDefiningClass()))); } else { setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister, RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(method.getDefiningClass()))); RegisterType uninit = RegisterType.getRegisterType(RegisterType.UNINIT, null); for (int i=0; i<nonParameterRegisters; i++) { setPostRegisterTypeAndPropagateChanges(startOfMethod, i, uninit);
static boolean canPropagateTypeAfterInstanceOf(AnalyzedInstruction analyzedInstanceOfInstruction, AnalyzedInstruction analyzedIfInstruction, ClassPath classPath) { if (!classPath.isArt()) { return false; } Instruction ifInstruction = analyzedIfInstruction.instruction; if (((Instruction21t)ifInstruction).getRegisterA() == analyzedInstanceOfInstruction.getDestinationRegister()) { Reference reference = ((Instruction22c)analyzedInstanceOfInstruction.getInstruction()).getReference(); RegisterType registerType = RegisterType.getRegisterType(classPath, (TypeReference)reference); try { if (registerType.type != null && !registerType.type.isInterface()) { int objectRegister = ((TwoRegisterInstruction)analyzedInstanceOfInstruction.getInstruction()) .getRegisterB(); RegisterType originalType = analyzedIfInstruction.getPreInstructionRegisterType(objectRegister); return isNotWideningConversion(originalType, registerType); } } catch (UnresolvedClassException ex) { return false; } } return false; }
RegisterType newType = RegisterType.getRegisterType(classPath, (TypeReference)instanceOfInstruction.getReference());
private void analyzeConstClass(@Nonnull AnalyzedInstruction analyzedInstruction) { TypeProto classClass = classPath.getClass("Ljava/lang/Class;"); RegisterType classType = RegisterType.getRegisterType(RegisterType.REFERENCE, classClass); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, classType); }
private void analyzeConstString(@Nonnull AnalyzedInstruction analyzedInstruction) { TypeProto stringClass = classPath.getClass("Ljava/lang/String;"); RegisterType stringType = RegisterType.getRegisterType(RegisterType.REFERENCE, stringClass); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, stringType); }
private void analyzeIgetSgetWideObject(@Nonnull AnalyzedInstruction analyzedInstruction) { ReferenceInstruction referenceInstruction = (ReferenceInstruction)analyzedInstruction.instruction; FieldReference fieldReference = (FieldReference)referenceInstruction.getReference(); RegisterType fieldType = RegisterType.getRegisterType(classPath, fieldReference.getType()); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType); }