From f772e48b3697221237a06d399af2ce5b4b04fec5 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Thu, 14 Nov 2024 21:08:38 -0600 Subject: [PATCH] [ox] Add Vector/Array/Span overflow checking --- deps/ox/src/ox/model/desctypes.hpp | 7 +++--- deps/ox/src/ox/model/descwrite.hpp | 27 +++++++++++++++++--- deps/ox/src/ox/model/modelvalue.hpp | 35 ++++++++++++++------------ deps/ox/src/ox/std/array.hpp | 2 ++ deps/ox/src/ox/std/assert.cpp | 39 ++++++++++++++++++++++++++++- deps/ox/src/ox/std/assert.hpp | 31 ++++------------------- deps/ox/src/ox/std/error.hpp | 9 +++++++ deps/ox/src/ox/std/span.hpp | 4 +++ deps/ox/src/ox/std/trace.hpp | 6 ++++- deps/ox/src/ox/std/vector.hpp | 2 ++ 10 files changed, 112 insertions(+), 50 deletions(-) diff --git a/deps/ox/src/ox/model/desctypes.hpp b/deps/ox/src/ox/model/desctypes.hpp index 6a1bcc4f..045cc86b 100644 --- a/deps/ox/src/ox/model/desctypes.hpp +++ b/deps/ox/src/ox/model/desctypes.hpp @@ -90,7 +90,7 @@ constexpr Error model(T *io, CommonPtrWith auto *type) noexcept { } oxReturnError(io->field("length", &type->length)); oxReturnError(io->field("smallSzLen", &type->smallSzLen)); - return OxError(0); + return {}; } using SubscriptStack = Vector; @@ -119,6 +119,7 @@ struct DescriptorField { subscriptLevels(pSubscriptLevels), subscriptStack(std::move(pSubscriptType)), typeId(std::move(pTypeId)) { + oxAssert(subscriptLevels <= static_cast(subscriptStack.size()), "Subscript level mismatch"); } constexpr DescriptorField(const DescriptorField &other) noexcept: @@ -202,7 +203,7 @@ constexpr Error model(T *io, CommonPtrWith auto *type) noexcept oxReturnError(io->field("fieldList", &type->fieldList)); oxReturnError(io->field("length", &type->length)); oxReturnError(io->field("preloadable", &type->preloadable)); - return OxError(0); + return {}; } template @@ -215,7 +216,7 @@ constexpr Error model(T *io, CommonPtrWith auto *field) noexcep // defaultValue is unused now, but leave placeholder for backwards compatibility int defaultValue = 0; oxReturnError(io->field("defaultValue", &defaultValue)); - return OxError(0); + return {}; } template diff --git a/deps/ox/src/ox/model/descwrite.hpp b/deps/ox/src/ox/model/descwrite.hpp index 817bfc14..8e50f501 100644 --- a/deps/ox/src/ox/model/descwrite.hpp +++ b/deps/ox/src/ox/model/descwrite.hpp @@ -97,8 +97,14 @@ class TypeDescWriter { std::size_t fields = ModelFieldCount_v) noexcept; template - constexpr Error field(StringViewCR name, const T *val, std::size_t valLen, - const SubscriptStack &subscriptStack = {}) noexcept; + constexpr Error field( + StringViewCR name, + T const*val, + std::size_t valLen, + SubscriptStack const&subscriptStack) noexcept; + + template + constexpr Error field(StringViewCR name, T const*val, std::size_t valLen) noexcept; template constexpr Error field(StringViewCR name, UnionView val) noexcept; @@ -193,7 +199,7 @@ constexpr ox::Error TypeDescWriter::setTypeInfo( // array handler template -constexpr Error TypeDescWriter::field(StringViewCR name, const T*, std::size_t, const SubscriptStack &subscriptStack) noexcept { +constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t, SubscriptStack const&subscriptStack) noexcept { if (m_type) { constexpr typename remove_pointer::type *p = nullptr; const auto t = type(p); @@ -204,6 +210,21 @@ constexpr Error TypeDescWriter::field(StringViewCR name, const T*, std::size_t, return OxError(1); } +// array handler +template +constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t) noexcept { + if (m_type) { + constexpr typename remove_pointer::type *p = nullptr; + const auto t = type(p); + oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated"); + auto const lvls = detail::indirectionLevels_v + 1; + SubscriptStack subscriptStack{lvls}; + m_type->fieldList.emplace_back(t, String(name), lvls, subscriptStack, buildTypeId(*t)); + return OxError(0); + } + return OxError(1); +} + template constexpr Error TypeDescWriter::field(StringViewCR name, UnionView val) noexcept { if (m_type) { diff --git a/deps/ox/src/ox/model/modelvalue.hpp b/deps/ox/src/ox/model/modelvalue.hpp index 7a62060a..84dc58b1 100644 --- a/deps/ox/src/ox/model/modelvalue.hpp +++ b/deps/ox/src/ox/model/modelvalue.hpp @@ -188,8 +188,8 @@ class ModelValue { constexpr Error setType( DescriptorType const*type, - int subscriptLevels = 0, - SubscriptStack const& = {}) noexcept; + SubscriptStack const& = {}, + int subscriptLevels = 0) noexcept; template constexpr Error setType() noexcept; @@ -242,7 +242,7 @@ class ModelValueArray { m_vec.resize(sz); if (sz > oldSz) { for (auto i = oldSz; i < sz; ++i) { - oxReturnError(m_vec[i].setType(m_type, m_typeSubscriptLevels)); + oxReturnError(m_vec[i].setType(m_type, m_subscriptStack, m_typeSubscriptLevels)); } } return {}; @@ -276,8 +276,9 @@ class ModelValueArray { constexpr Error setType( DescriptorType const*type, - int subscriptLevels, - SubscriptStack subscriptStack) noexcept { + SubscriptStack subscriptStack, + int subscriptLevels) noexcept { + oxAssert(subscriptLevels <= static_cast(subscriptStack.size()), "subscript level mismatch"); m_type = type; m_typeSubscriptLevels = subscriptLevels; m_subscriptStack = std::move(subscriptStack); @@ -400,7 +401,7 @@ class ModelValueVector { m_vec.resize(sz); if (sz > oldSz) { for (auto i = oldSz; i < sz; ++i) { - oxReturnError(m_vec[i].setType(m_type, m_typeSubscriptLevels, m_subscriptStack)); + oxReturnError(m_vec[i].setType(m_type, m_subscriptStack, m_typeSubscriptLevels)); } } return {}; @@ -418,8 +419,9 @@ class ModelValueVector { constexpr Error setType( DescriptorType const*type, - int subscriptLevels, - SubscriptStack subscriptStack) noexcept { + SubscriptStack subscriptStack, + int subscriptLevels) noexcept { + oxAssert(subscriptLevels <= static_cast(subscriptStack.size()), "subscript level mismatch"); m_type = type; m_typeSubscriptLevels = subscriptLevels; m_subscriptStack = std::move(subscriptStack); @@ -674,11 +676,11 @@ class ModelObject { for (const auto &f : type->fieldList) { auto field = make_unique(); field->name = f.fieldName; - oxReturnError(field->value.setType(f.type, f.subscriptLevels, f.subscriptStack)); + oxReturnError(field->value.setType(f.type, f.subscriptStack, f.subscriptLevels)); m_fields[field->name] = &field->value; m_fieldsOrder.emplace_back(std::move(field)); } - return OxError(0); + return {}; } }; @@ -797,12 +799,12 @@ class ModelUnion { auto field = make_unique(); field->name = f.fieldName; field->idx = i; - oxReturnError(field->value.setType(f.type, f.subscriptLevels)); + oxReturnError(field->value.setType(f.type, SubscriptStack{static_cast(f.subscriptLevels)}, f.subscriptLevels)); m_fields[field->name] = field.get(); m_fieldsOrder.emplace_back(std::move(field)); ++i; } - return OxError(0); + return {}; } [[nodiscard]] @@ -1076,20 +1078,21 @@ constexpr ModelValue::Type ModelValue::type() const noexcept { constexpr Error ModelValue::setType( const DescriptorType *type, - int subscriptLevels, - SubscriptStack const&subscriptStack) noexcept { + SubscriptStack const&subscriptStack, + int subscriptLevels) noexcept { freeResources(); + oxAssert(subscriptLevels <= static_cast(subscriptStack.size()), "subscript level mismatch"); if (subscriptLevels) { auto const&subscript = subscriptStack[subscriptStack.size() - static_cast(subscriptLevels)]; if (subscript.subscriptType == Subscript::SubscriptType::InlineArray) { m_type = Type::InlineArray; m_data.array = new ModelValueArray; - oxReturnError(m_data.array->setType(type, subscriptLevels - 1, subscriptStack)); + oxReturnError(m_data.array->setType(type, subscriptStack, subscriptLevels - 1)); oxReturnError(m_data.array->setSize(static_cast(subscript.length))); } else { m_type = Type::Vector; m_data.vec = new ModelValueVector; - oxReturnError(m_data.vec->setType(type, subscriptLevels - 1, subscriptStack)); + oxReturnError(m_data.vec->setType(type, subscriptStack, subscriptLevels - 1)); } return {}; } else if (type->typeName == types::Bool) { diff --git a/deps/ox/src/ox/std/array.hpp b/deps/ox/src/ox/std/array.hpp index 18926ecf..2e28331b 100644 --- a/deps/ox/src/ox/std/array.hpp +++ b/deps/ox/src/ox/std/array.hpp @@ -174,11 +174,13 @@ constexpr Array &Array::operator=(Array &&other) noe template constexpr T &Array::operator[](std::size_t i) noexcept { + ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Array access overflow"); return m_items[i]; } template constexpr const T &Array::operator[](std::size_t i) const noexcept { + ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Array access overflow"); return m_items[i]; } diff --git a/deps/ox/src/ox/std/assert.cpp b/deps/ox/src/ox/std/assert.cpp index 3f5f68cb..0a8b7f70 100644 --- a/deps/ox/src/ox/std/assert.cpp +++ b/deps/ox/src/ox/std/assert.cpp @@ -6,6 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#include "fmt.hpp" #include "stacktrace.hpp" #include "trace.hpp" @@ -13,7 +14,7 @@ namespace ox { -void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept { +void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err) noexcept { oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg); if (err.msg) { oxErrf("\tError Message:\t{}\n", err.msg); @@ -31,4 +32,40 @@ void panic(const char *file, int line, const char *panicMsg, const Error &err) n #endif } +void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept { + panic(StringView{file}, line, StringView{panicMsg}, err); +} + +void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept { +#ifdef OX_USE_STDLIB + auto output = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg); + output += genStackTrace(2); + oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line); + std::abort(); +#else + oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg); + oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line); + constexprPanic(file, line, msg); +#endif +} + +void assertFailFuncRuntime(StringViewCR file, int line, [[maybe_unused]] const Error &err, StringViewCR, StringViewCR assertMsg) noexcept { +#if defined(OX_USE_STDLIB) + auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg); + if (err.msg) { + msg += sfmt("\tError Message:\t{}\n", err.msg); + } + msg += sfmt("\tError Code:\t{}\n", static_cast(err)); + if (err.file != nullptr) { + msg += sfmt("\tError Location:\t{}:{}\n", err.file, err.line); + } + msg += genStackTrace(2); + oxErr(msg); + oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line); + std::abort(); +#else + constexprPanic(file, line, assertMsg); +#endif +} + } diff --git a/deps/ox/src/ox/std/assert.hpp b/deps/ox/src/ox/std/assert.hpp index 4ea28bf1..b9873b9d 100644 --- a/deps/ox/src/ox/std/assert.hpp +++ b/deps/ox/src/ox/std/assert.hpp @@ -32,19 +32,13 @@ constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg } } +void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept; +void assertFailFuncRuntime(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept; + constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused]]StringViewCR assertTxt, [[maybe_unused]]StringViewCR msg) noexcept { if (!pass) { if (!std::is_constant_evaluated()) { -#ifdef OX_USE_STDLIB - auto output = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg); - output += genStackTrace(2); - oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line); - std::abort(); -#else - oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg); - oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line); - constexprPanic(file, line, msg); -#endif + assertFailFuncRuntime(file, line, assertTxt, msg); } else { while (true); } @@ -54,22 +48,7 @@ constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept { if (err) { if (!std::is_constant_evaluated()) { -#if defined(OX_USE_STDLIB) - auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg); - if (err.msg) { - msg += sfmt("\tError Message:\t{}\n", err.msg); - } - msg += sfmt("\tError Code:\t{}\n", static_cast(err)); - if (err.file != nullptr) { - msg += sfmt("\tError Location:\t{}:{}\n", err.file, err.line); - } - msg += genStackTrace(2); - oxErr(msg); - oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line); - std::abort(); -#else - constexprPanic(file, line, assertMsg); -#endif + assertFailFuncRuntime(file, line, err, {}, assertMsg); } else { while (true); } diff --git a/deps/ox/src/ox/std/error.hpp b/deps/ox/src/ox/std/error.hpp index 45d217ea..49e29174 100644 --- a/deps/ox/src/ox/std/error.hpp +++ b/deps/ox/src/ox/std/error.hpp @@ -24,6 +24,7 @@ class exception { } #endif +#include "defines.hpp" #include "def.hpp" #include "typetraits.hpp" #include "utility.hpp" @@ -332,4 +333,12 @@ constexpr Error toError(const Result &r) noexcept { } +constexpr void primitiveAssert(const char *file, int line, bool pass, const char *msg) noexcept { + if constexpr(ox::defines::Debug) { + if (!pass) [[unlikely]] { + panic(file, line, msg, OxError(1)); + } + } +} + } diff --git a/deps/ox/src/ox/std/span.hpp b/deps/ox/src/ox/std/span.hpp index 9c8bb2aa..2e336daa 100644 --- a/deps/ox/src/ox/std/span.hpp +++ b/deps/ox/src/ox/std/span.hpp @@ -103,10 +103,12 @@ class SpanView { } constexpr const T &operator[](std::size_t i) const noexcept { + ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow"); return m_items[i]; } constexpr SpanView operator+(size_t i) const noexcept { + ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow"); return {m_items + i, m_size - i}; } @@ -229,10 +231,12 @@ class Span { } constexpr T &operator[](std::size_t i) noexcept { + ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span overflow"); return m_items[i]; } constexpr const T &operator[](std::size_t i) const noexcept { + ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span overflow"); return m_items[i]; } diff --git a/deps/ox/src/ox/std/trace.hpp b/deps/ox/src/ox/std/trace.hpp index de7c5369..b156957f 100644 --- a/deps/ox/src/ox/std/trace.hpp +++ b/deps/ox/src/ox/std/trace.hpp @@ -173,7 +173,7 @@ class OutStream { return *this; } - constexpr OutStream &operator<<(const char *v) noexcept { + constexpr OutStream &operator<<(StringViewCR v) noexcept { if (m_msg.msg.len()) { m_msg.msg += m_delimiter; } @@ -181,6 +181,10 @@ class OutStream { return *this; } + constexpr OutStream &operator<<(const char *v) noexcept { + return operator<<(StringView{v}); + } + template constexpr OutStream &operator<<(const IString &v) noexcept { return operator<<(v.c_str()); diff --git a/deps/ox/src/ox/std/vector.hpp b/deps/ox/src/ox/std/vector.hpp index 8035dfb7..4627bdb3 100644 --- a/deps/ox/src/ox/std/vector.hpp +++ b/deps/ox/src/ox/std/vector.hpp @@ -422,11 +422,13 @@ constexpr Vector &Vector constexpr T &Vector::operator[](std::size_t i) noexcept { + ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Vector access overflow"); return m_items[i]; } template constexpr const T &Vector::operator[](std::size_t i) const noexcept { + ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Vector access overflow"); return m_items[i]; }