Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions src/openvic-simulation/core/Assert.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#pragma once

#include <bit> // IWYU pragma: keep for use of cross-library reference for standard library macro definitions

#ifdef __GLIBCXX__
#include <debug/assertions.h>

#define OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, MSG) __glibcxx_assert(BEGIN <= END)
#define OV_HARDEN_ASSERT_NONEMPTY_RANGE(BEGIN, END, FUNC_NAME) __glibcxx_requires_non_empty_range(BEGIN, END)

#define OV_HARDEN_ASSERT_ACCESS(INDEX, FUNC_NAME) __glibcxx_requires_subscript(INDEX)
#define OV_HARDEN_ASSERT_NONEMPTY(FUNC_NAME) __glibcxx_requires_nonempty()
#define OV_HARDEN_ASSERT_VALID_ITERATOR(IT, FUNC_NAME) \
OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(IT, end(), FUNC_NAME " called with a non-dereferenceable iterator")

#elif defined(_LIBCPP_VERSION)
#include <__assert>

#define OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, MSG) _LIBCPP_ASSERT_VALID_INPUT_RANGE(BEGIN <= END, MSG)
#define OV_HARDEN_ASSERT_NONEMPTY_RANGE(BEGIN, END, FUNC_NAME) \
OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, FUNC_NAME " called with an invalid range")

#define OV_HARDEN_ASSERT_ACCESS(INDEX, FUNC_NAME) \
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(INDEX < size(), FUNC_NAME " index out of bounds")
#define OV_HARDEN_ASSERT_NONEMPTY(FUNC_NAME) \
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), FUNC_NAME " called on an empty container")
#define OV_HARDEN_ASSERT_VALID_ITERATOR(IT, FUNC_NAME) \
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(IT != end(), FUNC_NAME " called with a non-dereferenceable iterator")

#elif defined(_MSVC_STL_VERSION) && _MSVC_STL_HARDENING == 1
#include <yvals.h>

#define OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, MSG) _STL_VERIFY(BEGIN <= END, MSG)
#define OV_HARDEN_ASSERT_NONEMPTY_RANGE(BEGIN, END, FUNC_NAME) \
OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, FUNC_NAME " called with an invalid range")

#define OV_HARDEN_ASSERT_ACCESS(INDEX, FUNC_NAME) _STL_VERIFY(INDEX < size(), FUNC_NAME " index out of bounds")
#define OV_HARDEN_ASSERT_NONEMPTY(FUNC_NAME) _STL_VERIFY(!empty(), FUNC_NAME " called on an empty container")
#define OV_HARDEN_ASSERT_VALID_ITERATOR(IT, FUNC_NAME) \
OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(IT, end(), FUNC_NAME " called with a non-dereferenceable iterator")

#else
#define OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(BEGIN, END, MSG)
#define OV_HARDEN_ASSERT_NONEMPTY_RANGE(BEGIN, END, FUNC_NAME)
#define OV_HARDEN_ASSERT_ACCESS(INDEX, FUNC_NAME)
#define OV_HARDEN_ASSERT_NONEMPTY(FUNC_NAME)
#define OV_HARDEN_ASSERT_VALID_ITERATOR(IT, FUNC_NAME)

// clang-format off
# if defined(_GLIBCXX_ASSERTIONS) || _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_FAST || _MSVC_STL_HARDENING == 1
#warning "Unsupported standard library for memory hardening, hardening asserts will be ignored."
# endif
// clang-format on

