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

Java 11 Fixes #199

Merged
merged 8 commits into from
Jul 27, 2023
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ jobs:
fail-fast: false
matrix:
# java: [ '8', '11', '16', '17' ]
java: [ '8', '16' ]
java: [ '8', '11', '16' ]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Build Phosphor
run: mvn -B -DskipTests install
run: mvn -B -ntp -DskipTests install
- name: Setup java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: ${{ matrix.java }}
- name: Run tests
run: mvn install -Ddacapo.skip=false
run: mvn install -ntp -Ddacapo.skip=false

Large diffs are not rendered by default.

153 changes: 3 additions & 150 deletions Phosphor/src/main/java/edu/columbia/cs/psl/phosphor/Instrumenter.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package edu.columbia.cs.psl.phosphor;

import edu.columbia.cs.psl.phosphor.instrumenter.ConfigurationEmbeddingMV;
import edu.columbia.cs.psl.phosphor.instrumenter.TaintTrackingClassVisitor;
import edu.columbia.cs.psl.phosphor.runtime.StringUtils;
import edu.columbia.cs.psl.phosphor.runtime.jdk.unsupported.UnsafeProxy;
import edu.columbia.cs.psl.phosphor.struct.harmony.util.*;
import org.apache.commons.cli.CommandLine;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.ModuleHashesAttribute;
import org.objectweb.asm.commons.ModuleResolutionAttribute;
import org.objectweb.asm.commons.ModuleTargetAttribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.ModuleExportNode;

import java.io.*;
import java.lang.instrument.ClassFileTransformer;
Expand Down Expand Up @@ -709,148 +705,6 @@ private static class Result {
byte[] buf;
}

public static byte[] transformJavaBaseModuleInfo(InputStream is, java.util.Collection<String> packages) throws IOException {
ClassNode classNode = new ClassNode();
ClassReader cr = new ClassReader(is);
java.util.List<Attribute> attrs = new java.util.ArrayList<>();
attrs.add(new ModuleTargetAttribute());
attrs.add(new ModuleResolutionAttribute());
attrs.add(new ModuleHashesAttribute());

cr.accept(classNode, attrs.toArray(new Attribute[0]), 0);
//Add export
classNode.module.exports.add(new ModuleExportNode("edu/columbia/cs/psl/phosphor", 0, null));
classNode.module.exports.add(new ModuleExportNode("edu/columbia/cs/psl/phosphor/control", 0, null));
classNode.module.exports.add(new ModuleExportNode("edu/columbia/cs/psl/phosphor/control/standard", 0, null));
classNode.module.exports.add(new ModuleExportNode("edu/columbia/cs/psl/phosphor/runtime", 0, null));
classNode.module.exports.add(new ModuleExportNode("edu/columbia/cs/psl/phosphor/struct", 0, null));

//Add pac
classNode.module.packages.addAll(packages);
ClassWriter cw = new ClassWriter(0);
classNode.accept(cw);
return cw.toByteArray();
}

public static boolean isPhosphorClassPatchedAtInstTime(String name){
return name.equals("edu/columbia/cs/psl/phosphor/Configuration.class") || name.equals("edu/columbia/cs/psl/phosphor/runtime/RuntimeJDKInternalUnsafePropagator.class");
}

/**
* We do rewriting of various phosphor classes to ensure easy compilation for java < 9
*/
public static byte[] patchPhosphorClass(String name, InputStream is) throws IOException {
if(name.equals("edu/columbia/cs/psl/phosphor/Configuration.class")){
return embedPhopshorConfiguration(is);
}
if (name.equals("edu/columbia/cs/psl/phosphor/runtime/RuntimeJDKInternalUnsafePropagator.class")) {
return transformRuntimeUnsafePropagator(is, "jdk/internal/misc/Unsafe");
}
throw new UnsupportedEncodingException("We do not plan to instrument " + name);
}

