Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -535,10 +535,18 @@ private boolean performInstrumentation(
for (MethodNode methodNode : classNode.methods) {
List<ProbeDefinition> matchingDefs = new ArrayList<>();
for (ProbeDefinition definition : definitions) {
if (definition.getWhere().isMethodMatching(methodNode, classFileLines)
&& remainingDefinitions.contains(definition)) {
matchingDefs.add(definition);
remainingDefinitions.remove(definition);
Where.MethodMatching methodMatching =
definition.getWhere().isMethodMatching(methodNode, classFileLines);
if (remainingDefinitions.contains(definition)) {
if (methodMatching == Where.MethodMatching.MATCH) {
// method matches, add into collection of definitions to instrument
matchingDefs.add(definition);
}
if (methodMatching == Where.MethodMatching.MATCH
|| methodMatching == Where.MethodMatching.SKIP)
// match or need to skip instrumentation (because bridge) remove from remaining
// definitions to avoid reporting error
remainingDefinitions.remove(definition);
}
}
if (matchingDefs.isEmpty()) {
Expand Down Expand Up @@ -850,7 +858,7 @@ private List<MethodNode> matchMethodDescription(
List<MethodNode> result = new ArrayList<>();
try {
for (MethodNode methodNode : classNode.methods) {
if (where.isMethodMatching(methodNode, classFileLines)) {
if (where.isMethodMatching(methodNode, classFileLines) == Where.MethodMatching.MATCH) {
result.add(methodNode);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,27 +127,38 @@ public boolean isMethodNameMatching(String targetMethod) {
return methodName == null || methodName.equals("*") || methodName.equals(targetMethod);
}

public boolean isMethodMatching(MethodNode methodNode, ClassFileLines classFileLines) {
public enum MethodMatching {
MATCH,
SKIP,
FAIL
}

public MethodMatching isMethodMatching(MethodNode methodNode, ClassFileLines classFileLines) {
String targetName = methodNode.name;
String targetMethodDescriptor = methodNode.desc;
// try exact matching: name + FQN signature
if (!isMethodNameMatching(targetName)
|| ((methodNode.access & Opcodes.ACC_BRIDGE) == Opcodes.ACC_BRIDGE)) {
return false;
if (!isMethodNameMatching(targetName)) {
return MethodMatching.FAIL;
}
if ((methodNode.access & Opcodes.ACC_BRIDGE) == Opcodes.ACC_BRIDGE) {
// name is matching but method is a bridge method
return MethodMatching.SKIP;
}
if (signature == null) {
if (lines == null || lines.length == 0) {
return true;
return MethodMatching.MATCH;
}
// try matching by line
List<MethodNode> methodsByLine = classFileLines.getMethodsByLine(lines[0].getFrom());
if (methodsByLine == null || methodsByLine.isEmpty()) {
return false;
return MethodMatching.FAIL;
}
return methodsByLine.stream().anyMatch(m -> m == methodNode);
return methodsByLine.stream().anyMatch(m -> m == methodNode)
? MethodMatching.MATCH
: MethodMatching.FAIL;
}
if (signature.equals("*") || signature.equals(targetMethodDescriptor)) {
return true;
return MethodMatching.MATCH;
}
// try full JVM signature: "(Ljava.lang.String;Ljava.util.Map;I)V"
if (probeMethodDescriptor == null) {
Expand All @@ -160,20 +171,22 @@ public boolean isMethodMatching(MethodNode methodNode, ClassFileLines classFileL
}
}
if (probeMethodDescriptor.isEmpty()) {
return true;
return MethodMatching.MATCH;
}
if (probeMethodDescriptor.equals(targetMethodDescriptor)) {
return true;
return MethodMatching.MATCH;
}
// fallback to signature without return type: "Ljava.lang.String;Ljava.util.Map;I"
String noRetTypeDescriptor = removeReturnType(probeMethodDescriptor);
targetMethodDescriptor = removeReturnType(targetMethodDescriptor);
if (noRetTypeDescriptor.equals(targetMethodDescriptor)) {
return true;
return MethodMatching.MATCH;
}
// Fallback to signature without Fully Qualified Name: "LString;LMap;I"
String simplifiedSignature = removeFQN(targetMethodDescriptor);
return noRetTypeDescriptor.equals(simplifiedSignature);
return noRetTypeDescriptor.equals(simplifiedSignature)
? MethodMatching.MATCH
: MethodMatching.FAIL;
}

private static boolean isMissingReturnType(String probeMethodDescriptor) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,43 +101,54 @@ public void convertLineToMethod() {
@Test
public void methodMatching() {
Where where = new Where("String", "substring", "(int,int)", new String[0], null);
assertTrue(
assertEquals(
Where.MethodMatching.MATCH,
where.isMethodMatching(createMethodNode("substring", "(II)Ljava/lang/String;"), null));
where = new Where("String", "replaceAll", "(String,String)", new String[0], null);
assertTrue(
assertEquals(
Where.MethodMatching.MATCH,
where.isMethodMatching(
createMethodNode(
"replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
null));
where = new Where("HashMap", "<init>", "(Map)", new String[0], null);
assertTrue(where.isMethodMatching(createMethodNode("<init>", "(Ljava/util/Map;)V"), null));
assertEquals(
Where.MethodMatching.MATCH,
where.isMethodMatching(createMethodNode("<init>", "(Ljava/util/Map;)V"), null));
where = new Where("ArrayList", "removeIf", "(Predicate)", new String[0], null);
assertTrue(
assertEquals(
Where.MethodMatching.MATCH,
where.isMethodMatching(
createMethodNode("removeIf", "(Ljava/util/function/Predicate;)Z"), null));
where = new Where("String", "concat", "", new String[0], null);
assertTrue(where.isMethodMatching(createMethodNode("concat", "String (String)"), null));
assertEquals(
Where.MethodMatching.MATCH,
where.isMethodMatching(createMethodNode("concat", "String (String)"), null));
where = new Where("String", "concat", " \t", new String[0], null);
assertTrue(where.isMethodMatching(createMethodNode("concat", "String (String)"), null));
assertEquals(
Where.MethodMatching.MATCH,
where.isMethodMatching(createMethodNode("concat", "String (String)"), null));
where =
new Where(
"Inner",
"innerMethod",
"(com.datadog.debugger.probe.Outer$Inner)",
new String[0],
null);
assertTrue(
assertEquals(
Where.MethodMatching.MATCH,
where.isMethodMatching(
createMethodNode("innerMethod", "(Lcom/datadog/debugger/probe/Outer$Inner;)V"), null));
where = new Where("Inner", "innerMethod", "(Outer$Inner)", new String[0], null);
assertTrue(
assertEquals(
Where.MethodMatching.MATCH,
where.isMethodMatching(
createMethodNode("innerMethod", "(Lcom/datadog/debugger/probe/Outer$Inner;)V"), null));
where = new Where("MyClass", "myMethod", null, new String[] {"42"}, null);
ClassFileLines classFileLines = mock(ClassFileLines.class);
MethodNode myMethodNode = createMethodNode("myMethod", "()V");
when(classFileLines.getMethodsByLine(42)).thenReturn(Arrays.asList(myMethodNode));
assertTrue(where.isMethodMatching(myMethodNode, classFileLines));
assertEquals(Where.MethodMatching.MATCH, where.isMethodMatching(myMethodNode, classFileLines));
}

private MethodNode createMethodNode(String name, String desc) {
Expand Down
Loading