-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Description
Just tracked down a nasty bug. Only happens on Windows on MSVC ABI.
When you throw an exception in a PCH, in a member function of a dllexported class, the metadata for that exception type becomes corrupted: its CatchableType::copyFunction becomes null, so whenever the exception has to be copied, a bitwise copy is performed instead of a deep copy.
This in turn leads to heap corruption, e.g. when calling std::current_exception(). It should deep-copy the exception into a shared_ptr, but instead bitwise copies it, so when the resulting std::exception_ptr dies, it brings the original exception down with it, which then crashes either when you destroy the original, or when you try to call std::current_exception() the second time.
Here's how you reproduce this:
// 1.hpp
#include <stdexcept>
struct __declspec(dllexport) A
{
void foo()
{
throw std::runtime_error("Foo!");
}
};// 1.cpp
int main()
{
try
{
throw std::runtime_error("Bar!");
}
catch (...)
{
(void)std::current_exception();
}
}Also create an empty pch.cpp for the PCH generation.
Run:
clang-cl /EHsc /MDd /Yc1.hpp /Fp1.pch /FI1.hpp /Fopch.obj -c pch.cpp
clang-cl /EHsc /MDd /Yu1.hpp /Fp1.pch /FI1.hpp /Fo1.obj -c 1.cpp
clang-cl pch.obj 1.obj /link /out:a.exe
.\a.exeOr GNU-style flags: (on Windows, assuming the stock Clang build with MSVC being the default target)
clang++ -Xclang --dependent-lib=msvcrtd -D_DEBUG -D_DLL -D_MT -o 1pch.gch -xc++-header 1.hpp
clang++ -Xclang --dependent-lib=msvcrtd -D_DEBUG -D_DLL -D_MT 1.cpp -c -o 1.o -include1pch
clang++ -nostartfiles 1.o -o a.exe -v
.\a.exeThis shows the following messagebox:

Removing __declspec(dllexport) fixes this.
I'm testing this on Clang 19.1.3. Also reproduces on Clang 18.x.