Skip to content

Commit 07f728d

Browse files
authored
Merge pull request #60266 from apple/wip-dont-hang-bad-target-call
[Distributed] Dont hang calls on not found accessors
2 parents b971d69 + 9646298 commit 07f728d

File tree

5 files changed

+118
-4
lines changed

5 files changed

+118
-4
lines changed

stdlib/public/Distributed/DistributedActor.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ static void swift_distributed_execute_target_resume(
109109
return resumeInParent(parentCtx, error);
110110
}
111111

112+
SWIFT_CC(swift)
113+
SWIFT_EXPORT_FROM(swiftDistributed)
114+
SwiftError* swift_distributed_makeDistributedTargetAccessorNotFoundError(
115+
const char *targetNameStart, size_t targetNameLength);
116+
112117
SWIFT_CC(swiftasync)
113118
void swift_distributed_execute_target(
114119
SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
@@ -124,8 +129,12 @@ void swift_distributed_execute_target(
124129
void **decoderWitnessTable) {
125130
auto *accessor = findDistributedAccessor(targetNameStart, targetNameLength);
126131
if (!accessor) {
127-
assert(false && "no distributed accessor");
128-
return; // FIXME(distributed): return -1 here so the lib can fail the call
132+
SwiftError *error =
133+
swift_distributed_makeDistributedTargetAccessorNotFoundError(targetNameStart, targetNameLength);
134+
auto resumeInParent =
135+
reinterpret_cast<TargetExecutorSignature::ContinuationType *>(
136+
callerContext->ResumeParent);
137+
return resumeInParent(callerContext, error);
129138
}
130139

131140
auto *asyncFnPtr = reinterpret_cast<

stdlib/public/Distributed/DistributedActorSystem.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ extension DistributedActorSystem {
212212
/// some other mismatch between them happens. In general, this
213213
/// method is allowed to throw in any situation that might otherwise
214214
/// result in an illegal or unexpected invocation being performed.
215+
///
216+
/// Throws ``ExecuteDistributedTargetMissingAccessorError`` if the `target`
217+
/// does not resolve to a valid distributed function accessor, i.e. the
218+
/// call identifier is incorrect, corrupted, or simply not present in this process.
215219
public func executeDistributedTarget<Act>(
216220
on actor: Act,
217221
target: RemoteCallTarget,
@@ -574,10 +578,28 @@ public protocol DistributedActorSystemError: Error {}
574578

575579
@available(SwiftStdlib 5.7, *)
576580
public struct ExecuteDistributedTargetError: DistributedActorSystemError {
577-
let message: String
581+
public let errorCode: ErrorCode
582+
public let message: String
583+
584+
public enum ErrorCode {
585+
/// Thrown when unable to resolve the target identifier to a function accessor.
586+
/// This can happen when the identifier is corrupt, illegal, or wrong in the
587+
/// sense that the caller and callee do not have the called function recorded
588+
/// using the same identifier.
589+
case targetAccessorNotFound
590+
591+
/// A general issue during the execution of the distributed call target ocurred.
592+
case other
593+
}
578594

579595
public init(message: String) {
580596
self.message = message
597+
self.errorCode = .other
598+
}
599+
600+
public init(message: String, errorCode: ErrorCode) {
601+
self.message = message
602+
self.errorCode = errorCode
581603
}
582604
}
583605

stdlib/public/Distributed/DistributedMetadata.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,13 @@ func _getWitnessTablesFor(
108108
environment: UnsafeRawPointer,
109109
genericArguments: UnsafeRawPointer
110110
) -> (UnsafeRawPointer, Int)
111+
112+
@available(SwiftStdlib 5.7, *)
113+
@_silgen_name("swift_distributed_makeDistributedTargetAccessorNotFoundError")
114+
internal // SPI Distributed
115+
func _makeDistributedTargetAccessorNotFoundError() -> Error {
116+
/// We don't include the name of the target in case the input was compromised.
117+
return ExecuteDistributedTargetError(
118+
message: "Failed to locate distributed function accessor",
119+
errorCode: .targetAccessorNotFound)
120+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift
3+
// RUN: %target-build-swift -module-name main -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out
4+
// RUN: %target-run %t/a.out | %FileCheck %s --color
5+
6+
// REQUIRES: executable_test
7+
// REQUIRES: concurrency
8+
// REQUIRES: distributed
9+
10+
// rdar://76038845
11+
// UNSUPPORTED: use_os_stdlib
12+
// UNSUPPORTED: back_deployment_runtime
13+
14+
// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574
15+
// UNSUPPORTED: OS=windows-msvc
16+
17+
import Distributed
18+
import FakeDistributedActorSystems
19+
20+
typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem
21+
22+
distributed actor Greeter {
23+
distributed func greet(name: String) -> String {
24+
"Hello, \(name)!"
25+
}
26+
}
27+
28+
func test() async throws {
29+
let system = DefaultDistributedActorSystem()
30+
let local = Greeter(actorSystem: system)
31+
let ref = try Greeter.resolve(id: local.id, using: system)
32+
33+
// Make sure normal call works ok:
34+
let greeting = try await ref.greet(name: "Caplin")
35+
print("\(greeting)")
36+
// CHECK: Hello, Caplin!
37+
38+
let correctTargetIdentifier = "$s4main7GreeterC5greet4nameS2S_tYaKFTE"
39+
_ = correctTargetIdentifier
40+
let badModuleTargetIdentifier = "$s9BADMODULE7GreeterC5greet4nameS2S_tYaKFTE"
41+
// the BADMODULE is a bad module, and we won't be able to find the distributed accessor
42+
// this should result in a failed call, but not hang the call.
43+
44+
var invocation = Greeter.ActorSystem.InvocationEncoder()
45+
invocation.arguments = ["BadCall"]
46+
invocation.returnType = String.self
47+
48+
let badTarget = RemoteCallTarget(badModuleTargetIdentifier)
49+
50+
do {
51+
// CHECK: >> remoteCall: on:main.Greeter, target:BADMODULE.Greeter.greet(name:)
52+
let call = try await system.remoteCall(
53+
on: local,
54+
target: badTarget,
55+
invocation: &invocation,
56+
throwing: Never.self,
57+
returning: String.self
58+
)
59+
} catch {
60+
// CHECK: << onThrow: ExecuteDistributedTargetError(errorCode: Distributed.ExecuteDistributedTargetError.ErrorCode.targetAccessorNotFound, message: "Failed to locate distributed function accessor")
61+
// CHECK: << remoteCall throw: ExecuteDistributedTargetError(errorCode: Distributed.ExecuteDistributedTargetError.ErrorCode.targetAccessorNotFound, message: "Failed to locate distributed function accessor")
62+
print("caught error: \(error)")
63+
print("call target was: \(badTarget.identifier)")
64+
// CHECK: caught error: ExecuteDistributedTargetError(errorCode: Distributed.ExecuteDistributedTargetError.ErrorCode.targetAccessorNotFound, message: "Failed to locate distributed function accessor")
65+
// CHECK: call target was: $s9BADMODULE7GreeterC5greet4nameS2S_tYaKFTE
66+
}
67+
}
68+
69+
@main struct Main {
70+
static func main() async {
71+
try! await test()
72+
}
73+
}

test/Distributed/Runtime/distributed_actor_remoteCall.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ func test() async throws {
492492
invocationDecoder: &decodeErrDecoder,
493493
handler: FakeResultHandler()
494494
)
495-
// CHECK: ERROR: ExecuteDistributedTargetError(message: "Failed to decode of Int??? (for a test)")
495+
// CHECK: ERROR: ExecuteDistributedTargetError(errorCode: Distributed.ExecuteDistributedTargetError.ErrorCode.other, message: "Failed to decode of Int??? (for a test)")
496496

497497
print("done")
498498
// CHECK-NEXT: done

0 commit comments

Comments
 (0)