Skip to content

Commit

Permalink
Allow control of throwDeniedThreadAccess via TruffleContext.threadAcc…
Browse files Browse the repository at this point in the history
…essDeniedHandler
  • Loading branch information
Jaroslav Tulach committed Sep 20, 2024
1 parent a8b0afe commit 85854c0
Show file tree
Hide file tree
Showing 16 changed files with 406 additions and 223 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,8 @@ public abstract Object createContext(Object receiver, SandboxPolicy sandboxPolic
Object hostAccess,
Object polyglotAccess,
boolean allowNativeAccess,
boolean allowCreateThread, boolean allowHostClassLoading, boolean allowInnerContextOptions, boolean allowExperimentalOptions,
boolean allowCreateThread,
boolean allowHostClassLoading, boolean allowInnerContextOptions, boolean allowExperimentalOptions,
Predicate<String> classFilter,
Map<String, String> options,
Map<String, String[]> arguments, String[] onlyLanguages, Object ioAccess, Object logHandler, boolean allowCreateProcess, ProcessHandler processHandler,
Expand Down
1 change: 1 addition & 0 deletions truffle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This changelog summarizes major changes between Truffle versions relevant to lan
* GR-57164 Added support for reading unaligned ints, shorts and long to `ByteArraySupport`.
* GR-57164 `RootNode.translateStackTraceElement()` is now always consulted for polyglot and debugger stack traces. Stack traces now use the source section, the executable name, the name of the declared meta-object to build `StackTraceElement` instances.
* GR-57322 Added `TruffleLanguage.Env.getHostLanguage()` returning the host language info. This allows languages to lookup the top scope of the host language using `Env.getScopeInternal(LanguageInfo)`.
* PR-8266 Allow control of `throwDeniedThreadAccess` via `TruffleContext.threadAccessDeniedHandler`


## Version 24.1.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2268,10 +2268,10 @@ void create(String[] expectedServices) {
}

