Skip to content
Open
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
39 changes: 39 additions & 0 deletions agent/src/main/java/io/type/pollution/agent/Agent.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,21 @@
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.pool.TypePool;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

Expand All @@ -39,6 +45,8 @@ public class Agent {
private static final int TRACING_DELAY_SECS = Integer.getInteger("io.type.pollution.delay", 0);
private static final Long REPORT_INTERVAL_SECS = Long.getLong("io.type.pollution.report.interval");
private static final boolean ENABLE_LAMBDA_INSTRUMENTATION = Boolean.getBoolean("io.type.pollution.lambda");
private static final String EXPORT_AFFECTS_TO_FILE = System.getProperty("io.type.pollution.export");
public static final boolean TRACE_WITH_DESC = EXPORT_AFFECTS_TO_FILE != null ? true : Boolean.getBoolean("io.type.pollution.trace.withdesc");

public static void premain(String agentArgs, Instrumentation inst) {
if (ENABLE_FULL_STACK_TRACES) {
Expand Down Expand Up @@ -167,6 +175,9 @@ private static void printReport(boolean last) {
summary.append("Date:\t").append(REPORT_TIMESTAMP.format(LocalDateTime.now())).append('\n');
summary.append("Last:\t").append(last).append('\n');
CharSequence typePollutionReport = reportOf(TraceInstanceOf.orderedTypePollutionCountersSnapshot(TYPE_UPDATE_COUNT_MIN));
if (EXPORT_AFFECTS_TO_FILE != null) {
exportAffectedMethods(TraceInstanceOf.orderedTypePollutionCountersSnapshot(TYPE_UPDATE_COUNT_MIN));
}
if (typePollutionReport.length() > 0) {
summary.append("--------------------------\nType Pollution:\n");
summary.append(typePollutionReport);
Expand Down Expand Up @@ -223,6 +234,34 @@ private static void printReport(boolean last) {
}
}

private static void exportAffectedMethods(Collection<TraceInstanceOf.TraceCounter.Snapshot> counters) {
if (counters.isEmpty()) {
return;
}
Set<String> affectedMethods = new HashSet<>();
StringBuilder sb = new StringBuilder();
for (TraceInstanceOf.TraceCounter.Snapshot counter : counters) {
for (TraceInstanceOf.TraceCounter.Snapshot.TraceSnapshot stack : counter.traces) {
String[] traceContents = stack.trace.split("--");
if (affectedMethods.add(traceContents[0])) {
sb.append(traceContents[0]).append("\n");
}
}
}
long pid = ProcessHandle.current().pid();
String fileName = EXPORT_AFFECTS_TO_FILE;
File file = new File(fileName);
if (file.exists()) {
fileName = fileName + "-" + pid + ".txt";
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
writer.write(sb.toString());
System.out.println("Affected methods are dumped to " + fileName);
} catch (IOException e) {
e.printStackTrace();
}
}

private static boolean closeDump() {
try {
DUMP.close();
Expand Down
10 changes: 7 additions & 3 deletions agent/src/main/java/io/type/pollution/agent/ByteBuddyUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.jar.asm.Type;

import static io.type.pollution.agent.Agent.TRACE_WITH_DESC;

public class ByteBuddyUtils {

static class ByteBuddyTypePollutionInstructionAdapter extends net.bytebuddy.jar.asm.MethodVisitor {
Expand All @@ -13,21 +15,23 @@ static class ByteBuddyTypePollutionInstructionAdapter extends net.bytebuddy.jar.
private final String methodName;

private final String classFile;
private final String desc;

private String tracePrefix;

private int line;

protected ByteBuddyTypePollutionInstructionAdapter(int api, net.bytebuddy.jar.asm.MethodVisitor methodVisitor, String classDescriptor, String methodName, String classFile) {
protected ByteBuddyTypePollutionInstructionAdapter(int api, net.bytebuddy.jar.asm.MethodVisitor methodVisitor, String classDescriptor, String methodName, String classFile, String desc) {
super(api, methodVisitor);
this.classDescriptor = classDescriptor;
this.methodName = methodName;
this.classFile = classFile;
this.desc = desc;
}

private String trace() {
if (tracePrefix == null) {
tracePrefix = classDescriptor.replace('/', '.') + "." + methodName + "(" + (classFile != null ? classFile : "Unknown Source)");
tracePrefix = classDescriptor.replace('/', '.') + "." + methodName + (TRACE_WITH_DESC ? desc + "--" : "") + "(" + (classFile != null ? classFile : "Unknown Source)");
}
if (classFile != null) {
return tracePrefix + ":" + line + ")";
Expand Down Expand Up @@ -139,7 +143,7 @@ public void visit(final int version, final int access, final String name, final
public net.bytebuddy.jar.asm.MethodVisitor visitMethod(int flags, String name,
String desc, String signature, String[] exceptions) {
return new ByteBuddyTypePollutionInstructionAdapter(api, super.visitMethod(flags, name, desc,
signature, exceptions), this.name, name, source);
signature, exceptions), this.name, name, source, desc);
}
}
}