Skip to content

Commit bcc7588

Browse files
Merge pull request swiftlang#22125 from aschwaighofer/workaround_dynamic_replacement_failure
DynamicReplacement: Don't fail when a library is closed and reloaded
2 parents 6b9e5e5 + eb6b1a1 commit bcc7588

File tree

4 files changed

+89
-0
lines changed

4 files changed

+89
-0
lines changed

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,11 +1696,15 @@ void DynamicReplacementDescriptor::enableReplacement() const {
16961696
replacedFunctionKey->root.get());
16971697

16981698
// Make sure this entry is not already enabled.
1699+
// This does not work until we make sure that when a dynamic library is
1700+
// unloaded all descriptors are removed.
1701+
#if 0
16991702
for (auto *curr = chainRoot; curr != nullptr; curr = curr->next) {
17001703
if (curr == chainEntry.get()) {
17011704
swift::swift_abortDynamicReplacementEnabling();
17021705
}
17031706
}
1707+
#endif
17041708

17051709
// Unlink the previous entry if we are not chaining.
17061710
if (!shouldChain() && chainRoot->next) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
struct A {
2+
dynamic var value : Int {
3+
return 1
4+
}
5+
}
6+
7+
public func test() -> Int{
8+
return A().value
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@_private(sourceFile: "dynamic_replacement_dlclose.swift") import Module1
2+
3+
extension A {
4+
@_dynamicReplacement(for: value)
5+
var repl: Int {
6+
return 2
7+
}
8+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift-dylib(%t/%target-library-name(Module1)) -DMODULE -module-name Module1 -emit-module -emit-module-path %t/Module1.swiftmodule -swift-version 5 %S/Inputs/dynamic_replacement_dlclose.swift -Xfrontend -enable-private-imports
3+
// RUN: %target-build-swift-dylib(%t/%target-library-name(Module2)) -I%t -L%t -lModule1 %target-rpath(%t) -DMODULE2 -module-name Module2 -emit-module -emit-module-path %t/Module2.swiftmodule -swift-version 5 %S/Inputs/dynamic_replacement_dlclose2.swift
4+
// RUN: %target-build-swift -I%t -L%t -lModule1 -DMAIN -o %t/main %target-rpath(%t) %s -swift-version 5
5+
// RUN: %target-codesign %t/main %t/%target-library-name(Module1) %t/%target-library-name(Module2)
6+
// RUN: %target-run %t/main %t/%target-library-name(Module1) %t/%target-library-name(Module2)
7+
8+
import Module1
9+
10+
import StdlibUnittest
11+
12+
#if os(Linux)
13+
import Glibc
14+
#elseif os(Windows)
15+
import MSVCRT
16+
import WinSDK
17+
#else
18+
import Darwin
19+
#endif
20+
21+
var DynamicallyReplaceable = TestSuite("DynamicallyReplaceable")
22+
23+
24+
25+
private func target_library_name(_ name: String) -> String {
26+
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
27+
return "lib\(name).dylib"
28+
#elseif os(Windows)
29+
return "\(name).dll"
30+
#else
31+
return "lib\(name).so"
32+
#endif
33+
}
34+
35+
36+
DynamicallyReplaceable.test("DynamicallyReplaceable") {
37+
var executablePath = CommandLine.arguments[0]
38+
executablePath.removeLast(4)
39+
expectEqual(1, test())
40+
// Now, test with the module containing the replacements.
41+
42+
#if os(Linux)
43+
let h = dlopen(target_library_name("Module2"), RTLD_NOW)
44+
#elseif os(Windows)
45+
let h = LoadLibraryA(target_library_name("Module2"))
46+
#else
47+
let h = dlopen(executablePath+target_library_name("Module2"), RTLD_NOW)
48+
#endif
49+
50+
expectEqual(2, test())
51+
52+
#if os(Linux)
53+
#elseif os(Windows)
54+
#else
55+
dlclose(h)
56+
#endif
57+
58+
#if os(Linux)
59+
_ = dlopen(target_library_name("Module2"), RTLD_NOW)
60+
#elseif os(Windows)
61+
#else
62+
_ = dlopen(executablePath+target_library_name("Module2"), RTLD_NOW)
63+
#endif
64+
expectEqual(2, test())
65+
66+
}
67+
68+
runAllTests()

0 commit comments

Comments
 (0)