Bladeren bron

Report fatal error in the case of out of memory

This is the second part of recommit of r325224. The previous part was
committed in r325426, which deals with C++ memory allocation. Solution
for C memory allocation involved functions `llvm::malloc` and similar.
This was a fragile solution because it caused ambiguity errors in some
cases. In this commit the new functions have names like `llvm::safe_malloc`.

The relevant part of original comment is below, updated for new function
names.

Analysis of fails in the case of out of memory errors can be tricky on
Windows. Such error emerges at the point where memory allocation function
fails, but manifests itself when null pointer is used. These two points
may be distant from each other. Besides, next runs may not exhibit
allocation error.

In some cases memory is allocated by a call to some of C allocation
functions, malloc, calloc and realloc. They are used for interoperability
with C code, when allocated object has variable size and when it is
necessary to avoid call of constructors. In many calls the result is not
checked for null pointer. To simplify checks, new functions are defined
in the namespace 'llvm': `safe_malloc`, `safe_calloc` and `safe_realloc`.
They behave as corresponding standard functions but produce fatal error if
allocation fails. This change replaces the standard functions like 'malloc'
in the cases when the result of the allocation function is not checked
for null pointer.

Finally, there are plain C code, that uses malloc and similar functions. If
the result is not checked, assert statement is added.

Differential Revision: https://reviews.llvm.org/D43010


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@325551 91177308-0d34-0410-b5e6-96231b3b80d8
Serge Pavlov 7 jaren geleden
bovenliggende
commit
06c71d8a6f

+ 4 - 3
include/llvm/ADT/BitVector.h

@@ -828,7 +828,8 @@ private:
   }
   }
 
 
   MutableArrayRef<BitWord> allocate(size_t NumWords) {
   MutableArrayRef<BitWord> allocate(size_t NumWords) {
-    BitWord *RawBits = (BitWord *)std::malloc(NumWords * sizeof(BitWord));
+    BitWord *RawBits = static_cast<BitWord *>(
+        safe_malloc(NumWords * sizeof(BitWord)));
     return MutableArrayRef<BitWord>(RawBits, NumWords);
     return MutableArrayRef<BitWord>(RawBits, NumWords);
   }
   }
 
 
@@ -867,8 +868,8 @@ private:
   void grow(unsigned NewSize) {
   void grow(unsigned NewSize) {
     size_t NewCapacity = std::max<size_t>(NumBitWords(NewSize), Bits.size() * 2);
     size_t NewCapacity = std::max<size_t>(NumBitWords(NewSize), Bits.size() * 2);
     assert(NewCapacity > 0 && "realloc-ing zero space");
     assert(NewCapacity > 0 && "realloc-ing zero space");
-    BitWord *NewBits =
-        (BitWord *)std::realloc(Bits.data(), NewCapacity * sizeof(BitWord));
+    BitWord *NewBits = static_cast<BitWord *>(
+        safe_realloc(Bits.data(), NewCapacity * sizeof(BitWord)));
     Bits = MutableArrayRef<BitWord>(NewBits, NewCapacity);
     Bits = MutableArrayRef<BitWord>(NewBits, NewCapacity);
     clear_unused_bits();
     clear_unused_bits();
   }
   }

+ 1 - 1
include/llvm/ADT/SparseMultiSet.h

@@ -211,7 +211,7 @@ public:
     // The Sparse array doesn't actually need to be initialized, so malloc
     // The Sparse array doesn't actually need to be initialized, so malloc
     // would be enough here, but that will cause tools like valgrind to
     // would be enough here, but that will cause tools like valgrind to
     // complain about branching on uninitialized data.
     // complain about branching on uninitialized data.
-    Sparse = reinterpret_cast<SparseT*>(calloc(U, sizeof(SparseT)));
+    Sparse = static_cast<SparseT*>(safe_calloc(U, sizeof(SparseT)));
     Universe = U;
     Universe = U;
   }
   }
 
 

+ 2 - 1
include/llvm/ADT/SparseSet.h

@@ -22,6 +22,7 @@
 
 
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Allocator.h"
 #include <cassert>
 #include <cassert>
 #include <cstdint>
 #include <cstdint>
 #include <cstdlib>
 #include <cstdlib>
@@ -163,7 +164,7 @@ public:
     // The Sparse array doesn't actually need to be initialized, so malloc
     // The Sparse array doesn't actually need to be initialized, so malloc
     // would be enough here, but that will cause tools like valgrind to
     // would be enough here, but that will cause tools like valgrind to
     // complain about branching on uninitialized data.
     // complain about branching on uninitialized data.
-    Sparse = reinterpret_cast<SparseT*>(calloc(U, sizeof(SparseT)));
+    Sparse = static_cast<SparseT*>(safe_calloc(U, sizeof(SparseT)));
     Universe = U;
     Universe = U;
   }
   }
 
 

+ 28 - 0
include/llvm/Support/Allocator.h

@@ -439,6 +439,34 @@ public:
   T *Allocate(size_t num = 1) { return Allocator.Allocate<T>(num); }
   T *Allocate(size_t num = 1) { return Allocator.Allocate<T>(num); }
 };
 };
 
 
+/// \{
+/// Counterparts of allocation functions defined in namespace 'std', which crash
+/// on allocation failure instead of returning null pointer.
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) {
+  void *Result = std::malloc(Sz);
+  if (Result == nullptr)
+    report_bad_alloc_error("Allocation failed.");
+  return Result;
+}
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_calloc(size_t Count,
+                                                        size_t Sz) {
+  void *Result = std::calloc(Count, Sz);
+  if (Result == nullptr)
+    report_bad_alloc_error("Allocation failed.");
+  return Result;
+}
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) {
+  void *Result = std::realloc(Ptr, Sz);
+  if (Result == nullptr)
+    report_bad_alloc_error("Allocation failed.");
+  return Result;
+}
+
+/// \}
+
 } // end namespace llvm
 } // end namespace llvm
 
 
 template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold>
 template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold>

+ 3 - 2
include/llvm/Support/OnDiskHashTable.h

