Skip to content

Commit acd5bcf

Browse files
author
Alan Bateman
committed
8289610: Degrade Thread.stop
Reviewed-by: rriggs, cjplummer, jpai, mchung, prr, mullan
1 parent 05c8cab commit acd5bcf

File tree

26 files changed

+179
-226
lines changed

26 files changed

+179
-226
lines changed

src/java.base/share/classes/java/io/FilterOutputStream.java

-8
Original file line numberDiff line numberDiff line change
@@ -190,17 +190,9 @@ public void close() throws IOException {
190190
try {
191191
out.close();
192192
} catch (Throwable closeException) {
193-
// evaluate possible precedence of flushException over closeException
194-
if ((flushException instanceof ThreadDeath) &&
195-
!(closeException instanceof ThreadDeath)) {
196-
flushException.addSuppressed(closeException);
197-
throw (ThreadDeath) flushException;
198-
}
199-
200193
if (flushException != closeException) {
201194
closeException.addSuppressed(flushException);
202195
}
203-
204196
throw closeException;
205197
}
206198
}

src/java.base/share/classes/java/io/ObjectInputStream.java

+4-15
Original file line numberDiff line numberDiff line change
@@ -2430,8 +2430,6 @@ private void readSerialData(Object obj, ObjectStreamClass desc)
24302430
// Read fields of the current descriptor into a new FieldValues and discard
24312431
new FieldValues(slotDesc, true);
24322432
} else if (slotDesc.hasReadObjectMethod()) {
2433-
ThreadDeath t = null;
2434-
boolean reset = false;
24352433
SerialCallbackContext oldContext = curContext;
24362434
if (oldContext != null)
24372435
oldContext.check();
@@ -2450,19 +2448,10 @@ private void readSerialData(Object obj, ObjectStreamClass desc)
24502448
*/
24512449
handles.markException(passHandle, ex);
24522450
} finally {
2453-
do {
2454-
try {
2455-
curContext.setUsed();
2456-
if (oldContext!= null)
2457-
oldContext.check();
2458-
curContext = oldContext;
2459-
reset = true;
2460-
} catch (ThreadDeath x) {
2461-
t = x; // defer until reset is true
2462-
}
2463-
} while (!reset);
2464-
if (t != null)
2465-
throw t;
2451+
curContext.setUsed();
2452+
if (oldContext!= null)
2453+
oldContext.check();
2454+
curContext = oldContext;
24662455
}
24672456

