Skip to content

Commit 6af9c99

Browse files
authored
Merge pull request #70046 from rintaro/macros-plugin-disablesandbox
[Macros] Add option to disable sandbox for exectuable plugins
2 parents bd4ee46 + 0c9f099 commit 6af9c99

File tree

9 files changed

+116
-11
lines changed

9 files changed

+116
-11
lines changed

include/swift/AST/PluginLoader.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class PluginLoader {
4444

4545
ASTContext &Ctx;
4646
DependencyTracker *DepTracker;
47+
const bool disableSandbox;
4748

4849
/// Map a module name to an plugin entry that provides the module.
4950
llvm::Optional<llvm::DenseMap<swift::Identifier, PluginEntry>> PluginMap;
@@ -52,8 +53,9 @@ class PluginLoader {
5253
llvm::DenseMap<swift::Identifier, PluginEntry> &getPluginMap();
5354

5455
public:
55-
PluginLoader(ASTContext &Ctx, DependencyTracker *DepTracker)
56-
: Ctx(Ctx), DepTracker(DepTracker) {}
56+
PluginLoader(ASTContext &Ctx, DependencyTracker *DepTracker,
57+
bool disableSandbox = false)
58+
: Ctx(Ctx), DepTracker(DepTracker), disableSandbox(disableSandbox) {}
5759

5860
void setRegistry(PluginRegistry *newValue);
5961
PluginRegistry *getRegistry();

include/swift/AST/PluginRegistry.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ class LoadedExecutablePlugin {
8989
/// Callbacks to be called when the connection is restored.
9090
llvm::SmallVector<std::function<void(void)> *, 0> onReconnect;
9191

92+
/// Disable sandbox.
93+
bool disableSandbox = false;
94+
9295
/// Flag to dump plugin messagings.
9396
bool dumpMessaging = false;
9497

@@ -99,9 +102,11 @@ class LoadedExecutablePlugin {
99102

100103
public:
101104
LoadedExecutablePlugin(llvm::StringRef ExecutablePath,
102-
llvm::sys::TimePoint<> LastModificationTime)
105+
llvm::sys::TimePoint<> LastModificationTime,
106+
bool disableSandbox)
103107
: ExecutablePath(ExecutablePath),
104-
LastModificationTime(LastModificationTime){};
108+
LastModificationTime(LastModificationTime),
109+
disableSandbox(disableSandbox){};
105110
~LoadedExecutablePlugin();
106111

107112
/// The last modification time of 'ExecutablePath' when this object is
@@ -181,7 +186,7 @@ class PluginRegistry {
181186
/// Load an executable plugin specified by \p path .
182187
/// If \p path plugin is already loaded, this returns the cached object.
183188
llvm::Expected<LoadedExecutablePlugin *>
184-
loadExecutablePlugin(llvm::StringRef path);
189+
loadExecutablePlugin(llvm::StringRef path, bool disableSandbox);
185190
};
186191

187192
} // namespace swift

include/swift/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,9 @@ class FrontendOptions {
415415
/// are present at LTO time.
416416
bool HermeticSealAtLink = false;
417417

418+
/// Disable using the sandbox when executing subprocesses.
419+
bool DisableSandbox = false;
420+
418421
/// The different modes for validating TBD against the LLVM IR.
419422
enum class TBDValidationMode {
420423
Default, ///< Do the default validation for the current platform.

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1948,4 +1948,9 @@ def load_plugin_executable:
19481948
"of module names where the macro types are declared">,
19491949
MetaVarName<"<path>#<module-names>">;
19501950

1951+
def disable_sandbox:
1952+
Flag<["-"], "disable-sandbox">,
1953+
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
1954+
HelpText<"Disable using the sandbox when executing subprocesses">;
1955+
19511956
include "FrontendOptions.td"

lib/AST/PluginLoader.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ PluginLoader::loadExecutablePlugin(StringRef path) {
199199
DepTracker->addDependency(resolvedPath, /*IsSystem=*/false);
200200

201201
// Load the plugin.
202-
auto plugin = getRegistry()->loadExecutablePlugin(resolvedPath);
202+
auto plugin =
203+
getRegistry()->loadExecutablePlugin(resolvedPath, disableSandbox);
203204
if (!plugin) {
204205
resolvedPath.push_back(0);
205206
return llvm::handleErrors(

lib/AST/PluginRegistry.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void *LoadedLibraryPlugin::getAddressOfSymbol(const char *symbolName) {
8484
}
8585

8686
llvm::Expected<LoadedExecutablePlugin *>
87-
PluginRegistry::loadExecutablePlugin(StringRef path) {
87+
PluginRegistry::loadExecutablePlugin(StringRef path, bool disableSandbox) {
8888
llvm::sys::fs::file_status stat;
8989
if (auto err = llvm::sys::fs::status(path, stat)) {
9090
return llvm::errorCodeToError(err);
@@ -114,7 +114,7 @@ PluginRegistry::loadExecutablePlugin(StringRef path) {
114114
}
115115

116116
auto plugin = std::make_unique<LoadedExecutablePlugin>(
117-
path, stat.getLastModificationTime());
117+
path, stat.getLastModificationTime(), disableSandbox);
118118

119119
plugin->setDumpMessaging(dumpMessaging);
120120

@@ -147,7 +147,9 @@ llvm::Error LoadedExecutablePlugin::spawnIfNeeded() {
147147

148148
// Apply sandboxing.
149149
llvm::BumpPtrAllocator Allocator;
150-
Sandbox::apply(command, Allocator);
150+
if (!disableSandbox) {
151+
Sandbox::apply(command, Allocator);
152+
}
151153

152154
// Launch.
153155
auto childInfo = ExecuteWithPipe(command[0], command);

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,8 @@ bool ArgsToFrontendOptionsConverter::convert(
395395
Opts.UseCASBackend = Args.hasArg(OPT_cas_backend);
396396
Opts.EmitCASIDFile = Args.hasArg(OPT_cas_emit_casid_file);
397397

398+
Opts.DisableSandbox = Args.hasArg(OPT_disable_sandbox);
399+
398400
return false;
399401
}
400402

lib/Frontend/Frontend.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -812,8 +812,9 @@ bool CompilerInstance::setUpModuleLoaders() {
812812

813813
bool CompilerInstance::setUpPluginLoader() {
814814
/// FIXME: If Invocation has 'PluginRegistry', we can set it. But should we?
815-
auto loader =
816-
std::make_unique<PluginLoader>(*Context, getDependencyTracker());
815+
auto loader = std::make_unique<PluginLoader>(
816+
*Context, getDependencyTracker(),
817+
Invocation.getFrontendOptions().DisableSandbox);
817818
Context->setPluginLoader(std::move(loader));
818819
return false;
819820
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
// sandbox-exec is only avaiable in Darwin
4+
// REQUIRES: OS=macosx
5+
6+
// RUN: %empty-directory(%t)
7+
// RUN: %empty-directory(%t/plugins)
8+
9+
// RUN: split-file %s %t
10+
11+
//== Build the plugins
12+
// RUN: %host-build-swift \
13+
// RUN: -swift-version 5 \
14+
// RUN: -emit-library \
15+
// RUN: -o %t/plugins/%target-library-name(MacroDefinition) \
16+
// RUN: -module-name=MacroDefinition \
17+
// RUN: %t/MacroDefinition.swift \
18+
// RUN: -g -no-toolchain-stdlib-rpath
19+
20+
// RUN: %swift-build-cxx-plugin -o %t/mock-plugin %t/TestPlugin.c
21+
22+
//== Nested sandbox. Expected to fail because sandbox-exec doesn't support nested sandboxing.
23+
// RUN: not sandbox-exec -p '(version 1)(allow default)' \
24+
// RUN: %swift-target-frontend \
25+
// RUN: -typecheck -verify \
26+
// RUN: -swift-version 5 \
27+
// RUN: -external-plugin-path %t/plugins#%swift-plugin-server \
28+
// RUN: -load-plugin-executable %t/mock-plugin#TestPlugin \
29+
// RUN: -module-name MyApp \
30+
// RUN: %t/test.swift
31+
32+
//== Avoid nested sandbox by -disable-sandbox
33+
// RUN: sandbox-exec -p '(version 1)(allow default)' \
34+
// RUN: %swift-target-frontend \
35+
// RUN: -disable-sandbox \
36+
// RUN: -typecheck -verify \
37+
// RUN: -swift-version 5 \
38+
// RUN: -external-plugin-path %t/plugins#%swift-plugin-server \
39+
// RUN: -load-plugin-executable %t/mock-plugin#TestPlugin \
40+
// RUN: -module-name MyApp \
41+
// RUN: %t/test.swift
42+
43+
44+
//--- MacroDefinition.swift
45+
import SwiftSyntax
46+
import SwiftSyntaxBuilder
47+
import SwiftSyntaxMacros
48+
49+
public struct StringifyMacro: ExpressionMacro {
50+
public static func expansion(
51+
of macro: some FreestandingMacroExpansionSyntax,
52+
in context: some MacroExpansionContext
53+
) -> ExprSyntax {
54+
guard let argument = macro.arguments.first?.expression else {
55+
fatalError("boom")
56+
}
57+
58+
return "(\(argument), \(StringLiteralExprSyntax(content: argument.description)))"
59+
}
60+
}
61+
62+
//--- TestPlugin.c
63+
#include "swift-c/MockPlugin/MockPlugin.h"
64+
65+
MOCK_PLUGIN([
66+
{
67+
"expect": {"getCapability": {}},
68+
"response": {"getCapabilityResult": {"capability": {"protocolVersion": 1}}}
69+
},
70+
{
71+
"expect": {"expandFreestandingMacro": {
72+
"macro": {"moduleName": "TestPlugin", "typeName": "TestStringMacro"}}},
73+
"response": {"expandMacroResult": {"expandedSource": "\"test string\"", "diagnostics": []}}
74+
}
75+
])
76+
77+
//--- test.swift
78+
@freestanding(expression) macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")
79+
@freestanding(expression) macro testString() -> String = #externalMacro(module: "TestPlugin", type: "TestStringMacro")
80+
81+
func test() {
82+
let _: String = #stringify(42).1
83+
let _: String = #testString
84+
}

0 commit comments

Comments
 (0)