public static byte[] transformRuntimeUnsafePropagator(InputStream is, String targetUnsafeInternalName) throws IOException {
final String UNSAFE_PROXY_INTERNAL_NAME = Type.getInternalName(UnsafeProxy.class);
final String UNSAFE_PROXY_DESC = Type.getDescriptor(UnsafeProxy.class);
final String TARGET_UNSAFE_INTERNAL_NAME = targetUnsafeInternalName;
final String TARGET_UNSAFE_DESC = "L" + targetUnsafeInternalName + ";";
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM9, cw) {
private String patchInternalName(String in) {
if (in.equals(UNSAFE_PROXY_INTERNAL_NAME)) {
return TARGET_UNSAFE_INTERNAL_NAME;
}
return in;
}

private String patchDesc(String in) {
if (in == null) {
return null;
}
return in.replace(UNSAFE_PROXY_DESC, TARGET_UNSAFE_DESC);
}

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, patchDesc(descriptor), patchDesc(signature), exceptions);
return new MethodVisitor(Opcodes.ASM9, mv) {

@Override
public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
for (int i = 0; i < numLocal; i++) {
if (local[i] instanceof String) {
local[i] = patchInternalName((String) local[i]);
}
}
for (int i = 0; i < numStack; i++) {
if (stack[i] instanceof String) {
stack[i] = patchInternalName((String) stack[i]);
}
}
super.visitFrame(type, numLocal, local, numStack, stack);
}

@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
super.visitFieldInsn(opcode, patchInternalName(owner), name, patchDesc(descriptor));
}

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
super.visitMethodInsn(opcode, patchInternalName(owner), name, patchDesc(descriptor), isInterface);
}

@Override
public void visitTypeInsn(int opcode, String type) {
super.visitTypeInsn(opcode, patchInternalName(type));
}

@Override
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
super.visitLocalVariable(name, patchDesc(descriptor), signature, start, end, index);
}
};
}
};
cr.accept(cv, 0);
return cw.toByteArray();

}
/**
* To boot the JVM... we need to have this flag set correctly.
*
* Default to setting it to be Java 8.
*
* In Java 9+, we pack Phosphor into the java.base module, and rewrite the configuration file
* to set the flag to false.
*
* @param is
* @return
* @throws IOException
*/
public static byte[] embedPhopshorConfiguration(InputStream is) throws IOException {
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(cr, 0);

ClassVisitor cv = new ClassVisitor(Opcodes.ASM9, cw) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (name.equals("<clinit>")) {
return new ConfigurationEmbeddingMV(mv);
} else {
return mv;
}
}
};

cr.accept(cv, 0);
return cw.toByteArray();

}


