Search in sources :

Example 6 with ClassInformation

use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.

the class ClassMatch method processRequiredClassAnnotations.

private void processRequiredClassAnnotations(ClassCache cache) {
    final List<AnnotationNode> annotationsInOriginal = WeaveUtils.getClassAnnotations(original);
    Set<String> classAnnotations = Sets.newHashSetWithExpectedSize(annotationsInOriginal.size());
    for (AnnotationNode annotationNode : annotationsInOriginal) {
        classAnnotations.add(Type.getType(annotationNode.desc).getClassName());
    }
    // Exact match
    if (isOneOfRequiredAnnotations(classAnnotations, requiredClassAnnotations)) {
        return;
    }
    if (WeaveUtils.isWeaveWithAnnotationInterfaceMatch(weave)) {
        try {
            for (String interfaceName : original.interfaces) {
                ClassInformation interfaceInformation = cache.getClassInformation(interfaceName);
                if (isOneOfRequiredAnnotations(interfaceInformation.classAnnotationNames, requiredClassAnnotations)) {
                    return;
                }
            }
        } catch (IOException e) {
        }
    }
    addViolation(CLASS_MISSING_REQUIRED_ANNOTATIONS);
}
Also used : ClassInformation(com.newrelic.weave.utils.ClassInformation) AnnotationNode(org.objectweb.asm.tree.AnnotationNode) IOException(java.io.IOException)

Example 7 with ClassInformation

use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.

the class ClassMatch method match.

private void match(ClassCache cache) {
    // cannot annotate an interface
    if ((weave.access & Opcodes.ACC_INTERFACE) != 0) {
        addViolation(CLASS_WEAVE_IS_INTERFACE);
        fatalWeaveViolation = true;
        return;
    }
    if ((weave.access & Opcodes.ACC_ENUM) != 0) {
        processEnumMethods();
    }
    if (weave.version > WeaveUtils.RUNTIME_MAX_SUPPORTED_CLASS_VERSION) {
        addViolation(INCOMPATIBLE_BYTECODE_VERSION);
    }
    boolean isWeaveWithAnnotation = !requiredClassAnnotations.isEmpty() || !requiredMethodAnnotations.isEmpty();
    // cannot increase class visibility
    if ((original.access & Opcodes.ACC_PUBLIC) != (weave.access & Opcodes.ACC_PUBLIC)) {
        // WeaveWithAnnotation class access does not need to match original class access
        if (!isWeaveWithAnnotation) {
            addViolation(CLASS_ACCESS_MISMATCH);
        }
    }
    // weave can only implement interfaces that the original implements
    if (weave.interfaces.size() > 0) {
        for (String weaveInterface : weave.interfaces) {
            if (!allOriginalInterfaces.contains(weaveInterface)) {
                addViolation(CLASS_IMPLEMENTS_ILLEGAL_INTERFACE);
            }
        }
    }
    if (!requiredClassAnnotations.isEmpty()) {
        processRequiredClassAnnotations(cache);
    }
    if (requiredClassAnnotations.isEmpty() && !requiredMethodAnnotations.isEmpty()) {
        processRequiredMethodAnnotations(cache);
    }
    // weave can only extend the exact superclass that the original extends
    if (!weave.superName.equals(WeaveUtils.JAVA_LANG_OBJECT_NAME) && !weave.superName.equals(original.superName)) {
        addViolation(CLASS_EXTENDS_ILLEGAL_SUPERCLASS);
    }
    // weave cannot be a non-static inner class
    if (WeaveUtils.isNonstaticInnerClass(weave)) {
        addViolation(CLASS_NESTED_NONSTATIC_UNSUPPORTED);
    }
    weavesAllMethod = findAndValidateWeaveIntoAllMethod();
    // identify new, anonymous, and matched inner classes
    Map<String, InnerClassNode> originalInnerClasses = new HashMap<>();
    for (InnerClassNode innerClassNode : original.innerClasses) {
        originalInnerClasses.put(innerClassNode.name, innerClassNode);
    }
    for (InnerClassNode weaveInnerClass : weave.innerClasses) {
        String name = weaveInnerClass.name;
        if (weave.name.equals(name)) {
            // if the weave class IS an inner class, it will be listed - skip it
            continue;
        }
        if (weaveInnerClass.outerName != null && !weaveInnerClass.outerName.equals(weave.name)) {
            // we're using an inner class from another class - skip it
            continue;
        }
        if (WeaveUtils.isAnonymousInnerClass(weaveInnerClass)) {
            // all anon classes are new
            newInnerClasses.add(name);
        } else if (originalInnerClasses.containsKey(name)) {
            matchedInnerClasses.add(name);
        } else {
            newInnerClasses.add(name);
        }
    }
    // identify new and matched fields
    Map<String, FieldNode> originalFields = new HashMap<>();
    for (FieldNode originalField : original.fields) {
        originalFields.put(originalField.name, originalField);
    }
    for (FieldNode weaveField : weave.fields) {
        if (weaveField.name.equals(SERIAL_VERSION_UID_FIELD_NAME)) {
            addViolation(FIELD_SERIALVERSIONUID_UNSUPPORTED, weaveField);
            continue;
        }
        FieldNode originalField = originalFields.get(weaveField.name);
        if (originalField == null) {
            newFields.add(weaveField.name);
        } else {
            validateMatchedField(originalField, weaveField);
            matchedFields.add(weaveField.name);
        }
    }
    if ((weave.access & Opcodes.ACC_ENUM) != 0) {
        if (newFields.size() > 0) {
            addViolation(ENUM_NEW_FIELD);
        }
    }
    // identify new and matched methods
    MethodNode clinit = null;
    for (MethodNode weaveMethod : weave.methods) {
        if (weaveMethod.name.equals(WeaveUtils.CLASS_INIT_NAME)) {
            clinit = weaveMethod;
            // we don't weave <clinit> into a target (only extensions)
            continue;
        }
        if (weaveMethod.name.equals(WeaveUtils.INIT_NAME)) {
            // validate ctor field assignment calls and remove redundant Weaver.callOriginal() invocations
            // must happen before we skip empty ctors below to support final field assignments w/out a ctor match
            // see ConstructorWeaveTest.testInitFinalFieldWithNoDefaultConstructor()
            processInitFieldAssignment(weaveMethod);
        }
        if (WeaveUtils.isEmptyConstructor(weaveMethod)) {
            // skip empty constructors
            continue;
        }
        if ((weaveMethod.access & Opcodes.ACC_BRIDGE) != 0) {
            // skip autogenerated bridge methods
            continue;
        }
        if (WeaveUtils.isSyntheticAccessor(weaveMethod.name)) {
            if ((weaveMethod.access & Opcodes.ACC_SYNTHETIC) != Opcodes.ACC_SYNTHETIC) {
                addViolation(METHOD_SYNTHETIC_WEAVE_ILLEGAL, weaveMethod);
                continue;
            }
            GeneratedNewFieldMethod generatedNewFieldMethod = GeneratedNewFieldMethod.isGeneratedNewFieldMethod(weaveMethod, newFields);
            if (generatedNewFieldMethod != null) {
                generatedNewFieldMethods.put(generatedNewFieldMethod.method, generatedNewFieldMethod);
            }
            // generated methods are handled specially
            continue;
        }
        if (WeaveUtils.hasWeaveIntoAllMethodsAnnotation(weaveMethod)) {
            processWeaveIntoAllMethods(weaveMethod, cache);
            continue;
        }
        MatchableMethod matchedMethod = matchableMethods.get(new MethodKey(weaveMethod));
        Method asmMethod = new Method(weaveMethod.name, weaveMethod.desc);
        if (matchedMethod == null) {
            newMethods.add(asmMethod);
        } else {
            validateMatchedMethod(matchedMethod, weaveMethod);
            matchedMethods.add(asmMethod);
        }
    }
    if (null != clinit) {
        // clinit matching needs to go last, which is why we didn't do it in the loop
        extensionClassInit = validateClassInit(clinit);
    }
    // we do not call validateMatchedMethod because there is no original
    if (isInterfaceMatch && newMethods.contains(WeaveUtils.DEFAULT_CONSTRUCTOR)) {
        newMethods.remove(WeaveUtils.DEFAULT_CONSTRUCTOR);
        matchedMethods.add(WeaveUtils.DEFAULT_CONSTRUCTOR);
    }
    weavesAllConstructors = validateWeaveAllConstructors();
    boolean collectClassAnnotations = false;
    // validate weave methods *after* match - match info is needed, e.g. to ensure no new methods call each other
    for (MethodNode weaveMethod : weave.methods) {
        WeaveMethodInstructionScanner instructionInfo = new WeaveMethodInstructionScanner();
        weaveMethod.accept(instructionInfo);
        validateWeaveMethod(weaveMethod, instructionInfo);
        if (instructionInfo.isClassAnnotationGetter) {
            classAnnotationGetters.add(weaveMethod);
            collectClassAnnotations = true;
        }
        if (instructionInfo.isMethodAnnotationGetter) {
            if (weaveMethod.equals(weavesAllMethod)) {
                for (MethodNode originalMethod : original.methods) {
                    storeMethodAnnotations(originalMethod);
                }
            } else {
                MethodNode originalMethod = WeaveUtils.getMethodNode(original, weaveMethod.name, weaveMethod.desc);
                storeMethodAnnotations(originalMethod);
            }
            if (WeaveUtils.isWeaveWithAnnotationInterfaceMatch(weave)) {
                // Add store method annotations for methods in interface
                for (String interfaceName : original.interfaces) {
                    try {
                        ClassInformation interfaceInformation = cache.getClassInformation(interfaceName);
                        Set<MethodKey> weaveMethodKeys = new HashSet<>();
                        for (MethodNode method : weave.methods) {
                            weaveMethodKeys.add(new MethodKey(method));
                        }
                        for (MethodNode method : weaveAllMatchedMethods.keySet()) {
                            weaveMethodKeys.add(new MethodKey(method));
                        }
                        for (ClassInformation.MemberInformation method : interfaceInformation.methods) {
                            // If method is same as weave method,
                            // Pull out method annotations and add it to methodToAnnotations
                            MethodKey methodKey = new MethodKey(method.name, method.desc);
                            if (weaveMethodKeys.contains(methodKey)) {
                                if (!methodsToAnnotations.containsKey(methodKey)) {
                                    methodsToAnnotations.put(methodKey, new HashMap<String, AnnotationNode>());
                                }
                                for (AnnotationNode annotation : method.annotations) {
                                    methodsToAnnotations.get(methodKey).put(Type.getType(annotation.desc).getClassName(), annotation);
                                }
                            }
                        }
                    } catch (IOException ignored) {
                    }
                // Need to get annotation nodes for each member in interfaceInformation.
                }
            }
        }
    }
    if (collectClassAnnotations) {
        List<AnnotationNode> classAnnotations = WeaveUtils.getClassAnnotations(original);
        for (AnnotationNode classAnnotation : classAnnotations) {
            classAnnotationMap.put(Type.getType(classAnnotation.desc).getClassName(), classAnnotation);
        }
        if (WeaveUtils.isWeaveWithAnnotationInterfaceMatch(weave)) {
            // Collect interface annotations.
            for (String interfaceName : original.interfaces) {
                try {
                    ClassInformation interfaceInformation = cache.getClassInformation(interfaceName);
                    for (AnnotationNode annotationNode : interfaceInformation.classAnnotationNodes) {
                        classAnnotationMap.put(Type.getType(annotationNode.desc).getClassName(), annotationNode);
                    }
                } catch (IOException ignored) {
                }
            }
        }
    }
}
Also used : FieldNode(org.objectweb.asm.tree.FieldNode) ClassInformation(com.newrelic.weave.utils.ClassInformation) HashMap(java.util.HashMap) Method(org.objectweb.asm.commons.Method) IOException(java.io.IOException) InnerClassNode(org.objectweb.asm.tree.InnerClassNode) MethodNode(org.objectweb.asm.tree.MethodNode) AnnotationNode(org.objectweb.asm.tree.AnnotationNode) HashSet(java.util.HashSet)

