dexonsmith created this revision.
dexonsmith added reviewers: mclow.lists, EricWF.
dexonsmith added a subscriber: cfe-commits.

The following program is obviously broken:

    #include <vector>
    int main(int argc, const char * argv[]) {
        std::vector<int> v;
        v.push_back(0);
        v.pop_back();
        v.pop_back();
        return 0;
    }

The failure mode at -O0 is pretty painful though.  There's no crash;
instead std::vector<int>::~vector() hits an infinite loop in
`std::__vector_base<int>::destruct_at_end()`.  In the following snippet,
`__new_last` starts *smaller* than `__end_`:

    while (__new_last != __end_)
        __alloc_traits::destroy(__alloc(), _VSTD::__to_raw_pointer(--__end_));

Note that `__alloc_traits::destroy()` is a no-op because `int` is POD,
so we don't get any bad memory accesses here.  ASan does not catch this.

This patch changes the condition to:

    while (__new_last < __end_)
        __alloc_traits::destroy(__alloc(), _VSTD::__to_raw_pointer(--__end_));

making the infinite loop less likely.  Since `__new_last` and `__end_`
are raw pointers, `<` should be the same cost as `!=`.

Unfortunately, I'm not sure how to add a test for this change.

I'm also not confident this is the best approach; suggestions welcome.
Maybe someone can even argue that the infinite loop is *better*...?

http://reviews.llvm.org/D17053

Files:
  include/vector

Index: include/vector
===================================================================
--- include/vector
+++ include/vector
@@ -420,7 +420,7 @@
 void
 __vector_base<_Tp, _Allocator>::__destruct_at_end(pointer __new_last) _NOEXCEPT
 {
-    while (__new_last != __end_)
+    while (__new_last < __end_)
         __alloc_traits::destroy(__alloc(), _VSTD::__to_raw_pointer(--__end_));
 }
 


Index: include/vector
===================================================================
--- include/vector
+++ include/vector
@@ -420,7 +420,7 @@
 void
 __vector_base<_Tp, _Allocator>::__destruct_at_end(pointer __new_last) _NOEXCEPT
 {
-    while (__new_last != __end_)
+    while (__new_last < __end_)
         __alloc_traits::destroy(__alloc(), _VSTD::__to_raw_pointer(--__end_));
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to