Skip to content

Commit dceaa0f

Browse files
authored
[Support] Use malloc instead of non-throwing new (#92157)
When allocating a memory buffer, we use a non-throwing new so that we can explicitly handle memory buffers that are too large to fit into memory. However, when exceptions are disabled, LLVM installs a custom new handler (https://github.com/llvm/llvm-project/blob/90109d444839683b09f0aafdc50b749cb4b3203b/llvm/lib/Support/InitLLVM.cpp#L61) that explicitly crashes when we run out of memory (https://github.com/llvm/llvm-project/blob/de14b749fee41d4ded711e771e43043ae3100cb3/llvm/lib/Support/ErrorHandling.cpp#L188) and that means this particular out-of-memory situation cannot be gracefully handled. This was discovered while working on #embed (#68620) on Windows and resulted in a crash rather than the preprocessor issuing a diagnostic as expected. This patch switches away from the non-throwing new to a call to malloc (and free), which will return a null pointer without calling a custom new handler. It is the only instance in Clang or LLVM that I could find which used a non-throwing new, so I did not think we would need anything more involved than this change. Testing this would be highly platform dependent and so it does not come with test coverage. And because it doesn't change behavior that users are likely to be able to observe, it does not come with a release note.
1 parent 8a4cbea commit dceaa0f

File tree

1 file changed

+9
-2
lines changed

1 file changed

+9
-2
lines changed

llvm/lib/Support/MemoryBuffer.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class MemoryBufferMem : public MB {
9898

9999
/// Disable sized deallocation for MemoryBufferMem, because it has
100100
/// tail-allocated data.
101-
void operator delete(void *p) { ::operator delete(p); }
101+
void operator delete(void *p) { std::free(p); }
102102

103103
StringRef getBufferIdentifier() const override {
104104
// The name is stored after the class itself.
@@ -315,7 +315,14 @@ WritableMemoryBuffer::getNewUninitMemBuffer(size_t Size,
315315
size_t RealLen = StringLen + Size + 1 + BufAlign.value();
316316
if (RealLen <= Size) // Check for rollover.
317317
return nullptr;
318-
char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow));
318+
// We use a call to malloc() rather than a call to a non-throwing operator
319+
// new() because LLVM unconditionally installs an out of memory new handler
320+
// when exceptions are disabled. This new handler intentionally crashes to
321+
// aid with debugging, but that makes non-throwing new calls unhelpful.
322+
// See MemoryBufferMem::operator delete() for the paired call to free(), and
323+
// llvm::install_out_of_memory_new_handler() for the installation of the
324+
// custom new handler.
325+
char *Mem = static_cast<char *>(std::malloc(RealLen));
319326
if (!Mem)
320327
return nullptr;
321328

0 commit comments

Comments
 (0)