Skip to content
This repository was archived by the owner on Sep 19, 2023. It is now read-only.

Commit 7cf71bc

Browse files
author
Alan Bateman
committed
8287982: Concurrent implicit attach from native threads crashes VM
Reviewed-by: dholmes, rehn
1 parent 9e2d9ac commit 7cf71bc

File tree

7 files changed

+381
-38
lines changed

7 files changed

+381
-38
lines changed

make/test/JtregNativeJdk.gmk

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ BUILD_JDK_JTREG_EXECUTABLES_CFLAGS_exeJliLaunchTest := \
5555

5656
# Platform specific setup
5757
ifeq ($(call isTargetOs, windows), true)
58-
BUILD_JDK_JTREG_EXCLUDE += libDirectIO.c libInheritedChannel.c exelauncher.c
58+
BUILD_JDK_JTREG_EXCLUDE += libDirectIO.c libInheritedChannel.c \
59+
libExplicitAttach.c libImplicitAttach.c \
60+
exelauncher.c
5961

6062
WIN_LIB_JAVA := $(SUPPORT_OUTPUTDIR)/native/java.base/libjava/java.lib
6163
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := $(WIN_LIB_JAVA)
@@ -84,6 +86,9 @@ else
8486
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLinkerInvokerUnnamed := $(LIBCXX) -pthread
8587
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLinkerInvokerModule := $(LIBCXX) -pthread
8688
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLoaderLookupInvoker := $(LIBCXX) -pthread
89+
BUILD_JDK_JTREG_LIBRARIES_LIBS_libExplicitAttach := -ljvm
90+
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libExplicitAttach := -pthread
91+
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libImplicitAttach := -pthread
8792
BUILD_JDK_JTREG_EXCLUDE += exerevokeall.c
8893
ifeq ($(call isTargetOs, linux), true)
8994
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava

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

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -652,43 +652,48 @@ private static ClassLoader contextClassLoader(Thread parent) {
652652
@SuppressWarnings("removal")
653653
Thread(ThreadGroup g, String name, int characteristics, Runnable task,
654654
long stackSize, AccessControlContext acc) {
655-
if (name == null) {
656-
throw new InternalError("name cannot be null");
657-
}
658655

659656
Thread parent = currentThread();
660657
boolean attached = (parent == this); // primordial or JNI attached
661-
if (attached && g == null) {
662-
throw new InternalError("group cannot be null when attaching");
663-
}
664658

665-
SecurityManager security = System.getSecurityManager();
666-
if (g == null) {
667-
// the security manager can choose the thread group
668-
if (security != null) {
669-
g = security.getThreadGroup();
659+
if (attached) {
660+
if (g == null) {
661+
throw new InternalError("group cannot be null when attaching");
670662
}
671-
672-
// default to current thread's group
663+
this.holder = new FieldHolder(g, task, stackSize, NORM_PRIORITY, false);
664+
} else {
665+
SecurityManager sm = System.getSecurityManager();
673666
if (g == null) {
674-
g = parent.getThreadGroup();
667+
// the security manager can choose the thread group
668+
if (sm != null) {
669+
g = sm.getThreadGroup();
670+
}
671+
672+
// default to current thread's group
673+
if (g == null) {
674+
g = parent.getThreadGroup();
675+
}
675676
}
676-
}
677677

678-
// permission checks when creating a child Thread
679-
if (!attached && security != null) {
680-
security.checkAccess(g);
681-
if (isCCLOverridden(getClass())) {
682-
security.checkPermission(SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
678+
// permission checks when creating a child Thread
679+
if (sm != null) {
680+
sm.checkAccess(g);
681+
if (isCCLOverridden(getClass())) {
682+
sm.checkPermission(SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
683+
}
683684
}
685+
686+
int priority = Math.min(parent.getPriority(), g.getMaxPriority());
687+
this.holder = new FieldHolder(g, task, stackSize, priority, parent.isDaemon());
684688
}
685689

686690
if (attached && VM.initLevel() < 1) {
687691
this.tid = 1; // primordial thread
688692
} else {
689693
this.tid = ThreadIdentifiers.next();
690694
}
691-
this.name = name;
695+
this.name = (name != null) ? name : genThreadName();
696+
692697
if (acc != null) {
693698
this.inheritedAccessControlContext = acc;
694699
} else {
@@ -720,18 +725,6 @@ private static ClassLoader contextClassLoader(Thread parent) {
720725
this.contextClassLoader = ClassLoader.getSystemClassLoader();
721726
}
722727
}
723-
724-
int priority;
725-
boolean daemon;
726-
if (attached) {
727-
// primordial or attached thread
728-
priority = NORM_PRIORITY;
729-
daemon = false;
730-
} else {
731-
priority = Math.min(parent.getPriority(), g.getMaxPriority());
732-
daemon = parent.isDaemon();
733-
}
734-
this.holder = new FieldHolder(g, task, stackSize, priority, daemon);
735728
}
736729

737730
/**
@@ -1153,7 +1146,7 @@ private static String checkName(String name) {
11531146
* @see <a href="#inheritance">Inheritance when creating threads</a>
11541147
*/
11551148
public Thread() {
1156-
this(null, genThreadName(), 0, null, 0, null);
1149+
this(null, null, 0, null, 0, null);
11571150
}
11581151

11591152
/**
@@ -1174,7 +1167,7 @@ public Thread() {
11741167
* @see <a href="#inheritance">Inheritance when creating threads</a>
11751168
*/
11761169
public Thread(Runnable task) {
1177-
this(null, genThreadName(), 0, task, 0, null);
1170+
this(null, null, 0, task, 0, null);
11781171
}
11791172

11801173
/**
@@ -1183,7 +1176,7 @@ public Thread(Runnable task) {
11831176
* This is not a public constructor.
11841177
*/
11851178
Thread(Runnable task, @SuppressWarnings("removal") AccessControlContext acc) {
1186-
this(null, genThreadName(), 0, task, 0, acc);
1179+
this(null, null, 0, task, 0, acc);
11871180
}
11881181

11891182
/**
@@ -1216,7 +1209,7 @@ public Thread(Runnable task) {
12161209
* @see <a href="#inheritance">Inheritance when creating threads</a>
12171210
*/
12181211
public Thread(ThreadGroup group, Runnable task) {
1219-
this(group, genThreadName(), 0, task, 0, null);
1212+
this(group, null, 0, task, 0, null);
12201213
}
12211214

12221215
/**
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/**
25+
* @test
26+
* @bug 8287982
27+
* @summary Test native threads attaching to the VM with JNI AttachCurrentThread
28+
* @requires (os.family == "linux" | os.family == "mac")
29+
* @library /test/lib
30+
* @compile ExplicitAttach.java
31+
* @run main AttachTest ExplicitAttach 1
32+
* @run main AttachTest ExplicitAttach 2
33+
* @run main AttachTest ExplicitAttach 4
34+
*/
35+
36+
/**
37+
* @test
38+
* @summary Test native threads attaching implicitly to the VM by means of an upcall
39+
* @requires (os.family == "linux" | os.family == "mac") & (sun.arch.data.model == "64")
40+
* @library /test/lib
41+
* @compile --enable-preview -source ${jdk.version} ImplicitAttach.java
42+
* @run main AttachTest --enable-preview --enable-native-access=ALL-UNNAMED ImplicitAttach 1
43+
* @run main AttachTest --enable-preview --enable-native-access=ALL-UNNAMED ImplicitAttach 2
44+
* @run main AttachTest --enable-preview --enable-native-access=ALL-UNNAMED ImplicitAttach 4
45+
*/
46+
47+
import java.util.stream.Stream;
48+
import jdk.test.lib.process.ProcessTools;
49+
import jdk.test.lib.process.OutputAnalyzer;
50+
51+
public class AttachTest {
52+
static final String TEST_CLASSES = System.getProperty("test.classes");
53+
static final String JAVA_LIBRARY_PATH = System.getProperty("java.library.path");
54+
55+
public static void main(String[] args) throws Exception {
56+
// prepend -cp ${test.classes} -Djava.library.path=${java.library.path}
57+
String[] opts = Stream.concat(Stream.of(
58+
"-cp", TEST_CLASSES,
59+
"-Djava.library.path=" + JAVA_LIBRARY_PATH),
60+
Stream.of(args))
61+
.toArray(String[]::new);
62+
OutputAnalyzer outputAnalyzer = ProcessTools
63+
.executeTestJava(opts)
64+
.outputTo(System.out)
65+
.errorTo(System.out);
66+
int exitValue = outputAnalyzer.getExitValue();
67+
if (exitValue != 0)
68+
throw new RuntimeException("Test failed");
69+
}
70+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.util.concurrent.CountDownLatch;
25+
26+
/**
27+
* Test native threads attaching to the VM with JNI AttachCurrentThread.
28+
*/
29+
public class ExplicitAttach {
30+
private static volatile CountDownLatch latch;
31+
32+
public static void main(String[] args) throws Exception {
33+
int threadCount;
34+
if (args.length > 0) {
35+
threadCount = Integer.parseInt(args[0]);
36+
} else {
37+
threadCount = 2;
38+
}
39+
latch = new CountDownLatch(threadCount);
40+
41+
// start the threads and wait for the threads to call home
42+
startThreads(threadCount);
43+
latch.await();
44+
}
45+
46+
/**
47+
* Invoked by attached threads.
48+
*/
49+
private static void callback() {
50+
System.out.println(Thread.currentThread());
51+
latch.countDown();
52+
}
53+
54+
/**
55+
* Start n native threads that attach to the VM and invoke callback.
56+
*/
57+
private static native void startThreads(int n);
58+
59+
static {
60+
System.loadLibrary("ExplicitAttach");
61+
}
62+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.lang.foreign.*;
25+
import java.lang.invoke.MethodHandle;
26+
import java.lang.invoke.MethodHandles;
27+
import java.lang.invoke.MethodType;
28+
import java.util.concurrent.CountDownLatch;
29+
30+
/**
31+
* Test native threads attaching implicitly to the VM by means of an upcall.
32+
*/
33+
public class ImplicitAttach {
34+
private static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT.withBitAlignment(32);
35+
private static final ValueLayout.OfAddress C_POINTER = ValueLayout.ADDRESS.withBitAlignment(64);
36+
37+
private static volatile CountDownLatch latch;
38+
39+
public static void main(String[] args) throws Throwable {
40+
int threadCount;
41+
if (args.length > 0) {
42+
threadCount = Integer.parseInt(args[0]);
43+
} else {
44+
threadCount = 2;
45+
}
46+
latch = new CountDownLatch(threadCount);
47+
48+
Linker abi = Linker.nativeLinker();
49+
50+
// stub to invoke callback
51+
MethodHandle callback = MethodHandles.lookup()
52+
.findStatic(ImplicitAttach.class, "callback", MethodType.methodType(void.class));
53+
MemorySegment upcallStub = abi.upcallStub(callback,
54+
FunctionDescriptor.ofVoid(),
55+
MemorySession.openImplicit());
56+
57+
// void start_threads(int count, void *(*f)(void *))
58+
SymbolLookup symbolLookup = SymbolLookup.loaderLookup();
59+
MemorySegment symbol = symbolLookup.lookup("start_threads").orElseThrow();
60+
FunctionDescriptor desc = FunctionDescriptor.ofVoid(C_INT, C_POINTER);
61+
MethodHandle start_threads = abi.downcallHandle(symbol, desc);
62+
63+
// start the threads and wait for the threads to call home
64+
start_threads.invoke(threadCount, upcallStub);
65+
latch.await();
66+
}
67+
68+
/**
69+
* Invoked from native thread.
70+
*/
71+
private static void callback() {
72+
System.out.println(Thread.currentThread());
73+
latch.countDown();
74+
}
75+
76+
static {
77+
System.loadLibrary("ImplicitAttach");
78+
}
79+
}

0 commit comments

Comments
 (0)