[Bug 52017] New: LLDB keeps DLL loaded after FreeLibrary is called.

Bug ID 52017
Summary LLDB keeps DLL loaded after FreeLibrary is called.
Product lldb
Version 12.0
Hardware PC
OS Windows NT
Status NEW
Severity normal
Priority P
Component All Bugs
Assignee lldb-dev@lists.llvm.org
Reporter george.owen@savoch.net
CC jdevlieghere@apple.com, llvm-bugs@lists.llvm.org

Created attachment 25307 [details]
Test case

Repro:
 * Build a shared library DLL
 * Create an executable that does not link that DLL
 * Load a DLL in code using LoadLibrary
 * Unload the same DLL using FreeLibrary on the HMODULE obtained from the first
step
 * Observe that LLDB does not release its lock on the DLL file, until LLDB is
closed.

LLDB keeps DLL loaded (and therefore the file locked) even after the
FreeLibrary is called. This means that the DLL, and PDB, both remain locked and
unable to be modified, even after they are no longer required by LLDB.

This can be observed by building the attached test case and running it through
LLDB. Once the program is either breakpointed or paused after the FreeLibrary
call, you can either attempt to delete the files and observe they cannot be
deleted, or use a program such as Process Explorer
([https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer)) to
see the processes that keep a handle to the file. This is only released when
LLDB is closed.

Debugging the same test case with Visual Studio 2019 (Version 16.9.4) shows
that Visual Studio does not keep the DLL or PDB locked after FreeLibrary is
called.

After SBDebugger::Destroy(), Terminate() there are still file mappings are active for loaded modules. MapViewOfFile was called, but UnmapViewOfFile not/or DuplicateHandler is still alive. (it’s in Windows\Path.inc).

Anyway, after unmapping all that stuff and closing duplicated handles - modules were unlocked.
LLVM 13.0.1

lldb caches the modules it has read between runs in so that subsequent reruns are fast. This can be a significant speedup for repeat debugging sessions with apps that load lots of shared libraries. If you want to force all un-referenced modules to be discarded after a session, you can call SBDebugger.MemoryPressureDetected. If that doesn’t free up all these file mappings, then we should fix that. But the fact that lldb keeps references to the previous shared sessions loaded libraries otherwise is by design.

MemoryPressureDetected() does nothing about this issue. I tried “target delete -ac” instead (it sets flag “true” to force removing shared modules from memory), but also without success.
It would be nice to have some configuration flag - to keep modules in memory or not after SBDebugger::Destroy()/Terminate().

That’s the bug, right? Either of these methods should have freed these modules and closed the file handles to them, but they didn’t. Another configuration flag would just call into the same non-working code…