Skip to content

Commit 371d1a8

Browse files
authored
[lldb] Use weak pointers instead of shared pointers in DynamicLoader (#156446)
DynamicLoaderWindowsDYLD uses pointers to Modules to maintain a map from modules to their addresses, but it does not need to keep "strong" references to them. Weak pointers should be enough, and would allow modules to be released elsewhere. Other DynamicLoader classes do not use shared pointers as well. For example, DynamicLoaderPOSIXDYLD has a similar map with weak pointers. Actually testing for modules being completely released can be tricky. The test here is just to illustrate the case where shared pointers kept modules in DynamicLoaderWindowsDYLD and prevented them from being released. The test executes the following sequence: 1. Create a target, load an executable and run it. 2. Remove one module from the target. The target should be the last actual use of the module, but we have another reference to it in the shared module cache. 3. Call MemoryPressureDetected to remove this last reference from the cache. 4. Replace the corresponding DLL file. LLDB memory maps DLLs, and this makes files read-only on Windows. Unless the modules are completely released (and therefore unmapped), (4) is going to fail with "access denied". However, the test does not trigger the bug completely - it passes with and without the change.
1 parent 4e8b4d6 commit 371d1a8

File tree

6 files changed

+70
-1
lines changed

6 files changed

+70
-1
lines changed

lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ class DynamicLoaderWindowsDYLD : public DynamicLoader {
4545
lldb::addr_t GetLoadAddress(lldb::ModuleSP executable);
4646

4747
private:
48-
std::map<lldb::ModuleSP, lldb::addr_t> m_loaded_modules;
48+
std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>>
49+
m_loaded_modules;
4950
};
5051

5152
} // namespace lldb_private
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include Makefile.rules
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
from lldbsuite.test.lldbtest import *
4+
from lldbsuite.test import lldbutil
5+
6+
import gc
7+
import os
8+
9+
10+
class ReplaceDllTestCase(TestBase):
11+
@skipUnlessWindows
12+
def test(self):
13+
"""
14+
Test that LLDB unlocks module files once all references are released.
15+
"""
16+
17+
exe = self.getBuildArtifact("a.out")
18+
foo = self.getBuildArtifact("foo.dll")
19+
bar = self.getBuildArtifact("bar.dll")
20+
21+
self.build(
22+
dictionary={
23+
"DYLIB_NAME": "foo",
24+
"DYLIB_C_SOURCES": "foo.c",
25+
"C_SOURCES": "test.c",
26+
}
27+
)
28+
self.build(
29+
dictionary={
30+
"DYLIB_ONLY": "YES",
31+
"DYLIB_NAME": "bar",
32+
"DYLIB_C_SOURCES": "bar.c",
33+
}
34+
)
35+
36+
target = self.dbg.CreateTarget(exe)
37+
self.assertTrue(target, VALID_TARGET)
38+
39+
shlib_names = ["foo"]
40+
environment = self.registerSharedLibrariesWithTarget(target, shlib_names)
41+
process = target.LaunchSimple(
42+
None, environment, self.get_process_working_directory()
43+
)
44+
self.assertEqual(process.GetExitStatus(), 42)
45+
46+
module = next((m for m in target.modules if "foo" in m.file.basename), None)
47+
self.assertIsNotNone(module)
48+
self.assertEqual(module.file.fullpath, foo)
49+
50+
target.RemoveModule(module)
51+
del module
52+
gc.collect()
53+
54+
self.dbg.MemoryPressureDetected()
55+
56+
os.remove(foo)
57+
os.rename(bar, foo)
58+
59+
process = target.LaunchSimple(
60+
None, environment, self.get_process_working_directory()
61+
)
62+
self.assertEqual(process.GetExitStatus(), 43)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__declspec(dllexport) int foo() { return 43; }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__declspec(dllexport) int foo() { return 42; }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
int foo(void);
2+
3+
int main() { return foo(); }

0 commit comments

Comments
 (0)