Hi,

Exemple code to deadlock the JVM. Only Runtime.halt from within the JVM or a 
SIGKILL from outside stops it. Normal kills and Ctrl-C (which is a SIGTERM) 
fail to do so.

public class ExitInHookDemo {
            public static void main(String...args) {
                        Runtime.getRuntime().addShutdownHook(new Thread("hook") 
{
                                    public void run() { System.exit(1); }
});
            }
}

I've tried to more or less do a pure java patch in java.lang.Shutdown but the 
only way to have a real patch would be to have Thread.destroy still there and 
implemented or anything allowing Shutdown to destroy a thread. In essence, 
System.exit is a no return method call. So using Thread.stop which raise a 
ThreadDeath error is not enough (the method go back to the caller with the 
error). Only Thread.destroy has the contract of being a no return call. Yes the 
documentation said it is unsafe because it does not release locks & co, but 
right now that is exactly what is happening, so Thread.destroy limitations are 
acceptable. Throwing something that is not catchable, something legit to throw 
but not legit to catch, even by a catch Throwable, is not enough because it 
would still run finally blocks, which cannot happen for no return methods like 
System.exit and Runtime.halt: try { System.exit(0); /* code that should never 
be reached */ } catch (Throwable t) { /* code that should never be reached */ } 
finally { /* code that should also never be reached */ }

I've searched the known/documented bugs but I either missed the fact it was 
already reported, or I only got entries about removing Thread.destroy.

By the way, I'm not really asking to have Thread.destroy implemented were it is 
currently defined (a public method inside Thread). I mean at least 
java.lang.Shutdown should have a way to destroy Threads, even a private one. 
Threads destroyed that way should make threads stuck joining the destroyed one 
must be released.

I got the bug on java 1.8, oracle and openjdk ones. Not tested it one >=9 ones.

Here is what the approximation of a patch using pure java, but I'm no jdk 
expert and had no access to thread destruction, so it is not perfect. The code 
is from java.lang.Shutdown
    static void exit(int status) {
        boolean wasRunning = false; // < - - new var
        boolean runMoreFinalizers = false;
        synchronized (lock) {
            switch (state) {
            case RUNNING:       /* Initiate shutdown */
                state = HOOKS;
                wasRunning = true; // < - - first call to System.exit, the 
caller will run all of what is needed -hooks, maybe finalizers, etc.
                if (status != 0) runFinalizersOnExit = false; // < - - also 
moved the runFinalizersOnExit block to avoid having it changed/altered by 
several threads trying to exit with different status code
                break;
            case HOOKS:         /* Stall and halt */
                break;
            case FINALIZERS:
                if (status != 0) {
                    /* Halt immediately on nonzero status */
                    halt(status);
                } else {
                    /* Compatibility with old behavior:
                     * Run more finalizers and then halt
                     */
                    runMoreFinalizers = runFinalizersOnExit;
                }
                break;
            }
        }
        if (!wasRunning) Thread.currentThread().stop(); // < - - should be a 
destroy rather than a stop. This thread is not the 1st who called System.exit, 
and since it should never return, it must die asap. We are outside of the 
synchronized block so if any lock remains acquired by this thread, they are 
acquired by the caller which should have released them before calling exit on 
the 1st place. If the caller called us while having locks, it is a caller bug, 
not a Shutdown.exit one. Current implementation since it never returns (and 
yield the stuck bug I report) also never release any of the locks it has too
        // < - - beyond this line nothing has been modified
        if (runMoreFinalizers) {
            runAllFinalizers();
            halt(status);
        }
        synchronized (Shutdown.class) {
            /* Synchronize on the class object, causing any other thread
             * that attempts to initiate shutdown to stall indefinitely
             */
            sequence();
            halt(status);
        }
    }


Regards,
Ogrom.

_________________________________________________________________________________________________________________________

Ce message et ses pieces jointes peuvent contenir des informations 
confidentielles ou privilegiees et ne doivent donc
pas etre diffuses, exploites ou copies sans autorisation. Si vous avez recu ce 
message par erreur, veuillez le signaler
a l'expediteur et le detruire ainsi que les pieces jointes. Les messages 
electroniques etant susceptibles d'alteration,
Orange decline toute responsabilite si ce message a ete altere, deforme ou 
falsifie. Merci.

This message and its attachments may contain confidential or privileged 
information that may be protected by law;
they should not be distributed, used or copied without authorisation.
If you have received this email in error, please notify the sender and delete 
this message and its attachments.
As emails may be altered, Orange is not liable for messages that have been 
modified, changed or falsified.
Thank you.

Reply via email to