diff --git a/llvm/include/llvm/ADT/SmallString.h b/llvm/include/llvm/ADT/SmallString.h --- a/llvm/include/llvm/ADT/SmallString.h +++ b/llvm/include/llvm/ADT/SmallString.h @@ -269,6 +269,8 @@ const char* c_str() { this->push_back(0); this->pop_back(); + // Unpoison the address of the null terminator. + __asan_unpoison_memory_region(this->end(), 1); return this->data(); } diff --git a/llvm/include/llvm/ADT/SmallVector.h b/llvm/include/llvm/ADT/SmallVector.h --- a/llvm/include/llvm/ADT/SmallVector.h +++ b/llvm/include/llvm/ADT/SmallVector.h @@ -219,16 +219,19 @@ SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon(Size) {} static void destroy_range(T *S, T *E) { + const LLVM_ATTRIBUTE_UNUSED size_t Size = E - S; while (S != E) { --E; E->~T(); } + __asan_poison_memory_region(S, Size * sizeof(T)); } /// Move the range [I, E) into the uninitialized memory starting with "Dest", /// constructing elements as needed. template static void uninitialized_move(It1 I, It1 E, It2 Dest) { + __asan_unpoison_memory_region(Dest, std::distance(I, E) * sizeof(T)); std::uninitialized_copy(std::make_move_iterator(I), std::make_move_iterator(E), Dest); } @@ -237,6 +240,7 @@ /// constructing elements as needed. template static void uninitialized_copy(It1 I, It1 E, It2 Dest) { + __asan_unpoison_memory_region(Dest, std::distance(I, E) * sizeof(T)); std::uninitialized_copy(I, E, Dest); } @@ -249,6 +253,7 @@ void push_back(const T &Elt) { if (LLVM_UNLIKELY(this->size() >= this->capacity())) this->grow(); + __asan_unpoison_memory_region(this->end(), sizeof(T)); ::new ((void*) this->end()) T(Elt); this->set_size(this->size() + 1); } @@ -256,6 +261,7 @@ void push_back(T &&Elt) { if (LLVM_UNLIKELY(this->size() >= this->capacity())) this->grow(); + __asan_unpoison_memory_region(this->end(), sizeof(T)); ::new ((void*) this->end()) T(::std::move(Elt)); this->set_size(this->size() + 1); } @@ -263,6 +269,7 @@ void pop_back() { this->set_size(this->size() - 1); this->end()->~T(); + __asan_poison_memory_region(this->end(), sizeof(T)); } }; @@ -326,7 +333,9 @@ SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon(Size) {} // No need to do a destroy loop for POD's. - static void destroy_range(T *, T *) {} + static void destroy_range(T *B, T *E) { + __asan_poison_memory_region(B, (E - B) * sizeof(T)); + } /// Move the range [I, E) onto the uninitialized memory /// starting with "Dest", constructing elements into it as needed. @@ -341,6 +350,7 @@ template static void uninitialized_copy(It1 I, It1 E, It2 Dest) { // Arbitrary iterator types; just use the basic implementation. + __asan_unpoison_memory_region(Dest, std::distance(I, E) * sizeof(T)); std::uninitialized_copy(I, E, Dest); } @@ -355,6 +365,7 @@ // iterators): std::uninitialized_copy optimizes to memmove, but we can // use memcpy here. Note that I and E are iterators and thus might be // invalid for memcpy if they are equal. + __asan_unpoison_memory_region(Dest, (E - I) * sizeof(T)); if (I != E) memcpy(reinterpret_cast(Dest), I, (E - I) * sizeof(T)); } @@ -367,11 +378,15 @@ void push_back(const T &Elt) { if (LLVM_UNLIKELY(this->size() >= this->capacity())) this->grow(); + __asan_unpoison_memory_region(this->end(), sizeof(T)); memcpy(reinterpret_cast(this->end()), &Elt, sizeof(T)); this->set_size(this->size() + 1); } - void pop_back() { this->set_size(this->size() - 1); } + void pop_back() { + this->set_size(this->size() - 1); + __asan_poison_memory_region(this->end(), sizeof(T)); + } }; /// This class consists of common code factored out of the SmallVector class to @@ -413,6 +428,8 @@ } else if (N > this->size()) { if (this->capacity() < N) this->grow(N); + __asan_unpoison_memory_region(this->end(), + (N - this->size()) * sizeof(T)); for (auto I = this->end(), E = this->begin() + N; I != E; ++I) new (&*I) T(); this->set_size(N); @@ -426,6 +443,8 @@ } else if (N > this->size()) { if (this->capacity() < N) this->grow(N); + __asan_unpoison_memory_region(this->end(), + (N - this->size()) * sizeof(T)); std::uninitialized_fill(this->end(), this->begin()+N, NV); this->set_size(N); } @@ -463,6 +482,7 @@ if (NumInputs > this->capacity() - this->size()) this->grow(this->size()+NumInputs); + __asan_unpoison_memory_region(this->end(), NumInputs * sizeof(T)); std::uninitialized_fill_n(this->end(), NumInputs, Elt); this->set_size(this->size() + NumInputs); } @@ -478,6 +498,7 @@ clear(); if (this->capacity() < NumElts) this->grow(NumElts); + __asan_unpoison_memory_region(this->begin(), NumElts * sizeof(T)); this->set_size(NumElts); std::uninitialized_fill(this->begin(), this->end(), Elt); } @@ -544,6 +565,7 @@ I = this->begin()+EltNo; } + __asan_unpoison_memory_region(this->end(), sizeof(T)); ::new ((void*) this->end()) T(::std::move(this->back())); // Push everything else over. std::move_backward(I, this->end()-1, this->end()); @@ -569,10 +591,19 @@ assert(I <= this->end() && "Inserting past the end of the vector."); if (this->size() >= this->capacity()) { - size_t EltNo = I-this->begin(); + if (&Elt >= this->begin() && &Elt < this->end()) { + // If we are inserting from an element inside the SmallVector and we + // need to grow, the reference to the element will become invalidated on + // the call to grow. + T Copy(Elt); + return insert(I, std::move(Copy)); + } + size_t EltNo = I - this->begin(); this->grow(); - I = this->begin()+EltNo; + I = this->begin() + EltNo; } + + __asan_unpoison_memory_region(this->end(), sizeof(T)); ::new ((void*) this->end()) T(std::move(this->back())); // Push everything else over. std::move_backward(I, this->end()-1, this->end()); @@ -626,6 +657,7 @@ // not inserting at the end. // Move over the elements that we're about to overwrite. + __asan_unpoison_memory_region(this->end(), NumToInsert * sizeof(T)); T *OldEnd = this->end(); this->set_size(this->size() + NumToInsert); size_t NumOverwritten = OldEnd-I; @@ -684,6 +716,7 @@ // Move over the elements that we're about to overwrite. T *OldEnd = this->end(); + __asan_unpoison_memory_region(this->end(), NumToInsert * sizeof(T)); this->set_size(this->size() + NumToInsert); size_t NumOverwritten = OldEnd-I; this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten); @@ -706,6 +739,7 @@ template reference emplace_back(ArgTypes &&... Args) { if (LLVM_UNLIKELY(this->size() >= this->capacity())) this->grow(); + __asan_unpoison_memory_region(this->end(), sizeof(T)); ::new ((void *)this->end()) T(std::forward(Args)...); this->set_size(this->size() + 1); return this->back(); @@ -806,7 +840,7 @@ // Otherwise, use assignment for the already-constructed elements. std::copy(RHS.begin(), RHS.begin()+CurSize, this->begin()); } - + __asan_unpoison_memory_region(this->begin(), RHSSize * sizeof(T)); // Copy construct the new elements in place. this->uninitialized_copy(RHS.begin()+CurSize, RHS.end(), this->begin()+CurSize); @@ -866,7 +900,7 @@ // Otherwise, use assignment for the already-constructed elements. std::move(RHS.begin(), RHS.begin()+CurSize, this->begin()); } - + __asan_unpoison_memory_region(this->begin(), RHSSize * sizeof(T)); // Move-construct the new elements in place. this->uninitialized_move(RHS.begin()+CurSize, RHS.end(), this->begin()+CurSize); @@ -882,6 +916,18 @@ /// to avoid allocating unnecessary storage. template struct SmallVectorStorage { +#if LLVM_ADDRESS_SANITIZER_BUILD + SmallVectorStorage() { + __asan_poison_memory_region(&InlineElts, sizeof(InlineElts)); + } + ~SmallVectorStorage() { + // Although we don't want to be able to dereference pointers held to + // InlineElts, we need to unpoison the memory for the case when the memory + // is reused. This is especially important if the SmallVector lives on the + // stack. + __asan_unpoison_memory_region(&InlineElts, sizeof(InlineElts)); + } +#endif AlignedCharArrayUnion InlineElts[N]; }; diff --git a/llvm/lib/Support/Twine.cpp b/llvm/lib/Support/Twine.cpp --- a/llvm/lib/Support/Twine.cpp +++ b/llvm/lib/Support/Twine.cpp @@ -51,6 +51,8 @@ toVector(Out); Out.push_back(0); Out.pop_back(); + // Unpoison the address of the null terminator. + __asan_unpoison_memory_region(Out.end(), 1); return StringRef(Out.data(), Out.size()); }