Hi mclow.lists,

Fix vector asan annotations with RAII.
Add a test.
Also, remove one dead function.

http://reviews.llvm.org/D4170

Files:
  include/vector
  test/containers/sequences/vector/asan_throw.pass.cc
  test/support/asan_testing.h
Index: test/containers/sequences/vector/asan_throw.pass.cc
===================================================================
--- /dev/null
+++ test/containers/sequences/vector/asan_throw.pass.cc
@@ -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();
+}
Index: test/support/asan_testing.h
===================================================================
--- test/support/asan_testing.h
+++ test/support/asan_testing.h
@@ -19,7 +19,7 @@
 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 @@
 #endif
  
 
-#endif  // ASAN_TESTING_H
\ No newline at end of file
+#endif  // ASAN_TESTING_H
Index: include/vector
===================================================================
--- include/vector
+++ include/vector
@@ -788,7 +788,6 @@
             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
@@ -840,34 +839,50 @@
     // 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)
         __sanitizer_annotate_contiguous_container(__beg, __end, __old_mid, __new_mid);
 #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>
@@ -963,12 +978,13 @@
 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);
 }
 
@@ -984,12 +1000,13 @@
 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);
 }
 
@@ -1005,22 +1022,9 @@
     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_;
     }
 }
@@ -1582,9 +1586,10 @@
 {
     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
@@ -1600,10 +1605,11 @@
 {
     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
@@ -1633,10 +1639,11 @@
 {
     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
@@ -1716,7 +1723,7 @@
     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(),
@@ -1731,6 +1738,7 @@
                 ++__xr;
             *__p = *__xr;
         }
+        __annotator.__done();
     }
     else
     {
@@ -1756,7 +1764,7 @@
     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(),
@@ -1769,6 +1777,7 @@
             __move_range(__p, this->__end_, __p + 1);
             *__p = _VSTD::move(__x);
         }
+        __annotator.__done();
     }
     else
     {
@@ -1795,7 +1804,7 @@
     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(),
@@ -1809,6 +1818,7 @@
             __move_range(__p, this->__end_, __p + 1);
             *__p = _VSTD::move(__tmp);
         }
+        __annotator.__done();
     }
     else
     {
@@ -1847,8 +1857,9 @@
             }
             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;
@@ -1958,8 +1969,9 @@
             }
             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);
             }
         }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to