下面列出了org.objectweb.asm.Type#equals ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private static void findTargets(ASMData target, Map<Field, Class<?>> classTargetToSource, Map<Field, Class<?>> fieldTargetToSource) {
final String targetClassName = target.getClassName();
final String targetObject = target.getObjectName();
final Type sourceClassName = (Type)target.getAnnotationInfo().get("value");
try {
final Class<?> targetClass = Class.forName(targetClassName);
final Class<?> sourceClass;
if (sourceClassName == null || sourceClassName.equals(USE_DECLARING_TYPE_MARKER))
sourceClass = targetClass;
else
sourceClass = Class.forName(sourceClassName.getClassName());
if (targetClassName.equals(targetObject))
addClassFields(classTargetToSource, targetClass, sourceClass);
else
addField(fieldTargetToSource, targetClass, targetObject, sourceClass);
} catch (Exception e) {
Log.warn(e, "Failed to fill type variable holder at %s:%s", targetClassName, targetObject);
}
}
public Type invokeStatic(Type ownerType, String methodName, Type... argumentTypes) {
Class<?>[] arguments = Stream.of(argumentTypes).map(this::toJavaType).toArray(Class[]::new);
Method foundMethod;
if (ownerType.equals(getSelfType())) {
foundMethod = findMethod(
getStaticMethods().keySet().stream(),
methodName,
arguments);
} else {
foundMethod = findMethod(
Arrays.stream(toJavaType(ownerType).getMethods())
.filter(m -> isStatic(m.getModifiers()))
.map(Method::getMethod),
methodName,
arguments);
}
g.invokeStatic(ownerType, foundMethod);
return foundMethod.getReturnType();
}
public static AbstractInsnNode loadNumericValue(Number n, Type requiredType) {
if (n instanceof Double || n instanceof Float) {
if (requiredType.equals(Type.LONG_TYPE)) return ASMUtils.loadLong(n.longValue());
else if (requiredType.equals(Type.INT_TYPE)) return ASMUtils.loadInt(n.intValue());
else if (requiredType.equals(Type.DOUBLE_TYPE)) return ASMUtils.loadDouble(n.doubleValue());
else {
throw new UnsupportedOperationException("Unsupported required type: " + requiredType);
}
}
else {
if (requiredType.equals(Type.LONG_TYPE)) return ASMUtils.loadLong(n.longValue());
else if (requiredType.equals(Type.INT_TYPE)) return ASMUtils.loadInt(n.intValue());
else if (requiredType.equals(Type.DOUBLE_TYPE)) return ASMUtils.loadDouble(n.doubleValue());
else {
throw new UnsupportedOperationException("Unsupported required type: " + requiredType);
}
}
}
/**
* Returns whether the class corresponding to the first argument is either the same as, or is a
* superclass or superinterface of the class corresponding to the second argument. The default
* implementation of this method loads the classes and uses the reflection API to return its
* result (unless the result can be computed from the class being verified, and the types of its
* super classes and implemented interfaces).
*
* @param type1 a type.
* @param type2 another type.
* @return whether the class corresponding to 'type1' is either the same as, or is a superclass or
* superinterface of the class corresponding to 'type2'.
*/
protected boolean isAssignableFrom(final Type type1, final Type type2) {
if (type1.equals(type2)) {
return true;
}
if (currentClass != null && currentClass.equals(type1)) {
if (getSuperClass(type2) == null) {
return false;
} else {
if (isInterface) {
return type2.getSort() == Type.OBJECT || type2.getSort() == Type.ARRAY;
}
return isAssignableFrom(type1, getSuperClass(type2));
}
}
if (currentClass != null && currentClass.equals(type2)) {
if (isAssignableFrom(type1, currentSuperClass)) {
return true;
}
if (currentClassInterfaces != null) {
for (Type currentClassInterface : currentClassInterfaces) {
if (isAssignableFrom(type1, currentClassInterface)) {
return true;
}
}
}
return false;
}
return getClass(type1).isAssignableFrom(getClass(type2));
}
/** Confirm that this method has the given return and param types or throw */
public void assertType(Type returnType, Type... paramTypes) {
Type actualReturnType = Type.getReturnType(methodSig);
if (!returnType.equals(actualReturnType))
throw new IllegalArgumentException("Invalid return type, expected " + returnType + ", got " + actualReturnType);
Type[] actualParamTypes = Type.getArgumentTypes(methodSig);
if (!Arrays.equals(paramTypes, actualParamTypes))
throw new IllegalArgumentException("Invalid arg types, expected " + Arrays.toString(paramTypes) +
", got " + Arrays.toString(actualParamTypes));
}
@Override
protected BasicValue getElementValue(final BasicValue objectArrayValue) throws AnalyzerException {
Type arrayType = objectArrayValue.getType();
if (arrayType != null) {
if (arrayType.getSort() == Type.ARRAY) {
return newValue(Type.getType(arrayType.getDescriptor().substring(1)));
} else if (arrayType.equals(NULL_TYPE)) {
return objectArrayValue;
}
}
throw new AssertionError();
}
@Override
protected BasicValue getElementValue(final BasicValue objectArrayValue) throws AnalyzerException {
Type arrayType = objectArrayValue.getType();
if (arrayType != null) {
if (arrayType.getSort() == Type.ARRAY) {
return newValue(Type.getType(arrayType.getDescriptor().substring(1)));
} else if (arrayType.equals(NULL_TYPE)) {
return objectArrayValue;
}
}
throw new AssertionError();
}
/**
* Returns whether the class corresponding to the first argument is either the same as, or is a
* superclass or superinterface of the class corresponding to the second argument. The default
* implementation of this method loads the classes and uses the reflection API to return its
* result (unless the result can be computed from the class being verified, and the types of its
* super classes and implemented interfaces).
*
* @param type1 a type.
* @param type2 another type.
* @return whether the class corresponding to 'type1' is either the same as, or is a superclass or
* superinterface of the class corresponding to 'type2'.
*/
protected boolean isAssignableFrom(final Type type1, final Type type2) {
if (type1.equals(type2)) {
return true;
}
if (currentClass != null && currentClass.equals(type1)) {
if (getSuperClass(type2) == null) {
return false;
} else {
if (isInterface) {
return type2.getSort() == Type.OBJECT || type2.getSort() == Type.ARRAY;
}
return isAssignableFrom(type1, getSuperClass(type2));
}
}
if (currentClass != null && currentClass.equals(type2)) {
if (isAssignableFrom(type1, currentSuperClass)) {
return true;
}
if (currentClassInterfaces != null) {
for (Type currentClassInterface : currentClassInterfaces) {
if (isAssignableFrom(type1, currentClassInterface)) {
return true;
}
}
}
return false;
}
return getClass(type1).isAssignableFrom(getClass(type2));
}
/**
* Generates unboxing bytecode for the passed type. An {@link Object} is expected to be on the
* stack when these bytecodes are inserted.
*
* ASM takes a short cut when dealing with short/byte types and convert them into int rather
* than short/byte types. This is not an issue on the jvm nor Android's ART but it is an issue
* on Dalvik.
*
* @param mv the {@link GeneratorAdapter} generating a method implementation.
* @param type the expected un-boxed type.
*/
public static void unbox(GeneratorAdapter mv, Type type) {
if (type.equals(Type.SHORT_TYPE)) {
mv.checkCast(NUMBER_TYPE);
mv.invokeVirtual(NUMBER_TYPE, SHORT_VALUE);
} else if (type.equals(Type.BYTE_TYPE)) {
mv.checkCast(NUMBER_TYPE);
mv.invokeVirtual(NUMBER_TYPE, BYTE_VALUE);
} else {
mv.unbox(type);
}
}
/**
* Called inside {@link #validateParams} but can also be used directly. This
* method checks whether the supplied type is compatible with the specified
* handler argument, apply coercion logic where necessary.
*
* @param index Handler argument index, pass in a negative value (by
* convention -1) to specify handler return type
* @param toType Desired type based on the injector contract
* @param description human-readable description of the handler method, used
* in raised exception
* @param allowCoercion True if coercion logic can be applied to this
* argument, false to only allow a precise match
* @return <tt>false</tt> if the argument matched perfectly, <tt>true</tt>
* if coercion is required for the argument
*/
protected final boolean checkCoerce(int index, Type toType, String description, boolean allowCoercion) {
Type fromType = index < 0 ? this.returnType : this.methodArgs[index];
if (index >= this.methodArgs.length) {
throw new InvalidInjectionException(this.info, String.format(
"%s has an invalid signature. Not enough arguments: expected argument type %s at index %d",
description, SignaturePrinter.getTypeName(toType), index));
}
AnnotationNode coerce = Annotations.getInvisibleParameter(this.methodNode, Coerce.class, index);
boolean isReturn = index < 0;
String argType = isReturn ? "return" : "argument";
Object argIndex = isReturn ? "" : " at index " + index;
if (fromType.equals(toType)) {
if (coerce != null && this.info.getContext().getOption(Option.DEBUG_VERBOSE)) {
Injector.logger.info("Possibly-redundant @Coerce on {} {} type{}, {} is identical to {}", description, argType, argIndex,
SignaturePrinter.getTypeName(toType), SignaturePrinter.getTypeName(fromType));
}
return false;
}
if (coerce == null || !allowCoercion) {
String coerceWarning = coerce != null ? ". @Coerce not allowed here" : "";
throw new InvalidInjectionException(this.info, String.format(
"%s has an invalid signature. Found unexpected %s type %s%s, expected %s%s", description, argType,
SignaturePrinter.getTypeName(fromType), argIndex, SignaturePrinter.getTypeName(toType), coerceWarning));
}
boolean canCoerce = Injector.canCoerce(fromType, toType);
if (!canCoerce) {
throw new InvalidInjectionException(this.info, String.format(
"%s has an invalid signature. Cannot @Coerce %s type %s%s to %s", description, argType,
SignaturePrinter.getTypeName(toType), argIndex, SignaturePrinter.getTypeName(fromType)));
}
return true;
}
@Override
protected boolean isAssignableFrom(Type t, Type u) {
if (t.equals(u)) {
return true;
}
// Null is assignable to any reference type
if ("Lnull;".equals(u.getDescriptor()) && t.getSort() >= Type.ARRAY) {
return true;
}
Type et, eu;
if (t.getSort() == Type.ARRAY) {
if (u.getSort() != Type.ARRAY ) {
return false;
}
et = t.getElementType();
eu = u.getElementType();
int dt = t.getDimensions();
int du = u.getDimensions();
boolean isObject = et.equals(((BasicValue)BasicValue.REFERENCE_VALUE).getType());
// u must be an array of equals dimension or bigger dimension if t is Object
if (dt == du || dt < du && isObject) {
// Ok
} else {
return false;
}
} else {
et = t;
eu = u;
}
/*
Type commonType = classHierarchy.getCommonSuperType(et, eu);
*/
// isAssignableFrom(Number, Integer) => getCommonSuperType(Integer, Number) == Number
// Use ClassHierarchy.isSubclass biased behavior (for performance)
Type commonType = classHierarchy.getCommonSuperType(eu, et);
return commonType.equals(et);
}
/**
* @param i
* @param ignoreNonFound
* @param ref
* @param retType
* @param sigType
* @throws SerianalyzerException
*/
public void foundImprovedReturnType ( Index i, boolean ignoreNonFound, MethodReference ref, Type retType, Type sigType )
throws SerianalyzerException {
MethodReference c = ref.comparable();
this.checkedReturnType.add(c);
if ( "java.lang.Object".equals(sigType.getClassName()) //$NON-NLS-1$
|| ( "java.io.Serializable".equals(sigType.getClassName()) && //$NON-NLS-1$
!"java.lang.Object".equals(retType.getClassName()) ) ) { //$NON-NLS-1$
if ( this.returnTypes.put(c, retType) != null ) {
this.bench.improvedReturnType();
}
return;
}
else if ( sigType.getSort() != Type.OBJECT || sigType.getClassName().endsWith("[]") ) { //$NON-NLS-1$
return;
}
if ( this.returnTypes.containsKey(c) ) {
return;
}
Type moreConcreteType = TypeUtil.getMoreConcreteType(i, ignoreNonFound, retType, sigType);
if ( this.returnTypes.put(c, moreConcreteType) == null ) {
if ( moreConcreteType.equals(retType) && !moreConcreteType.equals(sigType) ) {
this.bench.improvedReturnType();
}
else {
this.bench.nonImprovedReturnType();
}
}
}
/**
* Two types are congruent if they are primitive and the same, or if one is a subclass of another.
* @param a type A
* @param b type B
* @return true if type A and B are congruent
*/
private boolean areTypesCongruent(Type a, Type b) {
if (a.equals(b)) {
return true;
}
boolean eArr = a.getSort() == Type.ARRAY;
boolean aArr = b.getSort() == Type.ARRAY;
if(eArr != aArr) {
return false;
}
if(eArr) {
a = a.getElementType();
b = b.getElementType();
}
if(TypeUtils.isPrimitive(a) || TypeUtils.isPrimitive(b)) {
return false;
}
if(a == Type.VOID_TYPE || b == Type.VOID_TYPE) {
return false;
}
ClassNode cnA = app.findClassNode(a.getInternalName());
ClassNode cnB = app.findClassNode(b.getInternalName());
ClassTree tree = app.getClassTree();
return tree.getAllParents(cnB).contains(cnA) ||
tree.getAllParents(cnA).contains(cnB);
}
public boolean hasStaticField(String fieldName, String fieldDescriptor) {
try {
Field f = class_.getDeclaredField(fieldName);
if ((f.getModifiers() & Modifier.STATIC) == 0) {
// not a static field
return false;
}
Type fieldType = Type.getType(f.getType());
Type argType = Type.getType(fieldDescriptor);
return argType.equals(fieldType);
} catch (NoSuchFieldException nsfe) {
return false;
}
}
private static boolean isWideType(Type aType) {
return aType.equals(Type.LONG_TYPE) || aType.equals(Type.DOUBLE_TYPE);
}
@Override
public BasicValue merge(final BasicValue value1, final BasicValue value2) {
if (!value1.equals(value2)) {
Type type1 = value1.getType();
Type type2 = value2.getType();
if (type1 != null
&& (type1.getSort() == Type.OBJECT || type1.getSort() == Type.ARRAY)
&& type2 != null
&& (type2.getSort() == Type.OBJECT || type2.getSort() == Type.ARRAY)) {
if (type1.equals(NULL_TYPE)) {
return value2;
}
if (type2.equals(NULL_TYPE)) {
return value1;
}
if (isAssignableFrom(type1, type2)) {
return value1;
}
if (isAssignableFrom(type2, type1)) {
return value2;
}
int numDimensions = 0;
if (type1.getSort() == Type.ARRAY
&& type2.getSort() == Type.ARRAY
&& type1.getDimensions() == type2.getDimensions()
&& type1.getElementType().getSort() == Type.OBJECT
&& type2.getElementType().getSort() == Type.OBJECT) {
numDimensions = type1.getDimensions();
type1 = type1.getElementType();
type2 = type2.getElementType();
}
do {
if (type1 == null || isInterface(type1)) {
return newArrayValue(Type.getObjectType("java/lang/Object"), numDimensions);
}
type1 = getSuperClass(type1);
if (isAssignableFrom(type1, type2)) {
return newArrayValue(type1, numDimensions);
}
} while (true);
}
return BasicValue.UNINITIALIZED_VALUE;
}
return value1;
}
/**
* Generates the instruction to check that the top stack value is of the given type.
*
* @param type a class or interface type.
*/
public void checkCast(final Type type) {
if (!type.equals(OBJECT_TYPE)) {
typeInsn(Opcodes.CHECKCAST, type);
}
}
boolean checkDescriptor(String desc) {
if (this.getDescriptor().equals(desc)) {
return true; // Descriptor matches exactly, this is good
}
if (this.target.getSimpleCallbackDescriptor().equals(desc) && !this.canCaptureLocals) {
this.captureArgs = false;
return true;
}
Type[] inTypes = Type.getArgumentTypes(desc);
Type[] myTypes = Type.getArgumentTypes(this.descl);
if (inTypes.length != myTypes.length) {
return false;
}
for (int arg = 0; arg < myTypes.length; arg++) {
Type type = inTypes[arg];
if (type.equals(myTypes[arg])) {
continue; // Type matches
}
if (type.getSort() == Type.ARRAY) {
return false; // Array types must match exactly
}
if (Annotations.getInvisibleParameter(this.handler, Coerce.class, arg) == null) {
return false; // No @Coerce specified, types must match
}
if (!Injector.canCoerce(inTypes[arg], myTypes[arg])) {
// if (Injector.canCoerce(myTypes[arg], inTypes[arg])) {
// this.typeCasts[arg] = inTypes[arg];
// } else {
return false; // Can't coerce or cast source type to local type, give up
// }
}
}
return true;
}
protected boolean isInterface(final Type t) {
if (currentClass != null && t.equals(currentClass)) {
return isInterface;
}
return getClass(t).isInterface();
}
/**
* @param opcode
* @param args
* @param tgt
* @param r
* @param signatureTypes
* @return
*/
private List<Type> setupTainting ( MethodReference call, int opcode, List<BaseType> args, Object tgt, MethodReference r, Type[] signatureTypes ) {
if ( opcode != Opcodes.INVOKESTATIC && opcode != Opcodes.INVOKEDYNAMIC ) {
if ( tgt == null || ! ( tgt instanceof BaseType ) || ( (BaseType) tgt ).isTainted() ) {
r.taintCallee();
}
}
boolean foundTypes = true;
List<Type> actualTypes = new ArrayList<>();
if ( signatureTypes.length != args.size() ) {
return null;
}
for ( int i = 0; i < signatureTypes.length; i++ ) {
Object object = args.get(i);
if ( object instanceof BaseType ) {
if ( object instanceof SimpleType ) {
Type type = ( (SimpleType) object ).getType();
Set<Type> altTypes = ( (BaseType) object ).getAlternativeTypes();
Type sigType = signatureTypes[ i ];
if ( type == null ) {
actualTypes.add(sigType);
}
else if ( altTypes == null || altTypes.isEmpty() ) {
try {
Type moreConcreteType = this.parent.getAnalyzer().getMoreConcreteType(type, sigType);
if ( !moreConcreteType.equals(sigType) ) {
// log.info("Improving type to " + moreConcreteType + " for " + call + " in " +
// this.ref);
}
actualTypes.add(moreConcreteType);
}
catch ( SerianalyzerException e ) {
this.log.error("Failed to determine argument type", e); //$NON-NLS-1$
this.log.warn("Formal arguments are " + Arrays.toString(signatureTypes)); //$NON-NLS-1$
this.log.warn("Known arguments are " + args); //$NON-NLS-1$
this.log.warn("Failing arg " + i + ": " + object); //$NON-NLS-1$ //$NON-NLS-2$
this.log.warn("Failing arg type " + type); //$NON-NLS-1$
this.log.warn("Signature type " + sigType); //$NON-NLS-1$
this.log.warn("In " + this.ref); //$NON-NLS-1$
this.log.warn("Calling " + call); //$NON-NLS-1$
foundTypes = false;
}
}
}
else {
foundTypes = false;
}
if ( ( (BaseType) object ).isTainted() ) {
r.taintParameter(i);
}
if ( object instanceof BasicVariable && ( (BasicVariable) object ).isTaintReturns() ) {
r.taintParameterReturns(i);
}
}
else {
r.taintParameter(i);
foundTypes = false;
}
}
if ( foundTypes ) {
return actualTypes;
}
//
return null;
}