I'm having an issue with using iterators into vector<bitset< n>>. The following minimal program gets a heap-use-after-free warning from the AddressSanitizer.
#include <vector>
#include <bitset>
using namespace std;
int main(int argc, char const *argv[])
{
vector<bitset<26>> test(2);
auto endIter { test.end() };
for (auto iter { test.begin() }; iter != endIter; ++iter)
test.push_back(*iter);
return 0;
}
The warning message from AddressSanitizer is here
==8229==ERROR: AddressSanitizer: heap-use-after-free on address 0x000107200718 at pc 0x000105378d14 bp 0x00016b14b080 sp 0x00016b14a838
READ of size 8 at 0x000107200718 thread T0
#0 0x105378d10 in __asan_memcpy+0x1a4 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3cd10)
#1 0x104cba394 in void std::__1::allocator<std::__1::bitset<26ul> >::construct<std::__1::bitset<26ul>, std::__1::bitset<26ul> const&>(std::__1::bitset<26ul>*, std::__1::bitset<26ul> const&) allocator.h:154
#2 0x104cba33c in void std::__1::allocator_traits<std::__1::allocator<std::__1::bitset<26ul> > >::construct<std::__1::bitset<26ul>, std::__1::bitset<26ul> const&, void>(std::__1::allocator<std::__1::bitset<26ul> >&, std::__1::bitset<26ul>*, std::__1::bitset<26ul> const&) allocator_traits.h:290
#3 0x104cb9dac in void std::__1::vector<std::__1::bitset<26ul>, std::__1::allocator<std::__1::bitset<26ul> > >::__construct_one_at_end<std::__1::bitset<26ul> const&>(std::__1::bitset<26ul> const&) vector:948
#4 0x104cb74d4 in std::__1::vector<std::__1::bitset<26ul>, std::__1::allocator<std::__1::bitset<26ul> > >::push_back(std::__1::bitset<26ul> const&) vector:1660
#5 0x104cb6d54 in main test.cpp:10
#6 0x104f5d088 in start+0x204 (dyld:arm64e+0x5088)
0x000107200718 is located 8 bytes inside of 16-byte region [0x000107200710,0x000107200720)
freed by thread T0 here:
#0 0x10538a330 in wrap__ZdlPv+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x4e330)
#1 0x104cb988c in void std::__1::__libcpp_operator_delete<void*>(void*) new:245
#2 0x104cb983c in void std::__1::__do_deallocate_handle_size<>(void*, unsigned long) new:269
#3 0x104cb97e0 in std::__1::__libcpp_deallocate(void*, unsigned long, unsigned long) new:285
#4 0x104cb9770 in std::__1::allocator<std::__1::bitset<26ul> >::deallocate(std::__1::bitset<26ul>*, unsigned long) allocator.h:117
#5 0x104cb95e4 in std::__1::allocator_traits<std::__1::allocator<std::__1::bitset<26ul> > >::deallocate(std::__1::allocator<std::__1::bitset<26ul> >&, std::__1::bitset<26ul>*, unsigned long) allocator_traits.h:282
#6 0x104cbb570 in std::__1::__split_buffer<std::__1::bitset<26ul>, std::__1::allocator<std::__1::bitset<26ul> >&>::~__split_buffer() __split_buffer:347
#7 0x104cba8d0 in std::__1::__split_buffer<std::__1::bitset<26ul>, std::__1::allocator<std::__1::bitset<26ul> >&>::~__split_buffer() __split_buffer:344
#8 0x104cba190 in void std::__1::vector<std::__1::bitset<26ul>, std::__1::allocator<std::__1::bitset<26ul> > >::__push_back_slow_path<std::__1::bitset<26ul> const&>(std::__1::bitset<26ul> const&) vector:1651
#9 0x104cb74e4 in std::__1::vector<std::__1::bitset<26ul>, std::__1::allocator<std::__1::bitset<26ul> > >::push_back(std::__1::bitset<26ul> const&) vector:1663
#10 0x104cb6d54 in main test.cpp:10
#11 0x104f5d088 in start+0x204 (dyld:arm64e+0x5088)
previously allocated by thread T0 here:
#0 0x105389ef0 in wrap__Znwm+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x4def0)
#1 0x104cb8b7c in void* std::__1::__libcpp_operator_new<unsigned long>(unsigned long) new:235
#2 0x104cb8a48 in std::__1::__libcpp_allocate(unsigned long, unsigned long) new:261
#3 0x104cb898c in std::__1::allocator<std::__1::bitset<26ul> >::allocate(unsigned long) allocator.h:108
#4 0x104cb84c0 in std::__1::allocator_traits<std::__1::allocator<std::__1::bitset<26ul> > >::allocate(std::__1::allocator<std::__1::bitset<26ul> >&, unsigned long) allocator_traits.h:262
#5 0x104cb7a64 in std::__1::vector<std::__1::bitset<26ul>, std::__1::allocator<std::__1::bitset<26ul> > >::__vallocate(unsigned long) vector:1015
#6 0x104cb76b8 in std::__1::vector<std::__1::bitset<26ul>, std::__1::allocator<std::__1::bitset<26ul> > >::vector(unsigned long) vector:1148
#7 0x104cb6f70 in std::__1::vector<std::__1::bitset<26ul>, std::__1::allocator<std::__1::bitset<26ul> > >::vector(unsigned long) vector:1142
#8 0x104cb6c7c in main test.cpp:7
#9 0x104f5d088 in start+0x204 (dyld:arm64e+0x5088)
SUMMARY: AddressSanitizer: heap-use-after-free (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3cd10) in __asan_memcpy+0x1a4
Shadow bytes around the buggy address:
0x007020e60090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x007020e600a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x007020e600b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x007020e600c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x007020e600d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x007020e600e0: fa fa fd[fd]fa fa 00 04 fa fa 00 06 fa fa 00 06
0x007020e600f0: fa fa 00 00 fa fa fd fd fa fa fa fa fa fa fa fa
0x007020e60100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x007020e60110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x007020e60120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x007020e60130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==8229==ABORTING
Compiler/Platform info
Apple clang version 14.0.0 (clang-1400.0.29.102)
Target: arm64-apple-darwin21.6.0
compiled with "-fsanitize=adderss".
I'm having a hard time understanding this. It would work if endIter = next(test.begin()).
Also, the program itself runs and works without the sanitizer. Is there something I'm missing or is it an issue with the AddressSanitizer?