diff options
author | Christopher Vogt <oss.nsp@cvogt.org> | 2016-10-07 00:24:14 -0400 |
---|---|---|
committer | Christopher Vogt <oss.nsp@cvogt.org> | 2016-10-07 20:05:57 -0400 |
commit | 8529a70358921af282920c216a81609292c8ba6a (patch) | |
tree | 04a23a27b41c55fc6c5ab42c79406d2f41e14b79 /nailgun_launcher/TrapSecurityManager.java | |
parent | 95728f6041a32e081a1f4129b8483ef622179b45 (diff) | |
download | cbt-8529a70358921af282920c216a81609292c8ba6a.tar.gz cbt-8529a70358921af282920c216a81609292c8ba6a.tar.bz2 cbt-8529a70358921af282920c216a81609292c8ba6a.zip |
Fix exit code trapping across classloaders
A SecurityManager is once installed globally and stays the same across
all classloaders. TrapSecurityManager was installed this way, but it
looked up the `trapExitCode` in it's own classloader, while
classes in other classloaders (when cbt was using another version of
cbt) were writing it to their own classloader. This flag needs to be in
a global place instead to fix this, so we'll put it straight into the
TrapSecurityManager itself.
Diffstat (limited to 'nailgun_launcher/TrapSecurityManager.java')
-rw-r--r-- | nailgun_launcher/TrapSecurityManager.java | 52 |
1 files changed, 48 insertions, 4 deletions
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()) ); + } + } |