0

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?

R-penguins
  • 36
  • 4
  • 4
    You are invalidating the iterators by pushing back onto the vector... – ChrisMM Oct 24 '22 at 13:23
  • 1
    Vector's iterators are invalidated after push_back, since it may allocate new larger chunk of memory for storing it's contents. – fas Oct 24 '22 at 13:24
  • Thanks so much! I learnt my lesson. Totally forgot that iterators get invalidated after resizing... – R-penguins Oct 24 '22 at 13:32

0 Answers0