private boolean checkServices(String[] expectedServices) {
LOOP: for (String name : expectedServices) {
loop: for (String name : expectedServices) {
for (Object obj : services) {
if (findType(name, obj.getClass())) {
continue LOOP;
continue loop;
}
}
failInstrumentInitialization(env, String.format("%s declares service %s but doesn't register it", instrumentClassName, name), null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,10 @@
*/
package com.oracle.truffle.api.test;

import static com.oracle.truffle.api.test.common.AbstractExecutableTestLanguage.evalTestLanguage;
import static com.oracle.truffle.api.test.common.AbstractExecutableTestLanguage.execute;
import static com.oracle.truffle.api.test.polyglot.AbstractPolyglotTest.assertFails;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.function.Consumer;

Expand All @@ -67,9 +65,15 @@
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.test.common.AbstractExecutableTestLanguage;
import static com.oracle.truffle.api.test.common.AbstractExecutableTestLanguage.evalTestLanguage;
import com.oracle.truffle.api.test.common.NullObject;
import com.oracle.truffle.api.test.common.TestUtils;
import com.oracle.truffle.api.test.polyglot.AbstractPolyglotTest;
import com.oracle.truffle.api.test.polyglot.MultiThreadedLanguage;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import org.hamcrest.core.AllOf;
import static org.junit.Assert.fail;

/*
* There is other TruffleContextTest in com.oracle.truffle.api.instrumentation.test package.
Expand Down Expand Up @@ -239,6 +243,49 @@ public void testCancelledInnerContext() {
}
}

@Registration
static class InnerContextTestLanguage5 extends AbstractExecutableTestLanguage {
@TruffleBoundary
@Override
protected Object execute(RootNode node, Env env, Object[] contextArguments, Object[] frameArguments) throws Exception {
try (TruffleContext context = env.newInnerContextBuilder(MultiThreadedLanguage.ID).inheritAllAccess(true).threadAccessDeniedHandler((msg) -> {
assertThat(msg, AllOf.allOf(
containsString("Single threaded access requested"),
containsString("but is not allowed for language(s) MultiThreadedLanguage")));
throw new SecurityException("Threads are not secure!");
}).build()) {
MultiThreadedLanguage.isThreadAccessAllowed = (req) -> {
return false;
};
try {
context.initializePublic(node, MultiThreadedLanguage.ID);
fail();
} catch (SecurityException e) {
assertEquals("Threads are not secure!", e.getMessage());
}
try {
context.evalPublic(node, Source.newBuilder(MultiThreadedLanguage.ID, "", "cannot.eval.src").build());
fail();
} catch (SecurityException e) {
assertEquals("Threads are not secure!", e.getMessage());
}
// allow again so we can close
MultiThreadedLanguage.isThreadAccessAllowed = (req) -> {
return true;
};
}
return NullObject.SINGLETON;
}
}

/** Verifies {@code threadAccessDeniedHandler}. */
@Test
public void testNoThreadAllowedWithSecurityException() {
try (Context context = Context.newBuilder().allowPolyglotAccess(PolyglotAccess.ALL).build()) {
evalTestLanguage(context, InnerContextTestLanguage5.class, "");
}
}

@Registration
static class InnerContextExitTestLanguage1 extends AbstractExecutableTestLanguage {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ public void testThreadCheck() throws InterruptedException, ExecutionException {

@Registration(id = SINGLE_THREAD, name = SINGLE_THREAD)
public static class SingleThreadedLanguage extends TruffleLanguage<Env> {
public static final String ID = SINGLE_THREAD;

@Override
protected Env createContext(Env env) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@
@TruffleLanguage.Registration(id = MultiThreadedLanguage.ID, name = MultiThreadedLanguage.ID)
public class MultiThreadedLanguage extends TruffleLanguage<LanguageContext> {

static final String ID = "MultiThreadedLanguage";
public static final String ID = "MultiThreadedLanguage";

static final ThreadLocal<Function<Env, Object>> runinside = new ThreadLocal<>();
public static final ThreadLocal<Function<Env, Object>> runinside = new ThreadLocal<>();
static volatile Function<ThreadRequest, Void> initializeThread;
static volatile Function<ThreadRequest, Boolean> isThreadAccessAllowed;
public static volatile Function<ThreadRequest, Boolean> isThreadAccessAllowed;
static volatile Function<ThreadRequest, Void> initializeMultiThreading;
static volatile Function<LanguageContext, Void> finalizeContext;
static volatile Function<ThreadRequest, Void> disposeThread;
Expand All @@ -73,7 +73,7 @@ static class LanguageContext {

}

static class ThreadRequest {
public static final class ThreadRequest {

final LanguageContext context;
final Thread thread;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ protected HostEngineDispatch(HostPolyglotDispatch polyglot) {
@Override
public Object createContext(Object receiver, SandboxPolicy sandboxPolicy, OutputStream out, OutputStream err, InputStream in, boolean allowHostAccess, Object hostAccess,
Object polyglotAccess,
boolean allowNativeAccess, boolean allowCreateThread, boolean allowHostClassLoading, boolean allowInnerContextOptions, boolean allowExperimentalOptions,
boolean allowNativeAccess, boolean allowCreateThread, boolean allowHostClassLoading, boolean allowInnerContextOptions,
boolean allowExperimentalOptions,
Predicate<String> classFilter, Map<String, String> options, Map<String, String[]> arguments, String[] onlyLanguages, Object ioAccess, Object logHandler,
boolean allowCreateProcess, ProcessHandler processHandler, Object environmentAccess, Map<String, String> environment, ZoneId zone, Object limitsImpl,
String currentWorkingDirectory, String tmpDir, ClassLoader hostClassLoader, boolean allowValueSharing, boolean useSystemExit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
* then it is automatically closed together with the parent context.
* <p>
* Example usage:
*
*
* {@snippet file="com/oracle/truffle/api/TruffleContext.java"
* region="TruffleContextSnippets.MyNode#executeInContext"}
*
Expand Down Expand Up @@ -533,7 +533,7 @@ public <T> T leaveAndEnter(Node node, Supplier<T> runWhileOutsideContext) {
* function is run at most once.
* @return return value of the interruptible, or <code>null</code> if the interruptibe throws an
* {@link InterruptedException} without the context being cancelled or exited.
*
*
* @since 23.1
*/
@SuppressWarnings("unused")
Expand Down Expand Up @@ -757,6 +757,7 @@ public final class Builder {
private Boolean allowPolyglotAccess;
private Boolean allowEnvironmentAccess;
private ZoneId timeZone;
private Consumer<String> threadAccessDeniedHandler;

Builder(Env env) {
this.sourceEnvironment = env;
Expand Down Expand Up @@ -1036,6 +1037,23 @@ public Builder allowPolyglotAccess(boolean b) {
return this;
}

/**
* Installs handler to control what happens on multiple thread access. When multiple threads
* are accessing a context which isn't ready for multithreaded access an exception is
* yielded by default. By installing this {@code handler} one can control what shall happen.
* Either to throw exception (with the provided reason) or to resolve the multithreaded
* situation somehow and return to retry the thread access again.
*
* @param handler callback (that gets a reason as an input) that either throws an exception
* or returns to signal a <b>request for retry</b>
* @return this builder
* @since 24.2
*/
public Builder threadAccessDeniedHandler(Consumer<String> handler) {
this.threadAccessDeniedHandler = handler;
return this;
}

/**
* Allows or denies access to the parent context's environment in this context. Set to
* <code>true</code> to inherit variables from the outer context or <code>false</code> to
Expand Down Expand Up @@ -1208,7 +1226,8 @@ public TruffleContext build() {
return LanguageAccessor.engineAccess().createInternalContext(
sourceEnvironment.getPolyglotLanguageContext(), this.out, this.err, this.in, this.timeZone,
this.permittedLanguages, this.config, this.options, this.arguments, this.sharingEnabled, this.initializeCreatorContext, this.onCancelled, this.onExited,
this.onClosed, this.inheritAccess, this.allowCreateThread, this.allowNativeAccess, this.allowIO, this.allowHostLookup, this.allowHostClassLoading,
this.onClosed, this.inheritAccess, this.allowCreateThread, this.threadAccessDeniedHandler, this.allowNativeAccess, this.allowIO, this.allowHostLookup,
this.allowHostClassLoading,
this.allowCreateProcess, this.allowPolyglotAccess, this.allowEnvironmentAccess, this.environment, this.allowInnerContextOptions);
} catch (Throwable t) {
throw Env.engineToLanguageException(t);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ public final void detachOutputConsumer(DispatchOutputStream dos, OutputStream ou
public abstract TruffleContext createInternalContext(Object sourcePolyglotLanguageContext, OutputStream out, OutputStream err, InputStream in,
ZoneId timeZone, String[] permittedLanguages, Map<String, Object> config, Map<String, String> options, Map<String, String[]> arguments,
Boolean sharingEnabled, boolean initializeCreatorContext, Runnable onCancelled, Consumer<Integer> onExited,
Runnable onClosed, boolean inheritAccess, Boolean allowCreateThreads, Boolean allowNativeAccess, Boolean allowIO,
Runnable onClosed, boolean inheritAccess, Boolean allowCreateThreads, Consumer<String> threadAccessDeniedHandler, Boolean allowNativeAccess, Boolean allowIO,
Boolean allowHostLookup, Boolean allowHostClassLoading, Boolean allowCreateProcess, Boolean allowPolyglotAccess,
Boolean allowEnvironmentAccess, Map<String, String> environment, Boolean allowInnerContextOptions);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,7 @@ public TruffleContext createInternalContext(Object sourcePolyglotLanguageContext
String[] onlyLanguagesArray, Map<String, Object> config, Map<String, String> options, Map<String, String[]> arguments,
Boolean sharingEnabled, boolean initializeCreatorContext, Runnable onCancelledRunnable,
Consumer<Integer> onExitedRunnable, Runnable onClosedRunnable, boolean inheritAccess, Boolean allowCreateThreads,
Consumer<String> threadAccessDeniedHandler,
Boolean allowNativeAccess, Boolean allowIO, Boolean allowHostLookup, Boolean allowHostClassLoading,
Boolean allowCreateProcess, Boolean allowPolyglotAccess, Boolean allowEnvironmentAccess,
Map<String, String> customEnvironment, Boolean allowInnerContextOptions) {
Expand Down Expand Up @@ -1110,6 +1111,8 @@ public TruffleContext createInternalContext(Object sourcePolyglotLanguageContext

ZoneId useTimeZone = timeZone == null ? creatorConfig.timeZone : timeZone;

Consumer<String> useDeniedThreadAccess = threadAccessDeniedHandler != null ? threadAccessDeniedHandler : creatorConfig.threadAccessDeniedHandler;

Map<String, String[]> useArguments;
if (arguments == null) {
// change: application arguments are not inherited by default
Expand All @@ -1119,7 +1122,7 @@ public TruffleContext createInternalContext(Object sourcePolyglotLanguageContext
}

PolyglotContextConfig innerConfig = new PolyglotContextConfig(engine, creatorConfig.sandboxPolicy, sharingEnabled, useOut, useErr, useIn,
useAllowHostLookup, usePolyglotAccess, useAllowNativeAccess, useAllowCreateThread, useAllowHostClassLoading,
useAllowHostLookup, usePolyglotAccess, useAllowNativeAccess, useAllowCreateThread, useDeniedThreadAccess, useAllowHostClassLoading,
useAllowInnerContextOptions, creatorConfig.allowExperimentalOptions,
useClassFilter, useArguments, allowedLanguages, useOptions, fileSystemConfig, creatorConfig.logHandler,
useAllowCreateProcess, useProcessHandler, useEnvironmentAccess, useCustomEnvironment,
Expand Down Expand Up @@ -1184,9 +1187,14 @@ public Thread createThread(Object polyglotLanguageContext, Runnable runnable, Ob
newThread = new Thread(group, task, name, stackSize);
}
newThread.setUncaughtExceptionHandler(threadContext.getPolyglotExceptionHandler());

threadContext.context.checkMultiThreadedAccess(newThread);
return newThread;
for (;;) {
try {
threadContext.context.checkMultiThreadedAccess(newThread);
return newThread;
} catch (PolyglotThreadAccessException ex) {
ex.rethrow(threadContext.context);
}
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ final class PolyglotContextConfig {
final Runnable onCancelled;
final Consumer<Integer> onExited;
final Runnable onClosed;
final Consumer<String> threadAccessDeniedHandler;

/**
* Groups PolyglotContext's filesystem related configurations.
Expand Down Expand Up @@ -231,6 +232,7 @@ private static Map<String, String> computeCommonOptions(Map<String, String> opti
sharableConfig.polyglotAccess == null ? engine.getAPIAccess().getPolyglotAccessAll() : sharableConfig.polyglotAccess,
sharableConfig.nativeAccessAllowed,
sharableConfig.createThreadAllowed,
null,
false,
false,
false,
Expand All @@ -256,7 +258,7 @@ private static Map<String, String> computeCommonOptions(Map<String, String> opti
PolyglotContextConfig(PolyglotEngineImpl engine, SandboxPolicy sandboxPolicy, Boolean forceSharing,
OutputStream out, OutputStream err, InputStream in,
boolean hostLookupAllowed, Object polyglotAccess, boolean nativeAccessAllowed,
boolean createThreadAllowed, boolean hostClassLoadingAllowed,
boolean createThreadAllowed, Consumer<String> threadAccessDeniedHandler, boolean hostClassLoadingAllowed,
boolean contextOptionsAllowed, boolean allowExperimentalOptions,
Predicate<String> classFilter, Map<String, String[]> applicationArguments,
Set<String> onlyLanguages, Map<String, String> options, FileSystemConfig fileSystemConfig, LogHandler logHandler,
Expand All @@ -278,6 +280,7 @@ private static Map<String, String> computeCommonOptions(Map<String, String> opti
this.polyglotAccess = polyglotAccess;
this.nativeAccessAllowed = nativeAccessAllowed;
this.createThreadAllowed = createThreadAllowed;
this.threadAccessDeniedHandler = threadAccessDeniedHandler;
this.hostClassLoadingAllowed = hostClassLoadingAllowed;
this.innerContextOptionsAllowed = contextOptionsAllowed;
this.allowExperimentalOptions = allowExperimentalOptions;
Expand Down
Loading

0 comments on commit 85854c0

Please sign in to comment.