You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Apr 19, 2023. It is now read-only.
We iterated over several solutions to this and settled on a custom java agent that ‘disables’ security manager. This keeps nailgun protocol intact, but in our case improves compilation speed within pantsbuild from 75 to 12 minutes.
packagecom.r9.nailgun;
importjava.io.IOException;
importjava.lang.instrument.ClassDefinition;
importjava.lang.instrument.Instrumentation;
importjava.lang.instrument.UnmodifiableClassException;
importjava.net.JarURLConnection;
importjavassist.ClassPool;
importjavassist.CtClass;
importjavassist.CtMethod;
/** * This class disables security manager without breaking nailgun protocol that depends on it. * Implementation notes: * Can't use transformer cause classes are already loaded. * Can't add fields and methods or mark fields public with redefinition. * SecurityManager is not accessible with reflection. * Tested with nailgun 0.9.1 and java 8, should be compatible with nailgun 0.9.3 (and java 9 ???) * Warning: This agent disables security manager. Use on your own risk. * * @author Justinas Dabravolskas * @author Darius Prakaitis * */publicclassExitAgent {
// This is a storage for securityManager that is used in Runtime.exitpublicstaticvolatilejava.lang.SecurityManagerexitSecurity;
publicstaticvoidpremain(StringagentArgs, Instrumentationinst) {
try {
// make ExitAgent accessible to application, we probably load the second instance in// different class loader but who caresJarURLConnectionconnection = (JarURLConnection) ExitAgent.class.getClassLoader().getResource("com/r9/nailgun/ExitAgent.class").openConnection();
inst.appendToBootstrapClassLoaderSearch(connection.getJarFile());
inst.redefineClasses(newClassDefinition(Class.forName("java.lang.System"), getSystemByteCode()));
inst.redefineClasses(newClassDefinition(Class.forName("java.lang.Runtime"), getRuntimeByteCode()));
} catch (ClassNotFoundExceptione1) {
e1.printStackTrace();
thrownewRuntimeException(e1);
} catch (UnmodifiableClassExceptione1) {
e1.printStackTrace();
thrownewRuntimeException(e1);
} catch (IOExceptione) {
e.printStackTrace();
thrownewRuntimeException(e);
}
}
privatestaticbyte[] getSystemByteCode() {
try {
ClassPoolcp = ClassPool.getDefault();
CtClasscc = cp.get("java.lang.System");
// don't access volatile field at allCtMethodgetSecurityManager = cc.getDeclaredMethod("getSecurityManager", newCtClass[] {});
getSecurityManager.setBody("{return null;}");
CtMethodsetSecurityManager = cc.getDeclaredMethod("setSecurityManager", newCtClass[] { cp.get("java.lang.SecurityManager") });
// make security manager available to Runtime.exit onlysetSecurityManager.setBody("{com.r9.nailgun.ExitAgent.exitSecurity=$1;}");
byte[] byteCode = cc.toBytecode();
cc.detach();
returnbyteCode;
} catch (Exceptionex) {
ex.printStackTrace();
thrownewRuntimeException(ex);
}
}
privatestaticbyte[] getRuntimeByteCode() {
try {
ClassPoolcp = ClassPool.getDefault();
CtClasscc = cp.get("java.lang.Runtime");
CtMethodm = cc.getDeclaredMethod("exit", newCtClass[] { CtClass.intType });
m.setBody("{SecurityManager security = com.r9.nailgun.ExitAgent.exitSecurity; if(security != null){security.checkExit($1);} Shutdown.exit($1);}");
byte[] byteCode = cc.toBytecode();
cc.detach();
returnbyteCode;
} catch (Exceptionex) {
ex.printStackTrace();
thrownewRuntimeException(ex);
}
}
}
Running javac(not limited to) inside nailgun process has very high contention caused by security checks, in our case mostly:
We iterated over several solutions to this and settled on a custom java agent that ‘disables’ security manager. This keeps nailgun protocol intact, but in our case improves compilation speed within pantsbuild from 75 to 12 minutes.