Example 8 with ClassInformation

use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.

the class PublicNewFieldTest method weaveClass.

private static void weaveClass(String origName, PackageValidationResult result, ClassCache cache) throws IOException {
    ClassInformation ci = cache.getClassInformation(origName);
    byte[] compositeBytes = result.weave(WeaveUtils.getClassInternalName(origName), ci.getAllSuperNames(cache).toArray(new String[0]), ci.getAllInterfaces(cache).toArray(new String[0]), WeaveTestUtils.getClassBytes(origName), cache, Collections.emptyMap()).getCompositeBytes(cache);
    Assert.assertNotNull("Unable to weave: " + origName, compositeBytes);
    Assert.assertFalse("Original class should not be already loaded: " + origName, ClassLoaderUtils.isClassLoadedOnClassLoader(CLASSLOADER, WeaveUtils.getClassBinaryName(origName)));
    WeaveTestUtils.addToContextClassloader(origName, compositeBytes);
}
Also used : ClassInformation(com.newrelic.weave.utils.ClassInformation)

Example 9 with ClassInformation

use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.

the class WeavePackageManagerTest method testBootstrapWeave.

@Test
public void testBootstrapWeave() throws IOException {
    List<byte[]> weaveBytes = new ArrayList<>();
    weaveBytes.add(WeaveTestUtils.getClassBytes("com.newrelic.weave.weavepackage.WeavePackageManagerTest$ResultSet"));
    WeavePackageConfig config = WeavePackageConfig.builder().name("weave_bootstrap").source("com.newrelic.weave.weavepackage.WeavePackageManagerTest").build();
    WeavePackage bsPackage = new WeavePackage(config, weaveBytes);
    Assert.assertTrue(bsPackage.weavesBootstrap());
    WeaveTestUtils.expectViolations(bsPackage.validate(new ClassCache(BootstrapLoader.get())));
    WeavePackageManager wpm = new WeavePackageManager(null, Mockito.mock(Instrumentation.class), 10, true, true);
    Assert.assertTrue(wpm.canWeaveBootstrapClassLoader());
    wpm.register(bsPackage);
    ClassLoader classloader = Thread.currentThread().getContextClassLoader();
    ClassCache cache = new ClassCache(new ClassLoaderFinder(classloader));
    String targetClassName = "com.newrelic.weave.weavepackage.WeavePackageManagerTest$ResultSetImpl";
    String targetInternalName = targetClassName.replace('.', '/');
    ClassInformation classInformation = cache.getClassInformation(targetInternalName);
    Assert.assertNotNull(classInformation);
    String[] superNames = classInformation.getAllSuperNames(cache).toArray(new String[0]);
    String[] interfaceNames = classInformation.getAllInterfaces(cache).toArray(new String[0]);
    Assert.assertEquals(1, wpm.match(classloader, targetInternalName, cache).size());
    byte[] result = wpm.weave(classloader, targetInternalName, WeaveTestUtils.getClassBytes(targetClassName), Collections.emptyMap());
    Assert.assertTrue(bsPackage.hasMatcher(targetInternalName, superNames, interfaceNames, Collections.<String>emptySet(), Collections.<String>emptySet(), null));
    Assert.assertEquals(0, getCacheSize(wpm.invalidPackages));
    Assert.assertEquals(1, getCacheSize(wpm.validPackages));
    Assert.assertNotNull(wpm.validPackages.getIfPresent(BootstrapLoader.PLACEHOLDER));
    Assert.assertNotNull(wpm.validPackages.getIfPresent(BootstrapLoader.PLACEHOLDER).get(bsPackage));
    Assert.assertNotNull(result);
}
Also used : ClassInformation(com.newrelic.weave.utils.ClassInformation) ArrayList(java.util.ArrayList) Instrumentation(java.lang.instrument.Instrumentation) ClassLoaderFinder(com.newrelic.weave.utils.ClassLoaderFinder) ClassCache(com.newrelic.weave.utils.ClassCache) Test(org.junit.Test)

