Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow disabling muzzle checks for specific methods #7289

Merged
merged 4 commits into from
Dec 12, 2022
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
2 changes: 0 additions & 2 deletions conventions/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ dependencies {
implementation("com.google.guava:guava:31.1-jre")
implementation("gradle.plugin.com.google.protobuf:protobuf-gradle-plugin:0.8.18")
implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.2")
implementation("org.ow2.asm:asm:9.4")
implementation("org.ow2.asm:asm-tree:9.4")
implementation("org.apache.httpcomponents:httpclient:4.5.14")
implementation("org.gradle:test-retry-gradle-plugin:1.5.0")
implementation("org.owasp:dependency-check-gradle:7.4.1")
Expand Down
3 changes: 3 additions & 0 deletions dependencyManagement/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ val autoServiceVersion = "1.0.1"
val autoValueVersion = "1.10.1"
val errorProneVersion = "2.16"
val byteBuddyVersion = "1.12.19"
val asmVersion = "9.4"
val jmhVersion = "1.36"
val mockitoVersion = "4.9.0"
val slf4jVersion = "2.0.5"
Expand All @@ -57,6 +58,8 @@ val CORE_DEPENDENCIES = listOf(
"net.bytebuddy:byte-buddy-dep:${byteBuddyVersion}",
"net.bytebuddy:byte-buddy-agent:${byteBuddyVersion}",
"net.bytebuddy:byte-buddy-gradle-plugin:${byteBuddyVersion}",
"org.ow2.asm:asm:${asmVersion}",
"org.ow2.asm:asm-tree:${asmVersion}",
"org.openjdk.jmh:jmh-core:${jmhVersion}",
"org.openjdk.jmh:jmh-generator-bytecode:${jmhVersion}",
"org.mockito:mockito-core:${mockitoVersion}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ plugins {
}

dependencies {
compileOnly(project(":muzzle"))

compileOnly("com.google.auto.value:auto-value-annotations")
annotationProcessor("com.google.auto.value:auto-value")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.util.VirtualField;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import io.opentelemetry.javaagent.tooling.muzzle.NoMuzzle;
import javax.annotation.Nullable;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.consumer.ConsumerRecord;
Expand All @@ -23,22 +21,6 @@ final class InstrumentedRecordInterceptor<K, V> implements RecordInterceptor<K,
VirtualField.find(ConsumerRecord.class, Context.class);
private static final VirtualField<ConsumerRecord<?, ?>, State<ConsumerRecord<?, ?>>> stateField =
VirtualField.find(ConsumerRecord.class, State.class);
private static final MethodHandle interceptRecord;

static {
MethodHandle interceptRecordHandle;
try {
interceptRecordHandle =
MethodHandles.lookup()
.findVirtual(
RecordInterceptor.class,
"intercept",
MethodType.methodType(ConsumerRecord.class, ConsumerRecord.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
interceptRecordHandle = null;
}
interceptRecord = interceptRecordHandle;
}

private final Instrumenter<ConsumerRecord<?, ?>, Void> processInstrumenter;
@Nullable private final RecordInterceptor<K, V> decorated;
Expand All @@ -50,25 +32,13 @@ final class InstrumentedRecordInterceptor<K, V> implements RecordInterceptor<K,
this.decorated = decorated;
}

@SuppressWarnings({
"deprecation",
"unchecked"
}) // implementing deprecated method (removed in 3.0) for better compatibility
@NoMuzzle
@SuppressWarnings(
"deprecation") // implementing deprecated method (removed in 3.0) for better compatibility
@Override
public ConsumerRecord<K, V> intercept(ConsumerRecord<K, V> record) {
if (interceptRecord == null) {
return null;
}
start(record);
if (decorated == null) {
return null;
}
try {
return (ConsumerRecord<K, V>) interceptRecord.invoke(decorated, record);
} catch (Throwable e) {
rethrow(e);
return null; // unreachable
}
return decorated == null ? record : decorated.intercept(record);
}

@Override
Expand All @@ -77,11 +47,6 @@ public ConsumerRecord<K, V> intercept(ConsumerRecord<K, V> record, Consumer<K, V
return decorated == null ? record : decorated.intercept(record, consumer);
}

@SuppressWarnings("unchecked")
private static <E extends Throwable> void rethrow(Throwable e) throws E {
throw (E) e;
}

private void start(ConsumerRecord<K, V> record) {
Context parentContext = getParentContext(record);

Expand Down
28 changes: 21 additions & 7 deletions licenses/licenses.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions muzzle/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies {
annotationProcessor("com.google.auto.value:auto-value")

api("net.bytebuddy:byte-buddy-dep")
implementation("org.ow2.asm:asm-tree")

implementation(project(":javaagent-bootstrap"))
implementation(project(":instrumentation-api"))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.tooling.muzzle;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/** Skip muzzle checks for methods annotated with this annotation. */
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface NoMuzzle {}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.MethodNode;

/** Visit a class and collect all references made by the visited class. */
// Additional things we could check
Expand Down Expand Up @@ -244,11 +246,33 @@ public MethodVisitor visitMethod(
.build());
}

MethodVisitor methodVisitor =
super.visitMethod(access, name, descriptor, signature, exceptions);
MethodVisitor methodNode =
new MethodNode(Opcodes.ASM9, access, name, descriptor, signature, exceptions) {
@Override
public void visitEnd() {
super.visitEnd();

boolean skip = false;
if (invisibleAnnotations != null) {
for (AnnotationNode annotationNode : invisibleAnnotations) {
if (Type.getDescriptor(NoMuzzle.class).equals(annotationNode.desc)) {
skip = true;
break;
}
}
}
MethodVisitor target =
skip ? methodVisitor : new AdviceReferenceMethodVisitor(methodVisitor);
if (target != null) {
accept(target);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow, that's some tricky chaining👍

}
}
};
// Additional references we could check
// - Classes in signature (return type, params) and visible from this package
return new AdviceReferenceMethodVisitor(
new VirtualFieldCollectingMethodVisitor(
super.visitMethod(access, name, descriptor, signature, exceptions)));
return new VirtualFieldCollectingMethodVisitor(methodNode);
}

private static VisibilityFlag computeVisibilityFlag(int access) {
Expand Down