Skip to content

Commit e006df4

Browse files
committed
[GR-49914] Backport to 23.0: Prevent automatic leave of an explicitly entered context during close called from a host call
PullRequest: graal/16015
2 parents 408429e + 283d0f8 commit e006df4

File tree

6 files changed

+147
-23
lines changed

6 files changed

+147
-23
lines changed

sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Engine.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,11 @@ public ThreadScope createThreadScope() {
12391239
return null;
12401240
}
12411241

1242+
@Override
1243+
public boolean isInCurrentEngineHostCallback(Object engine) {
1244+
return false;
1245+
}
1246+
12421247
@Override
12431248
public OptionDescriptors createUnionOptionDescriptors(OptionDescriptors... optionDescriptors) {
12441249
return OptionDescriptors.createUnion(optionDescriptors);

sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/impl/AbstractPolyglotImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,10 @@ public ThreadScope createThreadScope() {
11861186
return getNext().createThreadScope();
11871187
}
11881188

1189+
public boolean isInCurrentEngineHostCallback(Object engine) {
1190+
return getNext().isInCurrentEngineHostCallback(engine);
1191+
}
1192+
11891193
public LogHandler newLogHandler(Object logHandlerOrStream) {
11901194
return getNext().newLogHandler(logHandlerOrStream);
11911195
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.api.test.polyglot;
42+
43+
import org.graalvm.polyglot.Context;
44+
import org.graalvm.polyglot.HostAccess;
45+
import org.junit.Assert;
46+
import org.junit.Test;
47+
48+
import com.oracle.truffle.api.ContextThreadLocal;
49+
import com.oracle.truffle.api.TruffleLanguage;
50+
import com.oracle.truffle.api.interop.InteropLibrary;
51+
import com.oracle.truffle.api.nodes.RootNode;
52+
import com.oracle.truffle.api.test.common.AbstractExecutableTestLanguage;
53+
54+
public class AutomaticLeaveTest {
55+
56+
static class ThreadContext {
57+
58+
}
59+
60+
@TruffleLanguage.Registration
61+
static class AutomaticLeaveInHostCallTestLanguage extends AbstractExecutableTestLanguage {
62+
63+
final ContextThreadLocal<ThreadContext> threadContext = createContextThreadLocal((c, t) -> new ThreadContext());
64+
65+
@Override
66+
protected Object execute(RootNode node, Env env, Object[] contextArguments, Object[] frameArguments) throws Exception {
67+
if (contextArguments[0] != null) {
68+
InteropLibrary.getUncached().invokeMember(contextArguments[0], "close");
69+
}
70+
// If the close operation automatically leaves the explicitly entered context, then
71+
// context thread local get fails.
72+
threadContext.get();
73+
return null;
74+
}
75+
}
76+
77+
public static class ContextCloser {
78+
private final Context context;
79+
80+
public ContextCloser(Context context) {
81+
this.context = context;
82+
}
83+
84+
public void close() {
85+
context.close();
86+
}
87+
}
88+
89+
@Test
90+
public void testAutomaticLeave() {
91+
try (Context context = Context.newBuilder().allowHostAccess(HostAccess.ALL).build()) {
92+
context.enter();
93+
AbstractExecutableTestLanguage.evalTestLanguage(context, AutomaticLeaveInHostCallTestLanguage.class, "", new Object[]{null});
94+
Context.getCurrent();
95+
}
96+
AbstractPolyglotTest.assertFails(Context::getCurrent, IllegalStateException.class, (e) -> Assert.assertTrue(e.getMessage().startsWith("No current context is available.")));
97+
}
98+
99+
@Test
100+
public void testNoAutomaticLeaveInHostCall() {
101+
try (Context context = Context.newBuilder().allowHostAccess(HostAccess.ALL).build()) {
102+
context.enter();
103+
AbstractExecutableTestLanguage.evalTestLanguage(context, AutomaticLeaveInHostCallTestLanguage.class, "", new ContextCloser(context));
104+
Context.getCurrent();
105+
}
106+
AbstractPolyglotTest.assertFails(Context::getCurrent, IllegalStateException.class, (e) -> Assert.assertTrue(e.getMessage().startsWith("No current context is available.")));
107+
}
108+
}

truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/reflection.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,5 +216,9 @@
216216
{
217217
"name": "com.oracle.truffle.polyglot.PolyglotLanguageInstance",
218218
"allDeclaredFields": true, "allPublicFields": true
219+
},
220+
{
221+
"name": "com.oracle.truffle.api.test.polyglot.AutomaticLeaveTest$ContextCloser",
222+
"allPublicMethods": true
219223
}
220224
]

truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotContextImpl.java

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@
9292
import com.oracle.truffle.api.CompilerDirectives;
9393
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
9494
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
95-
import com.oracle.truffle.api.RootCallTarget;
9695
import com.oracle.truffle.api.ThreadLocalAction;
9796
import com.oracle.truffle.api.Truffle;
9897
import com.oracle.truffle.api.TruffleContext;
@@ -1527,27 +1526,6 @@ static void printResult(PolyglotLanguageContext languageContext, Object result)
15271526
}
15281527
}
15291528

