Skip to content

Commit a967371

Browse files
committed
[5.0] DynamicReplacement: Don't fail when a library is closed and reloaded
rdar://47560273
1 parent 1993b4c commit a967371

File tree

4 files changed

+85
-0
lines changed

4 files changed

+85
-0
lines changed

stdlib/public/runtime/MetadataLookup.cpp

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

16791679
// Make sure this entry is not already enabled.
1680+
// This does not work until we make sure that when a dynamic library is
1681+
// unloaded all descriptors are removed.
1682+
#if 0
16801683
for (auto *curr = chainRoot; curr != nullptr; curr = curr->next) {
16811684
if (curr == chainEntry.get()) {
16821685
swift::swift_abortDynamicReplacementEnabling();
16831686
}
16841687
}
1688+
#endif
16851689

16861690
// Unlink the previous entry if we are not chaining.
16871691
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: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
dlclose(h)
53+
54+
#if os(Linux)
55+
_ = dlopen(target_library_name("Module2"), RTLD_NOW)
56+
#elseif os(Windows)
57+
#else
58+
_ = dlopen(executablePath+target_library_name("Module2"), RTLD_NOW)
59+
#endif
60+
expectEqual(2, test())
61+
62+
}
63+
64+
runAllTests()

0 commit comments

Comments
 (0)