[ox] Add Vector/Array/Span overflow checking

This commit is contained in:
Gary Talent 2024-11-14 21:08:38 -06:00
parent 13bfe88195
commit f772e48b36
10 changed files with 112 additions and 50 deletions

View File

@ -90,7 +90,7 @@ constexpr Error model(T *io, CommonPtrWith<Subscript> auto *type) noexcept {
}
oxReturnError(io->field("length", &type->length));
oxReturnError(io->field("smallSzLen", &type->smallSzLen));
return OxError(0);
return {};
}
using SubscriptStack = Vector<Subscript, 3>;
@ -119,6 +119,7 @@ struct DescriptorField {
subscriptLevels(pSubscriptLevels),
subscriptStack(std::move(pSubscriptType)),
typeId(std::move(pTypeId)) {
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "Subscript level mismatch");
}
constexpr DescriptorField(const DescriptorField &other) noexcept:
@ -202,7 +203,7 @@ constexpr Error model(T *io, CommonPtrWith<DescriptorType> 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<typename T>
@ -215,7 +216,7 @@ constexpr Error model(T *io, CommonPtrWith<DescriptorField> 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<typename ReaderBase>

View File

@ -97,8 +97,14 @@ class TypeDescWriter {
std::size_t fields = ModelFieldCount_v<T>) noexcept;
template<typename T>
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<typename T>
constexpr Error field(StringViewCR name, T const*val, std::size_t valLen) noexcept;
template<typename T, bool force>
constexpr Error field(StringViewCR name, UnionView<T, force> val) noexcept;
@ -193,7 +199,7 @@ constexpr ox::Error TypeDescWriter::setTypeInfo(
// array handler
template<typename T>
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<T>::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<typename T>
constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t) noexcept {
if (m_type) {
constexpr typename remove_pointer<T>::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<T> + 1;
SubscriptStack subscriptStack{lvls};
m_type->fieldList.emplace_back(t, String(name), lvls, subscriptStack, buildTypeId(*t));
return OxError(0);
}
return OxError(1);
}
template<typename T, bool force>
constexpr Error TypeDescWriter::field(StringViewCR name, UnionView<T, force> val) noexcept {
if (m_type) {

View File

@ -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<typename T>
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<int>(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<int>(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>();
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>();
field->name = f.fieldName;
field->idx = i;
oxReturnError(field->value.setType(f.type, f.subscriptLevels));
oxReturnError(field->value.setType(f.type, SubscriptStack{static_cast<size_t>(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<int>(subscriptStack.size()), "subscript level mismatch");
if (subscriptLevels) {
auto const&subscript = subscriptStack[subscriptStack.size() - static_cast<size_t>(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<size_t>(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) {

View File

@ -174,11 +174,13 @@ constexpr Array<T, ArraySize> &Array<T, ArraySize>::operator=(Array &&other) noe
template<typename T, std::size_t ArraySize>
constexpr T &Array<T, ArraySize>::operator[](std::size_t i) noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Array access overflow");
return m_items[i];
}
template<typename T, std::size_t ArraySize>
constexpr const T &Array<T, ArraySize>::operator[](std::size_t i) const noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Array access overflow");
return m_items[i];
}

View File

@ -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<ErrorCode>(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
}
}

View File

@ -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<ErrorCode>(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);
}

View File

@ -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<T> &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));
}
}
}
}

View File

@ -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];
}

View File

@ -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<std::size_t sz>
constexpr OutStream &operator<<(const IString<sz> &v) noexcept {
return operator<<(v.c_str());

View File

@ -422,11 +422,13 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Vector access overflow");
return m_items[i];
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr const T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) const noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Vector access overflow");
return m_items[i];
}