24682457
/*

src/java.base/share/classes/java/lang/Error.java

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

src/java.base/share/classes/java/lang/RuntimePermission.java

+1-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -179,16 +179,6 @@
179179
* </tr>
180180
*
181181
* <tr>
182-
* <th scope="row">stopThread</th>
183-
* <td>Stopping of threads via calls to the Thread {@code stop}
184-
* method</td>
185-
* <td>This allows code to stop any thread in the system provided that it is
186-
* already granted permission to access that thread.
187-
* This poses as a threat, because that code may corrupt the system by
188-
* killing existing threads.</td>
189-
* </tr>
190-
*
191-
* <tr>
192182
* <th scope="row">modifyThreadGroup</th>
193183
* <td>modification of thread groups, e.g., via calls to ThreadGroup
194184
* {@code destroy}, {@code getParent}, {@code resume},

src/java.base/share/classes/java/lang/Shutdown.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,7 @@ private static void runHooks() {
129129
}
130130
if (hook != null) hook.run();
131131
} catch (Throwable t) {
132-
if (t instanceof ThreadDeath td) {
133-
throw td;
134-
}
132+
// ignore
135133
}
136134
}
137135

src/java.base/share/classes/java/lang/Thread.java

+12-72
Original file line numberDiff line numberDiff line change
@@ -1629,59 +1629,19 @@ private void exit() {
16291629
}
16301630

16311631
/**
1632-
* Forces the thread to stop executing.
1633-
* <p>
1634-
* If there is a security manager installed, its {@code checkAccess}
1635-
* method is called with {@code this}
1636-
* as its argument. This may result in a
1637-
* {@code SecurityException} being raised (in the current thread).
1638-
* <p>
1639-
* If this thread is different from the current thread (that is, the current
1640-
* thread is trying to stop a thread other than itself), the
1641-
* security manager's {@code checkPermission} method (with a
1642-
* {@code RuntimePermission("stopThread")} argument) is called in
1643-
* addition.
1644-
* Again, this may result in throwing a
1645-
* {@code SecurityException} (in the current thread).
1646-
* <p>
1647-
* The thread represented by this thread is forced to stop whatever
1648-
* it is doing abnormally and to throw a newly created
1649-
* {@code ThreadDeath} object as an exception.
1650-
* <p>
1651-
* It is permitted to stop a thread that has not yet been started.
1652-
* If the thread is eventually started, it immediately terminates.
1653-
* <p>
1654-
* An application should not normally try to catch
1655-
* {@code ThreadDeath} unless it must do some extraordinary
1656-
* cleanup operation (note that the throwing of
1657-
* {@code ThreadDeath} causes {@code finally} clauses of
1658-
* {@code try} statements to be executed before the thread
1659-
* officially terminates). If a {@code catch} clause catches a
1660-
* {@code ThreadDeath} object, it is important to rethrow the
1661-
* object so that the thread actually terminates.
1662-
* <p>
1663-
* The top-level error handler that reacts to otherwise uncaught
1664-
* exceptions does not print out a message or otherwise notify the
1665-
* application if the uncaught exception is an instance of
1666-
* {@code ThreadDeath}.
1632+
* Throws {@code UnsupportedOperationException}.
16671633
*
1668-
* @throws SecurityException if the current thread cannot
1669-
* modify this thread.
1670-
* @throws UnsupportedOperationException if invoked on a virtual thread
1671-
* @see #interrupt()
1672-
* @see #checkAccess()
1673-
* @see ThreadDeath
1674-
* @see ThreadGroup#uncaughtException(Thread,Throwable)
1675-
* @see SecurityManager#checkAccess(Thread)
1676-
* @see SecurityManager#checkPermission
1677-
* @deprecated This method is inherently unsafe. Stopping a thread with
1678-
* Thread.stop causes it to unlock all of the monitors that it
1679-
* has locked (as a natural consequence of the unchecked
1680-
* {@code ThreadDeath} exception propagating up the stack). If
1634+
* @throws UnsupportedOperationException always
1635+
*
1636+
* @deprecated This method was originally specified to "stop" a victim
1637+
* thread by causing the victim thread to throw a {@link ThreadDeath}.
1638+
* It was inherently unsafe. Stopping a thread caused it to unlock
1639+
* all of the monitors that it had locked (as a natural consequence
1640+
* of the {@code ThreadDeath} exception propagating up the stack). If
16811641
* any of the objects previously protected by these monitors were in
1682-
* an inconsistent state, the damaged objects become visible to
1683-
* other threads, potentially resulting in arbitrary behavior. Many
1684-
* uses of {@code stop} should be replaced by code that simply
1642+
* an inconsistent state, the damaged objects became visible to
1643+
* other threads, potentially resulting in arbitrary behavior.
1644+
* Usages of {@code stop} should be replaced by code that simply
16851645
* modifies some variable to indicate that the target thread should
16861646
* stop running. The target thread should check this variable
16871647
* regularly, and return from its run method in an orderly fashion
@@ -1695,26 +1655,7 @@ private void exit() {
16951655
*/
16961656
@Deprecated(since="1.2", forRemoval=true)
16971657
public final void stop() {
1698-
@SuppressWarnings("removal")
1699-
SecurityManager security = System.getSecurityManager();
1700-
if (security != null) {
1701-
checkAccess();
1702-
if (this != Thread.currentThread()) {
1703-
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
1704-
}
1705-
}
1706-
1707-
if (isVirtual())
1708-
throw new UnsupportedOperationException();
1709-
1710-
// A zero status value corresponds to "NEW", it can't change to
1711-
// not-NEW because we hold the lock.
1712-
if (holder.threadStatus != 0) {
1713-
resume(); // Wake up thread if it was suspended; no-op otherwise
1714-
}
1715-
1716-
// The VM can handle all thread states
1717-
stop0(new ThreadDeath());
1658+
throw new UnsupportedOperationException();
17181659
}
17191660

17201661
/**
@@ -3094,7 +3035,6 @@ static void setHeadStackableScope(StackableScope scope) {
30943035

30953036
/* Some private helper methods */
30963037
private native void setPriority0(int newPriority);
3097-
private native void stop0(Object o);
30983038
private native void suspend0();
30993039
private native void resume0();
31003040
private native void interrupt0();

src/java.base/share/classes/java/lang/ThreadDeath.java

+10-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -26,26 +26,19 @@
2626
package java.lang;
2727

