Skip to content

Commit 3710146

Browse files
Prevent before callsites targeting calls to super in constructors
1 parent a39a27f commit 3710146

File tree

13 files changed

+215
-33
lines changed

13 files changed

+215
-33
lines changed

buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/impl/AdviceGeneratorImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import static datadog.trace.plugin.csi.util.CallSiteConstants.METHOD_HANDLER_CLASS;
1212
import static datadog.trace.plugin.csi.util.CallSiteConstants.OPCODES_FQDN;
1313
import static datadog.trace.plugin.csi.util.CallSiteConstants.STACK_DUP_MODE_CLASS;
14+
import static datadog.trace.plugin.csi.util.CallSiteConstants.TYPE_CLASS;
1415
import static datadog.trace.plugin.csi.util.CallSiteConstants.TYPE_RESOLVER;
1516
import static datadog.trace.plugin.csi.util.CallSiteUtils.deleteFile;
1617
import static datadog.trace.plugin.csi.util.JavaParserUtils.getPrimaryType;
@@ -185,20 +186,24 @@ private void addAdviceLambda(
185186
final MethodType pointCut = spec.getPointcut();
186187
final BlockStmt adviceBody = new BlockStmt();
187188
final Expression advice;
189+
final String type;
188190
if (spec.isInvokeDynamic()) {
189191
advice = invokeDynamicAdviceSignature(adviceBody);
190192
} else {
191193
advice = invokeAdviceSignature(adviceBody);
192194
}
193195
if (spec instanceof BeforeSpecification) {
196+
type = "BEFORE";
194197
writeStackOperations(spec, adviceBody);
195198
writeAdviceMethodCall(spec, adviceBody);
196199
writeOriginalMethodCall(spec, adviceBody);
197200
} else if (spec instanceof AfterSpecification) {
201+
type = "AFTER";
198202
writeStackOperations(spec, adviceBody);
199203
writeOriginalMethodCall(spec, adviceBody);
200204
writeAdviceMethodCall(spec, adviceBody);
201205
} else {
206+
type = "AROUND";
202207
writeAdviceMethodCall(spec, adviceBody);
203208
}
204209
body.addStatement(
@@ -207,6 +212,9 @@ private void addAdviceLambda(
207212
.setName("addAdvice")
208213
.setArguments(
209214
new NodeList<>(
215+
new FieldAccessExpr()
216+
.setScope(new TypeExpr(new ClassOrInterfaceType().setName(TYPE_CLASS)))
217+
.setName(type),
210218
new StringLiteralExpr(pointCut.getOwner().getInternalName()),
211219
new StringLiteralExpr(pointCut.getMethodName()),
212220
new StringLiteralExpr(pointCut.getMethodType().getDescriptor()),

buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/impl/ext/IastExtension.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,19 +364,19 @@ private static LambdaExpr findAdviceLambda(
364364
final MethodType pointcut = spec.getPointcut();
365365
for (final MethodCallExpr add : addAdvices) {
366366
final NodeList<Expression> arguments = add.getArguments();
367-
final String owner = arguments.get(0).asStringLiteralExpr().asString();
367+
final String owner = arguments.get(1).asStringLiteralExpr().asString();
368368
if (!owner.equals(pointcut.getOwner().getInternalName())) {
369369
continue;
370370
}
371-
final String method = arguments.get(1).asStringLiteralExpr().asString();
371+
final String method = arguments.get(2).asStringLiteralExpr().asString();
372372
if (!method.equals(pointcut.getMethodName())) {
373373
continue;
374374
}
375-
final String description = arguments.get(2).asStringLiteralExpr().asString();
375+
final String description = arguments.get(3).asStringLiteralExpr().asString();
376376
if (!description.equals(pointcut.getMethodType().getDescriptor())) {
377377
continue;
378378
}
379-
return arguments.get(3).asLambdaExpr();
379+
return arguments.get(4).asLambdaExpr();
380380
}
381381
throw new IllegalArgumentException("Cannot find lambda expression for pointcut " + pointcut);
382382
}

buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/util/CallSiteConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ private CallSiteConstants() {}
3030

3131
public static final String HAS_ENABLED_PROPERTY_CLASS = CALL_SITES_CLASS + ".HasEnabledProperty";
3232

33+
public static final String TYPE_CLASS = "Type";
34+
3335
public static final String STACK_DUP_MODE_CLASS = "StackDupMode";
3436

3537
public static final String METHOD_HANDLER_CLASS = "MethodHandler";

buildSrc/call-site-instrumentation-plugin/src/test/groovy/datadog/trace/plugin/csi/impl/AdviceGeneratorTest.groovy

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ final class AdviceGeneratorTest extends BaseCsiPluginTest {
4444
interfaces(CallSites)
4545
helpers(BeforeAdvice)
4646
advices(0) {
47+
type("BEFORE")
4748
pointcut('java/security/MessageDigest', 'getInstance', '(Ljava/lang/String;)Ljava/security/MessageDigest;')
4849
statements(
4950
'handler.dupParameters(descriptor, StackDupMode.COPY);',
@@ -76,6 +77,7 @@ final class AdviceGeneratorTest extends BaseCsiPluginTest {
7677
interfaces(CallSites)
7778
helpers(AroundAdvice)
7879
advices(0) {
80+
type("AROUND")
7981
pointcut('java/lang/String', 'replaceAll', '(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;')
8082
statements(
8183
'handler.advice("datadog/trace/plugin/csi/impl/AdviceGeneratorTest$AroundAdvice", "around", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");'
@@ -106,6 +108,7 @@ final class AdviceGeneratorTest extends BaseCsiPluginTest {
106108
interfaces(CallSites)
107109
helpers(AfterAdvice)
108110
advices(0) {
111+
type("AFTER")
109112
pointcut('java/lang/String', 'concat', '(Ljava/lang/String;)Ljava/lang/String;')
110113
statements(
111114
'handler.dupInvoke(owner, descriptor, StackDupMode.COPY);',

buildSrc/call-site-instrumentation-plugin/src/test/groovy/datadog/trace/plugin/csi/impl/assertion/AdviceAssert.groovy

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package datadog.trace.plugin.csi.impl.assertion
22

33
class AdviceAssert {
4+
protected String type
45
protected String owner
56
protected String method
67
protected String descriptor
78
protected Collection<String> statements
89

10+
void type(String type) {
11+
assert type == this.type
12+
}
13+
914
void pointcut(String owner, String method, String descriptor) {
1015
assert owner == this.owner
1116
assert method == this.method

buildSrc/call-site-instrumentation-plugin/src/test/groovy/datadog/trace/plugin/csi/impl/assertion/AssertBuilder.groovy

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,12 @@ class AssertBuilder<C extends CallSiteAssert> {
8383
return getMethodCalls(acceptMethod).findAll {
8484
it.nameAsString == 'addAdvice'
8585
}.collect {
86-
def (owner, method, descriptor) = it.arguments.subList(0, 3)*.asStringLiteralExpr()*.asString()
87-
final handlerLambda = it.arguments[3].asLambdaExpr()
86+
final adviceType = it.arguments.get(0).asFieldAccessExpr().getName()
87+
def (owner, method, descriptor) = it.arguments.subList(1, 4)*.asStringLiteralExpr()*.asString()
88+
final handlerLambda = it.arguments[4].asLambdaExpr()
8889
final advice = handlerLambda.body.asBlockStmt().statements*.toString()
8990
return new AdviceAssert([
91+
type : adviceType,
9092
owner : owner,
9193
method : method,
9294
descriptor: descriptor,

buildSrc/call-site-instrumentation-plugin/src/test/groovy/datadog/trace/plugin/csi/impl/ext/IastExtensionTest.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,8 @@ class IastExtensionTest extends BaseCsiPluginTest {
217217
return getMethodCalls(acceptMethod).findAll {
218218
it.nameAsString == 'addAdvice'
219219
}.collect {
220-
def (owner, method, descriptor) = it.arguments.subList(0, 3)*.asStringLiteralExpr()*.asString()
221-
final handlerLambda = it.arguments[3].asLambdaExpr()
220+
def (owner, method, descriptor) = it.arguments.subList(1, 4)*.asStringLiteralExpr()*.asString()
221+
final handlerLambda = it.arguments[4].asLambdaExpr()
222222
final statements = handlerLambda.body.asBlockStmt().statements
223223
final instrumentedStmt = statements.get(0).asIfStmt()
224224
final executedStmt = statements.get(1).asIfStmt()

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/csi/Advices.java

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import datadog.trace.agent.tooling.bytebuddy.ClassFileLocators;
77
import datadog.trace.agent.tooling.csi.CallSiteAdvice;
88
import datadog.trace.agent.tooling.csi.CallSites;
9+
import datadog.trace.agent.tooling.csi.InvokeAdvice;
10+
import datadog.trace.agent.tooling.csi.InvokeDynamicAdvice;
911
import java.lang.reflect.Field;
1012
import java.util.Arrays;
1113
import java.util.Collections;
@@ -141,6 +143,11 @@ public CallSiteAdvice findAdvice(
141143
return methodAdvices.get(descriptor);
142144
}
143145

146+
/** Gets the type of advice we are dealing with */
147+
public byte typeOf(final CallSiteAdvice advice) {
148+
return ((HasType) advice).getType();
149+
}
150+
144151
public String[] getHelpers() {
145152
return helpers;
146153
}
@@ -176,15 +183,17 @@ public void addHelpers(final String... helperClassNames) {
176183

177184
@Override
178185
public void addAdvice(
179-
final String type,
186+
final byte type,
187+
final String owner,
180188
final String method,
181189
final String descriptor,
182190
final CallSiteAdvice advice) {
183191
final Map<String, Map<String, CallSiteAdvice>> typeAdvices =
184-
advices.computeIfAbsent(type, k -> new HashMap<>());
192+
advices.computeIfAbsent(owner, k -> new HashMap<>());
185193
final Map<String, CallSiteAdvice> methodAdvices =
186194
typeAdvices.computeIfAbsent(method, k -> new HashMap<>());
187-
final CallSiteAdvice oldAdvice = methodAdvices.put(descriptor, advice);
195+
final CallSiteAdvice oldAdvice =
196+
methodAdvices.put(descriptor, HasType.withType(advice, type));
188197
if (oldAdvice != null) {
189198
throw new UnsupportedOperationException(
190199
String.format(
@@ -360,4 +369,67 @@ public interface Listener {
360369
void onConstantPool(
361370
@Nonnull TypeDescription type, @Nonnull ConstantPool pool, final byte[] classFile);
362371
}
372+
373+
private interface HasType {
374+
byte getType();
375+
376+
static CallSiteAdvice withType(final CallSiteAdvice advice, final byte type) {
377+
if (advice instanceof InvokeAdvice) {
378+
return new InvokeWithType((InvokeAdvice) advice, type);
379+
} else {
380+
return new InvokeDynamicWithType((InvokeDynamicAdvice) advice, type);
381+
}
382+
}
383+
}
384+
385+
private static class InvokeWithType implements InvokeAdvice, HasType {
386+
private final InvokeAdvice advice;
387+
private final byte type;
388+
389+
private InvokeWithType(InvokeAdvice advice, byte type) {
390+
this.advice = advice;
391+
this.type = type;
392+
}
393+
394+
@Override
395+
public byte getType() {
396+
return type;
397+
}
398+
399+
@Override
400+
public void apply(
401+
final MethodHandler handler,
402+
final int opcode,
403+
final String owner,
404+
final String name,
405+
final String descriptor,
406+
final boolean isInterface) {
407+
advice.apply(handler, opcode, owner, name, descriptor, isInterface);
408+
}
409+
}
410+
411+
private static class InvokeDynamicWithType implements InvokeDynamicAdvice, HasType {
412+
private final InvokeDynamicAdvice advice;
413+
private final byte type;
414+
415+
private InvokeDynamicWithType(final InvokeDynamicAdvice advice, final byte type) {
416+
this.advice = advice;
417+
this.type = type;
418+
}
419+
420+
@Override
421+
public byte getType() {
422+
return type;
423+
}
424+
425+
@Override
426+
public void apply(
427+
final MethodHandler handler,
428+
final String name,
429+
final String descriptor,
430+
final Handle bootstrapMethodHandle,
431+
final Object... bootstrapMethodArguments) {
432+
advice.apply(handler, name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
433+
}
434+
}
363435
}

0 commit comments

Comments
 (0)