Skip to content

Crash when building with /MT in MSVC (double-destructor) #1276

Description

@ZeroKwok

Description

When building CPR with /MT (static CRT) on MSVC, CPR defines an inline const std::unordered_map as a global variable(include/cpr/error.h:93). With MSVC, each translation unit generates its own copy of the destructor registration code. Although the data are COMDAT-folded into a single instance, the destructor registrations are not folded, causing the same object to be registered multiple times for destruction.

As a result, CPR triggers multiple destructor calls on the same global object during program shutdown, which leads to double free / memory corruption / crash.

This issue does not appear with /MD, because the dynamic CRT deduplicates destructor registration internally.

Example/How to Reproduce

  1. Build CPR using MSVC with /MT or /MTd
  2. Include CPR headers in multiple translation units (may require calling 'to_string(code)')
  3. Link and run the program
  4. Program crashes on exit due to double-destruction of the inline global map

Possible Fix

Avoid inline global objects with non-trivial destructors.

// include/cpr/error.h:93
inline const std::unordered_map<ErrorCode, std::string> error_code_to_string_mapping = { /*...*/ };

Use a function-local static instead:

const std::unordered_map<...>& get_error_map() {
    static const std::unordered_map<...> map = {
        /* ... */
    };
    return map;
}

inline std::string to_string(const cpr::ErrorCode& code) {
    return cpr::error_code_map().at(code);
}

Or

inline std::string to_string(const cpr::ErrorCode& code) {
    static const std::unordered_map<...> error_code_to_string_mapping = { ... };
    return error_code_to_string_mapping.at(code);
}

Where did you get it from?

vcpkg

Additional Context/Your Environment

  • OS: Windows 10/Windows 7
  • Version: 1.12.0

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions