Skip to content

Commit 1e82ef8

Browse files
committed
Fix dynamic replacement of weakly linked symbols
If the replaced symbol goes away in the original library, the replacement key in the replacement descriptor will be null. Handle this by ignoring the replacement entry rather than crashing. rdar://103307821
1 parent 5f3664e commit 1e82ef8

File tree

4 files changed

+62
-0
lines changed

4 files changed

+62
-0
lines changed

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2732,6 +2732,10 @@ static InitializeDynamicReplacementLookup initDynamicReplacements;
27322732
SWIFT_ALLOWED_RUNTIME_GLOBAL_CTOR_END
27332733

27342734
void DynamicReplacementDescriptor::enableReplacement() const {
2735+
// Weakly linked symbols can be zero.
2736+
if (replacedFunctionKey.get() == nullptr)
2737+
return;
2738+
27352739
auto *chainRoot = const_cast<DynamicReplacementChainEntry *>(
27362740
replacedFunctionKey->root.get());
27372741

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@_weakLinked import LibA
2+
3+
extension A {
4+
@_dynamicReplacement(for: printThis())
5+
func _replacementForPrintThis() {
6+
Swift.print("replacement")
7+
}
8+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
public struct A {
2+
public var x : Int = 0
3+
public var y : Int = 1
4+
public init() {}
5+
#if BEFORE
6+
public func print() {
7+
printThis()
8+
}
9+
10+
public dynamic func printThis() {
11+
Swift.print(x)
12+
Swift.print(y)
13+
}
14+
#else
15+
public func print() {
16+
printThis2()
17+
}
18+
19+
public dynamic func printThis2() {
20+
Swift.print(x)
21+
Swift.print(y)
22+
}
23+
24+
#endif
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift-dylib(%t/%target-library-name(LibA)) -DBEFORE -module-name LibA -emit-module -emit-module-path %t/LibA.swiftmodule -swift-version 5 %S/Inputs/dynamic_replacement_libA.swift
3+
// RUN: %target-build-swift-dylib(%t/%target-library-name(ReplacementA)) -I%t -L%t -lLibA -module-name ReplacementA -swift-version 5 %S/Inputs/dynamic_replacement_ReplacementA.swift
4+
// RUN: %target-build-swift-dylib(%t/%target-library-name(LibA)) -module-name LibA -emit-module -emit-module-path %t/LibA.swiftmodule -swift-version 5 %S/Inputs/dynamic_replacement_libA.swift
5+
// RUN: %target-build-swift -I%t -L%t -lLibA -o %t/main %target-rpath(%t) %s -swift-version 5
6+
// RUN: %target-codesign %t/main %t/%target-library-name(LibA) %t/%target-library-name(ReplacementA)
7+
// RUN: %target-run %t/main %t/%target-library-name(LibA) %t/%target-library-name(ReplacementA)
8+
9+
// REQUIRES: executable_test
10+
// REQUIRES: OS=macosx
11+
// REQUIRES: swift_test_mode_optimize_none
12+
13+
import Darwin
14+
15+
import LibA
16+
17+
private func target_library_name(_ name: String) -> String {
18+
return "lib\(name).dylib"
19+
}
20+
21+
var executablePath = CommandLine.arguments[0]
22+
executablePath.removeLast(4)
23+
_ = dlopen(executablePath + target_library_name("ReplacementA"), RTLD_NOW)
24+
25+
A().print()

0 commit comments

Comments
 (0)