[LLVMbugs] [Bug 22650] New: std::deque cannot tolerate allocator exceptions
bugzilla-daemon at llvm.org
bugzilla-daemon at llvm.org
Fri Feb 20 13:19:32 PST 2015
http://llvm.org/bugs/show_bug.cgi?id=22650
Bug ID: 22650
Summary: std::deque cannot tolerate allocator exceptions
Product: libc++
Version: 3.5
Hardware: PC
OS: Linux
Status: NEW
Severity: normal
Priority: P
Component: All Bugs
Assignee: unassignedclangbugs at nondot.org
Reporter: tavianator at tavianator.com
CC: llvmbugs at cs.uiuc.edu, mclow.lists at gmail.com
Classification: Unclassified
Created attachment 13919
--> http://llvm.org/bugs/attachment.cgi?id=13919&action=edit
Reproducer
In std::deque::{push,emplace}_{back,front}, if the allocator/operator new
throws std::bad_alloc, bad things happen:
$ clang++ -std=c++11 -stdlib=libc++ -lc++abi -DOPERATION=push_back
deque_bug.cpp && ./a.out
[2] 22243 segmentation fault (core dumped) ./a.out
$ clang++ -std=c++11 -stdlib=libc++ -lc++abi -DOPERATION=push_front
deque_bug.cpp && ./a.out
*** Error in `./a.out': free(): invalid pointer: 0x00007f8bf263ccd8 ***
...
The problem seems to be at lines 2281 and 2429 of <deque> which do
try
{
__buf.push_back(__alloc_traits::allocate(__a, __base::__block_size));
}
catch (...)
{
__alloc_traits::deallocate(__a, __buf.{front,back}(),
__base::__block_size);
throw;
}
This code seems wrong for a couple reasons:
- If allocate() throws, __buf.push_back() is never called, so
__buf.{front,back}() is bogus
- if __buf.push_back() throws, __buf.{front,back}() is *still* bogus
The following patch fixes my test case. There are other cases that should
probably be fixed as well, everywhere "catch (...)" appears, but I couldn't
trigger them so I didn't try to fix them. Actually, assuming the capacity of
__buf is set correctly, I imagine the try/catch blocks could be removed
entirely, but I didn't test that.
--- /usr/include/c++/v1/deque 2014-03-05 14:06:20.000000000 -0500
+++ deque 2015-02-20 16:15:06.500667124 -0500
@@ -2269,16 +2269,17 @@
__split_buffer<pointer, typename __base::__pointer_allocator&>
__buf(max<size_type>(2 * __base::__map_.capacity(), 1),
0, __base::__map_.__alloc());
+ pointer __block = __alloc_traits::allocate(__a, __base::__block_size);
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
- __buf.push_back(__alloc_traits::allocate(__a,
__base::__block_size));
+ __buf.push_back(__block);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- __alloc_traits::deallocate(__a, __buf.front(),
__base::__block_size);
+ __alloc_traits::deallocate(__a, __block, __base::__block_size);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
@@ -2417,16 +2418,17 @@
__buf(max<size_type>(2* __base::__map_.capacity(), 1),
__base::__map_.size(),
__base::__map_.__alloc());
+ pointer __block = __alloc_traits::allocate(__a, __base::__block_size);
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
- __buf.push_back(__alloc_traits::allocate(__a,
__base::__block_size));
+ __buf.push_back(__block);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- __alloc_traits::deallocate(__a, __buf.back(),
__base::__block_size);
+ __alloc_traits::deallocate(__a, __block, __base::__block_size);
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20150220/7fcbea43/attachment.html>
More information about the llvm-bugs
mailing list