[libcxx] r216995 - [asan] Make vector asan annotations exception-friendly
Kostya Serebryany
kcc at google.com
Tue Sep 2 16:43:38 PDT 2014
Author: kcc
Date: Tue Sep 2 18:43:38 2014
New Revision: 216995
URL: http://llvm.org/viewvc/llvm-project?rev=216995&view=rev
Log:
[asan] Make vector asan annotations exception-friendly
Fix vector asan annotations with RAII.
Add a test.
Also, remove one dead function.
Review: http://reviews.llvm.org/D4170
Added:
libcxx/trunk/test/containers/sequences/vector/asan_throw.pass.cc
Modified:
libcxx/trunk/include/vector
libcxx/trunk/test/support/asan_testing.h
Modified: libcxx/trunk/include/vector
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/vector?rev=216995&r1=216994&r2=216995&view=diff
==============================================================================
--- libcxx/trunk/include/vector (original)
+++ libcxx/trunk/include/vector Tue Sep 2 18:43:38 2014
@@ -784,7 +784,6 @@ private:
void
>::type
__construct_at_end(_ForwardIterator __first, _ForwardIterator __last);
- void __move_construct_at_end(pointer __first, pointer __last);
void __append(size_type __n);
void __append(size_type __n, const_reference __x);
_LIBCPP_INLINE_VISIBILITY
@@ -836,7 +835,7 @@ private:
// may not meet the AddressSanitizer alignment constraints.
// See the documentation for __sanitizer_annotate_contiguous_container for more details.
void __annotate_contiguous_container
- (const void *__beg, const void *__end, const void *__old_mid, const void *__new_mid)
+ (const void *__beg, const void *__end, const void *__old_mid, const void *__new_mid) const
{
#ifndef _LIBCPP_HAS_NO_ASAN
if (__beg && is_same<allocator_type, __default_allocator_type>::value)
@@ -844,26 +843,42 @@ private:
#endif
}
- void __annotate_new(size_type __current_size)
+ void __annotate_new(size_type __current_size) const
{
__annotate_contiguous_container(data(), data() + capacity(),
data() + capacity(), data() + __current_size);
}
- void __annotate_delete()
+ void __annotate_delete() const
{
__annotate_contiguous_container(data(), data() + capacity(),
data() + size(), data() + capacity());
}
- void __annotate_increase(size_type __n)
+ void __annotate_increase(size_type __n) const
{
__annotate_contiguous_container(data(), data() + capacity(),
data() + size(), data() + size() + __n);
}
- void __annotate_shrink(size_type __old_size)
+ void __annotate_shrink(size_type __old_size) const
{
__annotate_contiguous_container(data(), data() + capacity(),
data() + __old_size, data() + size());
}
+ // The annotation for size increase should happen before the actual increase,
+ // but if an exception is thrown after that the annotation has to be undone.
+ struct __RAII_IncreaseAnnotator {
+ __RAII_IncreaseAnnotator(const vector &__v, size_type __n = 1)
+ : __commit(false), __v(__v), __n(__n) {
+ __v.__annotate_increase(__n);
+ }
+ void __done() { __commit = true; }
+ ~__RAII_IncreaseAnnotator() {
+ if (__commit) return;
+ __v.__annotate_shrink(__v.size() + __n);
+ }
+ bool __commit;
+ size_type __n;
+ const vector &__v;
+ };
};
template <class _Tp, class _Allocator>
@@ -959,12 +974,13 @@ void
vector<_Tp, _Allocator>::__construct_at_end(size_type __n)
{
allocator_type& __a = this->__alloc();
- __annotate_increase(__n);
do
{
+ __RAII_IncreaseAnnotator __annotator(*this);
__alloc_traits::construct(__a, _VSTD::__to_raw_pointer(this->__end_));
++this->__end_;
--__n;
+ __annotator.__done();
} while (__n > 0);
}
@@ -980,12 +996,13 @@ void
vector<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x)
{
allocator_type& __a = this->__alloc();
- __annotate_increase(__n);
do
{
+ __RAII_IncreaseAnnotator __annotator(*this);
__alloc_traits::construct(__a, _VSTD::__to_raw_pointer(this->__end_), __x);
++this->__end_;
--__n;
+ __annotator.__done();
} while (__n > 0);
}
@@ -1001,22 +1018,9 @@ vector<_Tp, _Allocator>::__construct_at_
allocator_type& __a = this->__alloc();
for (; __first != __last; ++__first)
{
- __annotate_increase(1);
+ __RAII_IncreaseAnnotator __annotator(*this);
__alloc_traits::construct(__a, _VSTD::__to_raw_pointer(this->__end_), *__first);
- ++this->__end_;
- }
-}
-
-template <class _Tp, class _Allocator>
-void
-vector<_Tp, _Allocator>::__move_construct_at_end(pointer __first, pointer __last)
-{
- allocator_type& __a = this->__alloc();
- for (; __first != __last; ++__first)
- {
- __annotate_increase(1);
- __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(this->__end_),
- _VSTD::move(*__first));
+ __annotator.__done();
++this->__end_;
}
}
@@ -1578,9 +1582,10 @@ vector<_Tp, _Allocator>::push_back(const
{
if (this->__end_ != this->__end_cap())
{
- __annotate_increase(1);
+ __RAII_IncreaseAnnotator __annotator(*this);
__alloc_traits::construct(this->__alloc(),
_VSTD::__to_raw_pointer(this->__end_), __x);
+ __annotator.__done();
++this->__end_;
}
else
@@ -1596,10 +1601,11 @@ vector<_Tp, _Allocator>::push_back(value
{
if (this->__end_ < this->__end_cap())
{
- __annotate_increase(1);
+ __RAII_IncreaseAnnotator __annotator(*this);
__alloc_traits::construct(this->__alloc(),
_VSTD::__to_raw_pointer(this->__end_),
_VSTD::move(__x));
+ __annotator.__done();
++this->__end_;
}
else
@@ -1629,10 +1635,11 @@ vector<_Tp, _Allocator>::emplace_back(_A
{
if (this->__end_ < this->__end_cap())
{
- __annotate_increase(1);
+ __RAII_IncreaseAnnotator __annotator(*this);
__alloc_traits::construct(this->__alloc(),
_VSTD::__to_raw_pointer(this->__end_),
_VSTD::forward<_Args>(__args)...);
+ __annotator.__done();
++this->__end_;
}
else
@@ -1712,7 +1719,7 @@ vector<_Tp, _Allocator>::insert(const_it
pointer __p = this->__begin_ + (__position - begin());
if (this->__end_ < this->__end_cap())
{
- __annotate_increase(1);
+ __RAII_IncreaseAnnotator __annotator(*this);
if (__p == this->__end_)
{
__alloc_traits::construct(this->__alloc(),
@@ -1727,6 +1734,7 @@ vector<_Tp, _Allocator>::insert(const_it
++__xr;
*__p = *__xr;
}
+ __annotator.__done();
}
else
{
@@ -1752,7 +1760,7 @@ vector<_Tp, _Allocator>::insert(const_it
pointer __p = this->__begin_ + (__position - begin());
if (this->__end_ < this->__end_cap())
{
- __annotate_increase(1);
+ __RAII_IncreaseAnnotator __annotator(*this);
if (__p == this->__end_)
{
__alloc_traits::construct(this->__alloc(),
@@ -1765,6 +1773,7 @@ vector<_Tp, _Allocator>::insert(const_it
__move_range(__p, this->__end_, __p + 1);
*__p = _VSTD::move(__x);
}
+ __annotator.__done();
}
else
{
@@ -1791,7 +1800,7 @@ vector<_Tp, _Allocator>::emplace(const_i
pointer __p = this->__begin_ + (__position - begin());
if (this->__end_ < this->__end_cap())
{
- __annotate_increase(1);
+ __RAII_IncreaseAnnotator __annotator(*this);
if (__p == this->__end_)
{
__alloc_traits::construct(this->__alloc(),
@@ -1805,6 +1814,7 @@ vector<_Tp, _Allocator>::emplace(const_i
__move_range(__p, this->__end_, __p + 1);
*__p = _VSTD::move(__tmp);
}
+ __annotator.__done();
}
else
{
@@ -1843,8 +1853,9 @@ vector<_Tp, _Allocator>::insert(const_it
}
if (__n > 0)
{
- __annotate_increase(__n);
+ __RAII_IncreaseAnnotator __annotator(*this);
__move_range(__p, __old_last, __p + __old_n);
+ __annotator.__done();
const_pointer __xr = pointer_traits<const_pointer>::pointer_to(__x);
if (__p <= __xr && __xr < this->__end_)
__xr += __old_n;
@@ -1954,8 +1965,9 @@ vector<_Tp, _Allocator>::insert(const_it
}
if (__n > 0)
{
- __annotate_increase(__n);
+ __RAII_IncreaseAnnotator __annotator(*this, __n);
__move_range(__p, __old_last, __p + __old_n);
+ __annotator.__done();
_VSTD::copy(__first, __m, __p);
}
}
Added: libcxx/trunk/test/containers/sequences/vector/asan_throw.pass.cc
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/containers/sequences/vector/asan_throw.pass.cc?rev=216995&view=auto
==============================================================================
--- libcxx/trunk/test/containers/sequences/vector/asan_throw.pass.cc (added)
+++ libcxx/trunk/test/containers/sequences/vector/asan_throw.pass.cc Tue Sep 2 18:43:38 2014
@@ -0,0 +1,198 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Test asan vector annotations with a class that throws in a CTOR.
+
+#include <vector>
+#include <cassert>
+
+#include "asan_testing.h"
+
+class X {
+public:
+ X(const X &x) { Init(x.a); }
+ X(char arg) { Init(arg); }
+ X() { Init(42); }
+ X &operator=(const X &x) {
+ Init(x.a);
+ return *this;
+ }
+ void Init(char arg) {
+ if (arg == 42)
+ throw 0;
+ if (arg == 66)
+ arg = 42;
+ a = arg;
+ }
+ char get() const { return a; }
+ void set(char arg) { a = arg; }
+
+private:
+ char a;
+};
+
+void test_push_back() {
+ std::vector<X> v;
+ v.reserve(2);
+ v.push_back(X(2));
+ assert(v.size() == 1);
+ try {
+ v.push_back(X(66));
+ assert(0);
+ } catch (int e) {
+ assert(v.size() == 1);
+ }
+ assert(v.size() == 1);
+ assert(is_contiguous_container_asan_correct(v));
+}
+
+void test_emplace_back() {
+#ifndef _LIBCPP_HAS_NO_VARIADICS
+ std::vector<X> v;
+ v.reserve(2);
+ v.push_back(X(2));
+ assert(v.size() == 1);
+ try {
+ v.emplace_back(42);
+ assert(0);
+ } catch (int e) {
+ assert(v.size() == 1);
+ }
+ assert(v.size() == 1);
+ assert(is_contiguous_container_asan_correct(v));
+#endif // _LIBCPP_HAS_NO_VARIADICS
+}
+
+void test_insert_range() {
+ std::vector<X> v;
+ v.reserve(4);
+ v.push_back(X(1));
+ v.push_back(X(2));
+ assert(v.size() == 2);
+ assert(v.capacity() >= 4);
+ try {
+ char a[2] = {21, 42};
+ v.insert(v.end(), a, a + 2);
+ assert(0);
+ } catch (int e) {
+ assert(v.size() == 3);
+ }
+ assert(v.size() == 3);
+ assert(is_contiguous_container_asan_correct(v));
+}
+
+void test_insert() {
+ std::vector<X> v;
+ v.reserve(3);
+ v.insert(v.end(), X(1));
+ v.insert(v.begin(), X(2));
+ assert(v.size() == 2);
+ try {
+ v.insert(v.end(), X(66));
+ assert(0);
+ } catch (int e) {
+ assert(v.size() == 2);
+ }
+ assert(v.size() == 2);
+ assert(is_contiguous_container_asan_correct(v));
+}
+
+void test_emplace() {
+#ifndef _LIBCPP_HAS_NO_VARIADICS
+ std::vector<X> v;
+ v.reserve(3);
+ v.insert(v.end(), X(1));
+ v.insert(v.begin(), X(2));
+ assert(v.size() == 2);
+ try {
+ v.emplace(v.end(), 42);
+ assert(0);
+ } catch (int e) {
+ assert(v.size() == 2);
+ }
+ assert(v.size() == 2);
+ assert(is_contiguous_container_asan_correct(v));
+#endif // _LIBCPP_HAS_NO_VARIADICS
+}
+
+void test_insert_range2() {
+ std::vector<X> v;
+ v.reserve(4);
+ v.insert(v.end(), X(1));
+ v.insert(v.begin(), X(2));
+ assert(v.size() == 2);
+ assert(v.capacity() >= 4);
+ try {
+ char a[2] = {10, 42};
+ v.insert(v.begin(), a, a + 2);
+ assert(0);
+ } catch (int e) {
+ assert(v.size() <= 4);
+ assert(is_contiguous_container_asan_correct(v));
+ return;
+ }
+ assert(0);
+}
+
+void test_insert_n() {
+ std::vector<X> v;
+ v.reserve(10);
+ v.insert(v.end(), X(1));
+ v.insert(v.begin(), X(2));
+ assert(v.size() == 2);
+ try {
+ v.insert(v.begin(), 1, X(66));
+ assert(0);
+ } catch (int e) {
+ assert(v.size() <= 3);
+ assert(is_contiguous_container_asan_correct(v));
+ return;
+ }
+ assert(0);
+}
+
+void test_resize() {
+ std::vector<X> v;
+ v.reserve(3);
+ v.push_back(X(0));
+ try {
+ v.resize(3);
+ assert(0);
+ } catch (int e) {
+ assert(v.size() == 1);
+ }
+ assert(v.size() == 1);
+ assert(is_contiguous_container_asan_correct(v));
+}
+
+void test_resize_param() {
+ std::vector<X> v;
+ v.reserve(3);
+ v.push_back(X(0));
+ try {
+ v.resize(3, X(66));
+ assert(0);
+ } catch (int e) {
+ assert(v.size() == 1);
+ }
+ assert(v.size() == 1);
+ assert(is_contiguous_container_asan_correct(v));
+}
+
+int main() {
+ test_push_back();
+ test_emplace_back();
+ test_insert_range();
+ test_insert();
+ test_emplace();
+ test_insert_range2();
+ test_insert_n();
+ test_resize();
+ test_resize_param();
+}
Modified: libcxx/trunk/test/support/asan_testing.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/asan_testing.h?rev=216995&r1=216994&r2=216995&view=diff
==============================================================================
--- libcxx/trunk/test/support/asan_testing.h (original)
+++ libcxx/trunk/test/support/asan_testing.h Tue Sep 2 18:43:38 2014
@@ -19,7 +19,7 @@ extern "C" int __sanitizer_verify_contig
template <typename T, typename Alloc>
bool is_contiguous_container_asan_correct ( const std::vector<T, Alloc> &c )
{
- if ( std::is_same<Alloc, std::allocator<T>>::value && c.data() != NULL)
+ if ( std::is_same<Alloc, std::allocator<T> >::value && c.data() != NULL)
return __sanitizer_verify_contiguous_container (
c.data(), c.data() + c.size(), c.data() + c.capacity()) != 0;
return true;
@@ -34,4 +34,4 @@ bool is_contiguous_container_asan_correc
#endif
-#endif // ASAN_TESTING_H
\ No newline at end of file
+#endif // ASAN_TESTING_H
More information about the cfe-commits
mailing list