From 07725505345c28fd96b6a66141e323dc981ac5ea Mon Sep 17 00:00:00 2001
From: katherine-hough <32645020+katherine-hough@users.noreply.github.com>
Date: Mon, 27 Nov 2023 13:49:24 -0500
Subject: [PATCH] * Fixed issue with failure in AnnotationInstCase not being
reported for Java 8 * Fixed failure in AnnotationInstCase for Java 8 by
patching ASM for Java 8 * Fixed JavaDoc warnings * Refactored
ConfigurationEmbeddingMV * Moved classes not used to by the agent at runtime
to the package edu.columbia.cs.psl.phosphor.agent
---
Phosphor/pom.xml | 54 +++++---
.../cs/psl/phosphor/Configuration.java | 94 +------------
.../cs/psl/phosphor/PCLoggingTransformer.java | 12 +-
.../columbia/cs/psl/phosphor/Phosphor.java | 5 +-
.../cs/psl/phosphor/PhosphorOption.java | 8 +-
.../cs/psl/phosphor/agent/AsmPatcher.java | 44 +++++++
.../agent/ConfigurationEmbeddingMV.java | 80 ++++++++++++
.../EmbeddedPhosphorPatcher.java} | 55 ++------
.../psl/phosphor/agent}/InstrumentUtil.java | 17 ++-
.../InstrumentedJREProxyGenerator.java | 5 +-
.../cs/psl/phosphor/agent/PhosphorAgent.java | 7 +-
.../psl/phosphor/agent/PhosphorPatcher.java | 53 ++++++++
.../psl/phosphor/control/graph/FlowGraph.java | 2 +-
.../ConfigurationEmbeddingMV.java | 110 ----------------
.../phosphor/instrumenter/TaintAdapter.java | 2 +-
.../instrumenter/TaintMethodRecord.java | 5 +-
.../TaintTrackingClassVisitor.java | 20 +--
.../struct/harmony/util/AbstractList.java | 4 +-
.../struct/harmony/util/Comparator.java | 4 +-
.../psl/test/phosphor/AnnotationInstCase.java | 2 +-
.../driver/InstrumentJLinkPlugin.java | 15 ++-
.../cs/psl/phosphor/driver/Instrumenter.java | 1 +
.../cs/psl/phosphor/driver/JLinkInvoker.java | 7 +-
.../cs/psl/phosphor/driver/Packer.java | 123 ++++++------------
.../driver/PhosphorInstrumentation.java | 6 +-
.../phosphor/driver/ResourcePoolPacker.java | 80 ++++++++++++
.../psl/phosphor/plugin/InstrumentMojo.java | 2 +-
27 files changed, 400 insertions(+), 417 deletions(-)
create mode 100644 Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/AsmPatcher.java
create mode 100644 Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/ConfigurationEmbeddingMV.java
rename Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/{PhosphorPatcher.java => agent/EmbeddedPhosphorPatcher.java} (74%)
rename {phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver => Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent}/InstrumentUtil.java (82%)
rename Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/{instrumenter => agent}/InstrumentedJREProxyGenerator.java (96%)
create mode 100644 Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorPatcher.java
delete mode 100644 Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/ConfigurationEmbeddingMV.java
create mode 100644 phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/ResourcePoolPacker.java
diff --git a/Phosphor/pom.xml b/Phosphor/pom.xml
index 5a648514e..925f7e7bd 100644
--- a/Phosphor/pom.xml
+++ b/Phosphor/pom.xml
@@ -59,26 +59,6 @@
true
-
- org.codehaus.mojo
- exec-maven-plugin
-
-
- generate-stubs
-
- java
-
- process-classes
-
- edu.columbia.cs.psl.phosphor.instrumenter.InstrumentedJREProxyGenerator
-
-
- ${project.build.outputDirectory}
-
-
-
-
-
org.apache.maven.plugins
maven-shade-plugin
@@ -131,6 +111,40 @@
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+
+ generate-stubs
+
+ java
+
+ process-classes
+
+ edu.columbia.cs.psl.phosphor.agent.InstrumentedJREProxyGenerator
+
+
+ ${project.build.outputDirectory}
+
+
+
+
+ patch
+
+ java
+
+ package
+
+ edu.columbia.cs.psl.phosphor.agent.PhosphorPatcher
+
+
+ ${project.build.directory}/${project.build.finalName}.jar
+
+
+
+
+
org.apache.maven.plugins
maven-compiler-plugin
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/Configuration.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/Configuration.java
index ca722dda9..d19cbb78d 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/Configuration.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/Configuration.java
@@ -3,9 +3,7 @@
import edu.columbia.cs.psl.phosphor.control.ControlFlowManager;
import edu.columbia.cs.psl.phosphor.control.standard.StandardControlFlowManager;
import edu.columbia.cs.psl.phosphor.instrumenter.DataAndControlFlowTagFactory;
-import edu.columbia.cs.psl.phosphor.instrumenter.TaintAdapter;
import edu.columbia.cs.psl.phosphor.instrumenter.TaintTagFactory;
-import edu.columbia.cs.psl.phosphor.instrumenter.TaintTrackingClassVisitor;
import edu.columbia.cs.psl.phosphor.runtime.DerivedTaintListener;
import edu.columbia.cs.psl.phosphor.runtime.Taint;
import edu.columbia.cs.psl.phosphor.runtime.TaintSourceWrapper;
@@ -14,36 +12,30 @@
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Properties;
-
public class Configuration {
-
public static final int ASM_VERSION = Opcodes.ASM9;
public static final String TAINT_TAG_DESC = "Ledu/columbia/cs/psl/phosphor/runtime/Taint;";
public static final String TAINT_TAG_INTERNAL_NAME = "edu/columbia/cs/psl/phosphor/runtime/Taint";
public static final String TAINT_TAG_ARRAY_INTERNAL_NAME = "edu/columbia/cs/psl/phosphor/struct/TaggedArray";
public static final Object TAINT_TAG_STACK_TYPE = "edu/columbia/cs/psl/phosphor/runtime/Taint";
public static final int TAINT_LOAD_OPCODE = Opcodes.ALOAD;
- public static final int TAINT_STORE_OPCODE = Opcodes.ASTORE;
public static final Class> TAINT_TAG_OBJ_CLASS = (Taint.class);
public static final boolean DEBUG_STACK_FRAME_WRAPPERS = false;
public static boolean SKIP_LOCAL_VARIABLE_TABLE = false;
- public static String ADDL_IGNORE = null;
+ public static String IGNORE = null;
public static boolean REFERENCE_TAINTING = true;
- public static boolean DATAFLOW_TRACKING = true; //default
+ // default
+ public static boolean DATAFLOW_TRACKING = true;
public static boolean ARRAY_INDEX_TRACKING = false;
- public static boolean IMPLICIT_TRACKING = false; //TODO need to set this at runtime somewhere
+ // TODO need to set this at runtime somewhere
+ public static boolean IMPLICIT_TRACKING = false;
public static boolean IMPLICIT_LIGHT_TRACKING;
public static boolean IMPLICIT_HEADERS_NO_TRACKING = false;
public static boolean IMPLICIT_EXCEPTION_FLOW = false;
public static boolean WITHOUT_BRANCH_NOT_TAKEN = false;
- public static boolean SINGLE_TAINT_LABEL = false;
public static boolean ANNOTATE_LOOPS = false;
public static boolean WITH_ENUM_BY_VAL = false;
public static boolean WITH_UNBOX_ACMPEQ = false;
- public static boolean PREALLOC_STACK_OPS = false;
public static boolean WITHOUT_PROPAGATION = false;
public static boolean WITHOUT_FIELD_HIDING = false;
public static boolean READ_AND_SAVE_BCI = false;
@@ -55,17 +47,11 @@ public class Configuration {
public static String controlFlowManagerPackage = null;
public static boolean QUIET_MODE = false;
public static boolean IS_JAVA_8 = true;
-
public static Set ignoredMethods = new HashSet<>();
-
- public static Class extends TaintAdapter> extensionMethodVisitor;
- public static Class extends ClassVisitor> extensionClassVisitor;
public static TaintTagFactory taintTagFactory = new DataAndControlFlowTagFactory();
public static String taintTagFactoryPackage = null;
public static TaintSourceWrapper> autoTainter = new TaintSourceWrapper<>();
public static DerivedTaintListener derivedTaintListener = new DerivedTaintListener();
- public static boolean WITH_HEAVY_OBJ_EQUALS_HASHCODE = false;
- public static TransformationCache CACHE = null;
public static boolean TAINT_THROUGH_SERIALIZATION = true;
private Configuration() {
@@ -76,75 +62,5 @@ public static void init() {
if (IMPLICIT_TRACKING) {
ARRAY_INDEX_TRACKING = true;
}
- if (TaintTrackingClassVisitor.class.getClassLoader() != null) {
- URL r = TaintTrackingClassVisitor.class.getClassLoader().getResource("phosphor-mv");
- if (r != null) {
- try {
- Properties props = new Properties();
- props.load(r.openStream());
- if (props.containsKey("extraMV")) {
- extensionMethodVisitor = (Class extends TaintAdapter>) Class.forName(props.getProperty("extraMV"));
- }
- if (props.containsKey("extraCV")) {
- extensionClassVisitor = (Class extends ClassVisitor>) Class.forName(props.getProperty("extraCV"));
- }
- if(props.containsKey("taintTagFactory")) {
- taintTagFactory = (TaintTagFactory) Class.forName(props.getProperty("taintTagFactory")).newInstance();
- }
- if(props.containsKey("derivedTaintListener")) {
- derivedTaintListener = (DerivedTaintListener) Class.forName(props.getProperty("derivedTaintListener")).newInstance();
- }
- } catch(IOException ex) {
- //fail silently
- } catch(ClassNotFoundException | InstantiationException | IllegalAccessException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- public static class Method {
- final String name;
- final String owner;
-
- public Method(String name, String owner) {
- this.name = name;
- this.owner = owner;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- result = prime * result + ((owner == null) ? 0 : owner.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if(this == obj) {
- return true;
- }
- if(obj == null) {
- return false;
- }
- if(getClass() != obj.getClass()) {
- return false;
- }
- Method other = (Method) obj;
- if(name == null) {
- if(other.name != null) {
- return false;
- }
- } else if(!name.equals(other.name)) {
- return false;
- }
- if(owner == null) {
- return other.owner == null;
- } else {
- return owner.equals(other.owner);
- }
- }
}
}
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PCLoggingTransformer.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PCLoggingTransformer.java
index 218385167..e9454868d 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PCLoggingTransformer.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PCLoggingTransformer.java
@@ -73,8 +73,8 @@ public byte[] transform(ClassLoader loader, final String className2, Class> cl
return classfileBuffer;
}
}
- if (Configuration.CACHE != null) {
- byte[] cachedClass = Configuration.CACHE.load(className, classfileBuffer);
+ if (Phosphor.CACHE != null) {
+ byte[] cachedClass = Phosphor.CACHE.load(className, classfileBuffer);
if (cachedClass != null) {
return cachedClass;
}
@@ -114,8 +114,8 @@ public byte[] transform(ClassLoader loader, final String className2, Class> cl
fos.write(instrumentedBytes);
fos.close();
}
- if (Configuration.CACHE != null) {
- Configuration.CACHE.store(className, classfileBuffer, instrumentedBytes);
+ if (Phosphor.CACHE != null) {
+ Phosphor.CACHE.store(className, classfileBuffer, instrumentedBytes);
}
return instrumentedBytes;
} catch (Throwable ex) {
@@ -162,10 +162,6 @@ static byte[] instrumentWithRetry(ClassReader cr, byte[] classFileBuffer, boolea
//
}
}
- if (Configuration.extensionClassVisitor != null) {
- Constructor extends ClassVisitor> extra = Configuration.extensionClassVisitor.getConstructor(ClassVisitor.class, Boolean.TYPE);
- _cv = extra.newInstance(_cv, skipFrames);
- }
if (Phosphor.DEBUG || TaintUtils.VERIFY_CLASS_GENERATION) {
_cv = new CheckClassAdapter(_cv, false);
}
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/Phosphor.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/Phosphor.java
index ad3719a4d..335a5988f 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/Phosphor.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/Phosphor.java
@@ -14,6 +14,7 @@ public final class Phosphor {
public static boolean INSTRUMENTATION_EXCEPTION_OCCURRED = false;
public static ClassLoader bigLoader = Phosphor.class.getClassLoader();
public static InstrumentationAdaptor instrumentation;
+ public static TransformationCache CACHE = null;
private Phosphor() {
throw new AssertionError("Tried to instantiate static agent class: " + getClass());
@@ -27,7 +28,7 @@ public static void initialize(String agentArgs, InstrumentationAdaptor instrumen
PhosphorOption.configure(true, parseOptions(agentArgs));
}
if (System.getProperty("phosphorCacheDirectory") != null) {
- Configuration.CACHE = TransformationCache.getInstance(System.getProperty("phosphorCacheDirectory"));
+ CACHE = TransformationCache.getInstance(System.getProperty("phosphorCacheDirectory"));
}
// Ensure that BasicSourceSinkManager and anything needed to call isSourceOrSinkOrTaintThrough gets initialized
BasicSourceSinkManager.loadTaintMethods();
@@ -74,7 +75,7 @@ public static boolean isIgnoredClass(String owner) {
|| taintTagFactoryPackage != null && StringUtils.startsWith(owner, taintTagFactoryPackage)
|| controlFlowManagerPackage != null && StringUtils.startsWith(owner, controlFlowManagerPackage)
|| (Configuration.controlFlowManager != null && Configuration.controlFlowManager.isIgnoredClass(owner))
- || (Configuration.ADDL_IGNORE != null && StringUtils.startsWith(owner, Configuration.ADDL_IGNORE))
+ || (Configuration.IGNORE != null && StringUtils.startsWith(owner, Configuration.IGNORE))
// || !owner.startsWith("edu/columbia/cs/psl")
// For these classes: HotSpot expects fields to be at hardcoded offsets of these classes.
// If we instrument them, it will break those assumptions and segfault.
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PhosphorOption.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PhosphorOption.java
index 8af955070..26a5609d0 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PhosphorOption.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PhosphorOption.java
@@ -192,7 +192,7 @@ public void configure(boolean forRuntimeInst, boolean isPresent, CommandLine com
.argType(String.class)) {
@Override
public void configure(boolean forRuntimeInst, boolean isPresent, CommandLine commandLine) {
- Configuration.CACHE = isPresent ? TransformationCache.getInstance(commandLine.getOptionValue(optionName)) :
+ Phosphor.CACHE = isPresent ? TransformationCache.getInstance(commandLine.getOptionValue(optionName)) :
null;
}
},
@@ -273,7 +273,7 @@ public void configure(boolean forRuntimeInst, boolean isPresent, CommandLine com
@Override
public void configure(boolean forRuntimeInst, boolean isPresent, CommandLine commandLine) {
if(isPresent) {
- Configuration.ADDL_IGNORE = commandLine.getOptionValue(optionName);
+ Configuration.IGNORE = commandLine.getOptionValue(optionName);
}
}
},
@@ -295,9 +295,7 @@ public void configure(boolean forRuntimeInst, boolean isPresent, CommandLine com
true, false).argType(String.class).alternativeName("jvmModules")) {
@Override
public void configure(boolean forRuntimeInst, boolean isPresent, CommandLine commandLine) {
- /*
- Only used by instrumenter, which reads properties map
- */
+ // Only used by instrumenter, which reads properties map
}
};
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/AsmPatcher.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/AsmPatcher.java
new file mode 100644
index 000000000..e7f3cb9ab
--- /dev/null
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/AsmPatcher.java
@@ -0,0 +1,44 @@
+package edu.columbia.cs.psl.phosphor.agent;
+
+import edu.columbia.cs.psl.phosphor.Configuration;
+import edu.columbia.cs.psl.phosphor.instrumenter.TaintMethodRecord;
+import org.objectweb.asm.*;
+
+public class AsmPatcher extends ClassVisitor {
+ private static final String ASM_PREFIX = "edu/columbia/cs/psl/phosphor/org/objectweb/asm/";
+ private static final Type OBJECT_TYPE = Type.getType(Object.class);
+
+ public AsmPatcher(ClassWriter cw) {
+ super(Configuration.ASM_VERSION, cw);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String descriptor, String signature, String[] exceptions) {
+ MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
+ return new MethodVisitor(api, mv) {
+
+ @Override
+ public void visitMethodInsn(
+ int opcode, String owner, String name, String descriptor, boolean isInterface) {
+ super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ // Ensure that the return value is unwrapped if necessary
+ if (owner.startsWith("java/") && OBJECT_TYPE.equals(Type.getReturnType(descriptor))) {
+ TaintMethodRecord.TAINTED_REFERENCE_ARRAY_UNWRAP.delegateVisit(mv);
+ }
+ }
+ };
+ }
+
+ public static byte[] patch(byte[] classFileBuffer) {
+ ClassReader cr = new ClassReader(classFileBuffer);
+ ClassWriter cw = new ClassWriter(cr, 0);
+ ClassVisitor cv = new AsmPatcher(cw);
+ cr.accept(cv, 0);
+ return cw.toByteArray();
+ }
+
+ public static boolean isApplicable(String className) {
+ return className.startsWith(ASM_PREFIX);
+ }
+}
\ No newline at end of file
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/ConfigurationEmbeddingMV.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/ConfigurationEmbeddingMV.java
new file mode 100644
index 000000000..e204be3a7
--- /dev/null
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/ConfigurationEmbeddingMV.java
@@ -0,0 +1,80 @@
+package edu.columbia.cs.psl.phosphor.agent;
+
+import edu.columbia.cs.psl.phosphor.Configuration;
+import edu.columbia.cs.psl.phosphor.instrumenter.TaintMethodRecord;
+import edu.columbia.cs.psl.phosphor.struct.harmony.util.Set;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import static org.objectweb.asm.Opcodes.*;
+
+/**
+ * Embeds the current values for the field of {@link Configuration} into the class file for {@link Configuration}.
+ */
+public class ConfigurationEmbeddingMV extends MethodVisitor {
+ public ConfigurationEmbeddingMV(MethodVisitor mv) {
+ super(Configuration.ASM_VERSION, mv);
+ }
+
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
+ if (opcode == Opcodes.PUTSTATIC) {
+ try {
+ Field f = Configuration.class.getField(name);
+ f.setAccessible(true);
+ if (Modifier.isPublic(f.getModifiers()) || !Modifier.isFinal(f.getModifiers())) {
+ replaceValue(Type.getType(descriptor), f.get(null));
+ }
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException("Failed to access field owned by " + Configuration.class, e);
+ }
+ }
+ super.visitFieldInsn(opcode, owner, name, descriptor);
+ }
+
+ public void replaceValue(Type type, Object newValue) {
+ switch (type.getSort()) {
+ case Type.VOID:
+ case Type.ARRAY:
+ case Type.METHOD:
+ return;
+ }
+ // Pop the original value
+ super.visitInsn(type.getSize() == 1 ? POP : POP2);
+ // Push the new value
+ if (type.getSort() != Type.OBJECT || newValue instanceof String) {
+ super.visitLdcInsn(newValue);
+ } else if (newValue == null) {
+ super.visitInsn(ACONST_NULL);
+ } else if (newValue instanceof Class) {
+ mv.visitLdcInsn(Type.getType((Class>) newValue));
+ } else if (newValue instanceof Set) {
+ Set> set = (Set>) newValue;
+ newInstance(newValue.getClass());
+ for (Object element : set) {
+ super.visitInsn(DUP);
+ super.visitLdcInsn(element);
+ TaintMethodRecord.SET_ADD.delegateVisit(mv);
+ super.visitInsn(POP);
+ }
+ } else {
+ newInstance(newValue.getClass());
+ }
+ }
+
+ private void newInstance(Class> clazz) {
+ try {
+ clazz.getConstructor();
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("Public, zero-argument constructor not found for: " + clazz);
+ }
+ String className = Type.getInternalName(clazz);
+ super.visitTypeInsn(Opcodes.NEW, className);
+ super.visitInsn(DUP);
+ super.visitMethodInsn(INVOKESPECIAL, className, "", "()V", false);
+ }
+}
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PhosphorPatcher.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/EmbeddedPhosphorPatcher.java
similarity index 74%
rename from Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PhosphorPatcher.java
rename to Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/EmbeddedPhosphorPatcher.java
index 5c2328ecb..373d18a55 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/PhosphorPatcher.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/EmbeddedPhosphorPatcher.java
@@ -1,7 +1,6 @@
-package edu.columbia.cs.psl.phosphor;
+package edu.columbia.cs.psl.phosphor.agent;
-import edu.columbia.cs.psl.phosphor.instrumenter.ConfigurationEmbeddingMV;
-import edu.columbia.cs.psl.phosphor.instrumenter.TaintMethodRecord;
+import edu.columbia.cs.psl.phosphor.Configuration;
import edu.columbia.cs.psl.phosphor.runtime.jdk.unsupported.UnsafeProxy;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.ClassNode;
@@ -11,14 +10,17 @@
import java.io.IOException;
import java.io.InputStream;
-public class PhosphorPatcher {
+/**
+ * Performs patching of embedded Phosphors (for Java 9+).
+ */
+public class EmbeddedPhosphorPatcher {
private final boolean patchUnsafeNames;
- public PhosphorPatcher(byte[] unsafeClassFileBuffer) {
+ public EmbeddedPhosphorPatcher(byte[] unsafeClassFileBuffer) {
this(shouldPatchUnsafeNames(unsafeClassFileBuffer));
}
- public PhosphorPatcher(boolean patchUnsafeNames) {
+ public EmbeddedPhosphorPatcher(boolean patchUnsafeNames) {
this.patchUnsafeNames = patchUnsafeNames;
}
@@ -28,8 +30,6 @@ public byte[] patch(String name, byte[] content) throws IOException {
} else if (name.equals("edu/columbia/cs/psl/phosphor/runtime/RuntimeJDKInternalUnsafePropagator.class")) {
return transformUnsafePropagator(
new ByteArrayInputStream(content), "jdk/internal/misc/Unsafe", patchUnsafeNames);
- } else if (AsmPatchingCV.isApplicable(name)) {
- return AsmPatchingCV.patch(content);
} else {
return content;
}
@@ -153,43 +153,4 @@ public void visitLocalVariable(
};
}
}
-
- private static class AsmPatchingCV extends ClassVisitor {
- private static final String ASM_PREFIX = "edu/columbia/cs/psl/phosphor/org/objectweb/asm/";
- private static final Type OBJECT_TYPE = Type.getType(Object.class);
-
- public AsmPatchingCV(ClassWriter cw) {
- super(Configuration.ASM_VERSION, cw);
- }
-
- @Override
- public MethodVisitor visitMethod(
- int access, String name, String descriptor, String signature, String[] exceptions) {
- MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
- return new MethodVisitor(api, mv) {
-
- @Override
- public void visitMethodInsn(
- int opcode, String owner, String name, String descriptor, boolean isInterface) {
- super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
- // Ensure that the return value is unwrapped if necessary
- if (owner.startsWith("java/") && OBJECT_TYPE.equals(Type.getReturnType(descriptor))) {
- TaintMethodRecord.TAINTED_REFERENCE_ARRAY_UNWRAP.delegateVisit(mv);
- }
- }
- };
- }
-
- public static byte[] patch(byte[] classFileBuffer) {
- ClassReader cr = new ClassReader(classFileBuffer);
- ClassWriter cw = new ClassWriter(cr, 0);
- ClassVisitor cv = new AsmPatchingCV(cw);
- cr.accept(cv, 0);
- return cw.toByteArray();
- }
-
- public static boolean isApplicable(String className) {
- return className.startsWith(ASM_PREFIX);
- }
- }
}
diff --git a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/InstrumentUtil.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/InstrumentUtil.java
similarity index 82%
rename from phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/InstrumentUtil.java
rename to Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/InstrumentUtil.java
index 1312ad2e5..926db47a0 100644
--- a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/InstrumentUtil.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/InstrumentUtil.java
@@ -1,6 +1,7 @@
-package edu.columbia.cs.psl.phosphor.driver;
+package edu.columbia.cs.psl.phosphor.agent;
import java.io.*;
+import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -72,7 +73,6 @@ public static byte[] checksum(byte[] input) {
return md5Inst.digest(input);
}
-
/**
* Creates the specified directory if it does not already exist.
*
@@ -84,4 +84,17 @@ public static void ensureDirectory(File dir) throws IOException {
throw new IOException("Failed to create directory: " + dir);
}
}
+
+ public static void deleteFile(File file) throws IOException {
+ if (file.exists() && !file.delete()) {
+ throw new IOException("Failed to delete file: " + file);
+ }
+ }
+
+ public static File createTemporaryFile(String prefix, String suffix) throws IOException {
+ File file = Files.createTempFile(prefix, suffix).toFile();
+ file.deleteOnExit();
+ ensureDirectory(file.getParentFile());
+ return file;
+ }
}
\ No newline at end of file
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/InstrumentedJREProxyGenerator.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/InstrumentedJREProxyGenerator.java
similarity index 96%
rename from Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/InstrumentedJREProxyGenerator.java
rename to Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/InstrumentedJREProxyGenerator.java
index 7a8a988a6..b0f5ff366 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/InstrumentedJREProxyGenerator.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/InstrumentedJREProxyGenerator.java
@@ -1,8 +1,7 @@
-package edu.columbia.cs.psl.phosphor.instrumenter;
+package edu.columbia.cs.psl.phosphor.agent;
import edu.columbia.cs.psl.phosphor.Configuration;
-import edu.columbia.cs.psl.phosphor.PhosphorPatcher;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.util.CheckClassAdapter;
@@ -23,7 +22,7 @@ public static void main(String[] args) throws IOException {
String pathToUnsafePropagator = outputDir + "/edu/columbia/cs/psl/phosphor/runtime/jdk/unsupported/RuntimeSunMiscUnsafePropagator.class";
InputStream sunMiscUnsafeIn = new FileInputStream(pathToUnsafePropagator);
- byte[] instrumentedUnsafe = PhosphorPatcher.transformUnsafePropagator(sunMiscUnsafeIn,
+ byte[] instrumentedUnsafe = EmbeddedPhosphorPatcher.transformUnsafePropagator(sunMiscUnsafeIn,
"sun/misc/Unsafe", false);
Files.write(Paths.get(pathToUnsafePropagator), instrumentedUnsafe);
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorAgent.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorAgent.java
index f10b85ae5..0e7959dbd 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorAgent.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorAgent.java
@@ -8,7 +8,6 @@
import edu.columbia.cs.psl.phosphor.runtime.PhosphorStackFrame;
import java.lang.instrument.ClassFileTransformer;
-import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.security.ProtectionDomain;
@@ -70,8 +69,7 @@ public byte[] transform(
Class> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer,
- PhosphorStackFrame frame)
- throws IllegalClassFormatException {
+ PhosphorStackFrame frame) {
return transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
}
@@ -81,8 +79,7 @@ public byte[] transform(
String className,
Class> classBeingRedefined,
ProtectionDomain protectionDomain,
- byte[] classfileBuffer)
- throws IllegalClassFormatException {
+ byte[] classfileBuffer) {
try {
if (!INITED) {
Configuration.init();
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorPatcher.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorPatcher.java
new file mode 100644
index 000000000..eeb834e50
--- /dev/null
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/agent/PhosphorPatcher.java
@@ -0,0 +1,53 @@
+package edu.columbia.cs.psl.phosphor.agent;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+public class PhosphorPatcher {
+ public static void main(String[] args) throws IOException {
+ File archive = new File(args[0]);
+ File temp = InstrumentUtil.createTemporaryFile("patch-", ".jar");
+ try (ZipInputStream zin = new ZipInputStream(Files.newInputStream(archive.toPath()));
+ ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(temp.toPath()))) {
+ for (ZipEntry entry; (entry = zin.getNextEntry()) != null; ) {
+ byte[] content = InstrumentUtil.readAllBytes(zin);
+ if (entry.getName().endsWith(".class")) {
+ content = patch(entry.getName(), content);
+ }
+ writeEntry(zos, entry, content);
+ }
+ }
+ InstrumentUtil.deleteFile(archive);
+ if (!temp.renameTo(archive)) {
+ throw new IOException("Failed to move patched JAR: " + temp);
+ }
+ }
+
+ private static byte[] patch(String name, byte[] classFileBuffer) {
+ if (AsmPatcher.isApplicable(name)) {
+ return AsmPatcher.patch(classFileBuffer);
+ }
+ return classFileBuffer;
+ }
+
+ private static void writeEntry(ZipOutputStream zos, ZipEntry entry, byte[] content) throws IOException {
+ ZipEntry outEntry = new ZipEntry(entry.getName());
+ outEntry.setMethod(entry.getMethod());
+ if (entry.getMethod() == ZipEntry.STORED) {
+ // Uncompressed entries require entry size and CRC
+ outEntry.setSize(content.length);
+ outEntry.setCompressedSize(content.length);
+ CRC32 crc = new CRC32();
+ crc.update(content, 0, content.length);
+ outEntry.setCrc(crc.getValue());
+ }
+ zos.putNextEntry(outEntry);
+ zos.write(content);
+ zos.closeEntry();
+ }
+}
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/control/graph/FlowGraph.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/control/graph/FlowGraph.java
index d548a437e..a2229372a 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/control/graph/FlowGraph.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/control/graph/FlowGraph.java
@@ -528,7 +528,7 @@ public int hashCode() {
* @param fontSize value used for the fontsize attribute of the graph
* @throws NullPointerException if writer is null or printer is null
* @throws IOException if an I/O error occurs while writing to the specified writer
- * @throws IllegalArgumentException if fontSize <= 0
+ * @throws IllegalArgumentException if fontSize <= 0
*/
public void write(Writer writer, String graphName, Comparator vertexComparator,
Function printer, int fontSize) throws IOException {
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/ConfigurationEmbeddingMV.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/ConfigurationEmbeddingMV.java
deleted file mode 100644
index 3d9ed7471..000000000
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/ConfigurationEmbeddingMV.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package edu.columbia.cs.psl.phosphor.instrumenter;
-
-import edu.columbia.cs.psl.phosphor.Configuration;
-import edu.columbia.cs.psl.phosphor.struct.harmony.util.Set;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-
-import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
-import static org.objectweb.asm.Opcodes.ACONST_NULL;
-import static org.objectweb.asm.Opcodes.DUP;
-import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
-import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
-import static org.objectweb.asm.Opcodes.POP;
-import static org.objectweb.asm.Opcodes.POP2;
-
-public class ConfigurationEmbeddingMV extends MethodVisitor {
- public ConfigurationEmbeddingMV(MethodVisitor mv) {
- super(Configuration.ASM_VERSION, mv);
- }
-
- // Embed initialized Configuration class into class file.
- @Override
- public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
- if (opcode == Opcodes.PUTSTATIC) {
- Type type = Type.getType(descriptor);
- Object fieldValue;
- if (name.equals("IS_JAVA_8")) {
- fieldValue = false;
- } else {
- try {
- Field f = Configuration.class.getField(name);
- if ((f.getModifiers() & ACC_PUBLIC) == 0) {
- super.visitFieldInsn(opcode, owner, name, descriptor);
- return;
- }
- f.setAccessible(true);
- fieldValue = f.get(null);
- if (fieldValue instanceof Class) {
- fieldValue = Type.getType((Class>) fieldValue);
- }
- } catch (NoSuchFieldException | IllegalAccessException e) {
- super.visitFieldInsn(opcode, owner, name, descriptor);
- return;
- }
- }
- switch (type.getSort()) {
- case Type.LONG:
- case Type.DOUBLE:
- super.visitInsn(POP2);
- super.visitLdcInsn(fieldValue);
- break;
- case Type.BOOLEAN:
- case Type.INT:
- case Type.FLOAT:
- case Type.SHORT:
- case Type.BYTE:
- case Type.CHAR:
- super.visitInsn(POP);
- super.visitLdcInsn(fieldValue);
- break;
- case Type.OBJECT:
- if (fieldValue == null) {
- super.visitInsn(POP);
- super.visitInsn(ACONST_NULL);
- } else if (descriptor.equals("Ljava/lang/Class;") ||
- descriptor.equals("Ljava/lang/String;") ||
- fieldValue instanceof String) {
- super.visitInsn(POP);
- super.visitLdcInsn(fieldValue);
- } else if (descriptor.equals("Ledu/columbia/cs/psl/phosphor/struct/harmony/util/Set;")) {
- // All sets are Set.
- super.visitInsn(POP);
- String className = fieldValue.getClass().getName().replace(".", "/");
- super.visitTypeInsn(Opcodes.NEW, className);
- super.visitInsn(DUP);
- super.visitMethodInsn(INVOKESPECIAL, className, "", "()V", false);
-
- for (String s : ((Set) fieldValue)) {
- super.visitInsn(DUP);
- super.visitLdcInsn(s);
- super.visitMethodInsn(INVOKEINTERFACE,
- "Ledu/columbia/cs/psl/phosphor/struct/harmony/util/Set;",
- "add", "(Ljava/lang/Object;)Z", true);
- super.visitInsn(POP);
- }
- } else {
- Class> objectClass = fieldValue.getClass();
- try {
- // Make sure constructor is callable.
- Constructor> constructor = objectClass.getDeclaredConstructor();
- if ((constructor.getModifiers() & ACC_PUBLIC) != 0) {
- String className = objectClass.getName().replace(".", "/");
- super.visitInsn(POP);
- super.visitTypeInsn(Opcodes.NEW, className);
- super.visitInsn(DUP);
- super.visitMethodInsn(INVOKESPECIAL, className, "", "()V", false);
- }
- } catch (NoSuchMethodException e) {
- }
- }
- break;
- }
- }
- super.visitFieldInsn(opcode, owner, name, descriptor);
- }
-}
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintAdapter.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintAdapter.java
index 09e5b07d8..9fc252e52 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintAdapter.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintAdapter.java
@@ -146,7 +146,7 @@ public Object getTopOfStackObject() {
}
/**
- * Returns the type of the stack element n down from the top: n=0 -> top of
+ * Returns the type of the stack element n down from the top: n = 0 corresponds to the top of
* stack
*/
public Type getStackTypeAtOffset(int n) {
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintMethodRecord.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintMethodRecord.java
index f0259f787..c9670a594 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintMethodRecord.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintMethodRecord.java
@@ -5,6 +5,7 @@
import edu.columbia.cs.psl.phosphor.control.ControlFlowStack;
import edu.columbia.cs.psl.phosphor.runtime.*;
import edu.columbia.cs.psl.phosphor.struct.*;
+import edu.columbia.cs.psl.phosphor.struct.harmony.util.Set;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@@ -121,7 +122,9 @@ public enum TaintMethodRecord implements MethodRecord {
// Methods from TaintSourceWrapper
AUTO_TAINT(INVOKEVIRTUAL, TaintSourceWrapper.class, "autoTaint", Object.class, false, Object.class, String.class, String.class, int.class),
// TaggedReferenceArray
- TAINTED_REFERENCE_ARRAY_UNWRAP(INVOKESTATIC, TaggedReferenceArray.class, "unwrap", Object.class, false, Object.class);
+ TAINTED_REFERENCE_ARRAY_UNWRAP(INVOKESTATIC, TaggedReferenceArray.class, "unwrap", Object.class, false, Object.class),
+ // Set
+ SET_ADD(INVOKEVIRTUAL, Set.class, "add", boolean.class, true, Object.class);
private final int opcode;
private final String owner;
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintTrackingClassVisitor.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintTrackingClassVisitor.java
index 44ad701ac..59666cc3f 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintTrackingClassVisitor.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/instrumenter/TaintTrackingClassVisitor.java
@@ -18,7 +18,6 @@
import org.objectweb.asm.tree.*;
import java.io.Serializable;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -378,28 +377,12 @@ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[
super.visitFrame(type, nLocal, local, nStack, stack);
}
};
-
- if (Configuration.extensionMethodVisitor != null) {
- try {
- TaintAdapter custom = Configuration.extensionMethodVisitor.getConstructor(Integer.TYPE,
- String.class, String.class, String.class, String.class, String[].class, MethodVisitor.class,
- NeverNullArgAnalyzerAdapter.class, String.class, String.class).newInstance(access,
- className, name, desc, signature, _exceptions, rawMethod, null, classSource,
- classDebug);
- custom.setFields(fields);
- custom.setSuperName(superName);
- return custom;
- } catch (InstantiationException | SecurityException | NoSuchMethodException | InvocationTargetException
- | IllegalArgumentException | IllegalAccessException e) {
- e.printStackTrace();
- }
- }
return rawMethod;
} else {
// this is a native method. we want here to make a $taint method that will call
// the original one.
final MethodVisitor prev = super.visitMethod(access, name, desc, signature, _exceptions);
- MethodNode rawMethod = new MethodNode(Configuration.ASM_VERSION, access, name, desc, signature,
+ return new MethodNode(Configuration.ASM_VERSION, access, name, desc, signature,
_exceptions) {
@Override
public void visitEnd() {
@@ -410,7 +393,6 @@ public void visitEnd() {
}
}
};
- return rawMethod;
}
}
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/struct/harmony/util/AbstractList.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/struct/harmony/util/AbstractList.java
index 31ffdad4e..39fb4b116 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/struct/harmony/util/AbstractList.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/struct/harmony/util/AbstractList.java
@@ -728,9 +728,9 @@ public E set(int location, E object) {
* @return a subList view of this list starting from {@code start}
* (inclusive), and ending with {@code end} (exclusive)
* @throws IndexOutOfBoundsException
- * if (start < 0 || end > size())
+ * if {@code (start < 0 || end > size())}
* @throws IllegalArgumentException
- * if (start > end)
+ * if {@code (start > end)}
*/
public List subList(int start, int end) {
if (0 <= start && end <= size()) {
diff --git a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/struct/harmony/util/Comparator.java b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/struct/harmony/util/Comparator.java
index dc3316022..4000c84d7 100644
--- a/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/struct/harmony/util/Comparator.java
+++ b/Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/struct/harmony/util/Comparator.java
@@ -50,8 +50,8 @@ public interface Comparator {
* an {@code Object}.
* @param object2
* a second {@code Object} to compare with {@code object1}.
- * @return an integer < 0 if {@code object1} is less than {@code object2}, 0 if they are
- * equal, and > 0 if {@code object1} is greater than {@code object2}.
+ * @return an integer less than 0 if {@code object1} is less than {@code object2}, 0 if they are
+ * equal, and greater than 0 if {@code object1} is greater than {@code object2}.
* @throws ClassCastException
* if objects are not of the correct type.
*/
diff --git a/integration-tests/src/test/java/edu/columbia/cs/psl/test/phosphor/AnnotationInstCase.java b/integration-tests/src/test/java/edu/columbia/cs/psl/test/phosphor/AnnotationInstCase.java
index 5f8456bf2..178131703 100644
--- a/integration-tests/src/test/java/edu/columbia/cs/psl/test/phosphor/AnnotationInstCase.java
+++ b/integration-tests/src/test/java/edu/columbia/cs/psl/test/phosphor/AnnotationInstCase.java
@@ -9,7 +9,7 @@
import java.lang.annotation.Target;
import java.lang.reflect.Method;
-public class AnnotationInstCase {
+public class AnnotationInstCase extends BasePhosphorTest{
@Test
public void testEnum() throws ReflectiveOperationException {
Method method = Example.class.getDeclaredMethod("x");
diff --git a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/InstrumentJLinkPlugin.java b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/InstrumentJLinkPlugin.java
index e4d14a193..c01b62aa4 100644
--- a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/InstrumentJLinkPlugin.java
+++ b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/InstrumentJLinkPlugin.java
@@ -13,7 +13,7 @@
public class InstrumentJLinkPlugin implements Plugin {
private Instrumentation instrumentation;
- private Packer packer;
+ private ResourcePoolPacker packer;
@Override
public String getName() {
@@ -47,18 +47,19 @@ public void configure(Map config) {
}
@Override
- public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
- packer = new Packer(in, instrumentation);
- in.transformAndCopy(e -> transform(e, out), out);
+ public ResourcePool transform(ResourcePool pool, ResourcePoolBuilder out) {
+ packer = new ResourcePoolPacker(instrumentation, pool, out);
+ pool.transformAndCopy(this::transform, out);
return out.build();
}
- private ResourcePoolEntry transform(ResourcePoolEntry entry, ResourcePoolBuilder out) {
- if (entry.type().equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE) && entry.path().endsWith(".class")) {
+ private ResourcePoolEntry transform(ResourcePoolEntry entry) {
+ if (entry.type().equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
+ && entry.path().endsWith(".class")) {
if (entry.path().endsWith("module-info.class")) {
if (entry.path().startsWith("/java.base")) {
// Transform java.base's module-info.class file and pack core classes into java.base
- return packer.pack(entry, out);
+ return packer.pack(entry);
}
} else {
byte[] instrumented = instrumentation.apply(entry.contentBytes());
diff --git a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/Instrumenter.java b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/Instrumenter.java
index af852281e..21106bef7 100644
--- a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/Instrumenter.java
+++ b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/Instrumenter.java
@@ -1,5 +1,6 @@
package edu.columbia.cs.psl.phosphor.driver;
+import edu.columbia.cs.psl.phosphor.agent.InstrumentUtil;
import org.jacoco.core.internal.InputStreams;
import org.jacoco.core.internal.instr.SignatureRemover;
diff --git a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/JLinkInvoker.java b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/JLinkInvoker.java
index 45437af59..9cd31f9aa 100644
--- a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/JLinkInvoker.java
+++ b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/JLinkInvoker.java
@@ -1,9 +1,10 @@
package edu.columbia.cs.psl.phosphor.driver;
+import edu.columbia.cs.psl.phosphor.agent.InstrumentUtil;
+
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
-import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;
@@ -39,9 +40,7 @@ public static void invoke(
private static File storeOptions(Properties options) throws IOException {
// Write the options to a temporary file
- File file = Files.createTempFile("phosphor-", ".properties").toFile();
- file.deleteOnExit();
- InstrumentUtil.ensureDirectory(file.getParentFile());
+ File file = InstrumentUtil.createTemporaryFile("phosphor-", ".properties");
try (FileWriter writer = new FileWriter(file)) {
options.store(writer, null);
}
diff --git a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/Packer.java b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/Packer.java
index 82c0cdcaa..e3e3c4024 100644
--- a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/Packer.java
+++ b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/Packer.java
@@ -1,134 +1,87 @@
package edu.columbia.cs.psl.phosphor.driver;
-import jdk.tools.jlink.plugin.ResourcePool;
-import jdk.tools.jlink.plugin.ResourcePoolBuilder;
-import jdk.tools.jlink.plugin.ResourcePoolEntry;
-import org.objectweb.asm.Attribute;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.commons.ModuleHashesAttribute;
-import org.objectweb.asm.commons.ModuleResolutionAttribute;
-import org.objectweb.asm.commons.ModuleTargetAttribute;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.ModuleExportNode;
+import edu.columbia.cs.psl.phosphor.agent.InstrumentUtil;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.*;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-public class Packer {
+public abstract class Packer {
private final Instrumentation instrumentation;
private final Patcher patcher;
- public Packer(ResourcePool in, Instrumentation instrumentation) {
- if (in == null || instrumentation == null) {
- throw new NullPointerException();
- }
+ public Packer(Instrumentation instrumentation, Function entryLocator) {
this.instrumentation = instrumentation;
- this.patcher = instrumentation.createPatcher(path -> Packer.findEntry(in, path));
+ this.patcher = instrumentation.createPatcher(entryLocator);
}
- public ResourcePoolEntry pack(ResourcePoolEntry entry, ResourcePoolBuilder out) {
- try {
- // Pack classes into the java.bas
- Set packages = packClasses(out);
- // Transform java.base's module-info.class file
- try (InputStream in = entry.content()) {
- return entry.copyWithContent(transformBaseModuleInfo(in, packages));
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
+ public abstract void pack(String name, byte[] content) throws IOException;
- private Set packClasses(ResourcePoolBuilder out) throws IOException {
- // Pack the JARs and directories into the resource pool
+ public Set pack() throws IOException {
+ // Pack the JARs and directories
// Return the set of packages for packed classes
Set packages = new HashSet<>();
for (File element : instrumentation.getElementsToPack()) {
if (element.isDirectory()) {
- packDirectory(out, element, packages);
+ packDirectory(element, packages);
} else {
- packJar(out, element, packages);
+ packJar(element, packages);
}
}
return packages;
}
- private void packClass(ResourcePoolBuilder out, String name, File classFile, Set packages) {
- try {
- if (instrumentation.shouldPack(name)) {
- byte[] content = patcher.patch(name, Files.readAllBytes(classFile.toPath()));
- out.add(ResourcePoolEntry.create("/java.base/" + name, content));
+ private void packFile(String name, File classFile, Set packages) throws IOException {
+ if (instrumentation.shouldPack(name)) {
+ byte[] content = patcher.patch(name, InstrumentUtil.readAllBytes(classFile));
+ pack(name, content);
+ if (name.endsWith(".class")) {
packages.add(name.substring(0, name.lastIndexOf('/')));
}
- } catch (IOException e) {
- throw new IllegalArgumentException("Failed to pack: " + name, e);
}
}
- private void packDirectory(ResourcePoolBuilder out, File directory, Set packages) throws IOException {
+ private void packDirectory(File directory, Set packages) throws IOException {
try (Stream walk = Files.walk(directory.toPath())) {
- walk.filter(Files::isRegularFile)
- .forEach(p -> packClass(
- out,
- directory.toPath().relativize(p).toFile().getPath(),
- p.toAbsolutePath().toFile(),
- packages));
+ for (Path path : walk.filter(Files::isRegularFile).collect(Collectors.toList())) {
+ String name = directory.toPath().relativize(path).toFile().getPath();
+ File file = path.toAbsolutePath().toFile();
+ if (name.endsWith(".jar")) {
+ packJar(file, packages);
+ } else {
+ packFile(name, file, packages);
+ }
+ }
}
}
- private void packJar(ResourcePoolBuilder out, File element, Set packages) throws IOException {
+ private void packJar(File element, Set packages) throws IOException {
try (ZipFile zip = new ZipFile(element)) {
Enumeration extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
- if (instrumentation.shouldPack(entry.getName())) {
+ String name = entry.getName();
+ byte[] content;
+ if (instrumentation.shouldPack(name)) {
try (InputStream is = zip.getInputStream(entry)) {
- byte[] content = patcher.patch(entry.getName(), InstrumentUtil.readAllBytes(is));
- out.add(ResourcePoolEntry.create("/java.base/" + entry.getName(), content));
+ content = InstrumentUtil.readAllBytes(is);
+ }
+ pack(entry.getName(), patcher.patch(name, content));
+ if (name.endsWith(".class")) {
+ packages.add(name.substring(0, name.lastIndexOf('/')));
}
- packages.add(entry.getName().substring(0, entry.getName().lastIndexOf('/')));
}
}
}
}
-
- private byte[] transformBaseModuleInfo(InputStream in, Set packages) {
- try {
- ClassNode classNode = new ClassNode();
- ClassReader cr = new ClassReader(in);
- Attribute[] attributes = new Attribute[] {
- new ModuleTargetAttribute(), new ModuleResolutionAttribute(), new ModuleHashesAttribute()
- };
- cr.accept(classNode, attributes, 0);
- // Add exports
- for (String packageName : packages) {
- classNode.module.exports.add(new ModuleExportNode(packageName, 0, null));
- }
- // Add packages
- classNode.module.packages.addAll(packages);
- ClassWriter cw = new ClassWriter(0);
- classNode.accept(cw);
- return cw.toByteArray();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- private static byte[] findEntry(ResourcePool pool, String path) {
- ResourcePoolEntry entry = pool.findEntry(path)
- .orElseThrow(() -> new IllegalArgumentException("Unable to find entry for: " + path));
- try (InputStream in = entry.content()) {
- return InstrumentUtil.readAllBytes(in);
- } catch (IOException e) {
- throw new RuntimeException("Unable to read entry for: " + path, e);
- }
- }
}
diff --git a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/PhosphorInstrumentation.java b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/PhosphorInstrumentation.java
index 50dd9ee88..809485056 100644
--- a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/PhosphorInstrumentation.java
+++ b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/PhosphorInstrumentation.java
@@ -1,6 +1,8 @@
package edu.columbia.cs.psl.phosphor.driver;
import edu.columbia.cs.psl.phosphor.*;
+import edu.columbia.cs.psl.phosphor.agent.InstrumentUtil;
+import edu.columbia.cs.psl.phosphor.agent.EmbeddedPhosphorPatcher;
import edu.columbia.cs.psl.phosphor.instrumenter.TaintTrackingClassVisitor;
import edu.columbia.cs.psl.phosphor.org.apache.commons.cli.CommandLine;
@@ -61,8 +63,8 @@ public byte[] apply(byte[] classFileBuffer) {
@Override
public Patcher createPatcher(Function entryLocator) {
- String path = "/java.base/jdk/internal/misc/Unsafe.class";
- PhosphorPatcher patcher = new PhosphorPatcher(entryLocator.apply(path));
+ String path = "/java.base/jdk/internal/misc/Unsafe.class";
+ EmbeddedPhosphorPatcher patcher = new EmbeddedPhosphorPatcher(entryLocator.apply(path));
return patcher::patch;
}
diff --git a/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/ResourcePoolPacker.java b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/ResourcePoolPacker.java
new file mode 100644
index 000000000..19997c543
--- /dev/null
+++ b/phosphor-driver/src/main/java/edu/columbia/cs/psl/phosphor/driver/ResourcePoolPacker.java
@@ -0,0 +1,80 @@
+package edu.columbia.cs.psl.phosphor.driver;
+
+import edu.columbia.cs.psl.phosphor.agent.InstrumentUtil;
+import jdk.tools.jlink.plugin.ResourcePool;
+import jdk.tools.jlink.plugin.ResourcePoolBuilder;
+import jdk.tools.jlink.plugin.ResourcePoolEntry;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.commons.ModuleHashesAttribute;
+import org.objectweb.asm.commons.ModuleResolutionAttribute;
+import org.objectweb.asm.commons.ModuleTargetAttribute;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.ModuleExportNode;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Set;
+
+public class ResourcePoolPacker extends Packer {
+ private final ResourcePoolBuilder out;
+
+ public ResourcePoolPacker(Instrumentation instrumentation, ResourcePool pool, ResourcePoolBuilder out) {
+ super(instrumentation, path -> ResourcePoolPacker.findEntry(pool, path));
+ if (out == null) {
+ throw new NullPointerException();
+ }
+ this.out = out;
+ }
+
+ @Override
+ public void pack(String name, byte[] content) {
+ out.add(ResourcePoolEntry.create("/java.base/" + name, content));
+ }
+
+ public ResourcePoolEntry pack(ResourcePoolEntry entry) {
+ try {
+ // Pack classes into java.base
+ Set packages = pack();
+ // Transform java.base's module-info.class file
+ try (InputStream in = entry.content()) {
+ return entry.copyWithContent(transformBaseModuleInfo(in, packages));
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static byte[] transformBaseModuleInfo(InputStream in, Set packages) {
+ try {
+ ClassNode classNode = new ClassNode();
+ ClassReader cr = new ClassReader(in);
+ Attribute[] attributes = new Attribute[] {
+ new ModuleTargetAttribute(), new ModuleResolutionAttribute(), new ModuleHashesAttribute()
+ };
+ cr.accept(classNode, attributes, 0);
+ // Add exports
+ for (String packageName : packages) {
+ classNode.module.exports.add(new ModuleExportNode(packageName, 0, null));
+ }
+ // Add packages
+ classNode.module.packages.addAll(packages);
+ ClassWriter cw = new ClassWriter(0);
+ classNode.accept(cw);
+ return cw.toByteArray();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static byte[] findEntry(ResourcePool pool, String path) {
+ ResourcePoolEntry entry = pool.findEntry(path)
+ .orElseThrow(() -> new IllegalArgumentException("Unable to find entry for: " + path));
+ try (InputStream in = entry.content()) {
+ return InstrumentUtil.readAllBytes(in);
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to read entry for: " + path, e);
+ }
+ }
+}
diff --git a/phosphor-instrument-maven-plugin/src/main/java/edu/columbia/cs/psl/phosphor/plugin/InstrumentMojo.java b/phosphor-instrument-maven-plugin/src/main/java/edu/columbia/cs/psl/phosphor/plugin/InstrumentMojo.java
index 702f1f7d5..7a70c8fde 100644
--- a/phosphor-instrument-maven-plugin/src/main/java/edu/columbia/cs/psl/phosphor/plugin/InstrumentMojo.java
+++ b/phosphor-instrument-maven-plugin/src/main/java/edu/columbia/cs/psl/phosphor/plugin/InstrumentMojo.java
@@ -1,7 +1,7 @@
package edu.columbia.cs.psl.phosphor.plugin;
import edu.columbia.cs.psl.phosphor.driver.DeletingFileVisitor;
-import edu.columbia.cs.psl.phosphor.driver.InstrumentUtil;
+import edu.columbia.cs.psl.phosphor.agent.InstrumentUtil;
import edu.columbia.cs.psl.phosphor.driver.Instrumentation;
import edu.columbia.cs.psl.phosphor.driver.Instrumenter;
import org.apache.maven.plugin.AbstractMojo;