Any kind of container which runs Ant in-VM, such as the NetBeans IDE, that has its own SecurityManager already will need a way to intercept calls to System.setSecurityManager() made from Ant's Permissions class, since the VM can have only one global SM at a time. Currently attempting to use <java fork="false"> in any mode which uses Permissions (incl. failonerror="true" in Ant 1.6.x and always in 1.7) will just break with a SecurityException when run in an embedded environment like this. Could be solved by providing a hook in Ant letting the container manage some of the permissions, e.g. delegating from the VM-wide master SM to a thread/threadgroup-specific SM provided by Ant.
Cf. NetBeans bug: http://www.netbeans.org/issues/show_bug.cgi?id=47645
Cf. Java #5101798.
Alternatively, we could try and set the security manager, catch the exception and back off from the attempt, opting to fork the jvm instead.
> Alternatively, we could try and set the security manager, catch the exception > and back off from the attempt, opting to fork the jvm instead. I know that this kind of "catch a semi-expected exception and alter behaviour" is used frequently in the code, but is there no other way? I personally feel that using exceptions as a flow control mechanism is a code smell. I'd prefer an adapter approach mentioned in the report just my opinion Kev
Maybe both: an override for containers that know what they are doing, a probe+backoff for containers that dont do anything clever. Jesse, what kind of control mechanism do you propose?
Not sure yet. Maybe in Permissions: public class Permissions { // ... /** * For containers which wish to intercept * {@link System.setSecurityManager} safely. */ public interface SecurityManagerDelegator { void registerSecurityManager(SecurityManager); void unregisterSecurityManager(); } public static void installSecurityManagerDelegator(SecurityManagerDelegator) {...} } If P.iSMD were not called, Ant would do what it does now. If it were called, Permissions.{set,restore}SecurityManager would delegate to the new interface. This would - I hope - permit a container to manage Ant's SM implementation intelligently, say by having the real global SM delegate to Ant's SM according to the current thread group. But I would need to try writing a real P.SMD implementation, say for NetBeans, to confirm that it can really work. Note that the current code in Ant is not actually correct to begin with. You might expect that the following script: <?xml version="1.0"?> <project name="34229-demo" default="x"> <target name="x"> <echo file="Pause.java"> public class Pause { public static void main(String[] args) throws Exception { int status = Integer.parseInt(args[0]); System.out.println("Will pause... (status: " + status + ")"); Thread.sleep(2000); System.out.println("Done. (status: " + status + ")"); System.exit(status); } } </echo> <javac srcdir="." destdir="." includes="Pause.java"/> <parallel> <sequential> <java fork="false" classpath="." failonerror="true" classname="Pause"> <arg value="0"/> </java> </sequential> <sequential> <sleep milliseconds="1000"/> <java fork="false" classpath="." failonerror="true" classname="Pause"> <arg value="1"/> </java> </sequential> </parallel> <echo>OK??</echo> </target> </project> would when run from the command line (Ant 1.6.2) print Will pause... (status: 0) Will pause... (status: 1) Done. (status: 0) Done. (status: 1) BUILD FAILED /tmp/build.xml:24: Java returned: 1 since the second process finishes second and with a nonzero error code which should throw a BuildException. Instead, it prints only Will pause... (status: 0) Will pause... (status: 1) Done. (status: 0) Done. (status: 1) and then exits *Ant's* VM abruptly (with code 1). That is because the sequence of events is - System.sSM(MySM) for process #0 before it starts - System.sSM(MySM) for process #1 (overwriting #0's!) before it starts - System.exit(0) from #0, which is trapped and causes <java> to finish - System.sSM(null) (as stored by Permissions #0) after #0 finishes - System.exit(1) from #1, which is not trapped since there is no SM A contrived case, perhaps, but it shows that the logic in Permissions is wrong already - it should be installing a multiplexing SM itself, and perhaps checking the Thread of the caller. Switching to forked mode as an option of last resort might be an option; perhaps it would be a reasonable hot fix for Ant 1.6.3 until we can do better. I guess ExecuteJava would need to catch SecurityException from Permissions.sSM and switch to calling Java.fork(...) or something like that, and a similar fix for JUnitTestRunner. The main problem is that running the app forked is not completely transparent to the user; besides a performance hit, there might be some specific behavior which the user needs unforked mode for, and it might be confusing to magically switch to forked mode in some environments.
BTW this is currently worked around in NetBeans by switching <java> to forked mode in all cases. While I'm sure this causes problems for somebody somewhere, I haven't heard any complaints yet.
Hi all, I'm using Ant, embedded in my application. Unfortunately when a JAVA task is executed, I'm not able to maintain my SecurityManager, during the java task execution. Inside of my SecMan I've got all my logics to check if you are authorized or not. Going into code, I've seen that everything should work the Permissions instance is null but it's initialized during the checkConfiguration method of Java class. I think SecurityManagerDelegator could be the great solution, but I haven't seen anything in the code. Have you planned it? Or is there any other workaround (not fork=true ..) Of ocurse I can try to change by myself but I should change my ANT at every new release... Thanks a lot!
I am afraid there is no fix for this yet.
Thanks a lot Jesse. In the meantime I changed my class so now works perfectly! CU