Skip to content

Commit b4a169e

Browse files
authored
Merge pull request #74671 from rintaro/6.0-macros-respawn-before-loadlibrary
[6.0][Macros] Ensure plugin process is alive before sending a message
2 parents 6c74cce + e0e36ee commit b4a169e

File tree

2 files changed

+125
-3
lines changed

2 files changed

+125
-3
lines changed

lib/ASTGen/Sources/ASTGen/PluginHost.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,15 @@ struct CompilerPlugin {
138138
}
139139

140140
func sendMessageAndWaitWithoutLock(_ message: HostToPluginMessage) throws -> PluginToHostMessage {
141+
guard !Plugin_spawnIfNeeded(opaqueHandle) else {
142+
throw PluginError.stalePlugin
143+
}
141144
try sendMessage(message)
142145
return try waitForNextMessage()
143146
}
144147

145148
func sendMessageAndWait(_ message: HostToPluginMessage) throws -> PluginToHostMessage {
146149
try self.withLock {
147-
guard !Plugin_spawnIfNeeded(opaqueHandle) else {
148-
throw PluginError.stalePlugin
149-
}
150150
return try sendMessageAndWaitWithoutLock(message);
151151
}
152152
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// REQUIRES: swift_swift_parser
2+
// REQUIRES: OS=macosx
3+
4+
// RUN: %empty-directory(%t)
5+
// RUN: %empty-directory(%t/plugins)
6+
// RUN: split-file %s %t
7+
8+
//== Build the plugin library
9+
// RUN: %host-build-swift \
10+
// RUN: -swift-version 5 \
11+
// RUN: -emit-library \
12+
// RUN: -o %t/plugins/%target-library-name(MacroDefinition) \
13+
// RUN: -module-name=MacroDefinition \
14+
// RUN: %t/MacroDefinition.swift \
15+
// RUN: -g -no-toolchain-stdlib-rpath
16+
17+
// RUN: %host-build-swift \
18+
// RUN: -swift-version 5 \
19+
// RUN: -emit-library \
20+
// RUN: -o %t/plugins/%target-library-name(EvilMacros) \
21+
// RUN: -module-name=EvilMacros \
22+
// RUN: %t/EvilMacros.swift \
23+
// RUN: -g -no-toolchain-stdlib-rpath
24+
25+
// RUN: %cmake-c-compiler \
26+
// RUN: %c-flags -target %host_triple -isysroot %host_sdk \
27+
// RUN: -shared -o %t/plugins/libCrashOnLoad.dylib \
28+
// RUN: %t/CrashOnLoad.c
29+
30+
// RUN: %target-swift-frontend \
31+
// RUN: -swift-version 5 \
32+
// RUN: -emit-module -o \
33+
// RUN: %t/MacroLibrary.swiftmodule \
34+
// RUN: %t/MacroLibrary.swift \
35+
// RUN: -module-name MacroLibrary \
36+
// RUN: -external-plugin-path %t/plugins#%swift-plugin-server
37+
38+
// RUN: env SWIFT_DUMP_PLUGIN_MESSAGING=1 %target-swift-frontend \
39+
// RUN: -typecheck -verify \
40+
// RUN: -I %t \
41+
// RUN: -swift-version 5 \
42+
// RUN: -external-plugin-path %t/plugins#%swift-plugin-server \
43+
// RUN: -module-name MyApp \
44+
// RUN: %t/app.swift \
45+
// RUN: 2>&1 | tee %t/macro-expansions.txt
46+
47+
// RUN: %FileCheck -strict-whitespace %s < %t/macro-expansions.txt
48+
49+
// CHECK: ->(plugin:[[#PID1:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION:]]}}}
50+
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library"],"protocolVersion":[[#PROTOCOL_VERSION]]}}}
51+
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}CrashOnLoad.{{.*}}","moduleName":"CrashOnLoad"}}
52+
53+
// CHECK-NEXT: ->(plugin:[[#PID2:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}}
54+
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library"],"protocolVersion":[[#PROTOCOL_VERSION]]}}}
55+
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros{{.*}},"moduleName":"EvilMacros"}}
56+
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
57+
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"{{.*}}","lexicalContext":{{.*}},"macro":{"moduleName":"EvilMacros","name":"evil","typeName":"CrashingMacro"}{{.*}}
58+
59+
// CHECK-NEXT: ->(plugin:[[#PID3:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}}
60+
// CHECK-NEXT: <-(plugin:[[#PID3]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library"],"protocolVersion":[[#PROTOCOL_VERSION]]}}}
61+
// CHECK-NEXT: ->(plugin:[[#PID3]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros{{.*}}","moduleName":"EvilMacros"}}
62+
// CHECK-NEXT: <-(plugin:[[#PID3]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
63+
// CHECK-NEXT: ->(plugin:[[#PID3]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}MacroDefinition{{.*}}","moduleName":"MacroDefinition"}}
64+
// CHECK-NEXT: <-(plugin:[[#PID3]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
65+
// CHECK-NEXT: ->(plugin:[[#PID3]]) {"expandFreestandingMacro":{"discriminator":"{{.*}}","lexicalContext":{{.*}},"macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"}{{.*}}
66+
// CHECK-NEXT: <-(plugin:[[#PID3]]) {"expandMacroResult":{"diagnostics":[],"expandedSource":"(1, \"1\")"}}
67+
68+
//--- MacroDefinition.swift
69+
import SwiftSyntax
70+
import SwiftSyntaxBuilder
71+
import SwiftSyntaxMacros
72+
73+
public struct StringifyMacro: ExpressionMacro {
74+
public static func expansion(
75+
of macro: some FreestandingMacroExpansionSyntax,
76+
in context: some MacroExpansionContext
77+
) -> ExprSyntax {
78+
guard let argument = macro.arguments.first?.expression else {
79+
fatalError("boom")
80+
}
81+
82+
return "(\(argument), \(StringLiteralExprSyntax(content: argument.description)))"
83+
}
84+
}
85+
86+
//--- EvilMacros.swift
87+
import SwiftSyntax
88+
import SwiftSyntaxBuilder
89+
import SwiftSyntaxMacros
90+
91+
public struct CrashingMacro: ExpressionMacro {
92+
public static func expansion(
93+
of macro: some FreestandingMacroExpansionSyntax,
94+
in context: some MacroExpansionContext
95+
) -> ExprSyntax {
96+
let arg: UInt = UInt(macro.argumentList.first!.expression.description)!
97+
let zero: UInt = 0
98+
return "\(raw: zero - arg).description"
99+
}
100+
}
101+
102+
//--- CrashOnLoad.c
103+
#include <stdlib.h>
104+
105+
__attribute__((constructor))
106+
void crashMe(void) {
107+
abort();
108+
}
109+
110+
//--- MacroLibrary.swift
111+
@freestanding(expression) public macro crash() -> Int = #externalMacro(module: "CrashOnLoad", type: "WhateverMacro")
112+
@freestanding(expression) public macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")
113+
@freestanding(expression) public macro evil(_ value: Int) -> String = #externalMacro(module: "EvilMacros", type: "CrashingMacro")
114+
115+
//--- app.swift
116+
import MacroLibrary
117+
118+
func test() {
119+
_ = #crash() // expected-error {{external macro implementation type 'CrashOnLoad.WhateverMacro' could not be found for macro 'crash()'; failed to load library plugin}}
120+
_ = #evil(1) // expected-error {{failed to receive result from plugin (from macro 'evil')}}
121+
_ = #stringify(1)
122+
}

0 commit comments

Comments
 (0)