Skip to content

Commit 33998f4

Browse files
committed
Add memory hardening assert macros
Add hardening to CowVector Add hardening to FixedVector Add hardening to RingBuffer Add hardening to StackString Add abort to CowVector::at Add abort to CowVector::reserve
1 parent 5646230 commit 33998f4

File tree

6 files changed

+110
-24
lines changed

6 files changed

+110
-24
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#pragma once
2+
3+
#include <bit> // IWYU pragma: keep for use of cross-library reference for standard library macro definitions
4+
5+
#ifdef __GLIBCXX__
6+
#include <debug/assertions.h>
7+
8+
#define OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, MSG) __glibcxx_assert(BEGIN <= END)
9+
#define OV_HARDEN_ASSERT_NONEMPTY_RANGE(BEGIN, END, FUNC_NAME) __glibcxx_requires_non_empty_range(BEGIN, END)
10+
11+
#define OV_HARDEN_ASSERT_ACCESS(INDEX, FUNC_NAME) __glibcxx_requires_subscript(INDEX)
12+
#define OV_HARDEN_ASSERT_NONEMPTY(FUNC_NAME) __glibcxx_requires_nonempty()
13+
#define OV_HARDEN_ASSERT_VALID_ITERATOR(IT, FUNC_NAME) \
14+
OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(IT, end(), FUNC_NAME + " called with a non-dereferenceable iterator")
15+
16+
#elif defined(_LIBCPP_VERSION)
17+
#include <__assert>
18+
19+
#define OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, MSG) _LIBCPP_ASSERT_VALID_INPUT_RANGE(BEGIN <= END, MSG)
20+
#define OV_HARDEN_ASSERT_NONEMPTY_RANGE(BEGIN, END, FUNC_NAME) \
21+
OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, FUNC_NAME " called with an invalid range")
22+
23+
#define OV_HARDEN_ASSERT_ACCESS(INDEX, FUNC_NAME) \
24+
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(INDEX < size(), FUNC_NAME " index out of bounds")
25+
#define OV_HARDEN_ASSERT_NONEMPTY(FUNC_NAME) \
26+
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), FUNC_NAME " called on an empty container")
27+
#define OV_HARDEN_ASSERT_VALID_ITERATOR(IT, FUNC_NAME) \
28+
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(IT != end(), FUNC_NAME " called with a non-dereferenceable iterator")
29+
30+
#elif defined(_MSVC_STL_VERSION) && _MSVC_STL_HARDENING == 1
31+
#include <yvals.h>
32+
33+
#define OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, MSG) _STL_VERIFY(BEGIN <= END, MSG)
34+
#define OV_HARDEN_ASSERT_NONEMPTY_RANGE(BEGIN, END, FUNC_NAME) \
35+
OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, FUNC_NAME " called with an invalid range")
36+
37+
#define OV_HARDEN_ASSERT_ACCESS(INDEX, FUNC_NAME) _STL_VERIFY(INDEX < size(), FUNC_NAME " index out of bounds")
38+
#define OV_HARDEN_ASSERT_NONEMPTY(FUNC_NAME) _STL_VERIFY(!empty(), FUNC_NAME " called on an empty container")
39+
#define OV_HARDEN_ASSERT_VALID_ITERATOR(IT, FUNC_NAME) \
40+
OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(IT, end(), FUNC_NAME " called with a non-dereferenceable iterator")
41+
42+
#else
43+
#define OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, MSG)
44+
#define OV_HARDEN_ASSERT_NONEMPTY_RANGE(BEGIN, END, FUNC_NAME)
45+
#define OV_HARDEN_ASSERT_ACCESS(INDEX, FUNC_NAME)
46+
#define OV_HARDEN_ASSERT_NONEMPTY(FUNC_NAME)
47+
#define OV_HARDEN_ASSERT_VALID_ITERATOR(IT, FUNC_NAME)
48+
49+
// clang-format off
50+
# if defined(_GLIBCXX_ASSERTIONS) || _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_FAST || _MSVC_STL_HARDENING == 1
51+
#warning "Unsupported standard library for memory hardening, hardening asserts will be ignored."
52+
# endif
53+
// clang-format on
54+
55+
#endif

