From e39f2b2b2fba16e4259c0bc2624711ac810caaed Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Sat, 29 Nov 2025 15:12:15 +0100 Subject: [PATCH] CI updates --- .github/workflows/ci.yml | 2 +- src/util/membuffer.cpp | 226 +++++++++++++++++++++++++++++---------- src/util/membuffer.h | 22 ++-- 3 files changed, 184 insertions(+), 66 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5f539b5..88c49eee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -485,7 +485,7 @@ jobs: export upx_testsuite_SRCDIR="$(readlink -en ../deps/upx-testsuite)" env -C build/release/Release upx_exe=./upx.exe bash "$PWD"/misc/testsuite/upx_testsuite_1.sh - job-windows-toolchains: # build "by hand" using cmd.exe + job-windows-bh-toolchains: # build "by hand" using cmd.exe if: github.repository_owner == 'upx' needs: [ job-rebuild-and-verify-stubs ] strategy: diff --git a/src/util/membuffer.cpp b/src/util/membuffer.cpp index a6d73850..ad9380dc 100644 --- a/src/util/membuffer.cpp +++ b/src/util/membuffer.cpp @@ -87,6 +87,7 @@ MemBuffer::~MemBuffer() noexcept { this->dealloc(); } // skip == offset, take == size_in_bytes void *MemBuffer::subref_impl(const char *errfmt, size_t skip, size_t take) { debug_set(debug.last_return_address_subref, upx_return_address()); + checkState(); // check overrun and wrap-around if (skip + take > size_in_bytes || skip + take < skip) { char buf[100]; @@ -134,13 +135,13 @@ void MemBuffer::allocForDecompression(unsigned uncompressed_size, unsigned extra debug_set(debug.last_return_address_alloc, upx_return_address()); } -void MemBuffer::fill(unsigned off, unsigned len, int value) { +void MemBuffer::fill(size_t off, size_t bytes, int value) { debug_set(debug.last_return_address_fill, upx_return_address()); checkState(); - if (off > size_in_bytes || len > size_in_bytes || off + len > size_in_bytes) + if (off > size_in_bytes || bytes > size_in_bytes || off + bytes > size_in_bytes) throwCantPack("MemBuffer::fill out of range; take care!"); - if (len > 0) - memset(ptr + off, value, len); + if (bytes > 0) + memset(ptr + off, value, bytes); } /************************************************************************* @@ -249,6 +250,17 @@ void MemBuffer::dealloc() noexcept { // **************************************************************************/ +TEST_CASE("MemBuffer unused 1") { + MemBuffer mb; + (void) mb; +} + +TEST_CASE("MemBuffer unused 2") { + MemBuffer mb; + CHECK(mb.raw_ptr() == nullptr); + CHECK(mb.raw_size_in_bytes() == 0); +} + TEST_CASE("MemBuffer core") { constexpr size_t N = 64; MemBuffer mb; @@ -292,62 +304,158 @@ TEST_CASE("MemBuffer core") { } TEST_CASE("MemBuffer global overloads") { - MemBuffer mb1(1); - MemBuffer mb4(4); - mb1.clear(); - mb4.clear(); - CHECK(memcmp(mb1, "\x00", 1) == 0); - CHECK_THROWS(memcmp(mb1, "\x00\x00", 2)); // NOLINT(bugprone-unused-return-value) - CHECK_THROWS(memcmp("\x00\x00", mb1, 2)); // NOLINT(bugprone-unused-return-value) - CHECK_THROWS(memcmp(mb1, mb4, 2)); // NOLINT(bugprone-unused-return-value) - CHECK_THROWS(memcmp(mb4, mb1, 2)); // NOLINT(bugprone-unused-return-value) - CHECK_NOTHROW(memset(mb1, 255, 1)); - CHECK_THROWS(memset(mb1, 254, 2)); - CHECK(mb1[0] == 255); + { + MemBuffer mb1(1); + MemBuffer mb4(4); + mb1.clear(); + mb4.clear(); + CHECK(memcmp(mb1, "\x00", 1) == 0); + CHECK_THROWS(memcmp(mb1, "\x00\x00", 2)); // NOLINT(bugprone-unused-return-value) + CHECK_THROWS(memcmp("\x00\x00", mb1, 2)); // NOLINT(bugprone-unused-return-value) + CHECK_THROWS(memcmp(mb1, mb4, 2)); // NOLINT(bugprone-unused-return-value) + CHECK_THROWS(memcmp(mb4, mb1, 2)); // NOLINT(bugprone-unused-return-value) + CHECK_NOTHROW(memset(mb1, 255, 1)); + CHECK_THROWS(memset(mb1, 254, 2)); + CHECK(mb1[0] == 255); + } - CHECK_THROWS(get_ne16(mb1)); - CHECK_THROWS(get_ne24(mb1)); - CHECK_THROWS(get_ne32(mb1)); - CHECK_THROWS(get_ne64(mb1)); - CHECK_THROWS(get_be16(mb1)); - CHECK_THROWS(get_be24(mb1)); - CHECK_THROWS(get_be32(mb1)); - CHECK_THROWS(get_be64(mb1)); - CHECK_THROWS(get_le16(mb1)); - CHECK_THROWS(get_le24(mb1)); - CHECK_THROWS(get_le32(mb1)); - CHECK_THROWS(get_le64(mb1)); - - CHECK_NOTHROW(get_ne16(mb4)); - CHECK_NOTHROW(get_ne24(mb4)); - CHECK_NOTHROW(get_ne32(mb4)); - CHECK_THROWS(get_ne64(mb4)); - CHECK_NOTHROW(get_be16(mb4)); - CHECK_NOTHROW(get_be24(mb4)); - CHECK_NOTHROW(get_be32(mb4)); - CHECK_THROWS(get_be64(mb4)); - CHECK_NOTHROW(get_le16(mb4)); - CHECK_NOTHROW(get_le24(mb4)); - CHECK_NOTHROW(get_le32(mb4)); - CHECK_THROWS(get_le64(mb4)); - - CHECK_NOTHROW(set_ne32(mb4, 0)); - CHECK_THROWS(set_ne64(mb4, 0)); - CHECK_NOTHROW(set_be32(mb4, 0)); - CHECK_THROWS(set_be64(mb4, 0)); - CHECK_NOTHROW(set_le32(mb4, 0)); - CHECK_THROWS(set_le64(mb4, 0)); -} - -TEST_CASE("MemBuffer unused 1") { - MemBuffer mb; - (void) mb; -} - -TEST_CASE("MemBuffer unused 2") { - MemBuffer mb; - CHECK(mb.raw_ptr() == nullptr); - CHECK(mb.raw_size_in_bytes() == 0); +#if DEBUG || 0 + for (size_t i = 1; i <= 16; i++) { + MemBuffer mb(i); + mb.clear(); + if (i < 2) { + CHECK_THROWS(get_ne16(mb)); + CHECK_THROWS(get_be16(mb)); + CHECK_THROWS(get_le16(mb)); + CHECK_THROWS(set_ne16(mb, 0)); + CHECK_THROWS(set_be16(mb, 0)); + CHECK_THROWS(set_le16(mb, 0)); + } else { + CHECK_NOTHROW(get_ne16(mb)); + CHECK_NOTHROW(get_be16(mb)); + CHECK_NOTHROW(get_le16(mb)); + CHECK_NOTHROW(set_ne16(mb, 0)); + CHECK_NOTHROW(set_be16(mb, 0)); + CHECK_NOTHROW(set_le16(mb, 0)); + } + if (i < 3) { + CHECK_THROWS(get_ne24(mb)); + CHECK_THROWS(get_be24(mb)); + CHECK_THROWS(get_le24(mb)); + CHECK_THROWS(set_ne24(mb, 0)); + CHECK_THROWS(set_be24(mb, 0)); + CHECK_THROWS(set_le24(mb, 0)); + } else { + CHECK_NOTHROW(get_ne24(mb)); + CHECK_NOTHROW(get_be24(mb)); + CHECK_NOTHROW(get_le24(mb)); + CHECK_NOTHROW(set_ne24(mb, 0)); + CHECK_NOTHROW(set_be24(mb, 0)); + CHECK_NOTHROW(set_le24(mb, 0)); + } + if (i < 4) { + CHECK_THROWS(get_ne32(mb)); + CHECK_THROWS(get_be32(mb)); + CHECK_THROWS(get_le32(mb)); + CHECK_THROWS(set_ne32(mb, 0)); + CHECK_THROWS(set_be32(mb, 0)); + CHECK_THROWS(set_le32(mb, 0)); + } else { + CHECK_NOTHROW(get_ne32(mb)); + CHECK_NOTHROW(get_be32(mb)); + CHECK_NOTHROW(get_le32(mb)); + CHECK_NOTHROW(set_ne32(mb, 0)); + CHECK_NOTHROW(set_be32(mb, 0)); + CHECK_NOTHROW(set_le32(mb, 0)); + } + if (i < 8) { + CHECK_THROWS(get_ne64(mb)); + CHECK_THROWS(get_be64(mb)); + CHECK_THROWS(get_le64(mb)); + CHECK_THROWS(set_ne64(mb, 0)); + CHECK_THROWS(set_be64(mb, 0)); + CHECK_THROWS(set_le64(mb, 0)); + } else { + CHECK_NOTHROW(get_ne64(mb)); + CHECK_NOTHROW(get_be64(mb)); + CHECK_NOTHROW(get_le64(mb)); + CHECK_NOTHROW(set_ne64(mb, 0)); + CHECK_NOTHROW(set_be64(mb, 0)); + CHECK_NOTHROW(set_le64(mb, 0)); + } + // + CHECK_NOTHROW(mb.subref("", 0, 0)); + CHECK_NOTHROW(mb.subref("", 0, i)); + CHECK_NOTHROW(mb.subref("", i, 0)); + CHECK_NOTHROW(mb.subref("", i - 1, 1)); + CHECK_THROWS(mb.subref("", 0, i + 1)); + CHECK_THROWS(mb.subref("", i + 1, 0)); + CHECK_THROWS(mb.subref("", i, 1)); + CHECK_THROWS(mb.subref("", (size_t) -1, 0)); + CHECK_THROWS(mb.subref("", (size_t) -1, i)); + // + if (i < 2) { + CHECK_THROWS(mb.subref("", 0, sizeof(NE16))); + CHECK_THROWS(mb.subref("", 0, sizeof(BE16))); + CHECK_THROWS(mb.subref("", 0, sizeof(LE16))); + } else { + CHECK_NOTHROW(mb.subref("", 0, sizeof(NE16))); + CHECK_NOTHROW(mb.subref("", 0, sizeof(BE16))); + CHECK_NOTHROW(mb.subref("", 0, sizeof(LE16))); + } + if (i < 4) { + CHECK_THROWS(mb.subref("", 0, sizeof(NE32))); + CHECK_THROWS(mb.subref("", 0, sizeof(BE32))); + CHECK_THROWS(mb.subref("", 0, sizeof(LE32))); + } else { + CHECK_NOTHROW(mb.subref("", 0, sizeof(NE32))); + CHECK_NOTHROW(mb.subref("", 0, sizeof(BE32))); + CHECK_NOTHROW(mb.subref("", 0, sizeof(LE32))); + } + if (i < 8) { + CHECK_THROWS(mb.subref("", 0, sizeof(NE64))); + CHECK_THROWS(mb.subref("", 0, sizeof(BE64))); + CHECK_THROWS(mb.subref("", 0, sizeof(LE64))); + } else { + CHECK_NOTHROW(mb.subref("", 0, sizeof(NE64))); + CHECK_NOTHROW(mb.subref("", 0, sizeof(BE64))); + CHECK_NOTHROW(mb.subref("", 0, sizeof(LE64))); + } + // + CHECK_NOTHROW(mb.subref_u("", 0)); + CHECK_NOTHROW(mb.subref_u("", i - 1)); + CHECK_THROWS(mb.subref_u("", i)); + CHECK_THROWS(mb.subref_u("", (size_t) -1)); + // + if (i < 2) { + CHECK_THROWS(mb.subref_u("", 0)); + CHECK_THROWS(mb.subref_u("", 0)); + CHECK_THROWS(mb.subref_u("", 0)); + } else { + CHECK_NOTHROW(mb.subref_u("", 0)); + CHECK_NOTHROW(mb.subref_u("", 0)); + CHECK_NOTHROW(mb.subref_u("", 0)); + } + if (i < 4) { + CHECK_THROWS(mb.subref_u("", 0)); + CHECK_THROWS(mb.subref_u("", 0)); + CHECK_THROWS(mb.subref_u("", 0)); + } else { + CHECK_NOTHROW(mb.subref_u("", 0)); + CHECK_NOTHROW(mb.subref_u("", 0)); + CHECK_NOTHROW(mb.subref_u("", 0)); + } + if (i < 8) { + CHECK_THROWS(mb.subref_u("", 0)); + CHECK_THROWS(mb.subref_u("", 0)); + CHECK_THROWS(mb.subref_u("", 0)); + } else { + CHECK_NOTHROW(mb.subref_u("", 0)); + CHECK_NOTHROW(mb.subref_u("", 0)); + CHECK_NOTHROW(mb.subref_u("", 0)); + } + } +#endif } TEST_CASE("MemBuffer array access") { diff --git a/src/util/membuffer.h b/src/util/membuffer.h index 26c791ea..58366659 100644 --- a/src/util/membuffer.h +++ b/src/util/membuffer.h @@ -41,9 +41,9 @@ public: typedef T element_type; typedef typename std::add_lvalue_reference::type reference; typedef typename std::add_pointer::type pointer; - typedef unsigned size_type; // limited by UPX_RSIZE_MAX typedef pointer iterator; typedef typename std::add_pointer::type const_iterator; + typedef unsigned size_type; // limited by UPX_RSIZE_MAX protected: static const size_t element_size = sizeof(element_type); @@ -194,11 +194,11 @@ public: static unsigned getSizeForDecompression(unsigned uncompressed_size, unsigned extra = 0) may_throw; - void alloc(upx_uint64_t bytes) may_throw; + noinline void alloc(upx_uint64_t bytes) may_throw; void allocForCompression(unsigned uncompressed_size, unsigned extra = 0) may_throw; void allocForDecompression(unsigned uncompressed_size, unsigned extra = 0) may_throw; - void dealloc() noexcept; + noinline void dealloc() noexcept; void checkState() const may_throw; // explicit conversion @@ -208,8 +208,8 @@ public: unsigned getSize() const noexcept { return size_in_bytes; } // note: element_size == 1 // util - noinline void fill(unsigned off, unsigned len, int value) may_throw; - forceinline void clear(unsigned off, unsigned len) may_throw { fill(off, len, 0); } + noinline void fill(size_t off, size_t bytes, int value) may_throw; + forceinline void clear(size_t off, size_t bytes) may_throw { fill(off, bytes, 0); } forceinline void clear() may_throw { fill(0, size_in_bytes, 0); } // If the entire range [skip, skip+take) is inside the buffer, @@ -219,9 +219,19 @@ public: forceinline pointer subref(const char *errfmt, size_t skip, size_t take) may_throw { return (pointer) subref_impl(errfmt, skip, take); } + template + forceinline U subref_u(const char *errfmt, size_t skip) may_throw { + COMPILE_TIME_ASSERT(std::is_pointer::value) + return (U) subref_impl(errfmt, skip, sizeof(typename std::remove_pointer::type)); + } + template + forceinline U subref_u(const char *errfmt, size_t skip, size_t take) may_throw { + COMPILE_TIME_ASSERT(std::is_pointer::value) + return (U) subref_impl(errfmt, skip, take); + } private: - void *subref_impl(const char *errfmt, size_t skip, size_t take) may_throw; + noinline void *subref_impl(const char *errfmt, size_t skip, size_t take) may_throw; // static debug stats struct Stats {