diff options
author | Jan Christopher Vogt <oss.nsp@cvogt.org> | 2016-10-14 00:52:10 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-14 00:52:10 -0400 |
commit | 358a189db9842705d5c885a4c315635cd36fdc14 (patch) | |
tree | 7533ac2d08c686278256117a14ad64419d708274 /nailgun_launcher | |
parent | 86a4f0970c0e55ac072648691df8c159de50e969 (diff) | |
parent | dc01feea46cef8c075d41b1bcbb11f54d3f7fad1 (diff) | |
download | cbt-358a189db9842705d5c885a4c315635cd36fdc14.tar.gz cbt-358a189db9842705d5c885a4c315635cd36fdc14.tar.bz2 cbt-358a189db9842705d5c885a4c315635cd36fdc14.zip |
Merge pull request #276 from cvogt/fix-cross-classloader-security-manager
Fix exit code trapping and out/err redirection with and without nailgun
Diffstat (limited to 'nailgun_launcher')
-rw-r--r-- | nailgun_launcher/NailgunLauncher.java | 26 | ||||
-rw-r--r-- | nailgun_launcher/Stage0Lib.java | 10 | ||||
-rw-r--r-- | nailgun_launcher/ThreadLocalOutputStream.java | 30 | ||||
-rw-r--r-- | nailgun_launcher/TrapSecurityManager.java | 52 | ||||
-rw-r--r-- | nailgun_launcher/TrappedExitCode.java | 8 |
5 files changed, 101 insertions, 25 deletions
diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java index 5a70312..b1daf2a 100644 --- a/nailgun_launcher/NailgunLauncher.java +++ b/nailgun_launcher/NailgunLauncher.java @@ -23,13 +23,6 @@ public class NailgunLauncher{ public final static SecurityManager initialSecurityManager = System.getSecurityManager(); - public final static ThreadLocal<Boolean> trapExitCode = - new ThreadLocal<Boolean>() { - @Override protected Boolean initialValue() { - return false; - } - }; - public static String TARGET = System.getenv("TARGET"); private static String NAILGUN = "nailgun_launcher/"; private static String STAGE1 = "stage1/"; @@ -66,7 +59,24 @@ public class NailgunLauncher{ installProxySettings(); String[] diff = args[0].split("\\."); long start = _start - (Long.parseLong(diff[0]) * 1000L) - Long.parseLong(diff[1]); - + + // if nailgun didn't install it's threadLocal stdout/err replacements, install CBT's. + // this hack allows to later swap out System.out/err while still affecting things like + // scala.Console, which captured them at startup + try{ + System.out.getClass().getDeclaredField("streams"); // nailgun ThreadLocalPrintStream + assert(System.out.getClass().getName() == "com.martiansoftware.nailgun.ThreadLocalPrintStream"); + } catch( NoSuchFieldException e ){ + System.setOut( new PrintStream(new ThreadLocalOutputStream(System.out)) ); + } + try{ + System.err.getClass().getDeclaredField("streams"); // nailgun ThreadLocalPrintStream + assert(System.out.getClass().getName() == "com.martiansoftware.nailgun.ThreadLocalPrintStream"); + } catch( NoSuchFieldException e ){ + System.setErr( new PrintStream(new ThreadLocalOutputStream(System.err)) ); + } + // --------------------- + _assert(System.getenv("CBT_HOME") != null, "environment variable CBT_HOME not defined"); String CBT_HOME = System.getenv("CBT_HOME"); String cache = CBT_HOME + "/cache/"; diff --git a/nailgun_launcher/Stage0Lib.java b/nailgun_launcher/Stage0Lib.java index 11a9aab..452bdae 100644 --- a/nailgun_launcher/Stage0Lib.java +++ b/nailgun_launcher/Stage0Lib.java @@ -20,21 +20,21 @@ public class Stage0Lib{ } public static int runMain(String cls, String[] args, ClassLoader cl) throws Throwable{ - Boolean trapExitCodeBefore = NailgunLauncher.trapExitCode.get(); + Boolean trapExitCodeBefore = TrapSecurityManager.trapExitCode().get(); try{ - NailgunLauncher.trapExitCode.set(true); + TrapSecurityManager.trapExitCode().set(true); cl.loadClass(cls) .getMethod("main", String[].class) .invoke( null, (Object) args); return 0; }catch( InvocationTargetException exception ){ Throwable cause = exception.getCause(); - if(cause instanceof TrappedExitCode){ - return ((TrappedExitCode) cause).exitCode; + if(TrapSecurityManager.isTrappedExit(cause)){ + return TrapSecurityManager.exitCode(cause); } throw exception; } finally { - NailgunLauncher.trapExitCode.set(trapExitCodeBefore); + TrapSecurityManager.trapExitCode().set(trapExitCodeBefore); } } diff --git a/nailgun_launcher/ThreadLocalOutputStream.java b/nailgun_launcher/ThreadLocalOutputStream.java new file mode 100644 index 0000000..c12b775 --- /dev/null +++ b/nailgun_launcher/ThreadLocalOutputStream.java @@ -0,0 +1,30 @@ +package cbt; +import java.io.*; + +public class ThreadLocalOutputStream extends OutputStream{ + final public ThreadLocal<OutputStream> threadLocal; + final private OutputStream initialValue; + + public ThreadLocalOutputStream( OutputStream initialValue ){ + this.initialValue = initialValue; + threadLocal = new ThreadLocal<OutputStream>() { + @Override protected OutputStream initialValue() { + return ThreadLocalOutputStream.this.initialValue; + } + }; + } + + public OutputStream get(){ + return threadLocal.get(); + } + + public void set( OutputStream outputStream ){ + threadLocal.set( outputStream ); + } + + public void write( int b ) throws IOException{ + // after implementing this I realized NailgunLauncher uses the same hack, + // so probably this is not a problem performance + get().write(b); + } +} diff --git a/nailgun_launcher/TrapSecurityManager.java b/nailgun_launcher/TrapSecurityManager.java index fada878..1626787 100644 --- a/nailgun_launcher/TrapSecurityManager.java +++ b/nailgun_launcher/TrapSecurityManager.java @@ -9,6 +9,33 @@ would be Nailgun's if running on Nailgun. If we do not delegate to Nailgun, it s could in some cases kill the server process */ public class TrapSecurityManager extends ProxySecurityManager{ + public static ThreadLocal<Boolean> trapExitCode(){ + // storing the flag in the installed security manager + // instead of e.g. a static member is necessary because + // we run multiple versions of CBT with multiple TrapSecurityManager classes + // but we need to affect the installed one + SecurityManager sm = System.getSecurityManager(); + if(sm instanceof TrapSecurityManager){ + return ((TrapSecurityManager) sm)._trapExitCode; + } else { + try{ + @SuppressWarnings("unchecked") + ThreadLocal<Boolean> res = + (ThreadLocal<Boolean>) sm.getClass().getMethod("trapExitCode").invoke(null); + return res; + } catch(Exception e) { + throw new RuntimeException(e); + } + } + } + + private final ThreadLocal<Boolean> _trapExitCode = + new ThreadLocal<Boolean>() { + @Override protected Boolean initialValue() { + return false; + } + }; + public TrapSecurityManager(){ super(NailgunLauncher.initialSecurityManager); } @@ -19,21 +46,38 @@ public class TrapSecurityManager extends ProxySecurityManager{ Calling .super leads to ClassNotFound exteption for a lambda. Calling to the previous SecurityManager leads to a stack overflow */ - if(!NailgunLauncher.trapExitCode.get()){ + if(!TrapSecurityManager.trapExitCode().get()){ super.checkPermission(permission); } } public void checkPermission( Permission permission, Object context ){ /* Does this methods need to be overidden? */ - if(!NailgunLauncher.trapExitCode.get()){ + if(!TrapSecurityManager.trapExitCode().get()){ super.checkPermission(permission, context); } } + + private static final String prefix = "[TrappedExit] "; + @Override public void checkExit( int status ){ - if(NailgunLauncher.trapExitCode.get()){ - throw new TrappedExitCode(status); + if(TrapSecurityManager.trapExitCode().get()){ + // using a RuntimeException and a prefix here instead of a custom + // exception type because this is thrown by the installed TrapSecurityManager + // but other versions of cbt need to be able to catch it, that do not have access + // to that version of the TrapSecurityManager class + throw new RuntimeException(prefix+status); } super.checkExit(status); } + + public static boolean isTrappedExit( Throwable t ){ + return t instanceof RuntimeException && t.getMessage().startsWith(prefix); + } + + public static int exitCode( Throwable t ){ + assert(isTrappedExit(t)); + return Integer.parseInt( t.getMessage().substring(prefix.length()) ); + } + } diff --git a/nailgun_launcher/TrappedExitCode.java b/nailgun_launcher/TrappedExitCode.java deleted file mode 100644 index 154db27..0000000 --- a/nailgun_launcher/TrappedExitCode.java +++ /dev/null @@ -1,8 +0,0 @@ -package cbt; -import java.security.*; -public class TrappedExitCode extends SecurityException{ - public int exitCode; - public TrappedExitCode(int exitCode){ - this.exitCode = exitCode; - } -} |