src/openvic-simulation/types/Colour.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -871,10 +871,10 @@ struct fmt::formatter<T> {
871871
size_t i = 0;
872872
for (char& c : lower) {
873873
c = std::tolower(result[i]);
874-
if (c == '\0') {
874+
++i;
875+
if (i == result.size()) {
875876
break;
876877
}
877-
++i;
878878
}
879879
return detail::write(out, string_view { lower.data(), i }, specs, ctx.locale());
880880
}

src/openvic-simulation/types/CowVector.hpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <type_traits>
1212
#include <vector>
1313

14+
#include "openvic-simulation/core/Assert.hpp"
1415
#include "openvic-simulation/types/BasicIterator.hpp"
1516
#include "openvic-simulation/utility/Allocator.hpp"
1617
#include "openvic-simulation/core/Compare.hpp"
@@ -166,19 +167,24 @@ namespace OpenVic {
166167
}
167168

168169
const_reference at(size_type pos) const {
169-
// TODO: crash on boundary violation
170-
return (*this)[pos];
170+
if (OV_unlikely(pos >= size())) {
171+
std::abort();
172+
}
173+
return _data->array[pos];
171174
}
172175

173176
const_reference operator[](size_type pos) const {
177+
OV_HARDEN_ASSERT_ACCESS(pos, "operator[]");
174178
return _data->array[pos];
175179
}
176180

177181
const_reference front() const {
182+
OV_HARDEN_ASSERT_NONEMPTY("front");
178183
return *_data->array;
179184
}
180185

181186
const_reference back() const {
187+
OV_HARDEN_ASSERT_NONEMPTY("back");
182188
return *_data->array_end;
183189
}
184190

@@ -329,9 +335,8 @@ namespace OpenVic {
329335

330336
template<typename InputIt>
331337
inline difference_type _validate_iterator_difference(InputIt first, InputIt last) {
332-
difference_type result = last - first;
333-
// TODO: crash on negative result
334-
return result;
338+
OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(first, last, "_validate_iterator_difference called with invalid range");
339+
return last - first;
335340
}
336341

337342
struct for_overwrite_t {};
@@ -367,19 +372,24 @@ namespace OpenVic {
367372
}
368373

369374
reference at(size_type pos) {
370-
return (*this)[pos];
375+
if (OV_unlikely(pos >= size())) {
376+
std::abort();
377+
}
378+
return _data->array[pos];
371379
}
372380

373381
reference operator[](size_type pos) {
374-
// TODO: crash on boundary violation
382+
OV_HARDEN_ASSERT_ACCESS(pos, "operator[]");
375383
return _data->array[pos];
376384
}
377385

378386
reference front() {
387+
OV_HARDEN_ASSERT_NONEMPTY("front");
379388
return *_data->array;
380389
}
381390

382391
reference back() {
392+
OV_HARDEN_ASSERT_NONEMPTY("back");
383393
return *_data->array_end;
384394
}
385395

@@ -405,7 +415,7 @@ namespace OpenVic {
405415

406416
void reserve(size_type count) {
407417
if (count > max_size()) {
408-
// TODO: crash
418+
std::abort();
409419
}
410420
if (capacity() >= count) {
411421
return;
@@ -510,6 +520,7 @@ namespace OpenVic {
510520
}
511521

512522
iterator erase(const_iterator pos) {
523+
OV_HARDEN_ASSERT_VALID_ITERATOR(pos, "erase(const_iterator)");
513524
if (pos + 1 != end()) {
514525
std::move(pos + 1, end(), pos);
515526
}
@@ -561,7 +572,7 @@ namespace OpenVic {
561572
}
562573

563574
void pop_back() {
564-
// TODO: assert if empty
575+
OV_HARDEN_ASSERT_NONEMPTY("pop_back");
565576
--_data->array_end;
566577
allocator_traits::destroy(alloc, _data->array_end);
567578
}

src/openvic-simulation/types/FixedVector.hpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <memory>
77
#include <utility>
88

9+
#include "openvic-simulation/core/Assert.hpp"
910
#include "openvic-simulation/core/template/Concepts.hpp"
1011
#include "openvic-simulation/core/Typedefs.hpp"
1112

@@ -138,28 +139,28 @@ namespace OpenVic::_detail {
138139
const_reverse_iterator crend() const { return const_reverse_iterator(begin()); }
139140

140141
T& operator[](const size_t index) {
141-
assert(index < _size);
142+
OV_HARDEN_ASSERT_ACCESS(index, "operator[]");
142143
return _data_start_ptr[index];
143144
}
144145
const T& operator[](const size_t index) const {
145-
assert(index < _size);
146+
OV_HARDEN_ASSERT_ACCESS(index, "operator[]");
146147
return _data_start_ptr[index];
147148
}
148149

149150
T& front() {
150-
assert(!empty());
151+
OV_HARDEN_ASSERT_NONEMPTY("front");
151152
return *begin();
152153
}
153154
const T& front() const {
154-
assert(!empty());
155+
OV_HARDEN_ASSERT_NONEMPTY("front");
155156
return *cbegin();
156157
}
157158
T& back() {
158-
assert(!empty());
159+
OV_HARDEN_ASSERT_NONEMPTY("back");
159160
return *(end()-1);
160161
}
161162
const T& back() const {
162-
assert(!empty());
163+
OV_HARDEN_ASSERT_NONEMPTY("back");
163164
return *(cend()-1);
164165
}
165166

src/openvic-simulation/types/RingBuffer.hpp

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <range/v3/range/concepts.hpp>
1919
#include <range/v3/view/subrange.hpp>
2020

21+
#include "openvic-simulation/core/Assert.hpp"
2122
#include "openvic-simulation/core/Typedefs.hpp"
2223

2324
namespace OpenVic {
@@ -215,34 +216,49 @@ namespace OpenVic {
215216
allocator_type get_allocator() const {
216217
return _allocator;
217218
}
219+
220+
private:
221+
reference _unsafe_access(const size_type index) {
222+
return _data[_ring_wrap(_offset + index, capacity())];
223+
}
224+
const_reference _unsafe_access(const size_type index) const {
225+
return _data[_ring_wrap(_offset + index, capacity())];
226+
}
227+
228+
public:
218229
reference front() {
219-
return at(0);
230+
OV_HARDEN_ASSERT_NONEMPTY("front");
231+
return _unsafe_access(0);
220232
}
221233
reference back() {
222-
return at(size() - 1);
234+
OV_HARDEN_ASSERT_NONEMPTY("back");
235+
return _unsafe_access(size() - 1);
223236
}
224237
const_reference back() const {
225-
return at(size() - 1);
238+
OV_HARDEN_ASSERT_NONEMPTY("back");
239+
return _unsafe_access(size() - 1);
226240
}
227241

228242
const_reference operator[](const size_type index) const {
229-
return _data[_ring_wrap(_offset + index, capacity())];
243+
OV_HARDEN_ASSERT_ACCESS(index, "operator[]");
244+
return _unsafe_access(index);
230245
}
231246
reference operator[](const size_type index) {
232-
return _data[_ring_wrap(_offset + index, capacity())];
247+
OV_HARDEN_ASSERT_ACCESS(index, "operator[]");
248+
return _unsafe_access(index);
233249
}
234250

235251
const_reference at(const size_type index) const {
236252
if (OV_unlikely(index >= size())) {
237253
std::abort();
238254
}
239-
return (*this)[index];
255+
return _unsafe_access(index);
240256
}
241257
reference at(const size_type index) {
242258
if (OV_unlikely(index >= size())) {
243259
std::abort();
244260
}
245-
return (*this)[index];
261+
return _unsafe_access(index);
246262
}
247263

248264
iterator begin() noexcept {
@@ -693,6 +709,7 @@ namespace OpenVic {
693709
return erase(pos, last);
694710
}
695711
iterator erase(const_iterator pos) noexcept(noexcept(erase(pos, 1))) {
712+
OV_HARDEN_ASSERT_VALID_ITERATOR(pos, "erase(const_iterator)");
696713
return erase(pos, 1);
697714
}
698715

src/openvic-simulation/types/StackString.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <cstdint>
66
#include <string_view>
77

8+
#include "openvic-simulation/core/Assert.hpp"
89
#include "openvic-simulation/utility/Containers.hpp"
910

1011
namespace OpenVic {
@@ -40,6 +41,7 @@ namespace OpenVic {
4041
}
4142

4243
constexpr decltype(_array)::const_reference operator[](size_t index) const {
44+
OV_HARDEN_ASSERT_ACCESS(index, "operator[]");
4345
return _array[index];
4446
}
4547

0 commit comments

Comments
 (0)