Skip to content

Commit 6b0f202

Browse files
author
Fikret Ardal
committed
fix buffer overflow in packed iterator in non-padded arrays by padding the end of the array to the next multiple
1 parent 05881ef commit 6b0f202

File tree

4 files changed

+86
-34
lines changed

4 files changed

+86
-34
lines changed

c++/nda/mem/handle.hpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,11 @@ namespace nda::mem {
263263
*/
264264
handle_heap(long size, do_not_initialize_t) {
265265
if (size == 0) return;
266-
auto b = allocator.allocate(size * sizeof(T), type_alignment_info<T>::required_alignment);
266+
long new_size = size;
267+
if constexpr(Vectorizable<T>) {
268+
new_size = next_multiple(size, native_simd<T>::size());
269+
}
270+
auto b = allocator.allocate(new_size * sizeof(T), type_alignment_info<T>::required_alignment);
267271
if (not b.ptr) throw std::bad_alloc{};
268272
_data = (T *)b.ptr;
269273
_size = size;
@@ -275,7 +279,11 @@ namespace nda::mem {
275279
*/
276280
handle_heap(long size, init_zero_t) {
277281
if (size == 0) return;
278-
auto b = allocator.allocate_zero(size * sizeof(T), type_alignment_info<T>::required_alignment);
282+
long new_size = size;
283+
if constexpr(Vectorizable<T>) {
284+
new_size = next_multiple(size, native_simd<T>::size());
285+
}
286+
auto b = allocator.allocate_zero(new_size * sizeof(T), type_alignment_info<T>::required_alignment);
279287
if (not b.ptr) throw std::bad_alloc{};
280288
_data = (T *)b.ptr;
281289
_size = size;
@@ -295,10 +303,14 @@ namespace nda::mem {
295303
handle_heap(long size) {
296304
if (size == 0) return;
297305
blk_t b;
306+
long new_size = size;
307+
if constexpr(Vectorizable<T>) {
308+
new_size = next_multiple(size, native_simd<T>::size());
309+
}
298310
if constexpr (is_complex_v<T> && init_dcmplx)
299-
b = allocator.allocate_zero(size * sizeof(T), type_alignment_info<T>::required_alignment);
311+
b = allocator.allocate_zero(new_size * sizeof(T), type_alignment_info<T>::required_alignment);
300312
else
301-
b = allocator.allocate(size * sizeof(T), type_alignment_info<T>::required_alignment);
313+
b = allocator.allocate(new_size * sizeof(T), type_alignment_info<T>::required_alignment);
302314
if (not b.ptr) throw std::bad_alloc{};
303315
_data = (T *)b.ptr;
304316
_size = size;

c++/nda/packed.hpp

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#pragma once
22
#include "./concepts.hpp"
3+
#include "./mem/alignment.hpp"
34

45
#include <iterator>
56
#include <utility>
7+
#include <tuple>
8+
#include <algorithm>
69

710
namespace nda {
811
template <MemoryArray A>
@@ -24,9 +27,11 @@ namespace nda {
2427

2528
size_t index;
2629

27-
packed_iterator(const pointer data_ptr, const std::size_t idx) : data(data_ptr), index(idx) {}
30+
size_t last_index;
2831

29-
std::pair<simd_t, pointer> operator*() const {
32+
packed_iterator(const pointer data_ptr, const size_t idx, const size_t last_idx) : data(data_ptr), index(idx), last_index(last_idx) {}
33+
34+
std::tuple<simd_t, pointer, size_t> operator*() const noexcept {
3035
// Valid field counts= let j be the fastest dimension: let p be the padding. simd_size
3136
// (index + simd_size) % lengths[j] (index = 0 lengths[j] = 10, then valid_fields = 8;, index 8 lengtsah[j] = 10
3237
// ((lengths[j] - (index + simd_size + (lengths[j] / (index))^-1 * padding) % lengths[j]) % lengths[j])
@@ -35,64 +40,68 @@ namespace nda {
3540
// 8 + 8 - 10
3641
// 16 + 8 - 10 * 2 - 6
3742
if constexpr (aligned_and_padded) {
38-
return {simd_t(data + index), data + index};
43+
return {simd_t(data + index), data + index, std::min(simd_t::size(), last_index - index)};
3944
} else {
4045
simd_t tmp;
4146
tmp.load_unaligned(data + index);
42-
return {tmp, data + index};
47+
return {tmp, data + index, std::min(simd_t::size(), last_index - index)};
4348
}
4449
}
4550

46-
pointer operator->() const { return data + index; }
51+
pointer operator->() const noexcept { return data + index; }
4752

48-
packed_iterator &operator++() {
53+
packed_iterator &operator++() noexcept {
4954
index += simd_t::size();
5055
return *this;
5156
}
5257

53-
packed_iterator operator++(int) {
58+
packed_iterator operator++(int) noexcept {
5459
packed_iterator tmp = *this;
5560
index += simd_t::size();
5661
return tmp;
5762
}
5863

59-
packed_iterator &operator--() {
64+
packed_iterator &operator--() noexcept {
6065
index -= simd_t::size();
6166
return *this;
6267
}
6368

64-
packed_iterator operator--(int) {
69+
packed_iterator operator--(int) noexcept {
6570
packed_iterator tmp = *this;
6671
index -= simd_t::size();
6772
return tmp;
6873
}
6974

70-
packed_iterator &operator+=(std::ptrdiff_t n) {
75+
packed_iterator &operator+=(std::ptrdiff_t n) noexcept {
7176
index += n * simd_t::size();
7277
return *this;
7378
}
7479

75-
packed_iterator &operator-=(std::ptrdiff_t n) {
80+
packed_iterator &operator-=(std::ptrdiff_t n) noexcept {
7681
index -= n * simd_t::size();
7782
return *this;
7883
}
7984

80-
packed_iterator operator+(std::ptrdiff_t n) const { return packed_iterator(data, index + n * simd_t::size()); }
81-
packed_iterator operator-(std::ptrdiff_t n) const { return packed_iterator(data, index - n * simd_t::size()); }
82-
std::ptrdiff_t operator-(const packed_iterator &other) const { return (index - other.index) / simd_t::size(); }
83-
std::pair<simd_t, pointer> operator[](std::ptrdiff_t n) const {
84-
return {simd_t(data + index + n * simd_t::size()), data + index + n * simd_t::size()};
85+
packed_iterator operator+(std::ptrdiff_t n) const noexcept { return packed_iterator(data, index + n * simd_t::size()); }
86+
packed_iterator operator-(std::ptrdiff_t n) const noexcept { return packed_iterator(data, index - n * simd_t::size()); }
87+
std::ptrdiff_t operator-(const packed_iterator &other) const noexcept { return (index - other.index) / simd_t::size(); }
88+
std::tuple<simd_t, pointer, size_t> operator[](std::ptrdiff_t n) const noexcept {
89+
return {simd_t(data + index + n * simd_t::size()), data + index + n * simd_t::size(),
90+
std::min(simd_t::size(), last_index - index + n * simd_t::size())};
8591
}
8692

87-
bool operator==(const packed_iterator &other) const { return index == other.index; }
88-
bool operator!=(const packed_iterator &other) const { return !(*this == other); }
89-
bool operator<(const packed_iterator &other) const { return index < other.index; }
90-
bool operator>(const packed_iterator &other) const { return index > other.index; }
91-
bool operator<=(const packed_iterator &other) const { return index <= other.index; }
92-
bool operator>=(const packed_iterator &other) const { return index >= other.index; }
93+
bool operator==(const packed_iterator &other) const noexcept { return index == other.index; }
94+
bool operator!=(const packed_iterator &other) const noexcept { return !(*this == other); }
95+
bool operator<(const packed_iterator &other) const noexcept { return index < other.index; }
96+
bool operator>(const packed_iterator &other) const noexcept { return index > other.index; }
97+
bool operator<=(const packed_iterator &other) const noexcept { return index <= other.index; }
98+
bool operator>=(const packed_iterator &other) const noexcept { return index >= other.index; }
9399
};
94100

95-
packed_iterator begin() { return packed_iterator(array.data(), 0); }
96-
packed_iterator end() { return packed_iterator(array.data(), array.indexmap().capacity()); }
101+
packed_iterator begin() const noexcept { return packed_iterator(array.data(), 0, array.indexmap().capacity()); }
102+
packed_iterator end() const noexcept {
103+
return packed_iterator(array.data(), mem::next_multiple(array.indexmap().capacity(), native_simd<std::remove_cvref_t<get_value_t<A>>>::size()),
104+
array.indexmap().capacity());
105+
}
97106
};
98107
} // namespace nda

c++/nda/simd/arch/simd.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,35 @@
1111
#include "./AVX512/functions.hpp"
1212
#endif
1313

14+
#include <algorithm>
15+
1416
namespace nda {
1517
template <typename T>
1618
using native_simd = simd_type<std::conditional_t<std::is_same_v<T, long long>, int64_t, T>, abi::get_native_width<T>(), abi::get_native_abi_tag()>;
1719

20+
template <typename T, bool Aligned>
21+
struct simd_block {
22+
using simd_t = native_simd<T>;
23+
24+
simd_t value;
25+
T *data;
26+
size_t valid_field;
27+
28+
simd_block(const simd_t &v, const T *d, const size_t valid) : value(v), data(d), valid_field(valid) {}
29+
30+
void store() {
31+
if (valid_field == simd_t::size()) [[likely]] {
32+
if constexpr (Aligned) {
33+
value.store(data);
34+
} else {
35+
value.store_unaligned(data);
36+
}
37+
} else {
38+
alignas(simd_t::alignment()) std::array<T, simd_t::size()> tmp;
39+
value.store(tmp);
40+
std::copy_n(data, valid_field, tmp);
41+
}
42+
}
43+
};
44+
1845
} // namespace nda

test/c++/nda_simd.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,29 +1569,33 @@ TEST(NDA, OurSIMD) {
15691569
const long size1 = 2;
15701570
const long size2 = 10;
15711571
float k = 1;
1572-
array_aligned<float,2> s({size1, size2});
1573-
array_aligned<float,2> x({size1, size2});
1572+
array<float, 2> s({size1, size2});
1573+
array<float, 2> x({size1, size2});
15741574
for (int i = 0; i < size1; ++i) {
15751575
for (int j = 0; j < size2; ++j) { s(i, j) = k++; }
15761576
}
15771577
for (int i = 0; i < size1; ++i) {
15781578
for (int j = 0; j < size2; ++j) { x(i, j) = k++; }
15791579
}
1580+
for (auto [simd, pointer, valid_field] : packed(s)) {
1581+
using simd_t = native_simd<float>;
1582+
alignas(simd_t::alignment()) std::array<float, simd_t::size()> tmp;
1583+
simd.store(tmp.data());
1584+
std::cout << tmp << std::endl;
1585+
std::cout << valid_field << std::endl;
1586+
}
15801587
// s = array_aligned<float,2>::rand({size1, size2});
15811588
auto hop = make_array_view(s);
15821589
std::cout << hop << std::endl;
15831590
std::cout << hop.is_aligned << std::endl;
15841591
std::cout << typeid(hop).name() << std::endl;
15851592
std::cout << typeid(make_regular(hop)).name() << std::endl;
15861593
std::cout << hop.indexmap().capacity() << std::endl;
1587-
for (int i= 0; i < hop.indexmap().capacity() ; ++i) {
1588-
std::cout << *(hop.data() + i) << " ";
1589-
}
1594+
for (int i = 0; i < hop.indexmap().capacity(); ++i) { std::cout << *(hop.data() + i) << " "; }
15901595
std::cout << std::endl;
15911596
auto aa = make_regular(hop);
15921597
std::cout << aa.size() << std::endl;
15931598
std::cout << aa.is_aligned << std::endl;
15941599
bool a = s == hop;
15951600
std::cout << (hop == s) << std::endl;
1596-
15971601
}

0 commit comments

Comments
 (0)