`<format>`: `_malloc_dbg` allocations freed with `delete` in `std::format` (debug builds)
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 11.1k
- Forks
- 1.7k
- Avg merge
- 4d 15h
- Merged PRs (30d)
- 22
Description
Describe the bug
In MSVC STL debug builds, std::format appears to allocate temporary buffers using _malloc_dbg (or another internal heap allocation method) but frees them using the delete operator. This is a violation of C++ memory management rules, as memory allocated with _malloc_dbg must be freed with _free_dbg, and memory allocated with new must be freed with delete.
This behavior can lead to undefined behavior, including heap corruption or crashes, especially when using debug builds with CRT memory checks enabled.
Command-line test case
C:\Temp>type repro.cpp
#include <crtdbg.h>
#include <iostream>
#include <string>
#include <format>
#include <new>
// Custom new/delete to detect misuse
void* operator new(std::size_t size)
{
void* p = std::malloc(size);
if (!p) throw std::bad_alloc{};
std::cout << "[new] size = " << size << "p = " << p << std::endl;
return p;
}
void operator delete(void* p) noexcept
{
std::cout << "[delete] ptr = " << p << std::endl;
std::free(p);
}
static std::locale myLocale("en_US.UTF-8");
int main()
{
int value = 123456;
std::cout << "Calling std::format..." << std::endl;
std::string formatted = std::format(myLocale, "{:L}", value); // simple format
std::cout << "Result: " << formatted << std::endl;
return 0;
}
C:\Temp>cl /std:c++20 /MDd /Zi /EHsc repro.cpp
<I dont know what the template wants from me here?>
Expected behavior
The output should have a delete line matching every new line, but there is an extra delete line, which was never newed.
This is the output:
[new] size = 16p = 0000017AFF503990
[delete] ptr = 0000017AFF503990
Calling std::format...
[new] size = 16p = 0000017AFF521C10
[new] size = 16p = 0000017AFF522700
[delete] ptr = 0000017AFF521C60
[delete] ptr = 0000017AFF522700
Result: 123,456
[delete] ptr = 0000017AFF521C10
You can see there is one extra delete.
if you change the string formatting line to something like:
std::string formatted = std::string("") + std::to_string(value); // simple format
then the news and deletes match up
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by building the supplied repro.cpp command-line test with MSVC using /std:c++20 and /MDd, then trace the std::format path involved in localized integer formatting. Compare each allocation and deallocation in the output, including the pointer reported as deleted without a matching new. Done means the debug build no longer performs the mismatched deallocation and the repro's allocation and deletion records match.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100