Make SmallVector assert if it cannot grow.
authorAndrew Browne <browneee@google.com>
Mon, 6 Apr 2020 21:42:57 +0000 (14:42 -0700)
committerAndrew Browne <browneee@google.com>
Wed, 22 Apr 2020 00:53:39 +0000 (17:53 -0700)
commita30e7ea88e75568feed020aedae73c52de888835
tree9bfee37e5c8b3a71862f4166e8d7e35cee7a0f55
parent7375212172951d2fc283c81d03c1a8588c3280c6
Make SmallVector assert if it cannot grow.

Context:

  /// Double the size of the allocated memory, guaranteeing space for at
  /// least one more element or MinSize if specified.
  void grow(size_t MinSize = 0) { this->grow_pod(MinSize, sizeof(T)); }

  void push_back(const T &Elt) {
    if (LLVM_UNLIKELY(this->size() >= this->capacity()))
      this->grow();
    memcpy(reinterpret_cast<void *>(this->end()), &Elt, sizeof(T));
    this->set_size(this->size() + 1);
  }

When grow is called in push_back() without a MinSize specified, this is
relying on the guarantee of space for at least one more element.

There is an edge case bug where the SmallVector is already at its maximum size
and push_back() calls grow() with default MinSize of zero. Grow is unable to
provide space for one more element, but push_back() assumes the additional
element it will be available. This can result in silent memory corruption, as
this->end() will be an invalid pointer and the program may continue executing.

Another alternative to fix would be to remove the default argument from
grow(), which would mean several changing grow() to grow(this->size()+1)
in several places.

No test case added because it would require allocating ~4GB.

Reviewers: echristo

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D77601
llvm/include/llvm/ADT/SmallVector.h
llvm/lib/Support/SmallVector.cpp