@@ -95,7 +95,8 @@ private:
 
 
   /// \brief Resize the hash table, moving the old entries into the new buckets.
   /// \brief Resize the hash table, moving the old entries into the new buckets.
   void resize(size_t NewSize) {
   void resize(size_t NewSize) {
-    Bucket *NewBuckets = (Bucket *)std::calloc(NewSize, sizeof(Bucket));
+    Bucket *NewBuckets = static_cast<Bucket *>(
+        safe_calloc(NewSize, sizeof(Bucket)));
     // Populate NewBuckets with the old entries.
     // Populate NewBuckets with the old entries.
     for (size_t I = 0; I < NumBuckets; ++I)
     for (size_t I = 0; I < NumBuckets; ++I)
       for (Item *E = Buckets[I].Head; E;) {
       for (Item *E = Buckets[I].Head; E;) {
@@ -226,7 +227,7 @@ public:
     NumBuckets = 64;
     NumBuckets = 64;
     // Note that we do not need to run the constructors of the individual
     // Note that we do not need to run the constructors of the individual
     // Bucket objects since 'calloc' returns bytes that are all 0.
     // Bucket objects since 'calloc' returns bytes that are all 0.
-    Buckets = (Bucket *)std::calloc(NumBuckets, sizeof(Bucket));
+    Buckets = static_cast<Bucket *>(safe_calloc(NumBuckets, sizeof(Bucket)));
   }
   }
 
 
   ~OnDiskChainedHashTableGenerator() { std::free(Buckets); }
   ~OnDiskChainedHashTableGenerator() { std::free(Buckets); }

+ 2 - 2
lib/CodeGen/InterferenceCache.cpp

@@ -48,8 +48,8 @@ void InterferenceCache::reinitPhysRegEntries() {
   if (PhysRegEntriesCount == TRI->getNumRegs()) return;
   if (PhysRegEntriesCount == TRI->getNumRegs()) return;
   free(PhysRegEntries);
   free(PhysRegEntries);
   PhysRegEntriesCount = TRI->getNumRegs();
   PhysRegEntriesCount = TRI->getNumRegs();
-  PhysRegEntries = (unsigned char*)
-    calloc(PhysRegEntriesCount, sizeof(unsigned char));
+  PhysRegEntries = static_cast<unsigned char*>(
+      safe_calloc(PhysRegEntriesCount, sizeof(unsigned char)));
 }
 }
 
 
 void InterferenceCache::init(MachineFunction *mf,
 void InterferenceCache::init(MachineFunction *mf,

+ 1 - 1
lib/CodeGen/LiveIntervalUnion.cpp

@@ -187,7 +187,7 @@ void LiveIntervalUnion::Array::init(LiveIntervalUnion::Allocator &Alloc,
   clear();
   clear();
   Size = NSize;
   Size = NSize;
   LIUs = static_cast<LiveIntervalUnion*>(
   LIUs = static_cast<LiveIntervalUnion*>(
-    malloc(sizeof(LiveIntervalUnion)*NSize));
+      safe_malloc(sizeof(LiveIntervalUnion)*NSize));
   for (unsigned i = 0; i != Size; ++i)
   for (unsigned i = 0; i != Size; ++i)
     new(LIUs + i) LiveIntervalUnion(Alloc);
     new(LIUs + i) LiveIntervalUnion(Alloc);
 }
 }

+ 1 - 1
lib/CodeGen/RegisterPressure.cpp

@@ -635,7 +635,7 @@ void PressureDiffs::init(unsigned N) {
   }
   }
   Max = Size;
   Max = Size;
   free(PDiffArray);
   free(PDiffArray);
-  PDiffArray = reinterpret_cast<PressureDiff*>(calloc(N, sizeof(PressureDiff)));
+  PDiffArray = static_cast<PressureDiff*>(safe_calloc(N, sizeof(PressureDiff)));
 }
 }
 
 
 void PressureDiffs::addInstruction(unsigned Idx,
 void PressureDiffs::addInstruction(unsigned Idx,

+ 1 - 1
lib/ExecutionEngine/Interpreter/Execution.cpp

@@ -974,7 +974,7 @@ void Interpreter::visitAllocaInst(AllocaInst &I) {
   unsigned MemToAlloc = std::max(1U, NumElements * TypeSize);
   unsigned MemToAlloc = std::max(1U, NumElements * TypeSize);
 
 
   // Allocate enough memory to hold the type...
   // Allocate enough memory to hold the type...
-  void *Memory = malloc(MemToAlloc);
+  void *Memory = safe_malloc(MemToAlloc);
 
 
   DEBUG(dbgs() << "Allocated Type: " << *Ty << " (" << TypeSize << " bytes) x " 
   DEBUG(dbgs() << "Allocated Type: " << *Ty << " (" << TypeSize << " bytes) x " 
                << NumElements << " (Total: " << MemToAlloc << ") at "
                << NumElements << " (Total: " << MemToAlloc << ") at "

+ 1 - 1
lib/Object/Object.cpp

@@ -228,7 +228,7 @@ uint64_t LLVMGetRelocationType(LLVMRelocationIteratorRef RI) {
 const char *LLVMGetRelocationTypeName(LLVMRelocationIteratorRef RI) {
 const char *LLVMGetRelocationTypeName(LLVMRelocationIteratorRef RI) {
   SmallVector<char, 0> ret;
   SmallVector<char, 0> ret;
   (*unwrap(RI))->getTypeName(ret);
   (*unwrap(RI))->getTypeName(ret);
-  char *str = static_cast<char*>(malloc(ret.size()));
+  char *str = static_cast<char*>(safe_malloc(ret.size()));
   std::copy(ret.begin(), ret.end(), str);
   std::copy(ret.begin(), ret.end(), str);
   return str;
   return str;
 }
 }

+ 2 - 1
lib/Support/RWMutex.cpp

@@ -11,6 +11,7 @@
 //
 //
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 
 
+#include "llvm/Support/Allocator.h"
 #include "llvm/Support/RWMutex.h"
 #include "llvm/Support/RWMutex.h"
 #include "llvm/Config/config.h"
 #include "llvm/Config/config.h"
 
 
@@ -49,7 +50,7 @@ RWMutexImpl::RWMutexImpl()
 {
 {
   // Declare the pthread_rwlock data structures
   // Declare the pthread_rwlock data structures
   pthread_rwlock_t* rwlock =
   pthread_rwlock_t* rwlock =
-    static_cast<pthread_rwlock_t*>(malloc(sizeof(pthread_rwlock_t)));
+    static_cast<pthread_rwlock_t*>(safe_malloc(sizeof(pthread_rwlock_t)));
 
 
 #ifdef __APPLE__
 #ifdef __APPLE__
   // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init.
   // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init.

+ 5 - 8
lib/Support/StringMap.cpp

@@ -57,10 +57,9 @@ void StringMapImpl::init(unsigned InitSize) {
   NumItems = 0;
   NumItems = 0;
   NumTombstones = 0;
   NumTombstones = 0;
   
   
-  TheTable = (StringMapEntryBase **)calloc(NewNumBuckets+1,
-                                           sizeof(StringMapEntryBase **) +
-                                           sizeof(unsigned));
-
+  TheTable = static_cast<StringMapEntryBase **>(
+      std::calloc(NewNumBuckets+1,
+                  sizeof(StringMapEntryBase **) + sizeof(unsigned)));
   if (TheTable == nullptr)
   if (TheTable == nullptr)
     report_bad_alloc_error("Allocation of StringMap table failed.");
     report_bad_alloc_error("Allocation of StringMap table failed.");
 
 
@@ -219,10 +218,8 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
   unsigned NewBucketNo = BucketNo;
   unsigned NewBucketNo = BucketNo;
   // Allocate one extra bucket which will always be non-empty.  This allows the
   // Allocate one extra bucket which will always be non-empty.  This allows the
   // iterators to stop at end.
   // iterators to stop at end.
-  StringMapEntryBase **NewTableArray =
-    (StringMapEntryBase **)calloc(NewSize+1, sizeof(StringMapEntryBase *) +
-                                             sizeof(unsigned));
-
+  auto NewTableArray = static_cast<StringMapEntryBase **>(
+      std::calloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
   if (NewTableArray == nullptr)
   if (NewTableArray == nullptr)
     report_bad_alloc_error("Allocation of StringMap hash table failed.");
     report_bad_alloc_error("Allocation of StringMap hash table failed.");
 
 

+ 1 - 1
lib/Support/Unix/Signals.inc

@@ -138,7 +138,7 @@ static void CreateSigAltStack() {
     return;
     return;
 
 
   stack_t AltStack = {};
   stack_t AltStack = {};
-  AltStack.ss_sp = reinterpret_cast<char *>(malloc(AltStackSize));
+  AltStack.ss_sp = static_cast<char *>(safe_malloc(AltStackSize));
   NewAltStackPointer = AltStack.ss_sp; // Save to avoid reporting a leak.
   NewAltStackPointer = AltStack.ss_sp; // Save to avoid reporting a leak.
   AltStack.ss_size = AltStackSize;
   AltStack.ss_size = AltStackSize;
   if (sigaltstack(&AltStack, &OldAltStack) != 0)
   if (sigaltstack(&AltStack, &OldAltStack) != 0)

+ 2 - 2
lib/Support/Windows/RWMutex.inc

@@ -74,10 +74,10 @@ static bool loadSRW() {
 
 
 sys::RWMutexImpl::RWMutexImpl() {
 sys::RWMutexImpl::RWMutexImpl() {
   if (loadSRW()) {
   if (loadSRW()) {
-    data_ = calloc(1, sizeof(SRWLOCK));
+    data_ = safe_calloc(1, sizeof(SRWLOCK));
     fpInitializeSRWLock(static_cast<PSRWLOCK>(data_));
     fpInitializeSRWLock(static_cast<PSRWLOCK>(data_));
   } else {
   } else {
-    data_ = calloc(1, sizeof(CRITICAL_SECTION));
+    data_ = safe_calloc(1, sizeof(CRITICAL_SECTION));
     InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
     InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
   }
   }
 }
 }

+ 3 - 0
tools/llvm-c-test/attributes.c

@@ -14,6 +14,7 @@
 
 
 #include "llvm-c-test.h"
 #include "llvm-c-test.h"
 
 
+#include <assert.h>
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 int llvm_test_function_attributes(void) {
 int llvm_test_function_attributes(void) {
@@ -30,6 +31,7 @@ int llvm_test_function_attributes(void) {
       int AttrCount = LLVMGetAttributeCountAtIndex(F, Idx);
       int AttrCount = LLVMGetAttributeCountAtIndex(F, Idx);
       LLVMAttributeRef *Attrs =
       LLVMAttributeRef *Attrs =
           (LLVMAttributeRef *)malloc(AttrCount * sizeof(LLVMAttributeRef));
           (LLVMAttributeRef *)malloc(AttrCount * sizeof(LLVMAttributeRef));
+      assert(Attrs);
       LLVMGetAttributesAtIndex(F, Idx, Attrs);
       LLVMGetAttributesAtIndex(F, Idx, Attrs);
       free(Attrs);
       free(Attrs);
     }
     }
@@ -61,6 +63,7 @@ int llvm_test_callsite_attributes(void) {
             int AttrCount = LLVMGetCallSiteAttributeCount(I, Idx);
             int AttrCount = LLVMGetCallSiteAttributeCount(I, Idx);
             LLVMAttributeRef *Attrs = (LLVMAttributeRef *)malloc(
             LLVMAttributeRef *Attrs = (LLVMAttributeRef *)malloc(
                 AttrCount * sizeof(LLVMAttributeRef));
                 AttrCount * sizeof(LLVMAttributeRef));
+            assert(Attrs);
             LLVMGetCallSiteAttributes(I, Idx, Attrs);
             LLVMGetCallSiteAttributes(I, Idx, Attrs);
             free(Attrs);
             free(Attrs);
           }
           }

+ 2 - 1
tools/llvm-c-test/echo.cpp

@@ -90,7 +90,8 @@ struct TypeCloner {
         unsigned ParamCount = LLVMCountParamTypes(Src);
         unsigned ParamCount = LLVMCountParamTypes(Src);
         LLVMTypeRef* Params = nullptr;
         LLVMTypeRef* Params = nullptr;
         if (ParamCount > 0) {
         if (ParamCount > 0) {
-          Params = (LLVMTypeRef*) malloc(ParamCount * sizeof(LLVMTypeRef));
+          Params = static_cast<LLVMTypeRef*>(
+              safe_malloc(ParamCount * sizeof(LLVMTypeRef)));
           LLVMGetParamTypes(Src, Params);
           LLVMGetParamTypes(Src, Params);
           for (unsigned i = 0; i < ParamCount; i++)
           for (unsigned i = 0; i < ParamCount; i++)
             Params[i] = Clone(Params[i]);
             Params[i] = Clone(Params[i]);

+ 1 - 1
unittests/Support/AllocatorTest.cpp

@@ -147,7 +147,7 @@ public:
     // Allocate space for the alignment, the slab, and a void* that goes right
     // Allocate space for the alignment, the slab, and a void* that goes right
     // before the slab.
     // before the slab.
     size_t Alignment = 4096;
     size_t Alignment = 4096;
-    void *MemBase = malloc(Size + Alignment - 1 + sizeof(void*));
+    void *MemBase = safe_malloc(Size + Alignment - 1 + sizeof(void*));
 
 
     // Find the slab start.
     // Find the slab start.
     void *Slab = (void *)alignAddr((char*)MemBase + sizeof(void *), Alignment);
     void *Slab = (void *)alignAddr((char*)MemBase + sizeof(void *), Alignment);

+ 4 - 2
unittests/Support/ManagedStatic.cpp

@@ -6,6 +6,8 @@
 // License. See LICENSE.TXT for details.
 // License. See LICENSE.TXT for details.
 //
 //
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Allocator.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Config/config.h"
 #include "llvm/Config/config.h"
 #ifdef HAVE_PTHREAD_H
 #ifdef HAVE_PTHREAD_H
@@ -30,7 +32,7 @@ namespace test1 {
   // Valgrind's leak checker complains glibc's stack allocation.
   // Valgrind's leak checker complains glibc's stack allocation.
   // To appease valgrind, we provide our own stack for each thread.
   // To appease valgrind, we provide our own stack for each thread.
   void *allocate_stack(pthread_attr_t &a, size_t n = 65536) {
   void *allocate_stack(pthread_attr_t &a, size_t n = 65536) {
-    void *stack = malloc(n);
+    void *stack = safe_malloc(n);
     pthread_attr_init(&a);
     pthread_attr_init(&a);
 #if defined(__linux__)
 #if defined(__linux__)
     pthread_attr_setstack(&a, stack, n);
     pthread_attr_setstack(&a, stack, n);
@@ -83,7 +85,7 @@ TEST(ManagedStaticTest, NestedStatics) {
 namespace CustomCreatorDeletor {
 namespace CustomCreatorDeletor {
 struct CustomCreate {
 struct CustomCreate {
   static void *call() {
   static void *call() {
-    void *Mem = std::malloc(sizeof(int));
+    void *Mem = safe_malloc(sizeof(int));
     *((int *)Mem) = 42;
     *((int *)Mem) = 42;
     return Mem;
     return Mem;
   }
   }