#endif
4 changes: 2 additions & 2 deletions src/openvic-simulation/types/Colour.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -871,10 +871,10 @@ struct fmt::formatter<T> {
size_t i = 0;
for (char& c : lower) {
c = std::tolower(result[i]);
if (c == '\0') {
++i;
if (i == result.size()) {
break;
}
++i;
}
return detail::write(out, string_view { lower.data(), i }, specs, ctx.locale());
}
Expand Down
29 changes: 20 additions & 9 deletions src/openvic-simulation/types/CowVector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <type_traits>
#include <vector>

#include "openvic-simulation/core/Assert.hpp"
#include "openvic-simulation/types/BasicIterator.hpp"
#include "openvic-simulation/utility/Allocator.hpp"
#include "openvic-simulation/core/Compare.hpp"
Expand Down Expand Up @@ -166,19 +167,24 @@ namespace OpenVic {
}

const_reference at(size_type pos) const {
// TODO: crash on boundary violation
return (*this)[pos];
if (OV_unlikely(pos >= size())) {
std::abort();
}
return _data->array[pos];
}

const_reference operator[](size_type pos) const {
OV_HARDEN_ASSERT_ACCESS(pos, "operator[]");
return _data->array[pos];
}

const_reference front() const {
OV_HARDEN_ASSERT_NONEMPTY("front");
return *_data->array;
}

const_reference back() const {
OV_HARDEN_ASSERT_NONEMPTY("back");
return *_data->array_end;
}

Expand Down Expand Up @@ -329,9 +335,8 @@ namespace OpenVic {

template<typename InputIt>
inline difference_type _validate_iterator_difference(InputIt first, InputIt last) {
difference_type result = last - first;
// TODO: crash on negative result
return result;
OV_HARDEN_ASSERT_VALID_RANGE_MESSAGE(first, last, "_validate_iterator_difference called with invalid range");
return last - first;
}

struct for_overwrite_t {};
Expand Down Expand Up @@ -367,19 +372,24 @@ namespace OpenVic {
}

reference at(size_type pos) {
return (*this)[pos];
if (OV_unlikely(pos >= size())) {
std::abort();
}
return _data->array[pos];
}

reference operator[](size_type pos) {
// TODO: crash on boundary violation
OV_HARDEN_ASSERT_ACCESS(pos, "operator[]");
return _data->array[pos];
}

reference front() {
OV_HARDEN_ASSERT_NONEMPTY("front");
return *_data->array;
}

reference back() {
OV_HARDEN_ASSERT_NONEMPTY("back");
return *_data->array_end;
}

Expand All @@ -405,7 +415,7 @@ namespace OpenVic {

void reserve(size_type count) {
if (count > max_size()) {
// TODO: crash
std::abort();
}
if (capacity() >= count) {
return;
Expand Down Expand Up @@ -510,6 +520,7 @@ namespace OpenVic {
}

iterator erase(const_iterator pos) {
OV_HARDEN_ASSERT_VALID_ITERATOR(pos, "erase(const_iterator)");
if (pos + 1 != end()) {
std::move(pos + 1, end(), pos);
}
Expand Down Expand Up @@ -561,7 +572,7 @@ namespace OpenVic {
}

void pop_back() {
// TODO: assert if empty
OV_HARDEN_ASSERT_NONEMPTY("pop_back");
--_data->array_end;
allocator_traits::destroy(alloc, _data->array_end);
}
Expand Down
13 changes: 7 additions & 6 deletions src/openvic-simulation/types/FixedVector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <memory>
#include <utility>

#include "openvic-simulation/core/Assert.hpp"
#include "openvic-simulation/core/template/Concepts.hpp"
#include "openvic-simulation/core/Typedefs.hpp"

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

T& operator[](const size_t index) {
assert(index < _size);
OV_HARDEN_ASSERT_ACCESS(index, "operator[]");
return _data_start_ptr[index];
}
const T& operator[](const size_t index) const {
assert(index < _size);
OV_HARDEN_ASSERT_ACCESS(index, "operator[]");
return _data_start_ptr[index];
}

T& front() {
assert(!empty());
OV_HARDEN_ASSERT_NONEMPTY("front");
return *begin();
}
const T& front() const {
assert(!empty());
OV_HARDEN_ASSERT_NONEMPTY("front");
return *cbegin();
}
T& back() {
assert(!empty());
OV_HARDEN_ASSERT_NONEMPTY("back");
return *(end()-1);
}
const T& back() const {
assert(!empty());
OV_HARDEN_ASSERT_NONEMPTY("back");
return *(cend()-1);
}

Expand Down
31 changes: 24 additions & 7 deletions src/openvic-simulation/types/RingBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <range/v3/range/concepts.hpp>
#include <range/v3/view/subrange.hpp>

#include "openvic-simulation/core/Assert.hpp"
#include "openvic-simulation/core/Typedefs.hpp"

namespace OpenVic {
Expand Down Expand Up @@ -215,34 +216,49 @@ namespace OpenVic {
allocator_type get_allocator() const {
return _allocator;
}

private:
reference _unsafe_access(const size_type index) {
return _data[_ring_wrap(_offset + index, capacity())];
}
const_reference _unsafe_access(const size_type index) const {
return _data[_ring_wrap(_offset + index, capacity())];
}

public:
reference front() {
return at(0);
OV_HARDEN_ASSERT_NONEMPTY("front");
return _unsafe_access(0);
}
reference back() {
return at(size() - 1);
OV_HARDEN_ASSERT_NONEMPTY("back");
return _unsafe_access(size() - 1);
}
const_reference back() const {
return at(size() - 1);
OV_HARDEN_ASSERT_NONEMPTY("back");
return _unsafe_access(size() - 1);
}

const_reference operator[](const size_type index) const {
return _data[_ring_wrap(_offset + index, capacity())];
OV_HARDEN_ASSERT_ACCESS(index, "operator[]");
return _unsafe_access(index);
}
reference operator[](const size_type index) {
return _data[_ring_wrap(_offset + index, capacity())];
OV_HARDEN_ASSERT_ACCESS(index, "operator[]");
return _unsafe_access(index);
}

const_reference at(const size_type index) const {
if (OV_unlikely(index >= size())) {
std::abort();
}
return (*this)[index];
return _unsafe_access(index);
}
reference at(const size_type index) {
if (OV_unlikely(index >= size())) {
std::abort();
}
return (*this)[index];
return _unsafe_access(index);
}

iterator begin() noexcept {
Expand Down Expand Up @@ -693,6 +709,7 @@ namespace OpenVic {
return erase(pos, last);
}
iterator erase(const_iterator pos) noexcept(noexcept(erase(pos, 1))) {
OV_HARDEN_ASSERT_VALID_ITERATOR(pos, "erase(const_iterator)");
return erase(pos, 1);
}

Expand Down
2 changes: 2 additions & 0 deletions src/openvic-simulation/types/StackString.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <cstdint>
#include <string_view>

#include "openvic-simulation/core/Assert.hpp"
#include "openvic-simulation/utility/Containers.hpp"

namespace OpenVic {
Expand Down Expand Up @@ -40,6 +41,7 @@ namespace OpenVic {
}

constexpr decltype(_array)::const_reference operator[](size_t index) const {
OV_HARDEN_ASSERT_ACCESS(index, "operator[]");
return _array[index];
}

Expand Down