Should System.exit be controlled by a Scope Local?

Glavo zjx001202 at gmail.com
Sun Feb 27 15:40:51 UTC 2022


I think there is a problem with this: `System.exit` contains semantics to
interrupt the flow of control and exit, and if you implement it that way,
you might have some program abnormally execute parts of it that should
never be executed.

Of course, using exceptions like this should solve part of the problem:

class Exit extends Error {
    final int exitCode;
    public Exit(int exitCode) {
        this.exitCode = exitCode;
    }

    @Override
    public synchronized Throwable fillInStackTrace() {
        return this;
    }
}

try {
  Runtime.getRuntime().overridingExitBehavior(exitCode -> {throw new
Exit(exitCode);}, ...);
} catch (Exit exit) {
  ...
}

However, the calling method may catch this exception unexpectedly, and
there may be unexpected behavior under multithreading.
Of course, this part of the problem also exists for the security manager.
But, if possible, it would be better to have a solution for these
situations.
(`Continuation` might help us?)



On Sun, Feb 27, 2022 at 11:07 PM Ethan McCue <ethan at mccue.dev> wrote:

> That undermines my point some, but I think the overall shape of the use
> case still makes sense
>
> On Sun, Feb 27, 2022 at 8:01 AM Remi Forax <forax at univ-mlv.fr> wrote:
>
> > Hi Ethan,
> > there is a far simpler solution, call org.apache.ivy.run(args, true)
> > instead of org.apache.ivy.main(args) in your tool provider.
> >
> > regards,
> > Rémi
> >
> > ----- Original Message -----
> > > From: "Ethan McCue" <ethan at mccue.dev>
> > > To: "core-libs-dev" <core-libs-dev at openjdk.java.net>
> > > Sent: Saturday, February 26, 2022 11:14:19 PM
> > > Subject: Should System.exit be controlled by a Scope Local?
> >
> > > I have a feeling this has been considered and I might just be
> > articulating
> > > the obvious - but:
> > >
> > > As called out in JEP 411, one of the remaining legitimate uses of the
> > > Security Manager is to intercept calls to System.exit. This seems like
> a
> > > decent use case for the Scope Local mechanism.
> > >
> > >
> > >    public class Runtime {
> > >        ...
> > >        private final ScopeLocal<IntConsumer> EXIT =
> > > ScopeLocal.newInstance();
> > >
> > >        ...
> > >
> > >        public void overridingExitBehavior(IntConsumer exit, Runnable
> > run) {
> > >            ScopeLocal.with(EXIT, exit).run(run);
> > >        }
> > >
> > >        ...
> > >
> > >        public void exit(int status) {
> > >            if (EXIT.isBound()) {
> > >                EXIT.get().accept(status);
> > >            }
> > >            else {
> > >                Shutdown.exit(status);
> > >            }
> > >        }
> > >    }
> > >
> > >
> > > One of the likely minor benefits in the scope of things, but related to
> > the
> > > parts of the ecosystem I am doodling with so I'll mention it, is that
> it
> > > would become possible to wrap "naive" cli programs with the
> ToolProvider
> > > SPI without rewriting their code if this System.out, and System.err all
> > > became reliably configurable.
> > >
> > > For instance, Apache Ivy's CLI has a main class that looks like this
> > >
> > >
> >
> https://github.com/apache/ant-ivy/blob/424fa89419147f50a41b4bdc665d8ea92b5da516/src/java/org/apache/ivy/Main.java
> > >
> > >    package org.apache.ivy;
> > >
> > >    public final class Main {
> > >        ...
> > >
> > >        public static void main(String[] args) throws Exception {
> > >            try {
> > >                run(args, true);
> > >                System.exit(0);
> > >            } catch (ParseException ex) {
> > >                System.err.println(ex.getMessage());
> > >                System.exit(1);
> > >            }
> > >        }
> > >     }
> > >
> > > Making these otherwise static parts of the system configurable would
> > enable
> > > a third party library to write
> > >
> > >    public final class IvyToolProvider implements ToolProvider {
> > >        @Override
> > >        public String name() {
> > >            return "ivy";
> > >        }
> > >
> > >        @Override
> > >        public int run(PrintWriter out, PrintWriter err, String...
> args) {
> > >            var exit = new AtomicInteger(0);
> > >            Runtime.getRuntime().overridingExitBehavior(exit::set, ()
> -> {
> > >                System.overridingOut(out, () -> {
> > >                     System.overridingErr(err, Main::main);
> > >                }
> > >            };
> > >            return exit.get();
> > >        }
> > >    }
> > >
> > > Whether that would be enough to make it so that people other than
> > Christian
> > > Stein use the mechanism is anyone's guess, but might be worth a shot.
> > >
> > > https://grep.app/search?q=java.util.spi.ToolProvider
> >
>


More information about the core-libs-dev mailing list