Skip to content

Bad exception metadata leads to heap corruption on MSVC ABI, when throwing in a PCH from a member function of an exported class, then copying the exception #118276

@adalisk-emikhaylov

Description

@adalisk-emikhaylov

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.exe

Or 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.exe

This shows the following messagebox:
Image

Removing __declspec(dllexport) fixes this.

I'm testing this on Clang 19.1.3. Also reproduces on Clang 18.x.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions