TypeRefBuilder uses a cache when fetching field metadata, with the symbol's mangled name as the key. On the first access, the cache is filled for each metadata record in the loaded image.
The cache has two paths:
- A fast path, which uses
LLDBMemoryReader::resolvePointerAsSymbol
- A slow path which walks the metadata.
Crucially, LLDBMemoryReader::resolvePointerAsSymbol does not require the pointer to point at the beginning of the symbol. This means that when using incomplete symbol information, every address between known symbols A and B resolves to A. Since the cache uses the mangled name as the key, A's record in the cache will be overwritten by the last symbol encountered!
On Windows, swiftCore.dll does not ship with PDBs, leaving us to rely on the COFF exports table. As a result, it's very easy to corrupt the cache, and we do. For example:
main.swift:
let d = ["Hello": "World"]
print(d)
swiftc -g -debug-info-format=dwarf main.swift -Xlinker /debug -use-ld=lld -o main.exe
lldb.exe main.exe
(lldb) b main.swift:2
(lldb) fr v
([String : String]) d = <failed to update hashed container>
(also repros with PDB)
We should probably ship PDBs for redistributables but I personally think LLDBMemoryReader::resolvePointerAsSymbol's behavior in this context isn't what I would expect. It might make sense to add a check on Windows that the pointer points at the beginning of a symbol. We're already no-oping the method on Linux (possibly for similar reasons?) so tightening it up seems safe to me.
TypeRefBuilderuses a cache when fetching field metadata, with the symbol's mangled name as the key. On the first access, the cache is filled for each metadata record in the loaded image.The cache has two paths:
LLDBMemoryReader::resolvePointerAsSymbolCrucially,
LLDBMemoryReader::resolvePointerAsSymboldoes not require the pointer to point at the beginning of the symbol. This means that when using incomplete symbol information, every address between known symbols A and B resolves toA. Since the cache uses the mangled name as the key,A's record in the cache will be overwritten by the last symbol encountered!On Windows,
swiftCore.dlldoes not ship with PDBs, leaving us to rely on the COFF exports table. As a result, it's very easy to corrupt the cache, and we do. For example:main.swift:
swiftc -g -debug-info-format=dwarf main.swift -Xlinker /debug -use-ld=lld -o main.exe(also repros with PDB)
We should probably ship PDBs for redistributables but I personally think
LLDBMemoryReader::resolvePointerAsSymbol's behavior in this context isn't what I would expect. It might make sense to add a check on Windows that the pointer points at the beginning of a symbol. We're already no-oping the method on Linux (possibly for similar reasons?) so tightening it up seems safe to me.