2828
/**
29-
* An instance of {@code ThreadDeath} is thrown in the victim thread
30-
* when the (deprecated) {@link Thread#stop()} method is invoked.
29+
* An instance of {@code ThreadDeath} was originally specified to be thrown
30+
* by a victim thread when "stopped" with {@link Thread#stop()}.
3131
*
32-
* <p>An application should catch instances of this class only if it
33-
* must clean up after being terminated asynchronously. If
34-
* {@code ThreadDeath} is caught by a method, it is important that it
35-
* be rethrown so that the thread actually dies.
36-
*
37-
* <p>The {@linkplain ThreadGroup#uncaughtException top-level error
38-
* handler} does not print out a message if {@code ThreadDeath} is
39-
* never caught.
40-
*
41-
* <p>The class {@code ThreadDeath} is specifically a subclass of
42-
* {@code Error} rather than {@code Exception}, even though it is a
43-
* "normal occurrence", because many applications catch all
44-
* occurrences of {@code Exception} and then discard the exception.
32+
* @deprecated {@link Thread#stop()} was originally specified to "stop" a victim
33+
* thread by causing the victim thread to throw a {@code ThreadDeath}. It
34+
* was inherently unsafe and deprecated in an early JDK release. The ability
35+
* to "stop" a thread with {@code Thread.stop} has been removed and the
36+
* {@code Thread.stop} method changed to throw an exception. Consequently,
37+
* {@code ThreadDeath} is also deprecated, for removal.
4538
*
4639
* @since 1.0
4740
*/
48-
41+
@Deprecated(since="20", forRemoval=true)
4942
public class ThreadDeath extends Error {
5043
@java.io.Serial
5144
private static final long serialVersionUID = -4417128565033088268L;

src/java.base/share/classes/java/lang/ThreadGroup.java

+5-9
Original file line numberDiff line numberDiff line change
@@ -674,12 +674,9 @@ private void list(Map<ThreadGroup, List<Thread>> map, PrintStream out, int inden
674674
* uncaught exception handler} installed, and if so, its
675675
* {@code uncaughtException} method is called with the same
676676
* two arguments.
677-
* <li>Otherwise, this method determines if the {@code Throwable}
678-
* argument is an instance of {@link ThreadDeath}. If so, nothing
679-
* special is done. Otherwise, a message containing the
680-
* thread's name, as returned from the thread's {@link
681-
* Thread#getName getName} method, and a stack backtrace,
682-
* using the {@code Throwable}'s {@link
677+
* <li>Otherwise, a message containing the thread's name, as returned
678+
* from the thread's {@link Thread#getName getName} method, and a
679+
* stack backtrace, using the {@code Throwable}'s {@link
683680
* Throwable#printStackTrace() printStackTrace} method, is
684681
* printed to the {@linkplain System#err standard error stream}.
685682
* </ul>
@@ -699,9 +696,8 @@ public void uncaughtException(Thread t, Throwable e) {
699696
Thread.getDefaultUncaughtExceptionHandler();
700697
if (ueh != null) {
701698
ueh.uncaughtException(t, e);
702-
} else if (!(e instanceof ThreadDeath)) {
703-
System.err.print("Exception in thread \""
704-
+ t.getName() + "\" ");
699+
} else {
700+
System.err.print("Exception in thread \"" + t.getName() + "\" ");
705701
e.printStackTrace(System.err);
706702
}
707703
}

src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html

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

src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -178,7 +178,7 @@ else if (info.getClass() == int[].class) {
178178
catch (Error e) {
179179
// Pass through an Error, including BootstrapMethodError, any other
180180
// form of linkage error, such as IllegalAccessError if the bootstrap
181-
// method is inaccessible, or say ThreadDeath/OutOfMemoryError
181+
// method is inaccessible, or say OutOfMemoryError
182182
// See the "Linking Exceptions" section for the invokedynamic
183183
// instruction in JVMS 6.5.
184184
throw e;

src/java.base/share/classes/java/lang/invoke/CallSite.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ static CallSite makeSite(MethodHandle bootstrapMethod,
335335
} catch (Error e) {
336336
// Pass through an Error, including BootstrapMethodError, any other
337337
// form of linkage error, such as IllegalAccessError if the bootstrap
338-
// method is inaccessible, or say ThreadDeath/OutOfMemoryError
338+
// method is inaccessible, or say OutOfMemoryError
339339
// See the "Linking Exceptions" section for the invokedynamic
340340
// instruction in JVMS 6.5.
341341
throw e;

src/java.base/share/classes/sun/security/util/SecurityConstants.java

-4
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,6 @@ private SecurityConstants () {
124124
public static final RuntimePermission GET_CLASSLOADER_PERMISSION =
125125
new RuntimePermission("getClassLoader");
126126

127-
// java.lang.Thread
128-
public static final RuntimePermission STOP_THREAD_PERMISSION =
129-
new RuntimePermission("stopThread");
130-
131127
// java.lang.Thread
132128
public static final RuntimePermission GET_STACK_TRACE_PERMISSION =
133129
new RuntimePermission("getStackTrace");

src/java.base/share/native/libjava/Thread.c

-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737

3838
static JNINativeMethod methods[] = {
3939
{"start0", "()V", (void *)&JVM_StartThread},
40-
{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},
4140
{"isAlive0", "()Z", (void *)&JVM_IsThreadAlive},
4241
{"suspend0", "()V", (void *)&JVM_SuspendThread},
4342
{"resume0", "()V", (void *)&JVM_ResumeThread},

0 commit comments

Comments
 (0)