Skip to content

Commit

Permalink
Ensure disable private check cmd line option disables runtime private…
Browse files Browse the repository at this point in the history
… access checks (#10034)

Ensure that `--disable-private-check` cmd line option disables the runtime private access checks as well.
  • Loading branch information
Akirathan authored May 22, 2024
1 parent 91a2afb commit ba2787c
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.enso.polyglot.PolyglotContext;
import org.enso.polyglot.RuntimeOptions;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Context.Builder;
import org.graalvm.polyglot.Language;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
Expand Down Expand Up @@ -227,14 +228,16 @@ protected static Path createProject(
* Tests running the project located in the given {@code projDir}. Is equal to running {@code enso
* --run <projDir>}.
*
* @param ctxBuilder A context builder that might be initialized with some specific options.
* @param projDir Root directory of the project.
* @param resultConsumer Any action that is to be evaluated on the result of running the {@code
* main} method
*/
protected void testProjectRun(Path projDir, Consumer<Value> resultConsumer) {
protected void testProjectRun(
Context.Builder ctxBuilder, Path projDir, Consumer<Value> resultConsumer) {
assert projDir.toFile().exists() && projDir.toFile().isDirectory();
try (var ctx =
defaultContextBuilder()
ctxBuilder
.option(RuntimeOptions.PROJECT_ROOT, projDir.toAbsolutePath().toString())
.option(RuntimeOptions.STRICT_ERRORS, "true")
.option(RuntimeOptions.DISABLE_IR_CACHES, "true")
Expand All @@ -249,6 +252,17 @@ protected void testProjectRun(Path projDir, Consumer<Value> resultConsumer) {
}
}

/**
* Just a wrapper for {@link TestBase#testProjectRun(Builder, Path, Consumer)}.
*
* @param projDir Root directory of the project.
* @param resultConsumer Any action that is to be evaluated on the result of running the {@code
* main} method
*/
protected void testProjectRun(Path projDir, Consumer<Value> resultConsumer) {
testProjectRun(defaultContextBuilder(), projDir, resultConsumer);
}

/** A simple structure corresponding to an Enso module. */
public record SourceModule(QualifiedName name, String code) {}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.enso.interpreter.test;
package org.enso.interpreter.test.privateaccess;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
Expand All @@ -10,6 +10,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import org.enso.interpreter.test.TestBase;
import org.enso.interpreter.util.ScalaConversions;
import org.enso.polyglot.PolyglotContext;
import org.enso.polyglot.RuntimeOptions;
Expand Down Expand Up @@ -47,20 +48,13 @@ public void privateFieldIsNotExposedToPolyglot() throws IOException {
main = My_Type.Cons 42
""";
var projDir = createProject("My_Project", mainSrc, tempFolder);
var mainSrcPath = projDir.resolve("src").resolve("Main.enso");
try (var ctx =
defaultContextBuilder()
.option(RuntimeOptions.PROJECT_ROOT, projDir.toAbsolutePath().toString())
.build()) {
var polyCtx = new PolyglotContext(ctx);
var mainMod = polyCtx.evalModule(mainSrcPath.toFile());
var assocType = mainMod.getAssociatedType();
var mainMethod = mainMod.getMethod(assocType, "main").get();
var res = mainMethod.execute();
assertThat(res.hasMember("data"), is(false));
assertThat(res.canInvokeMember("data"), is(false));
assertThat(res.getMember("data"), is(nullValue()));
}
testProjectRun(
projDir,
res -> {
assertThat(res.hasMember("data"), is(false));
assertThat(res.canInvokeMember("data"), is(false));
assertThat(res.getMember("data"), is(nullValue()));
});
}

@Test
Expand Down Expand Up @@ -127,19 +121,12 @@ public void canPatternMatchOnPrivateConstructorFromSameProject() throws IOExcept
_ -> 0
""";
var projDir = createProject("My_Project", mainSrc, tempFolder);
var mainSrcPath = projDir.resolve("src").resolve("Main.enso");
try (var ctx =
defaultContextBuilder()
.option(RuntimeOptions.PROJECT_ROOT, projDir.toAbsolutePath().toString())
.build()) {
var polyCtx = new PolyglotContext(ctx);
var mainMod = polyCtx.evalModule(mainSrcPath.toFile());
var assocType = mainMod.getAssociatedType();
var mainMethod = mainMod.getMethod(assocType, "main").get();
var res = mainMethod.execute();
assertThat(res.isNumber(), is(true));
assertThat(res.asInt(), is(42));
}
testProjectRun(
projDir,
res -> {
assertThat(res.isNumber(), is(true));
assertThat(res.asInt(), is(42));
});
}

/** Tests that pattern matching on private constructors fails in compilation. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.enso.interpreter.test.privateaccess;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import java.io.IOException;
import org.enso.interpreter.test.TestBase;
import org.enso.polyglot.RuntimeOptions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class PrivateCheckDisabledTest extends TestBase {
@Rule public TemporaryFolder tempFolder = new TemporaryFolder();

@Test
public void privateCtorCanBeAccessedWhenPrivateCheckIsDisabled() throws IOException {
var libSrc = """
type T
private Cons data
""";
createProject("Lib", libSrc, tempFolder);
var mainSrc =
"""
from local.Lib import T
main =
obj = T.Cons 42
obj.data
""";
var mainDir = createProject("Main", mainSrc, tempFolder);
var ctxBuilder = defaultContextBuilder().option(RuntimeOptions.DISABLE_PRIVATE_CHECK, "true");
testProjectRun(
ctxBuilder,
mainDir,
res -> {
assertThat(res.isNumber(), is(true));
assertThat(res.asInt(), is(42));
});
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.enso.interpreter.node.callable.dispatch;

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleFile;
import com.oracle.truffle.api.dsl.Cached;
Expand Down Expand Up @@ -113,6 +114,16 @@ private PanicException makePrivateAccessPanic(Function targetFunction) {
return new PanicException(err, this);
}

private void ensureFunctionIsAccessible(Function function, FunctionSchema functionSchema) {
var isPrivateCheckDisabled = getContext().isPrivateCheckDisabled();
CompilerAsserts.compilationConstant(isPrivateCheckDisabled);
if (!isPrivateCheckDisabled
&& functionSchema.isProjectPrivate()
&& !isInSameProject(function)) {
throw makePrivateAccessPanic(function);
}
}

@Specialization(
guards = {"!getContext().isInlineCachingDisabled()", "function.getSchema() == cachedSchema"},
limit = Constants.CacheSizes.ARGUMENT_SORTER_NODE)
Expand All @@ -130,9 +141,7 @@ Object invokeCached(
"build(argumentMapping, getDefaultsExecutionMode(), getArgumentsExecutionMode(),"
+ " getTailStatus())")
CurryNode curryNode) {
if (cachedSchema.isProjectPrivate() && !isInSameProject(function)) {
throw makePrivateAccessPanic(function);
}
ensureFunctionIsAccessible(function, cachedSchema);

ArgumentSorterNode.MappedArguments mappedArguments =
mappingNode.execute(callerFrame, function, state, arguments);
Expand Down Expand Up @@ -174,9 +183,7 @@ Object invokeUncached(
Object[] arguments,
@Cached IndirectArgumentSorterNode mappingNode,
@Cached IndirectCurryNode curryNode) {
if (function.getSchema().isProjectPrivate() && !isInSameProject(function)) {
throw makePrivateAccessPanic(function);
}
ensureFunctionIsAccessible(function, function.getSchema());

CallArgumentInfo.ArgumentMapping argumentMapping =
CallArgumentInfo.ArgumentMappingBuilder.generate(function.getSchema(), getSchema());
Expand Down

0 comments on commit ba2787c

Please sign in to comment.