8289610: Degrade Thread.stop

Reviewed-by: rriggs, cjplummer, jpai, mchung, prr, mullan
This commit is contained in:
Alan Bateman 2022-09-23 07:55:29 +00:00
parent 05c8cabdad
commit acd5bcfc88
26 changed files with 179 additions and 226 deletions

View File

@ -190,17 +190,9 @@ public class FilterOutputStream extends OutputStream {
try { try {
out.close(); out.close();
} catch (Throwable closeException) { } catch (Throwable closeException) {
// evaluate possible precedence of flushException over closeException
if ((flushException instanceof ThreadDeath) &&
!(closeException instanceof ThreadDeath)) {
flushException.addSuppressed(closeException);
throw (ThreadDeath) flushException;
}
if (flushException != closeException) { if (flushException != closeException) {
closeException.addSuppressed(flushException); closeException.addSuppressed(flushException);
} }
throw closeException; throw closeException;
} }
} }

View File

@ -2430,8 +2430,6 @@ public class ObjectInputStream
// Read fields of the current descriptor into a new FieldValues and discard // Read fields of the current descriptor into a new FieldValues and discard
new FieldValues(slotDesc, true); new FieldValues(slotDesc, true);
} else if (slotDesc.hasReadObjectMethod()) { } else if (slotDesc.hasReadObjectMethod()) {
ThreadDeath t = null;
boolean reset = false;
SerialCallbackContext oldContext = curContext; SerialCallbackContext oldContext = curContext;
if (oldContext != null) if (oldContext != null)
oldContext.check(); oldContext.check();
@ -2450,19 +2448,10 @@ public class ObjectInputStream
*/ */
handles.markException(passHandle, ex); handles.markException(passHandle, ex);
} finally { } finally {
do { curContext.setUsed();
try { if (oldContext!= null)
curContext.setUsed(); oldContext.check();
if (oldContext!= null) curContext = oldContext;
oldContext.check();
curContext = oldContext;
reset = true;
} catch (ThreadDeath x) {
t = x; // defer until reset is true
}
} while (!reset);
if (t != null)
throw t;
} }
/* /*

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -29,9 +29,6 @@ package java.lang;
* An {@code Error} is a subclass of {@code Throwable} * An {@code Error} is a subclass of {@code Throwable}
* that indicates serious problems that a reasonable application * that indicates serious problems that a reasonable application
* should not try to catch. Most such errors are abnormal conditions. * should not try to catch. Most such errors are abnormal conditions.
* The {@code ThreadDeath} error, though a "normal" condition,
* is also a subclass of {@code Error} because most applications
* should not try to catch it.
* <p> * <p>
* A method is not required to declare in its {@code throws} * A method is not required to declare in its {@code throws}
* clause any subclasses of {@code Error} that might be thrown * clause any subclasses of {@code Error} that might be thrown
@ -42,7 +39,6 @@ package java.lang;
* exceptions for the purposes of compile-time checking of exceptions. * exceptions for the purposes of compile-time checking of exceptions.
* *
* @author Frank Yellin * @author Frank Yellin
* @see java.lang.ThreadDeath
* @jls 11.2 Compile-Time Checking of Exceptions * @jls 11.2 Compile-Time Checking of Exceptions
* @since 1.0 * @since 1.0
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -179,16 +179,6 @@ import java.lang.module.ModuleFinder;
* </tr> * </tr>
* *
* <tr> * <tr>
* <th scope="row">stopThread</th>
* <td>Stopping of threads via calls to the Thread {@code stop}
* method</td>
* <td>This allows code to stop any thread in the system provided that it is
* already granted permission to access that thread.
* This poses as a threat, because that code may corrupt the system by
* killing existing threads.</td>
* </tr>
*
* <tr>
* <th scope="row">modifyThreadGroup</th> * <th scope="row">modifyThreadGroup</th>
* <td>modification of thread groups, e.g., via calls to ThreadGroup * <td>modification of thread groups, e.g., via calls to ThreadGroup
* {@code destroy}, {@code getParent}, {@code resume}, * {@code destroy}, {@code getParent}, {@code resume},

View File

@ -129,9 +129,7 @@ class Shutdown {
} }
if (hook != null) hook.run(); if (hook != null) hook.run();
} catch (Throwable t) { } catch (Throwable t) {
if (t instanceof ThreadDeath td) { // ignore
throw td;
}
} }
} }

View File

@ -1629,59 +1629,19 @@ public class Thread implements Runnable {
} }
/** /**
* Forces the thread to stop executing. * Throws {@code UnsupportedOperationException}.
* <p>
* If there is a security manager installed, its {@code checkAccess}
* method is called with {@code this}
* as its argument. This may result in a
* {@code SecurityException} being raised (in the current thread).
* <p>
* If this thread is different from the current thread (that is, the current
* thread is trying to stop a thread other than itself), the
* security manager's {@code checkPermission} method (with a
* {@code RuntimePermission("stopThread")} argument) is called in
* addition.
* Again, this may result in throwing a
* {@code SecurityException} (in the current thread).
* <p>
* The thread represented by this thread is forced to stop whatever
* it is doing abnormally and to throw a newly created
* {@code ThreadDeath} object as an exception.
* <p>
* It is permitted to stop a thread that has not yet been started.
* If the thread is eventually started, it immediately terminates.
* <p>
* An application should not normally try to catch
* {@code ThreadDeath} unless it must do some extraordinary
* cleanup operation (note that the throwing of
* {@code ThreadDeath} causes {@code finally} clauses of
* {@code try} statements to be executed before the thread
* officially terminates). If a {@code catch} clause catches a
* {@code ThreadDeath} object, it is important to rethrow the
* object so that the thread actually terminates.
* <p>
* The top-level error handler that reacts to otherwise uncaught
* exceptions does not print out a message or otherwise notify the
* application if the uncaught exception is an instance of
* {@code ThreadDeath}.
* *
* @throws SecurityException if the current thread cannot * @throws UnsupportedOperationException always
* modify this thread. *
* @throws UnsupportedOperationException if invoked on a virtual thread * @deprecated This method was originally specified to "stop" a victim
* @see #interrupt() * thread by causing the victim thread to throw a {@link ThreadDeath}.
* @see #checkAccess() * It was inherently unsafe. Stopping a thread caused it to unlock
* @see ThreadDeath * all of the monitors that it had locked (as a natural consequence
* @see ThreadGroup#uncaughtException(Thread,Throwable) * of the {@code ThreadDeath} exception propagating up the stack). If
* @see SecurityManager#checkAccess(Thread)
* @see SecurityManager#checkPermission
* @deprecated This method is inherently unsafe. Stopping a thread with
* Thread.stop causes it to unlock all of the monitors that it
* has locked (as a natural consequence of the unchecked
* {@code ThreadDeath} exception propagating up the stack). If
* any of the objects previously protected by these monitors were in * any of the objects previously protected by these monitors were in
* an inconsistent state, the damaged objects become visible to * an inconsistent state, the damaged objects became visible to
* other threads, potentially resulting in arbitrary behavior. Many * other threads, potentially resulting in arbitrary behavior.
* uses of {@code stop} should be replaced by code that simply * Usages of {@code stop} should be replaced by code that simply
* modifies some variable to indicate that the target thread should * modifies some variable to indicate that the target thread should
* stop running. The target thread should check this variable * stop running. The target thread should check this variable
* regularly, and return from its run method in an orderly fashion * regularly, and return from its run method in an orderly fashion
@ -1695,26 +1655,7 @@ public class Thread implements Runnable {
*/ */
@Deprecated(since="1.2", forRemoval=true) @Deprecated(since="1.2", forRemoval=true)
public final void stop() { public final void stop() {
@SuppressWarnings("removal") throw new UnsupportedOperationException();
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if (this != Thread.currentThread()) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
if (isVirtual())
throw new UnsupportedOperationException();
// A zero status value corresponds to "NEW", it can't change to
// not-NEW because we hold the lock.
if (holder.threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
}
// The VM can handle all thread states
stop0(new ThreadDeath());
} }
/** /**
@ -3094,7 +3035,6 @@ public class Thread implements Runnable {
/* Some private helper methods */ /* Some private helper methods */
private native void setPriority0(int newPriority); private native void setPriority0(int newPriority);
private native void stop0(Object o);
private native void suspend0(); private native void suspend0();
private native void resume0(); private native void resume0();
private native void interrupt0(); private native void interrupt0();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,26 +26,19 @@
package java.lang; package java.lang;
/** /**
* An instance of {@code ThreadDeath} is thrown in the victim thread * An instance of {@code ThreadDeath} was originally specified to be thrown
* when the (deprecated) {@link Thread#stop()} method is invoked. * by a victim thread when "stopped" with {@link Thread#stop()}.
* *
* <p>An application should catch instances of this class only if it * @deprecated {@link Thread#stop()} was originally specified to "stop" a victim
* must clean up after being terminated asynchronously. If * thread by causing the victim thread to throw a {@code ThreadDeath}. It
* {@code ThreadDeath} is caught by a method, it is important that it * was inherently unsafe and deprecated in an early JDK release. The ability
* be rethrown so that the thread actually dies. * to "stop" a thread with {@code Thread.stop} has been removed and the
* * {@code Thread.stop} method changed to throw an exception. Consequently,
* <p>The {@linkplain ThreadGroup#uncaughtException top-level error * {@code ThreadDeath} is also deprecated, for removal.
* handler} does not print out a message if {@code ThreadDeath} is
* never caught.
*
* <p>The class {@code ThreadDeath} is specifically a subclass of
* {@code Error} rather than {@code Exception}, even though it is a
* "normal occurrence", because many applications catch all
* occurrences of {@code Exception} and then discard the exception.
* *
* @since 1.0 * @since 1.0
*/ */
@Deprecated(since="20", forRemoval=true)
public class ThreadDeath extends Error { public class ThreadDeath extends Error {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = -4417128565033088268L; private static final long serialVersionUID = -4417128565033088268L;

View File

@ -674,12 +674,9 @@ public class ThreadGroup implements Thread.UncaughtExceptionHandler {
* uncaught exception handler} installed, and if so, its * uncaught exception handler} installed, and if so, its
* {@code uncaughtException} method is called with the same * {@code uncaughtException} method is called with the same
* two arguments. * two arguments.
* <li>Otherwise, this method determines if the {@code Throwable} * <li>Otherwise, a message containing the thread's name, as returned
* argument is an instance of {@link ThreadDeath}. If so, nothing * from the thread's {@link Thread#getName getName} method, and a
* special is done. Otherwise, a message containing the * stack backtrace, using the {@code Throwable}'s {@link
* thread's name, as returned from the thread's {@link
* Thread#getName getName} method, and a stack backtrace,
* using the {@code Throwable}'s {@link
* Throwable#printStackTrace() printStackTrace} method, is * Throwable#printStackTrace() printStackTrace} method, is
* printed to the {@linkplain System#err standard error stream}. * printed to the {@linkplain System#err standard error stream}.
* </ul> * </ul>
@ -699,9 +696,8 @@ public class ThreadGroup implements Thread.UncaughtExceptionHandler {
Thread.getDefaultUncaughtExceptionHandler(); Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) { if (ueh != null) {
ueh.uncaughtException(t, e); ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) { } else {
System.err.print("Exception in thread \"" System.err.print("Exception in thread \"" + t.getName() + "\" ");
+ t.getName() + "\" ");
e.printStackTrace(System.err); e.printStackTrace(System.err);
} }
} }

View File

@ -1,6 +1,6 @@
<!doctype html> <!doctype html>
<!-- <!--
Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it This code is free software; you can redistribute it and/or modify it
@ -31,31 +31,32 @@
<body> <body>
<h1>Java Thread Primitive Deprecation</h1> <h1>Java Thread Primitive Deprecation</h1>
<hr> <hr>
<h2>Why is <code>Thread.stop</code> deprecated?</h2> <h2>Why is <code>Thread.stop</code> deprecated and the ability to
<p>Because it is inherently unsafe. Stopping a thread causes it to stop a thread removed?</h2>
unlock all the monitors that it has locked. (The monitors are <p>Because it was inherently unsafe. Stopping a thread caused it to
unlocked as the <code>ThreadDeath</code> exception propagates up unlock all the monitors that it had locked. (The monitors were
unlocked as the <code>ThreadDeath</code> exception propagated up
the stack.) If any of the objects previously protected by these the stack.) If any of the objects previously protected by these
monitors were in an inconsistent state, other threads may now view monitors were in an inconsistent state, other threads may have viewed
these objects in an inconsistent state. Such objects are said to be these objects in an inconsistent state. Such objects are said to be
<i>damaged</i>. When threads operate on damaged objects, arbitrary <i>damaged</i>. When threads operate on damaged objects, arbitrary
behavior can result. This behavior may be subtle and difficult to behavior can result. This behavior may be subtle and difficult to
detect, or it may be pronounced. Unlike other unchecked exceptions, detect, or it may be pronounced. Unlike other unchecked exceptions,
<code>ThreadDeath</code> kills threads silently; thus, the user has <code>ThreadDeath</code> killed threads silently; thus, the user had
no warning that his program may be corrupted. The corruption can no warning that their program may be corrupted. The corruption could
manifest itself at any time after the actual damage occurs, even manifest itself at any time after the actual damage occurs, even
hours or days in the future.</p> hours or days in the future.</p>
<hr> <hr>
<h2>Couldn't I just catch the <code>ThreadDeath</code> exception <h2>Couldn't I have just caught <code>ThreadDeath</code> and fixed
and fix the damaged object?</h2> the damaged object?</h2>
<p>In theory, perhaps, but it would <em>vastly</em> complicate the <p>In theory, perhaps, but it would <em>vastly</em> complicate the
task of writing correct multithreaded code. The task would be task of writing correct multithreaded code. The task would be
nearly insurmountable for two reasons:</p> nearly insurmountable for two reasons:</p>
<ol> <ol>
<li>A thread can throw a <code>ThreadDeath</code> exception <li>A thread could throw a <code>ThreadDeath</code> exception
<i>almost anywhere</i>. All synchronized methods and blocks would <i>almost anywhere</i>. All synchronized methods and blocks would
have to be studied in great detail, with this in mind.</li> have to be studied in great detail, with this in mind.</li>
<li>A thread can throw a second <code>ThreadDeath</code> exception <li>A thread could throw a second <code>ThreadDeath</code> exception
while cleaning up from the first (in the <code>catch</code> or while cleaning up from the first (in the <code>catch</code> or
<code>finally</code> clause). Cleanup would have to be repeated till <code>finally</code> clause). Cleanup would have to be repeated till
it succeeded. The code to ensure this would be quite complex.</li> it succeeded. The code to ensure this would be quite complex.</li>

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -178,7 +178,7 @@ final class BootstrapMethodInvoker {
catch (Error e) { catch (Error e) {
// Pass through an Error, including BootstrapMethodError, any other // Pass through an Error, including BootstrapMethodError, any other
// form of linkage error, such as IllegalAccessError if the bootstrap // form of linkage error, such as IllegalAccessError if the bootstrap
// method is inaccessible, or say ThreadDeath/OutOfMemoryError // method is inaccessible, or say OutOfMemoryError
// See the "Linking Exceptions" section for the invokedynamic // See the "Linking Exceptions" section for the invokedynamic
// instruction in JVMS 6.5. // instruction in JVMS 6.5.
throw e; throw e;

View File

@ -335,7 +335,7 @@ abstract sealed class CallSite permits ConstantCallSite, MutableCallSite, Volati
} catch (Error e) { } catch (Error e) {
// Pass through an Error, including BootstrapMethodError, any other // Pass through an Error, including BootstrapMethodError, any other
// form of linkage error, such as IllegalAccessError if the bootstrap // form of linkage error, such as IllegalAccessError if the bootstrap
// method is inaccessible, or say ThreadDeath/OutOfMemoryError // method is inaccessible, or say OutOfMemoryError
// See the "Linking Exceptions" section for the invokedynamic // See the "Linking Exceptions" section for the invokedynamic
// instruction in JVMS 6.5. // instruction in JVMS 6.5.
throw e; throw e;

View File

@ -124,10 +124,6 @@ public final class SecurityConstants {
public static final RuntimePermission GET_CLASSLOADER_PERMISSION = public static final RuntimePermission GET_CLASSLOADER_PERMISSION =
new RuntimePermission("getClassLoader"); new RuntimePermission("getClassLoader");
// java.lang.Thread
public static final RuntimePermission STOP_THREAD_PERMISSION =
new RuntimePermission("stopThread");
// java.lang.Thread // java.lang.Thread
public static final RuntimePermission GET_STACK_TRACE_PERMISSION = public static final RuntimePermission GET_STACK_TRACE_PERMISSION =
new RuntimePermission("getStackTrace"); new RuntimePermission("getStackTrace");

View File

@ -37,7 +37,6 @@
static JNINativeMethod methods[] = { static JNINativeMethod methods[] = {
{"start0", "()V", (void *)&JVM_StartThread}, {"start0", "()V", (void *)&JVM_StartThread},
{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},
{"isAlive0", "()Z", (void *)&JVM_IsThreadAlive}, {"isAlive0", "()Z", (void *)&JVM_IsThreadAlive},
{"suspend0", "()V", (void *)&JVM_SuspendThread}, {"suspend0", "()V", (void *)&JVM_SuspendThread},
{"resume0", "()V", (void *)&JVM_ResumeThread}, {"resume0", "()V", (void *)&JVM_ResumeThread},

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -167,11 +167,6 @@ public abstract class LWToolkit extends SunToolkit implements Runnable {
break; break;
} }
} }
} catch (ThreadDeath td) {
//XXX: if there isn't native code on the stack, the VM just
//kills the thread right away. Do we expect to catch it
//nevertheless?
break;
} catch (Throwable t) { } catch (Throwable t) {
// TODO: log // TODO: log
System.err.println("Exception on the toolkit thread"); System.err.println("Exception on the toolkit thread");

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -202,10 +202,6 @@ class EventDispatchThread extends Thread {
eq.dispatchEvent(event); eq.dispatchEvent(event);
} }
catch (ThreadDeath death) {
doDispatch = false;
throw death;
}
catch (InterruptedException interruptedException) { catch (InterruptedException interruptedException) {
doDispatch = false; // AppContext.dispose() interrupts all doDispatch = false; // AppContext.dispose() interrupts all
// Threads in the AppContext // Threads in the AppContext

View File

@ -198,13 +198,6 @@ class TimerQueue implements Runnable
} }
} }
} }
}
catch (ThreadDeath td) {
// Mark all the timers we contain as not being queued.
for (DelayedTimer delayedTimer : queue) {
delayedTimer.getTimer().cancelEvent();
}
throw td;
} finally { } finally {
running = false; running = false;
runningLock.unlock(); runningLock.unlock();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -2386,11 +2386,6 @@ class Parser implements DTDConstants {
errorContext(); errorContext();
error("exception", e.getClass().getName(), e.getMessage()); error("exception", e.getClass().getName(), e.getMessage());
e.printStackTrace(); e.printStackTrace();
} catch (ThreadDeath e) {
errorContext();
error("terminated");
e.printStackTrace();
throw e;
} finally { } finally {
for (; stack != null ; stack = stack.next) { for (; stack != null ; stack = stack.next) {
handleEndTag(stack.tag); handleEndTag(stack.tag);

View File

@ -727,9 +727,6 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
} }
dispatchEvent(ev); dispatchEvent(ev);
} catch (ThreadDeath td) {
XBaseWindow.ungrabInput();
return;
} catch (Throwable thr) { } catch (Throwable thr) {
XBaseWindow.ungrabInput(); XBaseWindow.ungrabInput();
processException(thr); processException(thr);
@ -1994,8 +1991,6 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
try { try {
task.run(); task.run();
} catch (ThreadDeath td) {
throw td;
} catch (Throwable thr) { } catch (Throwable thr) {
processException(thr); processException(thr);
} }

View File

@ -2666,8 +2666,6 @@ public class LogManager {
for (Runnable c : listeners.values().toArray(new Runnable[0])) { for (Runnable c : listeners.values().toArray(new Runnable[0])) {
try { try {
c.run(); c.run();
} catch (ThreadDeath death) {
throw death;
} catch (Error | RuntimeException x) { } catch (Error | RuntimeException x) {
if (t == null) t = x; if (t == null) t = x;
else t.addSuppressed(x); else t.addSuppressed(x);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
*/ */
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
@ -1030,7 +1030,7 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
try { try {
return doc.getXmlVersion(); return doc.getXmlVersion();
} // The VM ran out of memory or there was some other serious problem. Re-throw. } // The VM ran out of memory or there was some other serious problem. Re-throw.
catch (VirtualMachineError | ThreadDeath vme) { catch (VirtualMachineError vme) {
throw vme; throw vme;
} // Ignore all other exceptions and errors } // Ignore all other exceptions and errors
catch (Throwable t) { catch (Throwable t) {
@ -1046,7 +1046,7 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
try { try {
return doc.getInputEncoding(); return doc.getInputEncoding();
} // The VM ran out of memory or there was some other serious problem. Re-throw. } // The VM ran out of memory or there was some other serious problem. Re-throw.
catch (VirtualMachineError | ThreadDeath vme) { catch (VirtualMachineError vme) {
throw vme; throw vme;
} // Ignore all other exceptions and errors } // Ignore all other exceptions and errors
catch (Throwable t) { catch (Throwable t) {
@ -1062,7 +1062,7 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
try { try {
return doc.getXmlEncoding(); return doc.getXmlEncoding();
} // The VM ran out of memory or there was some other serious problem. Re-throw. } // The VM ran out of memory or there was some other serious problem. Re-throw.
catch (VirtualMachineError | ThreadDeath vme) { catch (VirtualMachineError vme) {
throw vme; throw vme;
} // Ignore all other exceptions and errors } // Ignore all other exceptions and errors
catch (Throwable t) { catch (Throwable t) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -261,10 +261,6 @@ public abstract class AttachProvider {
try { try {
providers.add(i.next()); providers.add(i.next());
} catch (Throwable t) { } catch (Throwable t) {
if (t instanceof ThreadDeath) {
ThreadDeath td = (ThreadDeath)t;
throw td;
}
// Log errors and exceptions since we cannot return them // Log errors and exceptions since we cannot return them
t.printStackTrace(); t.printStackTrace();
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -75,9 +75,6 @@ public abstract class HotSpotAttachProvider extends AttachProvider {
if (t instanceof ExceptionInInitializerError) { if (t instanceof ExceptionInInitializerError) {
t = t.getCause(); t = t.getCause();
} }
if (t instanceof ThreadDeath) {
throw (ThreadDeath)t;
}
if (t instanceof SecurityException) { if (t instanceof SecurityException) {
return result; return result;
} }
@ -101,9 +98,7 @@ public abstract class HotSpotAttachProvider extends AttachProvider {
result.add(new HotSpotVirtualMachineDescriptor(this, pid, name)); result.add(new HotSpotVirtualMachineDescriptor(this, pid, name));
} }
} catch (Throwable t) { } catch (Throwable t) {
if (t instanceof ThreadDeath) { // ignore
throw (ThreadDeath)t;
}
} finally { } finally {
if (mvm != null) { if (mvm != null) {
mvm.detach(); mvm.detach();
@ -138,10 +133,6 @@ public abstract class HotSpotAttachProvider extends AttachProvider {
return; return;
} }
} catch (Throwable t) { } catch (Throwable t) {
if (t instanceof ThreadDeath) {
ThreadDeath td = (ThreadDeath)t;
throw td;
}
// we do not know what this id is // we do not know what this id is
return; return;
} finally { } finally {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -99,12 +99,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManagerService {
try { try {
connector = connectors.next(); connector = connectors.next();
} catch (ThreadDeath x) { } catch (Exception | Error x) {
throw x;
} catch (Exception x) {
System.err.println(x);
continue;
} catch (Error x) {
System.err.println(x); System.err.println(x);
continue; continue;
} }
@ -128,12 +123,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManagerService {
try { try {
transportService = transportServices.next(); transportService = transportServices.next();
} catch (ThreadDeath x) { } catch (Exception | Error x) {
throw x;
} catch (Exception x) {
System.err.println(x);
continue;
} catch (Error x) {
System.err.println(x); System.err.println(x);
continue; continue;
} }

View File

@ -114,6 +114,7 @@ public class LocalExecutionControl extends DirectExecutionControl {
} }
@Override @Override
@SuppressWarnings("removal")
protected String invoke(Method doitMethod) throws Exception { protected String invoke(Method doitMethod) throws Exception {
if (allStop == null) { if (allStop == null) {
super.load(new ClassBytecodes[]{ genCancelClass() }); super.load(new ClassBytecodes[]{ genCancelClass() });

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -160,7 +160,7 @@ public class RemoteExecutionControl extends DirectExecutionControl implements Ex
} }
} }
@SuppressWarnings("serial") // serialVersionUID intentionally omitted @SuppressWarnings({"serial", "removal"}) // serialVersionUID intentionally omitted
private class StopExecutionException extends ThreadDeath { private class StopExecutionException extends ThreadDeath {
@Override @Override

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 8289610
* @summary Test Thread.stop throws UnsupportedOperationException
* @run testng StopTest
*/
import java.time.Duration;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
public class StopTest {
/**
* Test stop on the current thread.
*/
@Test
public void testCurrentThread() {
var thread = Thread.currentThread();
assertThrows(UnsupportedOperationException.class, thread::stop);
}
/**
* Test stop on an unstarted thread.
*/
@Test
public void testUnstartedThread() {
Thread thread = new Thread(() -> { });
assertThrows(UnsupportedOperationException.class, thread::stop);
assertTrue(thread.getState() == Thread.State.NEW);
}
/**
* Test stop on a thread spinning in a loop.
*/
@Test
public void testRunnableThread() throws Exception {
AtomicBoolean done = new AtomicBoolean();
Thread thread = new Thread(() -> {
while (!done.get()) {
Thread.onSpinWait();
}
});
thread.start();
try {
assertThrows(UnsupportedOperationException.class, thread::stop);
// thread should not terminate
boolean terminated = thread.join(Duration.ofMillis(500));
assertFalse(terminated);
} finally {
done.set(true);
thread.join();
}
}
/**
* Test stop on a thread that is parked.
*/
@Test
public void testWaitingThread() throws Exception {
Thread thread = new Thread(LockSupport::park);
thread.start();
try {
// wait for thread to park
while ((thread.getState() != Thread.State.WAITING)) {
Thread.sleep(10);
}
assertThrows(UnsupportedOperationException.class, thread::stop);
assertTrue(thread.getState() == Thread.State.WAITING);
} finally {
LockSupport.unpark(thread);
thread.join();
}
}
/**
* Test stop on a terminated thread.
*/
@Test
public void testTerminatedThread() throws Exception {
Thread thread = new Thread(() -> { });
thread.start();
thread.join();
assertThrows(UnsupportedOperationException.class, thread::stop);
assertTrue(thread.getState() == Thread.State.TERMINATED);
}
}