diff options
author | Alina Sbirlea <asbirlea@google.com> | 2022-08-23 15:39:09 -0700 |
---|---|---|
committer | Alina Sbirlea <asbirlea@google.com> | 2022-10-06 15:37:43 -0700 |
commit | 0fbeca0ee6f0cdc37b89e5b06fbb3ca6caf26f66 (patch) | |
tree | 66c81482b86a5852227183db1cb8edc7bc734ff6 /llvm/lib/Support/SmallVector.cpp | |
parent | 6d65ac500946c44457bbd2b2cfa7d0a6482e51f2 (diff) | |
download | llvm-0fbeca0ee6f0cdc37b89e5b06fbb3ca6caf26f66.zip llvm-0fbeca0ee6f0cdc37b89e5b06fbb3ca6caf26f66.tar.gz llvm-0fbeca0ee6f0cdc37b89e5b06fbb3ca6caf26f66.tar.bz2 |
[SmallVector] Reallocate if assigned memory is right after the current vector, created with capacity 0
Potential solution for
https://github.com/llvm/llvm-project/issues/57324.
Differential Revision: https://reviews.llvm.org/D132512
Diffstat (limited to 'llvm/lib/Support/SmallVector.cpp')
-rw-r--r-- | llvm/lib/Support/SmallVector.cpp | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/llvm/lib/Support/SmallVector.cpp b/llvm/lib/Support/SmallVector.cpp index 062e965..f7e7e80 100644 --- a/llvm/lib/Support/SmallVector.cpp +++ b/llvm/lib/Support/SmallVector.cpp @@ -108,12 +108,29 @@ static size_t getNewCapacity(size_t MinSize, size_t TSize, size_t OldCapacity) { return std::clamp(NewCapacity, MinSize, MaxSize); } +template <class Size_T> +void *SmallVectorBase<Size_T>::replaceAllocation(void *NewElts, size_t TSize, + size_t NewCapacity, + size_t VSize) { + void *NewEltsReplace = llvm::safe_malloc(NewCapacity * TSize); + if (VSize) + memcpy(NewEltsReplace, NewElts, VSize * TSize); + free(NewElts); + return NewEltsReplace; +} + // Note: Moving this function into the header may cause performance regression. template <class Size_T> -void *SmallVectorBase<Size_T>::mallocForGrow(size_t MinSize, size_t TSize, +void *SmallVectorBase<Size_T>::mallocForGrow(void *FirstEl, size_t MinSize, + size_t TSize, size_t &NewCapacity) { NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity()); - return llvm::safe_malloc(NewCapacity * TSize); + // Even if capacity is not 0 now, if the vector was originally created with + // capacity 0, it's possible for the malloc to return FirstEl. + void *NewElts = llvm::safe_malloc(NewCapacity * TSize); + if (NewElts == FirstEl) + NewElts = replaceAllocation(NewElts, TSize, NewCapacity); + return NewElts; } // Note: Moving this function into the header may cause performance regression. @@ -123,13 +140,17 @@ void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinSize, size_t NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity()); void *NewElts; if (BeginX == FirstEl) { - NewElts = safe_malloc(NewCapacity * TSize); + NewElts = llvm::safe_malloc(NewCapacity * TSize); + if (NewElts == FirstEl) + NewElts = replaceAllocation(NewElts, TSize, NewCapacity); // Copy the elements over. No need to run dtors on PODs. memcpy(NewElts, this->BeginX, size() * TSize); } else { // If this wasn't grown from the inline copy, grow the allocated space. - NewElts = safe_realloc(this->BeginX, NewCapacity * TSize); + NewElts = llvm::safe_realloc(this->BeginX, NewCapacity * TSize); + if (NewElts == FirstEl) + NewElts = replaceAllocation(NewElts, TSize, NewCapacity, size()); } this->BeginX = NewElts; |