Also fixes https://github.com/cloudius-systems/seastar/issues/54 ==5658==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6250006b7848 at pc 0x1413e02 bp 0x7fff7cd7f1e0 sp 0x7fff7cd7f1d8 WRITE of size 8 at 0x6250006b7848 thread T0 #0 0x1413e01 in unsigned long* std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m<std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long*>(std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long*) /usr/include/c++/4.9/bits/stl_algobase.h:336 #1 0x1413c59 in unsigned long* std::__copy_move_a<false, std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long*>(std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long*) /usr/include/c++/4.9/bits/stl_algobase.h:396 #2 0x1413aea in unsigned long* std::__copy_move_a2<false, std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long*>(std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long*) /usr/include/c++/4.9/bits/stl_algobase.h:434 #3 0x14138df in unsigned long* std::copy<std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long*>(std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long*) /usr/include/c++/4.9/bits/stl_algobase.h:466 #4 0x1413545 in unsigned long* std::__copy_n<std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long, unsigned long*>(std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long, unsigned long*, std::random_access_iterator_tag) /usr/include/c++/4.9/bits/stl_algo.h:779 #5 0x1412d44 in unsigned long* std::copy_n<std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long, unsigned long*>(std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long, unsigned long*) /usr/include/c++/4.9/bits/stl_algo.h:804 #6 0x14112b3 in unsigned long large_bitset::load<std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*> >(std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long) utils/large_bitset.hh:81 #7 0x13fcfc9 in _ZZZN8sstables7sstable11read_filterEvENKUlRT_E_clINS_6filterEEEDaS2_ENKUlvE_clEv (/home/tgrabiec/src/urchin/build/debug/scylla+0x13fcfc9) #8 0x1400a50 in apply /home/tgrabiec/src/urchin/seastar/core/apply.hh:34 #9 0x1400afb in apply<sstables::sstable::read_filter()::<lambda(auto:25&)> [with auto:25 = sstables::filter]::<lambda()> > /home/tgrabiec/src/urchin/seastar/core/apply.hh:42 #10 0x1400bb2 in apply<sstables::sstable::read_filter()::<lambda(auto:25&)> [with auto:25 = sstables::filter]::<lambda()> > /home/tgrabiec/src/urchin/seastar/core/future.hh:1062 #11 0x140f1b7 in _ZZN6futureIIEE4thenIZZN8sstables7sstable11read_filterEvENKUlRT_E_clINS2_6filterEEEDaS5_EUlvE_S0_EET0_OT_ENUlOS4_E_clI12future_stateIIEEEEDaSC_ (/home/tgrabiec/src/urchin/build/debug/scylla+0x140f1b7) #12 0x140f350 in run /home/tgrabiec/src/urchin/seastar/core/future.hh:359 #13 0x426e2c in reactor::run_tasks(circular_buffer<std::unique_ptr<task, std::default_delete<task> >, std::allocator<std::unique_ptr<task, std::default_delete<task> > > >&, unsigned long) core/reactor.cc:1093 #14 0x429cb1 in reactor::run() core/reactor.cc:1190 #15 0x72bc69 in app_template::run_deprecated(int, char**, std::function<void ()>&&) core/app-template.cc:122 #16 0xa119bc in main /home/tgrabiec/src/urchin/main.cc:279 #17 0x7ffc1b6beec4 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4) #18 0x412558 (/home/tgrabiec/src/urchin/build/debug/scylla+0x412558) 0x6250006b7848 is located 0 bytes to the right of 8008-byte region [0x6250006b5900,0x6250006b7848) allocated by thread T0 here: #0 0x7ffc1cf6c7df in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x547df) #1 0x7ffc204eef17 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x8df17) #2 0xfa5d4f in large_bitset::large_bitset(unsigned long) utils/large_bitset.cc:15 #3 0x13fcec6 in _ZZZN8sstables7sstable11read_filterEvENKUlRT_E_clINS_6filterEEEDaS2_ENKUlvE_clEv (/home/tgrabiec/src/urchin/build/debug/scylla+0x13fcec6) #4 0x1400a50 in apply /home/tgrabiec/src/urchin/seastar/core/apply.hh:34 #5 0x1400afb in apply<sstables::sstable::read_filter()::<lambda(auto:25&)> [with auto:25 = sstables::filter]::<lambda()> > /home/tgrabiec/src/urchin/seastar/core/apply.hh:42 #6 0x1400bb2 in apply<sstables::sstable::read_filter()::<lambda(auto:25&)> [with auto:25 = sstables::filter]::<lambda()> > /home/tgrabiec/src/urchin/seastar/core/future.hh:1062 #7 0x140f1b7 in _ZZN6futureIIEE4thenIZZN8sstables7sstable11read_filterEvENKUlRT_E_clINS2_6filterEEEDaS5_EUlvE_S0_EET0_OT_ENUlOS4_E_clI12future_stateIIEEEEDaSC_ (/home/tgrabiec/src/urchin/build/debug/scylla+0x140f1b7) #8 0x140f350 in run /home/tgrabiec/src/urchin/seastar/core/future.hh:359 #9 0x426e2c in reactor::run_tasks(circular_buffer<std::unique_ptr<task, std::default_delete<task> >, std::allocator<std::unique_ptr<task, std::default_delete<task> > > >&, unsigned long) core/reactor.cc:1093 #10 0x429cb1 in reactor::run() core/reactor.cc:1190 #11 0x72bc69 in app_template::run_deprecated(int, char**, std::function<void ()>&&) core/app-template.cc:122 #12 0xa119bc in main /home/tgrabiec/src/urchin/main.cc:279 #13 0x7ffc1b6beec4 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4) SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/include/c++/4.9/bits/stl_algobase.h:336 unsigned long* std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m<std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long*>(std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, std::_Deque_iterator<unsigned long, unsigned long&, unsigned long*>, unsigned long*) Shadow bytes around the buggy address: 0x0c4a800ceeb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c4a800ceec0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c4a800ceed0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c4a800ceee0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c4a800ceef0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c4a800cef00: 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa 0x0c4a800cef10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4a800cef20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4a800cef30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4a800cef40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4a800cef50: 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 Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Contiguous container OOB:fc ASan internal: fe ==5658==ABORTING
145 lines
4.6 KiB
C++
145 lines
4.6 KiB
C++
/*
|
|
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
|
*/
|
|
|
|
// A bitset containing a very large number of bits, so it uses fragmented
|
|
// storage in order not to stress the memory allocator.
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <limits>
|
|
#include <iterator>
|
|
#include <algorithm>
|
|
|
|
class large_bitset {
|
|
static constexpr size_t block_size() { return 128 * 1024; }
|
|
using int_type = unsigned long;
|
|
static constexpr size_t bits_per_int() {
|
|
return std::numeric_limits<int_type>::digits;
|
|
}
|
|
static constexpr size_t ints_per_block() {
|
|
return block_size() / sizeof(int_type);
|
|
}
|
|
static constexpr size_t bits_per_block() {
|
|
return ints_per_block() * bits_per_int();
|
|
}
|
|
size_t _nr_bits = 0;
|
|
std::vector<std::unique_ptr<int_type[]>> _storage;
|
|
public:
|
|
explicit large_bitset(size_t nr_bits);
|
|
large_bitset(large_bitset&&) = default;
|
|
large_bitset(const large_bitset&) = delete;
|
|
large_bitset& operator=(const large_bitset&) = delete;
|
|
size_t size() const {
|
|
return _nr_bits;
|
|
}
|
|
bool test(size_t idx) const {
|
|
auto idx1 = idx / bits_per_block();
|
|
idx %= bits_per_block();
|
|
auto idx2 = idx / bits_per_int();
|
|
idx %= bits_per_int();
|
|
auto idx3 = idx;
|
|
return (_storage[idx1][idx2] >> idx3) & 1;
|
|
}
|
|
void set(size_t idx) {
|
|
auto idx1 = idx / bits_per_block();
|
|
idx %= bits_per_block();
|
|
auto idx2 = idx / bits_per_int();
|
|
idx %= bits_per_int();
|
|
auto idx3 = idx;
|
|
_storage[idx1][idx2] |= int_type(1) << idx3;
|
|
}
|
|
void clear(size_t idx) {
|
|
auto idx1 = idx / bits_per_block();
|
|
idx %= bits_per_block();
|
|
auto idx2 = idx / bits_per_int();
|
|
idx %= bits_per_int();
|
|
auto idx3 = idx;
|
|
_storage[idx1][idx2] &= ~(int_type(1) << idx3);
|
|
}
|
|
void clear();
|
|
// load data from host bitmap (in host byte order); returns end bit position
|
|
template <typename IntegerIterator>
|
|
size_t load(IntegerIterator start, IntegerIterator finish, size_t position = 0);
|
|
template <typename IntegerIterator>
|
|
IntegerIterator save(IntegerIterator out, size_t position = 0, size_t n = std::numeric_limits<size_t>::max());
|
|
};
|
|
|
|
template <typename IntegerIterator>
|
|
size_t
|
|
large_bitset::load(IntegerIterator start, IntegerIterator finish, size_t position) {
|
|
using input_int_type = typename std::iterator_traits<IntegerIterator>::value_type;
|
|
if (position % bits_per_int() == 0 && sizeof(input_int_type) == sizeof(int_type)) {
|
|
auto idx = position;
|
|
auto idx1 = idx / bits_per_block();
|
|
idx %= bits_per_block();
|
|
auto idx2 = idx / bits_per_int();
|
|
while (start != finish) {
|
|
auto now = std::min<size_t>(ints_per_block() - idx2, std::distance(start, finish));
|
|
std::copy_n(start, now, _storage[idx1].get() + idx2);
|
|
start += now;
|
|
++idx1;
|
|
idx2 = 0;
|
|
}
|
|
} else {
|
|
while (start != finish) {
|
|
auto bitmask = *start++;
|
|
for (size_t i = 0; i < std::numeric_limits<input_int_type>::digits; ++i) {
|
|
if (bitmask & 1) {
|
|
set(position);
|
|
} else {
|
|
clear(position);
|
|
}
|
|
bitmask >>= 1;
|
|
++position;
|
|
}
|
|
}
|
|
}
|
|
return position;
|
|
}
|
|
|
|
template <typename IntegerIterator>
|
|
IntegerIterator
|
|
large_bitset::save(IntegerIterator out, size_t position, size_t n) {
|
|
n = std::min(n, size() - position);
|
|
using output_int_type = typename std::iterator_traits<IntegerIterator>::value_type;
|
|
if (position % bits_per_int() == 0
|
|
&& n % bits_per_int() == 0
|
|
&& sizeof(output_int_type) == sizeof(int_type)) {
|
|
auto idx = position;
|
|
auto idx1 = idx / bits_per_block();
|
|
idx %= bits_per_block();
|
|
auto idx2 = idx / bits_per_int();
|
|
auto n_ints = n / bits_per_int();
|
|
while (n_ints) {
|
|
auto now = std::min(ints_per_block() - idx2, n_ints);
|
|
out = std::copy_n(_storage[idx1].get() + idx2, now, out);
|
|
++idx1;
|
|
idx2 = 0;
|
|
n_ints -= now;
|
|
}
|
|
} else {
|
|
output_int_type result = 0;
|
|
unsigned bitpos = 0;
|
|
while (n) {
|
|
result |= output_int_type(test(position)) << bitpos;
|
|
++position;
|
|
++bitpos;
|
|
--n;
|
|
if (bitpos == std::numeric_limits<output_int_type>::digits) {
|
|
*out = result;
|
|
++out;
|
|
result = 0;
|
|
bitpos = 0;
|
|
}
|
|
}
|
|
if (bitpos) {
|
|
*out = result;
|
|
++out;
|
|
}
|
|
}
|
|
return out;
|
|
}
|