diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java index e291ba8d8aa..62dff6442d9 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/CapturedSnapshotTest.java @@ -2845,6 +2845,7 @@ private TestSnapshotListener setupInstrumentTheWorldTransformer( return listener; } + // TODO: JEP 500 - avoid mutating final fields private void setCorrelationSingleton(Object instance) { Class singletonClass = CorrelationAccess.class.getDeclaredClasses()[0]; try { diff --git a/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/Bug4304Instrumentation.java b/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/Bug4304Instrumentation.java index b185117f882..dcfcfe207cb 100644 --- a/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/Bug4304Instrumentation.java +++ b/dd-java-agent/instrumentation/akka/akka-http/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/appsec/Bug4304Instrumentation.java @@ -16,13 +16,17 @@ import datadog.trace.api.gateway.RequestContext; import datadog.trace.api.gateway.RequestContextSlot; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import de.thetaphi.forbiddenapis.SuppressForbidden; import java.lang.reflect.Field; import java.util.regex.Pattern; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; -/** See https://github.com/akka/akka-http/issues/4304 */ +/** + * See Duplicated 100 responses if there is + * an exception thrown by the unmarshaller + */ @AutoService(InstrumenterModule.class) public class Bug4304Instrumentation extends InstrumenterModule.AppSec implements Instrumenter.ForTypeHierarchy, @@ -91,6 +95,11 @@ public void methodAdvice(MethodTransformer transformer) { } static class GraphStageLogicAdvice { + // Field::set() is forbidden because it may be used to mutate final fields, disallowed by + // https://openjdk.org/jeps/500. + // However, in this case the method is called on a non-final field, so it is safe. See + // https://github.com/akka/akka-http/blob/8fb19fce3548c3bfa1e8ebcb1115be29f342df69/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala#L588 + @SuppressForbidden @Advice.OnMethodExit(suppress = Throwable.class) static void after(@Advice.This GraphStageLogic thiz) throws NoSuchFieldException, IllegalAccessException { diff --git a/dd-java-agent/instrumentation/weaver-0.9/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java b/dd-java-agent/instrumentation/weaver-0.9/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java index f28a45f03c5..fe8e60e4fd2 100644 --- a/dd-java-agent/instrumentation/weaver-0.9/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java +++ b/dd-java-agent/instrumentation/weaver-0.9/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java @@ -5,6 +5,7 @@ import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; +import de.thetaphi.forbiddenapis.SuppressForbidden; import java.lang.reflect.Field; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -42,6 +43,8 @@ public void methodAdvice(MethodTransformer transformer) { } public static class SbtTaskCreationAdvice { + // TODO: JEP 500 - avoid mutating final fields + @SuppressForbidden @Advice.OnMethodExit(suppress = Throwable.class) public static void onTaskCreation( @Advice.This Object sbtTask, @Advice.FieldValue("taskDef") TaskDef taskDef) { diff --git a/gradle/forbiddenApiFilters/main.txt b/gradle/forbiddenApiFilters/main.txt index db69659cb7a..334e0d79822 100644 --- a/gradle/forbiddenApiFilters/main.txt +++ b/gradle/forbiddenApiFilters/main.txt @@ -1,7 +1,7 @@ # loads and instantiates a class which may be inefficient depending on context java.lang.Class#forName(java.lang.String) -# String methods which uses regexes for matching +# String methods which use regexes for matching java.lang.String#split(java.lang.String) java.lang.String#split(java.lang.String,int) java.lang.String#replaceAll(java.lang.String,java.lang.String) @@ -34,6 +34,19 @@ java.lang.System#err java.lang.System#getenv() java.lang.System#getenv(java.lang.String) -#Use jdk LongAdder +# use jdk LongAdder @defaultMessage use LongAdder instead of the legacy jctools FixedSizeStripedLongCounter org.jctools.counters.FixedSizeStripedLongCounter + +# avoid methods that mutate final fields, as this will soon be disallowed. For more details: https://openjdk.org/jeps/500. +@defaultMessage Avoid mutating final fields (e.g. with methods such as Field::set and MethodHandles.Lookup::unreflectSetter). If the field is not final, override with @SuppressForbidden. +java.lang.reflect.Field#set(java.lang.Object,java.lang.Object) +java.lang.reflect.Field#setBoolean(java.lang.Object,boolean) +java.lang.reflect.Field#setByte(java.lang.Object,byte) +java.lang.reflect.Field#setChar(java.lang.Object,char) +java.lang.reflect.Field#setShort(java.lang.Object,short) +java.lang.reflect.Field#setInt(java.lang.Object,int) +java.lang.reflect.Field#setLong(java.lang.Object,long) +java.lang.reflect.Field#setFloat(java.lang.Object,float) +java.lang.reflect.Field#setDouble(java.lang.Object,double) +java.lang.invoke.MethodHandles.Lookup#unreflectSetter(java.lang.reflect.Field) diff --git a/internal-api/src/main/java/datadog/trace/api/iast/InstrumentationBridge.java b/internal-api/src/main/java/datadog/trace/api/iast/InstrumentationBridge.java index 7c5c9d1ae3f..835364fafcf 100644 --- a/internal-api/src/main/java/datadog/trace/api/iast/InstrumentationBridge.java +++ b/internal-api/src/main/java/datadog/trace/api/iast/InstrumentationBridge.java @@ -29,6 +29,7 @@ import datadog.trace.api.iast.sink.XContentTypeModule; import datadog.trace.api.iast.sink.XPathInjectionModule; import datadog.trace.api.iast.sink.XssModule; +import de.thetaphi.forbiddenapis.SuppressForbidden; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -124,6 +125,10 @@ private static M get(final Field field) { } } + // Field::set() is forbidden because it may be used to mutate final fields, disallowed by + // https://openjdk.org/jeps/500. + // However, in this case the method is called on a non-final field, so it is safe. + @SuppressForbidden private static void set(final Field field, final IastModule module) { try { field.set(null, module); diff --git a/internal-api/src/main/java/datadog/trace/util/UnsafeUtils.java b/internal-api/src/main/java/datadog/trace/util/UnsafeUtils.java index cc0830b68c8..06cd5f832a0 100644 --- a/internal-api/src/main/java/datadog/trace/util/UnsafeUtils.java +++ b/internal-api/src/main/java/datadog/trace/util/UnsafeUtils.java @@ -1,5 +1,6 @@ package datadog.trace.util; +import de.thetaphi.forbiddenapis.SuppressForbidden; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import org.slf4j.Logger; @@ -57,6 +58,8 @@ public static T tryShallowClone(T original) { } } + // TODO: JEP 500 - avoid mutating final fields + @SuppressForbidden private static void cloneFields(Class clazz, Object original, Object clone) throws Exception { for (Field field : clazz.getDeclaredFields()) { if ((field.getModifiers() & Modifier.STATIC) != 0) {