Closed mstorsjo closed 9 months ago
@llvm/issue-subscribers-lld-coff
Author: Martin Storsjö (mstorsjo)
As you say, yes, the assumption here was that the StringRef should refer to the memory mapped object file, or a stable copy created in the export parsing code, which lives forever.
Would it be sufficient to stabilize the COFF linker options when we read them in, since LTO object lifetime is shorter than Export lifetime? Say, here: https://github.com/llvm/llvm-project/blob/main/lld/COFF/InputFiles.cpp#L1084C41-L1084C41
As you say, yes, the assumption here was that the StringRef should refer to the memory mapped object file, or a stable copy created in the export parsing code, which lives forever.
Would it be sufficient to stabilize the COFF linker options when we read them in, since LTO object lifetime is shorter than Export lifetime? Say, here: https://github.com/llvm/llvm-project/blob/main/lld/COFF/InputFiles.cpp#L1084C41-L1084C41
It would be sufficient to e.g. wrap that in a StringSaver::save()
operation, yeah. For most LTO object files, the StringRef
seems to not refer to the SmallVector<char, 0> Strtab
but apparently somewhere in the memory mapped file, or somewhere else that sticks around, but for these LTO object files that need to be upgraded, we run into this. Tossing all these LTO file directives in a StringSaver
will use up a bit of memory for sure, but perhaps it's tolerable here?
The reason is that the export directives are stored as StringRef pointing at the source memory. In the case of LTO objects that have been upgraded, this is memory owned by SmallVector<char, 0> Strtab here: llvmorg-17.0.6/llvm/include/llvm/LTO/LTO.h#L119-L125 After compiling LTO, this object is destructed, and the StringRef is left with a dangling pointer. For LTO objects that didn't need to be upgraded (see llvmorg-17.0.6/llvm/lib/Object/IRSymtab.cpp#L404-L438), the StringRef seems to point into memory elsewhere (maybe part of a memory map?) which isn't destructed at that time.
It seems that InputFile::~InputFile
is called at checkError(ltoObj->add(std::move(f.obj), resols));checkError(ltoObj->add(std::move(f.obj), resols));
.
It would be sufficient to e.g. wrap that in a StringSaver::save() operation
Yes, using StringSaver::save()
seems reasonable.
When linking LTO objects that contain COFF directives (in particular, dllexports), use of those directives can end up with use-after-free.
This seems to be triggerable when the LTO object has been compiled with an older LLVM version of the compiler, than the version used in LTO.
To reproduce:
The reason is that the export directives are stored as
StringRef
pointing at the source memory. In the case of LTO objects that have been upgraded, this is memory owned bySmallVector<char, 0> Strtab
here: https://github.com/llvm/llvm-project/blob/llvmorg-17.0.6/llvm/include/llvm/LTO/LTO.h#L119-L125 After compiling LTO, this object is destructed, and theStringRef
is left with a dangling pointer. For LTO objects that didn't need to be upgraded (see https://github.com/llvm/llvm-project/blob/llvmorg-17.0.6/llvm/lib/Object/IRSymtab.cpp#L404-L438), theStringRef
seems to point into memory elsewhere (maybe part of a memory map?) which isn't destructed at that time.This issue is downstream issue https://github.com/mstorsjo/llvm-mingw/issues/392.
CC @rnk @MaskRay