diff --git a/deps/ox/src/ox/claw/read.cpp b/deps/ox/src/ox/claw/read.cpp index 7de19897..2abfaa6d 100644 --- a/deps/ox/src/ox/claw/read.cpp +++ b/deps/ox/src/ox/claw/read.cpp @@ -41,7 +41,7 @@ Result readClawHeader(const char *buff, std::size_t buffLen) noexcep buffLen -= s3Size + 1; ClawHeader hdr; - if (fmt == "M1") { + if (fmt == "M2") { hdr.fmt = ClawFormat::Metal; } else if (fmt == "O1") { hdr.fmt = ClawFormat::Organic; diff --git a/deps/ox/src/ox/claw/read.hpp b/deps/ox/src/ox/claw/read.hpp index 1ae56658..7dd6f29d 100644 --- a/deps/ox/src/ox/claw/read.hpp +++ b/deps/ox/src/ox/claw/read.hpp @@ -45,7 +45,6 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) { return OxError(Error_ClawTypeMismatch, "Claw Read: Type mismatch"); } if (header.typeVersion != getModelTypeVersion()) { - oxDebugf("version: {}, {}", header.typeVersion, getModelTypeVersion()); return OxError(Error_ClawTypeVersionMismatch, "Claw Read: Type Version mismatch"); } switch (header.fmt) { diff --git a/deps/ox/src/ox/claw/test/tests.cpp b/deps/ox/src/ox/claw/test/tests.cpp index 41c65e2f..e57eb249 100644 --- a/deps/ox/src/ox/claw/test/tests.cpp +++ b/deps/ox/src/ox/claw/test/tests.cpp @@ -116,7 +116,7 @@ std::map tests = { { "ClawHeaderReader2", [] { - ox::String hdr = "M1;com.drinkingtea.ox.claw.test.Header2;3;"; + ox::String hdr = "M2;com.drinkingtea.ox.claw.test.Header2;3;"; auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1); oxAssert(err, "Error parsing header"); oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong"); diff --git a/deps/ox/src/ox/claw/write.hpp b/deps/ox/src/ox/claw/write.hpp index 3b659995..48e8a65c 100644 --- a/deps/ox/src/ox/claw/write.hpp +++ b/deps/ox/src/ox/claw/write.hpp @@ -62,7 +62,7 @@ Result writeClawHeader(T *t, ClawFormat fmt) noexcept { String out; switch (fmt) { case ClawFormat::Metal: - out += "M1;"; + out += "M2;"; break; case ClawFormat::Organic: out += "O1;"; diff --git a/deps/ox/src/ox/event/signal.cpp b/deps/ox/src/ox/event/signal.cpp index f093202d..f7fb2013 100644 --- a/deps/ox/src/ox/event/signal.cpp +++ b/deps/ox/src/ox/event/signal.cpp @@ -20,3 +20,9 @@ SignalHandler::~SignalHandler() noexcept { } } + +/* + * 1. ProjectExplorer::fileOpened cannot notify StudioUI that it is being destroyed. + * 2. StudioUI tries to unsubscribe from ProjectExplorer::fileOpened upon its destruction. + * 3. Segfault + */ diff --git a/deps/ox/src/ox/event/signal.hpp b/deps/ox/src/ox/event/signal.hpp index da3ac4a5..708c451a 100644 --- a/deps/ox/src/ox/event/signal.hpp +++ b/deps/ox/src/ox/event/signal.hpp @@ -8,6 +8,8 @@ #pragma once +#include +#include #include #include #include @@ -36,10 +38,6 @@ struct isError { template class Signal { - private: - template - static constexpr void ignoreValue(const T&) {} - protected: struct BaseSlot { virtual ~BaseSlot() = default; @@ -85,7 +83,10 @@ class Signal { } void cleanup(Signal *signal) noexcept final { - oxIgnoreError(m_receiver->destruction.disconnectSignal(signal)); + auto err = m_receiver->destruction.disconnectSignal(signal); + if (err) { + oxErrorf("Signal could not notify receiver that it is being destroyed. Destruction of receiver will cause use-after-free. ({})", toStr(err)); + } } [[nodiscard]] @@ -196,7 +197,7 @@ Error Signal::disconnectObject(const void *receiver) const noexcept { --i; } } - return OxError(0); + return OxError(1, "Signal::disconnectObject: Receiver was not found among this Signal's slots"); } template @@ -263,7 +264,9 @@ class Signal { } void cleanup(Signal *signal) noexcept final { - oxIgnoreError(m_receiver->destruction.disconnectSignal(signal)); + auto err = m_receiver->destruction.disconnectSignal(signal); + oxErrorf("{}", toStr(err)); + //oxAssert(err, "Signal could not notify receiver that it is being destroyed. Destruction of receiver will cause use-after-free."); } [[nodiscard]] @@ -327,6 +330,11 @@ class SignalHandler { public: Signal destruction; + constexpr SignalHandler() noexcept = default; + SignalHandler(const SignalHandler&) = delete; + SignalHandler(SignalHandler&) = delete; + SignalHandler(SignalHandler&&) = delete; + virtual ~SignalHandler() noexcept; }; @@ -377,7 +385,7 @@ Error Signal::disconnectObject(const void *receiver) const noexc --i; } } - return OxError(0); + return OxError(1, "Signal::disconnectObject: Receiver was not found among this Signal's slots"); } template diff --git a/deps/ox/src/ox/mc/intops.hpp b/deps/ox/src/ox/mc/intops.hpp index 15627f73..1d6d4099 100644 --- a/deps/ox/src/ox/mc/intops.hpp +++ b/deps/ox/src/ox/mc/intops.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace ox::mc { @@ -43,6 +44,9 @@ constexpr std::size_t highestBit(I val) noexcept { } static_assert(highestBit(int8_t(0b10000000)) == 0); +static_assert(highestBit(~static_cast(-1)) == 0); +static_assert(highestBit(~static_cast(-2)) == 0); +static_assert(highestBit(~static_cast(-3)) == 1); static_assert(highestBit(1) == 0); static_assert(highestBit(2) == 1); static_assert(highestBit(4) == 2); @@ -60,6 +64,7 @@ template [[nodiscard]] constexpr McInt encodeInteger(I input) noexcept { McInt out; + auto inputNegative = is_signed_v && input < 0; // move input to uint64_t to allow consistent bit manipulation, and to avoid // overflow concerns uint64_t val = 0; @@ -67,26 +72,35 @@ constexpr McInt encodeInteger(I input) noexcept { if (val) { // bits needed to represent number factoring in space possibly // needed for signed bit - const auto bits = highestBit(val) + 1 + (is_signed_v ? 1 : 0); + const auto highBit = inputNegative ? (highestBit(~val)) : highestBit(val); + const auto bits = highBit + 1 + (is_signed_v ? 1 : 0); // bytes needed to store value std::size_t bytes = bits / 8 + (bits % 8 != 0); const auto bitsAvailable = bytes * 8; // bits available to integer value const auto bitsNeeded = bits + bytes; // factor in bits needed for bytesIndicator (does not affect bytesIndicator) - // bits for integer + bits neded to represent bytes > bits available + // bits for integer + bits needed to represent bytes > bits available if (bitsNeeded > bitsAvailable && bytes != 9) { ++bytes; } const auto bytesIndicator = onMask(bytes - 1); - // ensure we are copying from little endian represenstation - LittleEndian leVal = static_cast(val); + // ensure we are copying from little endian representation + LittleEndian leVal = val; + if (inputNegative) { + leVal |= static_cast(1 << (bitsNeeded - 1)); + } if (bytes == 9) { out.data[0] = bytesIndicator; ox_memcpy(&out.data[1], &leVal, sizeof(I)); + if (inputNegative) { + out.data[1] |= 0b1000'0000; + } } else { + const auto valBits = bytes * 8; + uint64_t negBit = inputNegative ? 1 : 0; auto intermediate = - static_cast(leVal.raw()) << bytes | + static_cast(leVal.raw() | (negBit << (valBits - 1))) << bytes | static_cast(bytesIndicator); ox_memcpy(out.data, &intermediate, sizeof(intermediate)); } @@ -106,15 +120,15 @@ static constexpr std::size_t countBytes(uint8_t b) noexcept { return i + 1; } -static_assert(countBytes(0b00000000) == 1); -static_assert(countBytes(0b00000001) == 2); -static_assert(countBytes(0b00000011) == 3); -static_assert(countBytes(0b00000111) == 4); -static_assert(countBytes(0b00001111) == 5); -static_assert(countBytes(0b00011111) == 6); -static_assert(countBytes(0b00111111) == 7); -static_assert(countBytes(0b01111111) == 8); -static_assert(countBytes(0b11111111) == 9); +static_assert(countBytes(0b0000'0000) == 1); +static_assert(countBytes(0b0000'0001) == 2); +static_assert(countBytes(0b0000'0011) == 3); +static_assert(countBytes(0b0000'0111) == 4); +static_assert(countBytes(0b0000'1111) == 5); +static_assert(countBytes(0b0001'1111) == 6); +static_assert(countBytes(0b0011'1111) == 7); +static_assert(countBytes(0b0111'1111) == 8); +static_assert(countBytes(0b1111'1111) == 9); template Result decodeInteger(const uint8_t buff[9], std::size_t buffLen, std::size_t *bytesRead) noexcept { @@ -122,26 +136,37 @@ Result decodeInteger(const uint8_t buff[9], std::size_t buffLen, std::size_t if (bytes == 9) { *bytesRead = bytes; I out = 0; - memcpy(&out, &buff[1], sizeof(I)); + ox_memcpy(&out, &buff[1], sizeof(I)); return static_cast(LittleEndian(out)); } else if (buffLen >= bytes) { *bytesRead = bytes; uint64_t decoded = 0; - memcpy(&decoded, &buff[0], bytes); + ox_memcpy(&decoded, &buff[0], bytes); decoded >>= bytes; - auto out = static_cast(decoded); // move sign bit if constexpr(is_signed_v) { - const auto valBits = bytes << 3; - // get sign - uint64_t sign = decoded >> (valBits - 1); - // remove sign - decoded &= uint64_t(~0) ^ (uint64_t(1) << valBits); - // set sign - decoded |= sign << (Bits - 1); - memcpy(&out, &decoded, sizeof(out)); + const auto negBit = bytes * 8 - bytes - 1; + // move sign + const auto negative = (decoded >> negBit) == 1; + if (negative) { + // fill in all bits between encoded sign and real sign with 1s + // split it up because the 32-bit ARM can't shift more than 32 bits + uint32_t *d = reinterpret_cast(&decoded); + auto bit = negBit; + for (; bit < ox::min(Bits, 32); ++bit) { + d[0] |= 1 << bit; + } + for (; bit < Bits; ++bit) { + d[1] |= 1 << bit; + } + } + I out = 0; + ox_memcpy(&out, &decoded, sizeof(out)); + return out; + } else { + auto out = static_cast(decoded); + return out; } - return out; } return OxError(1); } diff --git a/deps/ox/src/ox/mc/test/tests.cpp b/deps/ox/src/ox/mc/test/tests.cpp index 605afb4c..57d30cc4 100644 --- a/deps/ox/src/ox/mc/test/tests.cpp +++ b/deps/ox/src/ox/mc/test/tests.cpp @@ -196,23 +196,23 @@ std::map tests = { return OxError(0); }; - oxAssert(check(encodeInteger(int64_t(1)), {0b00000010}), "Encode 1 fail"); - oxAssert(check(encodeInteger(int64_t(2)), {0b00000100}), "Encode 2 fail"); - oxAssert(check(encodeInteger(int64_t(3)), {0b00000110}), "Encode 3 fail"); - oxAssert(check(encodeInteger(int64_t(4)), {0b00001000}), "Encode 4 fail"); - oxAssert(check(encodeInteger(int64_t(128)), {0b00000001, 0b10}), "Encode 128 fail"); - oxAssert(check(encodeInteger(int64_t(129)), {0b00000101, 0b10}), "Encode 129 fail"); - oxAssert(check(encodeInteger(int64_t(130)), {0b00001001, 0b10}), "Encode 130 fail"); - oxAssert(check(encodeInteger(int64_t(131)), {0b00001101, 0b10}), "Encode 131 fail"); + oxAssert(check(encodeInteger(int64_t(1)), {0b000'0001'0}), "Encode 1 fail"); + oxAssert(check(encodeInteger(int64_t(2)), {0b000'0010'0}), "Encode 2 fail"); + oxAssert(check(encodeInteger(int64_t(3)), {0b000'0011'0}), "Encode 3 fail"); + oxAssert(check(encodeInteger(int64_t(4)), {0b000'0100'0}), "Encode 4 fail"); + oxAssert(check(encodeInteger(int64_t(128)), {0b00'0000'01, 0b10}), "Encode 128 fail"); + oxAssert(check(encodeInteger(int64_t(129)), {0b00'0001'01, 0b10}), "Encode 129 fail"); + oxAssert(check(encodeInteger(int64_t(130)), {0b00'0010'01, 0b10}), "Encode 130 fail"); + oxAssert(check(encodeInteger(int64_t(131)), {0b00'0011'01, 0b10}), "Encode 131 fail"); - oxAssert(check(encodeInteger(int64_t(-1)), {255, 255, 255, 255, 255, 255, 255, 255, 255}), "Encode -1 fail"); - oxAssert(check(encodeInteger(int64_t(-2)), {255, 254, 255, 255, 255, 255, 255, 255, 255}), "Encode -2 fail"); - oxAssert(check(encodeInteger(int64_t(-3)), {255, 253, 255, 255, 255, 255, 255, 255, 255}), "Encode -3 fail"); - oxAssert(check(encodeInteger(int64_t(-4)), {255, 252, 255, 255, 255, 255, 255, 255, 255}), "Encode -4 fail"); - oxAssert(check(encodeInteger(int64_t(-128)), {255, 128, 255, 255, 255, 255, 255, 255, 255}), "Encode -128 fail"); - oxAssert(check(encodeInteger(int64_t(-129)), {255, 127, 255, 255, 255, 255, 255, 255, 255}), "Encode -129 fail"); - oxAssert(check(encodeInteger(int64_t(-130)), {255, 126, 255, 255, 255, 255, 255, 255, 255}), "Encode -130 fail"); - oxAssert(check(encodeInteger(int64_t(-131)), {255, 125, 255, 255, 255, 255, 255, 255, 255}), "Encode -131 fail"); + oxAssert(check(encodeInteger( int64_t(-1)), {0b111'1111'0}), "Encode -1 fail"); + oxAssert(check(encodeInteger( int64_t(-2)), {0b111'1110'0}), "Encode -2 fail"); + oxAssert(check(encodeInteger( int64_t(-3)), {0b111'1101'0}), "Encode -3 fail"); + oxAssert(check(encodeInteger( int64_t(-4)), {0b111'1100'0}), "Encode -4 fail"); + oxAssert(check(encodeInteger(int64_t(-128)), {0b00'0000'01, 0b11'1111'10}), "Encode -128 fail"); + oxAssert(check(encodeInteger(int64_t(-129)), {0b11'1111'01, 0b11'1111'01}), "Encode -129 fail"); + oxAssert(check(encodeInteger(int64_t(-130)), {0b11'1110'01, 0b11'1111'01}), "Encode -130 fail"); + oxAssert(check(encodeInteger(int64_t(-131)), {0b11'1101'01, 0b11'1111'01}), "Encode -131 fail"); oxAssert(check(encodeInteger(uint32_t(0xffffffff)), {0b11101111, 255, 255, 255, 0b00011111}), "Encode 0xffffffff fail"); oxAssert(check(encodeInteger(uint64_t(1)), {0b0010}), "Encode 1 fail"); @@ -250,11 +250,17 @@ std::map tests = { }; oxAssert(check(uint32_t(14)), "Decode of 14 failed."); oxAssert(check(int64_t(-1)), "Decode of -1 failed."); + oxAssert(check(int64_t(-2)), "Decode of -2 failed."); + oxAssert(check(int64_t(-127)), "Decode of -127 failed."); + oxAssert(check(int64_t(-128)), "Decode of -128 failed."); + oxAssert(check(int64_t(-129)), "Decode of -129 failed."); + oxAssert(check(int64_t(-129000)), "Decode of -129000 failed."); oxAssert(check(int64_t(1)), "Decode of 1 failed."); oxAssert(check(int64_t(2)), "Decode of 2 failed."); oxAssert(check(int64_t(42)), "Decode of 42 failed."); oxAssert(check(int64_t(130)), "Decode of 130 failed."); oxAssert(check(int64_t(131)), "Decode of 131 failed."); + oxAssert(check(int64_t(131000)), "Decode of 131000 failed."); oxAssert(check(uint64_t(1)), "Decode of 1 failed."); oxAssert(check(uint64_t(2)), "Decode of 2 failed."); oxAssert(check(uint64_t(42)), "Decode of 42 failed."); diff --git a/deps/ox/src/ox/std/memops.hpp b/deps/ox/src/ox/std/memops.hpp index 610e9547..be999020 100644 --- a/deps/ox/src/ox/std/memops.hpp +++ b/deps/ox/src/ox/std/memops.hpp @@ -8,7 +8,9 @@ #pragma once +#include "defines.hpp" #include "types.hpp" +#include "typetraits.hpp" #if __has_include() #include @@ -27,29 +29,41 @@ void *memset(void *ptr, int val, std::size_t size); int ox_memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept; constexpr void *ox_memcpy(void *dest, const void *src, std::size_t size) noexcept { - auto srcBuf = static_cast(src); - auto dstBuf = static_cast(dest); - for (std::size_t i = 0; i < size; ++i) { - dstBuf[i] = static_cast(srcBuf[i]); + if (std::is_constant_evaluated() || !ox::defines::UseStdLib) { + auto srcBuf = static_cast(src); + auto dstBuf = static_cast(dest); + for (std::size_t i = 0; i < size; ++i) { + dstBuf[i] = static_cast(srcBuf[i]); + } + return dest; + } else { + return memcpy(dest, src, size); } - return dest; } constexpr void *ox_memmove(void *dest, const void *src, std::size_t size) noexcept { - auto srcBuf = static_cast(src); - auto dstBuf = static_cast(dest); - for (std::size_t i = 0; i < size; ++i) { - dstBuf[i] = static_cast(srcBuf[i]); + if (std::is_constant_evaluated() || !ox::defines::UseStdLib) { + auto srcBuf = static_cast(src); + auto dstBuf = static_cast(dest); + for (std::size_t i = 0; i < size; ++i) { + dstBuf[i] = static_cast(srcBuf[i]); + } + return dest; + } else { + return memmove(dest, src, size); } - return dest; } constexpr void *ox_memset(void *ptr, int val, std::size_t size) noexcept { - auto buf = static_cast(ptr); - for (std::size_t i = 0; i < size; ++i) { - buf[i] = static_cast(val); + if (std::is_constant_evaluated() || !ox::defines::UseStdLib) { + auto buf = static_cast(ptr); + for (std::size_t i = 0; i < size; ++i) { + buf[i] = static_cast(val); + } + return ptr; + } else { + return memset(ptr, val, size); } - return ptr; } namespace ox {