Example 10 with ClassInformation

use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.

the class WeavePackageManager method match.

/**
 * Determine if the specified class and class loader match any packages.
 *
 * @param classloader classloader containing classpath to validate against
 * @param className name of the class
 * @param cache {@link ClassCache} used to resolve classes without loading them
 * @return validation result set
 */
public Set<PackageValidationResult> match(ClassLoader classloader, String className, ClassCache cache) throws IOException {
    classloader = classLoaderSub(classloader);
    ClassInformation classInformation = cache.getClassInformation(className);
    if (null == classInformation) {
        return Collections.emptySet();
    }
    String[] superNames = classInformation.getAllSuperNames(cache).toArray(new String[0]);
    String[] interfaceNames = classInformation.getAllInterfaces(cache).toArray(new String[0]);
    Set<String> classAnnotations = classInformation.classAnnotationNames;
    Set<String> methodAnnotations = classInformation.methodAnnotationNames;
    return match(classloader, cache, className, classAnnotations, methodAnnotations, superNames, interfaceNames);
}
Also used : ClassInformation(com.newrelic.weave.utils.ClassInformation)

Aggregations

ClassInformation (com.newrelic.weave.utils.ClassInformation)11 IOException (java.io.IOException)5 AnnotationNode (org.objectweb.asm.tree.AnnotationNode)3 ClassCache (com.newrelic.weave.utils.ClassCache)2 HashSet (java.util.HashSet)2 Method (org.objectweb.asm.commons.Method)2 MethodNode (org.objectweb.asm.tree.MethodNode)2 MemberInformation (com.newrelic.weave.utils.ClassInformation.MemberInformation)1 ClassLoaderFinder (com.newrelic.weave.utils.ClassLoaderFinder)1 SynchronizedFieldNode (com.newrelic.weave.utils.SynchronizedFieldNode)1 SynchronizedMethodNode (com.newrelic.weave.utils.SynchronizedMethodNode)1 WeaveViolation (com.newrelic.weave.violation.WeaveViolation)1 ClassWeavedListener (com.newrelic.weave.weavepackage.ClassWeavedListener)1 PackageWeaveResult (com.newrelic.weave.weavepackage.PackageWeaveResult)1 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)1 Instrumentation (java.lang.instrument.Instrumentation)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 Test (org.junit.Test)1