public static boolean isJava8JVMDir(File java_home) {
return new File(java_home, "bin" + File.separator + "java").exists()
&& !new File(java_home, "jmods").exists()
Expand All @@ -861,5 +715,4 @@ public static boolean isUnsafeClass(String className){
return (Configuration.IS_JAVA_8 && "sun/misc/Unsafe".equals(className))
|| (!Configuration.IS_JAVA_8 && "jdk/internal/misc/Unsafe".equals(className));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package edu.columbia.cs.psl.phosphor;

import edu.columbia.cs.psl.phosphor.instrumenter.ConfigurationEmbeddingMV;
import edu.columbia.cs.psl.phosphor.runtime.jdk.unsupported.UnsafeProxy;
import org.objectweb.asm.*;
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.MethodNode;
import org.objectweb.asm.tree.ModuleExportNode;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Set;

public class PhosphorPatcher {
private final boolean patchUnsafeNames;

public PhosphorPatcher(InputStream unsafeContent) throws IOException {
this.patchUnsafeNames = shouldPatchUnsafeNames(unsafeContent);
}

public byte[] patch(String name, byte[] content) throws IOException {
if (name.equals("edu/columbia/cs/psl/phosphor/Configuration.class")) {
return setConfigurationVersion(new ByteArrayInputStream(content));
} else if (name.equals("edu/columbia/cs/psl/phosphor/runtime/RuntimeJDKInternalUnsafePropagator.class")) {
return transformUnsafePropagator(new ByteArrayInputStream(content),
"jdk/internal/misc/Unsafe", patchUnsafeNames);
} else {
return content;
}
}

public byte[] transformBaseModuleInfo(InputStream in, Set<String> 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 boolean shouldPatchUnsafeNames(InputStream in) throws IOException {
ClassNode cn = new ClassNode();
new ClassReader(in).accept(cn, 0);
for (MethodNode mn : cn.methods) {
if (mn.name.contains("putReference")) {
return false;
}
}
return true;
}

/**
* Modify {@link Configuration} to set {@link Configuration#IS_JAVA_8} to false.
* This flag must be set correctly in order to boot the JVM.
*/
private static byte[] setConfigurationVersion(InputStream is) throws IOException {
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new ClassVisitor(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);
if (name.equals("<clinit>")) {
return new ConfigurationEmbeddingMV(mv);
} else {
return mv;
}
}
};
cr.accept(cv, 0);
return cw.toByteArray();
}

public static byte[] transformUnsafePropagator(InputStream in, String unsafeInternalName,
boolean patchUnsafeNames) throws IOException {
ClassReader cr = new ClassReader(in);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new UnsafePatchingCV(cw, unsafeInternalName, patchUnsafeNames);
cr.accept(cv, 0);
return cw.toByteArray();
}

private static class UnsafePatchingCV extends ClassVisitor {
private static final String UNSAFE_PROXY_INTERNAL_NAME = Type.getInternalName(UnsafeProxy.class);
private static final String UNSAFE_PROXY_DESC = Type.getDescriptor(UnsafeProxy.class);
private final String unsafeDesc;
private final boolean patchNames;
private final String unsafeInternalName;

public UnsafePatchingCV(ClassWriter cw, String unsafeInternalName, boolean patchNames) {
super(Configuration.ASM_VERSION, cw);
this.unsafeInternalName = unsafeInternalName;
this.unsafeDesc = "L" + unsafeInternalName + ";";
this.patchNames = patchNames;
}

private String patchInternalName(String name) {
return UNSAFE_PROXY_INTERNAL_NAME.equals(name) ? unsafeInternalName : name;
}

private String patchDesc(String desc) {
return desc == null ? null : desc.replace(UNSAFE_PROXY_DESC, unsafeDesc);
}

private String patchMethodName(String owner, String name) {
return patchNames && owner.equals(UNSAFE_PROXY_INTERNAL_NAME) ?
name.replace("Reference", "Object") : name;
}

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, patchDesc(descriptor), patchDesc(signature), exceptions);
return new MethodVisitor(api, mv) {
@Override
public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
for (int i = 0; i < numLocal; i++) {
if (local[i] instanceof String) {
local[i] = patchInternalName((String) local[i]);
}
}
for (int i = 0; i < numStack; i++) {
if (stack[i] instanceof String) {
stack[i] = patchInternalName((String) stack[i]);
}
}
super.visitFrame(type, numLocal, local, numStack, stack);
}

@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
super.visitFieldInsn(opcode, patchInternalName(owner), name, patchDesc(descriptor));
}

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
super.visitMethodInsn(opcode, patchInternalName(owner), patchMethodName(owner, name),
patchDesc(descriptor), isInterface);
}

@Override
public void visitTypeInsn(int opcode, String type) {
super.visitTypeInsn(opcode, patchInternalName(type));
}

@Override
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end,
int index) {
super.visitLocalVariable(name, patchDesc(descriptor), signature, start, end, index);
}
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@


import edu.columbia.cs.psl.phosphor.Configuration;
import edu.columbia.cs.psl.phosphor.Instrumenter;
import edu.columbia.cs.psl.phosphor.PhosphorPatcher;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.util.CheckClassAdapter;

import java.io.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

Expand All @@ -21,7 +23,8 @@ 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 = Instrumenter.transformRuntimeUnsafePropagator(sunMiscUnsafeIn, "sun/misc/Unsafe");
byte[] instrumentedUnsafe = PhosphorPatcher.transformUnsafePropagator(sunMiscUnsafeIn,
"sun/misc/Unsafe", false);
Files.write(Paths.get(pathToUnsafePropagator), instrumentedUnsafe);

for (String clazz : CLASSES) {
Expand Down
Loading