-
Notifications
You must be signed in to change notification settings - Fork 14.8k
Closed
Labels
compiler-rt:asanAddress sanitizerAddress sanitizerlibc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Description
https://reviews.llvm.org/rG490555026821db47d1cf4bf08c219b3e56ec6b45 made __sanitizer_annotate_contiguous_container
apply to std::vector
also when using custom allocators.
This can cause false container-overflow errors if the custom allocator touches the memory it manages.
Reproducer (reduced from https://crbug.com/1410719#c6):
$ cat /tmp/a.cc
#include <stdlib.h>
#include <string.h>
#include <vector>
template <typename T>
struct ZeroAlloc {
using value_type = T;
ZeroAlloc() noexcept {}
template <typename U> ZeroAlloc(const ZeroAlloc<U>&) noexcept {}
template <typename U> bool operator==(const ZeroAlloc<U>&) const noexcept { return true; }
template <typename U> bool operator!=(const ZeroAlloc<U>&) const noexcept { return false; }
T* allocate(size_t n) const {
return (T*)malloc(sizeof(T) * n);
}
void deallocate(T* p, size_t n) const noexcept {
memset(p, 0, sizeof(T) * n);
free(p);
}
};
int main() {
using Vector = std::vector<int, ZeroAlloc<int>>;
Vector v;
v.resize(100);
Vector w;
w.push_back(0);
w.reserve(10);
w = v; // Goes boom when deallocating w's storage.
return 0;
}
In the assignment, w
's storage will get deallocated, causing memset
to touch memory outside of w
's current size:
$ build2/bin/clang++ -g -fsanitize=address -stdlib=libc++ /tmp/a.cc && ASAN_SYMBOLIZER_PATH=/work/llvm-project/build2/bin/llvm-symbolizer LD_LIBRARY_PATH=build2/lib/x86_64-unknown-linux-gnu/ ./a.out
=================================================================
==1559804==ERROR: AddressSanitizer: container-overflow on address 0x604000000050 at pc 0x5628a2ee5f38 bp 0x7ffde290e7b0 sp 0x7ffde290df78
WRITE of size 40 at 0x604000000050 thread T0
#0 0x5628a2ee5f37 in __asan_memset /work/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:26:3
#1 0x5628a2f269b6 in ZeroAlloc<int>::deallocate(int*, unsigned long) const /tmp/a.cc:17:5
#2 0x5628a2f266d4 in std::__1::allocator_traits<ZeroAlloc<int>>::deallocate[abi:v170000](ZeroAlloc<int>&, int*, unsigned long) /work/llvm-project/build2/bin/../include/c++/v1/__memory/allocator_traits.h:288:13
#3 0x5628a2f2e022 in std::__1::vector<int, ZeroAlloc<int>>::__vdeallocate() /work/llvm-project/build2/bin/../include/c++/v1/vector:974:9
#4 0x5628a2f2d9e0 in void std::__1::vector<int, ZeroAlloc<int>>::assign<int*, 0>(int*, int*) /work/llvm-project/build2/bin/../include/c++/v1/vector:1404:9
#5 0x5628a2f26175 in std::__1::vector<int, ZeroAlloc<int>>::operator=[abi:v170000](std::__1::vector<int, ZeroAlloc<int>> const&) /work/llvm-project/build2/bin/../include/c++/v1/vector:1361:9
#6 0x5628a2f258f3 in main /tmp/a.cc:32:5
#7 0x7fa4d2cb1189 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#8 0x7fa4d2cb1244 in __libc_start_main csu/../csu/libc-start.c:381:3
#9 0x5628a2e4c340 in _start (/work/llvm-project/a.out+0x1e340)
0x604000000050 is located 0 bytes inside of 40-byte region [0x604000000050,0x604000000078)
allocated by thread T0 here:
#0 0x5628a2ee69be in __interceptor_malloc /work/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3
#1 0x5628a2f28fbc in ZeroAlloc<int>::allocate(unsigned long) const /tmp/a.cc:14:16
#2 0x5628a2f28e20 in std::__1::__allocation_result<std::__1::allocator_traits<ZeroAlloc<int>>::pointer> std::__1::__allocate_at_least[abi:v170000]<ZeroAlloc<int>>(ZeroAlloc<int>&, unsigned long) /work/llvm-project/build2/bin/../include/c++/v1/__memory/allocate_at_least.h:55:19
#3 0x5628a2f27559 in std::__1::__split_buffer<int, ZeroAlloc<int>&>::__split_buffer(unsigned long, unsigned long, ZeroAlloc<int>&) /work/llvm-project/build2/bin/../include/c++/v1/__split_buffer:323:29
#4 0x5628a2f25fae in std::__1::vector<int, ZeroAlloc<int>>::reserve(unsigned long) /work/llvm-project/build2/bin/../include/c++/v1/vector:1520:53
#5 0x5628a2f258e1 in main /tmp/a.cc:30:5
#6 0x7fa4d2cb1189 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
The reallocation logic in the assignment code looks like this:
__vdeallocate();
__vallocate(__recommend(__new_size));
__construct_at_end(__first, __last, __new_size);
Perhaps annotations should be added around the __vdeallocate
call to avoid the false positive.
Metadata
Metadata
Assignees
Labels
compiler-rt:asanAddress sanitizerAddress sanitizerlibc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.