Skip to content

Commit 7d452a8

Browse files
authored
Merge branch 'master' into smola/single-char
2 parents 0fcd18e + f2d21ae commit 7d452a8

26 files changed

Lines changed: 199 additions & 72 deletions

File tree

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ProcessHierarchy.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,21 @@ public boolean isChild() {
5050
* not one of the supported build system processes.
5151
*/
5252
public boolean isHeadless() {
53-
return !isChild() && !isParent();
53+
return !isChild() && !isParent() && !isWrapper();
5454
}
5555

5656
private boolean isParent() {
5757
return isMavenParent() || isGradleDaemon();
5858
}
5959

60+
/**
61+
* Determines if current process is a wrapper that starts the build system. In other words a
62+
* process that is not a build system, and not a JVM that runs tests.
63+
*/
64+
private boolean isWrapper() {
65+
return isGradleLauncher();
66+
}
67+
6068
private boolean isMavenParent() {
6169
return System.getProperty("maven.home") != null
6270
&& System.getProperty("classworlds.conf") != null;
@@ -70,6 +78,12 @@ private boolean isGradleDaemon() {
7078
&& System.getProperties().getProperty("org.gradle.internal.worker.tmpdir") == null;
7179
}
7280

81+
private boolean isGradleLauncher() {
82+
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
83+
return contextClassLoader.getResource("org/gradle/launcher/Main.class") != null
84+
|| contextClassLoader.getResource("org/gradle/launcher/GradleMain.class") != null;
85+
}
86+
7387
@Nullable
7488
public InetSocketAddress getSignalServerAddress() {
7589
// System.getProperty is used rather than Config,

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/test/ExecutionStrategy.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,11 @@ public TestRetryPolicy retryPolicy(TestIdentifier test) {
9999
public boolean isEarlyFlakeDetectionLimitReached() {
100100
int detectionsUsed = earlyFlakeDetectionsUsed.get();
101101
Collection<TestIdentifier> knownTests = executionSettings.getKnownTests();
102-
int totalTests = knownTests.size() + detectionsUsed;
102+
if (knownTests == null) {
103+
return false;
104+
}
103105

106+
int totalTests = knownTests.size() + detectionsUsed;
104107
EarlyFlakeDetectionSettings earlyFlakeDetectionSettings =
105108
executionSettings.getEarlyFlakeDetectionSettings();
106109
int threshold =

dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ public void onStringTrim(@Nonnull final String self, @Nullable final String resu
403403
}
404404

405405
@Override
406-
public void onStringConstructor(@Nonnull String self, @Nonnull String result) {
406+
public void onStringConstructor(@Nonnull CharSequence self, @Nonnull String result) {
407407
if (!canBeTainted(self)) {
408408
return;
409409
}

dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/propagation/StringModuleTest.groovy

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,47 @@ class StringModuleTest extends IastModuleImplTestBase {
810810
"A==>\u00cc\u00cc\u00cc<==B" | "a==>ììì<==b" | "en" | 5 | 5 | [[1, 3]]
811811
}
812812
813+
void 'onStringConstructor (#input)'() {
814+
given:
815+
final taintedObjects = ctx.getTaintedObjects()
816+
final self = addFromTaintFormat(taintedObjects, input)
817+
final result = new String(self)
818+
819+
when:
820+
module.onStringConstructor(self, result)
821+
def taintedObject = taintedObjects.get(result)
822+
823+
then:
824+
1 * tracer.activeSpan() >> span
825+
taintFormat(result, taintedObject.getRanges()) == expected
826+
827+
where:
828+
input | expected
829+
"==>123<==" | "==>123<=="
830+
sb("==>123<==") | "==>123<=="
831+
sbf("==>123<==") | "==>123<=="
832+
}
833+
834+
void 'onStringConstructor empty (#input)'() {
835+
given:
836+
final taintedObjects = ctx.getTaintedObjects()
837+
final self = addFromTaintFormat(taintedObjects, input)
838+
final result = new String(self)
839+
840+
when:
841+
module.onStringConstructor(self, result)
842+
843+
then:
844+
null == taintedObjects.get(result)
845+
result == expected
846+
847+
where:
848+
input | expected
849+
"" | ""
850+
sb("") | ""
851+
sbf("") | ""
852+
}
853+
813854
void 'test trim and make sure IastRequestContext is called'() {
814855
given:
815856
final taintedObjects = ctx.getTaintedObjects()
@@ -1269,6 +1310,10 @@ class StringModuleTest extends IastModuleImplTestBase {
12691310
return new StringBuilder(string)
12701311
}
12711312
1313+
private static StringBuilder sbf() {
1314+
return sbf('')
1315+
}
1316+
12721317
private static StringBuffer sbf(final String string) {
12731318
return new StringBuffer(string)
12741319
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package datadog.trace.instrumentation.gradle;
2+
3+
import datadog.trace.api.Config;
4+
import java.io.File;
5+
import java.nio.file.Path;
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import java.util.Properties;
9+
10+
public class GradleDaemonInjectionUtils {
11+
12+
public static Map<String, String> addJavaagentToGradleDaemonProperties(
13+
Map<String, String> jvmOptions) {
14+
File agentJar = Config.get().getCiVisibilityAgentJarFile();
15+
Path agentJarPath = agentJar.toPath();
16+
17+
StringBuilder agentArg = new StringBuilder("-javaagent:").append(agentJarPath).append('=');
18+
19+
Properties systemProperties = System.getProperties();
20+
for (Map.Entry<Object, Object> e : systemProperties.entrySet()) {
21+
String propertyName = (String) e.getKey();
22+
Object propertyValue = e.getValue();
23+
if (propertyName.startsWith(Config.PREFIX)) {
24+
agentArg.append(propertyName).append('=').append(propertyValue).append(',');
25+
}
26+
}
27+
28+
// creating a new map in case jvmOptions is immutable
29+
Map<String, String> updatedJvmOptions = new HashMap<>(jvmOptions);
30+
updatedJvmOptions.merge("org.gradle.jvmargs", agentArg.toString(), (o, n) -> o + " " + n);
31+
return updatedJvmOptions;
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package datadog.trace.instrumentation.gradle;
2+
3+
import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.implementsInterface;
4+
import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named;
5+
6+
import com.google.auto.service.AutoService;
7+
import datadog.trace.agent.tooling.Instrumenter;
8+
import datadog.trace.agent.tooling.InstrumenterModule;
9+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
10+
import java.util.Map;
11+
import net.bytebuddy.asm.Advice;
12+
import net.bytebuddy.description.type.TypeDescription;
13+
import net.bytebuddy.matcher.ElementMatcher;
14+
15+
/**
16+
* This instrumentation targets Gradle Launcher, which is the process that is started with
17+
* `gradle`/`gradlew` commands. The launcher starts Gradle Daemon (if not started yet), which is a
18+
* long-lived process that actually runs builds. The instrumentation injects the tracer and its
19+
* config properties into Gradle Daemon JVM settings when the daemon is started.
20+
*/
21+
@AutoService(InstrumenterModule.class)
22+
public class GradleLauncherInstrumentation extends InstrumenterModule.CiVisibility
23+
implements Instrumenter.ForTypeHierarchy {
24+
25+
public GradleLauncherInstrumentation() {
26+
super("gradle", "gradle-daemon-jvm-options");
27+
}
28+
29+
@Override
30+
public String hierarchyMarkerType() {
31+
return "org.gradle.launcher.configuration.AllProperties";
32+
}
33+
34+
@Override
35+
public ElementMatcher<TypeDescription> hierarchyMatcher() {
36+
return implementsInterface(named(hierarchyMarkerType()));
37+
}
38+
39+
@Override
40+
public void methodAdvice(MethodTransformer transformer) {
41+
transformer.applyAdvice(
42+
named("getProperties"),
43+
GradleLauncherInstrumentation.class.getName() + "$PropertiesAugmentationAdvice");
44+
}
45+
46+
@Override
47+
public String[] helperClassNames() {
48+
return new String[] {
49+
packageName + ".GradleDaemonInjectionUtils",
50+
};
51+
}
52+
53+
@SuppressFBWarnings(
54+
value = "UC_USELESS_OBJECT",
55+
justification = "jvmOptions is the return value of the original method")
56+
public static class PropertiesAugmentationAdvice {
57+
@Advice.OnMethodExit(suppress = Throwable.class)
58+
public static void addJavaagentToGradleDaemonProperties(
59+
@Advice.Return(readOnly = false) Map<String, String> jvmOptions) {
60+
jvmOptions = GradleDaemonInjectionUtils.addJavaagentToGradleDaemonProperties(jvmOptions);
61+
}
62+
}
63+
}

dd-java-agent/instrumentation/java-lang/src/main/java/datadog/trace/instrumentation/java/lang/StringCallSite.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,15 @@ public static String afterTrim(
201201
}
202202

203203
@CallSite.After("void java.lang.String.<init>(java.lang.String)")
204+
@CallSite.After("void java.lang.String.<init>(java.lang.StringBuffer)")
205+
@CallSite.After("void java.lang.String.<init>(java.lang.StringBuilder)")
204206
public static String afterStringConstructor(
205207
@CallSite.AllArguments @Nonnull final Object[] params,
206208
@CallSite.Return @Nonnull final String result) {
207209
final StringModule module = InstrumentationBridge.STRING;
208210
try {
209211
if (module != null) {
210-
module.onStringConstructor((String) params[0], result);
212+
module.onStringConstructor((CharSequence) params[0], result);
211213
}
212214
} catch (final Throwable e) {
213215
module.onUnexpectedException("afterStringConstructor threw", e);

dd-java-agent/instrumentation/java-lang/src/test/groovy/datadog/trace/instrumentation/java/lang/StringCallSiteTest.groovy

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,18 @@ class StringCallSiteTest extends AgentTestRunner {
176176
InstrumentationBridge.registerIastModule(module)
177177

178178
when:
179-
final result = TestStringSuite.stringConstructor("hello")
179+
final result = TestStringSuite.stringConstructor(param)
180180

181181
then:
182-
result == 'hello'
182+
result == expected
183183
1 * module.onStringConstructor(_, _)
184184
0 * _
185+
186+
where:
187+
param | expected
188+
'hello' | 'hello'
189+
new StringBuilder('hello') | 'hello'
190+
new StringBuffer('hello') | 'hello'
185191
}
186192

187193
void 'test string format'() {

dd-java-agent/instrumentation/java-lang/src/test/java/foo/bar/TestStringSuite.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,20 @@ public static String stringConstructor(String self) {
9292
return result;
9393
}
9494

95+
public static String stringConstructor(StringBuffer self) {
96+
LOGGER.debug("Before string stringConstructor {}", self);
97+
final String result = new String(self);
98+
LOGGER.debug("After string stringConstructor {}", result);
99+
return result;
100+
}
101+
102+
public static String stringConstructor(StringBuilder self) {
103+
LOGGER.debug("Before string stringConstructor {}", self);
104+
final String result = new String(self);
105+
LOGGER.debug("After string stringConstructor {}", result);
106+
return result;
107+
}
108+
95109
public static String stringConstructor(final byte[] value) {
96110
LOGGER.debug("Before string stringConstructor {}", value);
97111
final String result = new String(value);

dd-java-agent/instrumentation/kafka-clients-0.11/src/main/java/datadog/trace/instrumentation/kafka_clients/ConsumerCoordinatorInstrumentation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public final class ConsumerCoordinatorInstrumentation extends InstrumenterModule
3131
implements Instrumenter.ForSingleType {
3232

3333
public ConsumerCoordinatorInstrumentation() {
34-
super("kafka");
34+
super("kafka", "kafka-0.11");
3535
}
3636

3737
@Override

0 commit comments

Comments
 (0)