1530-
private static boolean isCurrentEngineHostCallback(PolyglotEngineImpl engine) {
1531-
RootNode topMostGuestToHostRootNode = Truffle.getRuntime().iterateFrames((f) -> {
1532-
RootNode root = ((RootCallTarget) f.getCallTarget()).getRootNode();
1533-
if (EngineAccessor.HOST.isGuestToHostRootNode(root)) {
1534-
return root;
1535-
}
1536-
return null;
1537-
});
1538-
if (topMostGuestToHostRootNode == null) {
1539-
return false;
1540-
} else {
1541-
PolyglotSharingLayer sharing = (PolyglotSharingLayer) EngineAccessor.NODES.getSharingLayer(topMostGuestToHostRootNode);
1542-
PolyglotEngineImpl rootEngine = sharing.engine;
1543-
if (rootEngine == engine) {
1544-
return true;
1545-
} else {
1546-
return false;
1547-
}
1548-
}
1549-
}
1550-
15511529
/**
15521530
* Embedder close.
15531531
*/
@@ -2365,7 +2343,7 @@ synchronized void clearExplicitContextStack() {
23652343
if (parent == null) {
23662344
engine.polyglotHostService.notifyClearExplicitContextStack(this);
23672345
}
2368-
if (isActive(Thread.currentThread()) && !isCurrentEngineHostCallback(engine)) {
2346+
if (isActive(Thread.currentThread()) && !engine.getImpl().getRootImpl().isInCurrentEngineHostCallback(engine)) {
23692347
PolyglotThreadInfo threadInfo = getCurrentThreadInfo();
23702348
if (!threadInfo.explicitContextStack.isEmpty()) {
23712349
PolyglotContextImpl c = this;

truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,14 @@
8181
import org.graalvm.polyglot.proxy.Proxy;
8282

8383
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
84+
import com.oracle.truffle.api.RootCallTarget;
85+
import com.oracle.truffle.api.Truffle;
8486
import com.oracle.truffle.api.TruffleFile;
8587
import com.oracle.truffle.api.TruffleLanguage;
8688
import com.oracle.truffle.api.TruffleOptions;
8789
import com.oracle.truffle.api.impl.DispatchOutputStream;
8890
import com.oracle.truffle.api.interop.TruffleObject;
91+
import com.oracle.truffle.api.nodes.RootNode;
8992
import com.oracle.truffle.api.source.Source;
9093
import com.oracle.truffle.api.strings.TruffleString;
9194
import com.oracle.truffle.polyglot.PolyglotEngineImpl.LogConfig;
@@ -519,6 +522,28 @@ public ThreadScope createThreadScope() {
519522
return null;
520523
}
521524

525+
@Override
526+
public boolean isInCurrentEngineHostCallback(Object engine) {
527+
RootNode topMostGuestToHostRootNode = Truffle.getRuntime().iterateFrames((f) -> {
528+
RootNode root = ((RootCallTarget) f.getCallTarget()).getRootNode();
529+
if (EngineAccessor.HOST.isGuestToHostRootNode(root)) {
530+
return root;
531+
}
532+
return null;
533+
});
534+
if (topMostGuestToHostRootNode == null) {
535+
return false;
536+
} else {
537+
PolyglotSharingLayer sharing = (PolyglotSharingLayer) EngineAccessor.NODES.getSharingLayer(topMostGuestToHostRootNode);
538+
PolyglotEngineImpl rootEngine = sharing.engine;
539+
if (rootEngine == engine) {
540+
return true;
541+
} else {
542+
return false;
543+
}
544+
}
545+
}
546+
522547
@Override
523548
public LogHandler newLogHandler(Object logHandlerOrStream) {
524549
return PolyglotLoggers.asLogHandler(this, logHandlerOrStream);

0 commit comments

Comments
 (0)