diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50a88aa1..f0d7f41c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,8 +12,8 @@ env: CMAKE_REQUIRED_QUIET: OFF DEBIAN_FRONTEND: noninteractive UPX_CMAKE_BUILD_FLAGS: --verbose - # 2023-08-26 - ZIG_DIST_VERSION: 0.12.0-dev.170+750998eef + # 2023-08-31 + ZIG_DIST_VERSION: 0.12.0-dev.244+f4c9e19bc jobs: job-rebuild-and-verify-stubs: diff --git a/.github/workflows/weekly-ci-cc-zigcc.yml b/.github/workflows/weekly-ci-cc-zigcc.yml index 0875bde5..e2e2df71 100644 --- a/.github/workflows/weekly-ci-cc-zigcc.yml +++ b/.github/workflows/weekly-ci-cc-zigcc.yml @@ -10,8 +10,8 @@ on: env: CMAKE_REQUIRED_QUIET: OFF DEBIAN_FRONTEND: noninteractive - # 2023-08-26 - ZIG_DIST_VERSION: 0.12.0-dev.170+750998eef + # 2023-08-31 + ZIG_DIST_VERSION: 0.12.0-dev.244+f4c9e19bc jobs: job-linux-zigcc: # uses cmake + make diff --git a/misc/testsuite/upx_testsuite_1.sh b/misc/testsuite/upx_testsuite_1.sh index 4875abec..a75d0261 100755 --- a/misc/testsuite/upx_testsuite_1.sh +++ b/misc/testsuite/upx_testsuite_1.sh @@ -103,6 +103,7 @@ all_errors= export UPX="--prefer-ucl --no-color --no-progress" export UPX_DEBUG_DISABLE_GITREV_WARNING=1 export UPX_DEBUG_DOCTEST_VERBOSE=0 +export NO_COLOR=1 rm -rf ./testsuite_1 mkdir testsuite_1 || exit 1 diff --git a/src/bele.h b/src/bele.h index e0676dfa..ad9a492e 100644 --- a/src/bele.h +++ b/src/bele.h @@ -69,7 +69,7 @@ struct LE32; struct LE64; // Note: -// void is explicitly allowed, but there is no automatic pointer conversion because of template +// void is explicitly allowed (but there is no automatic pointer conversion because of template!) // char is explicitly allowed // byte is explicitly allowed template @@ -161,13 +161,19 @@ static forceinline upx_uint64_t bswap64(upx_uint64_t v) noexcept { return _bytes #else static forceinline constexpr unsigned bswap16(unsigned v) noexcept { +#if defined(__riscv) && __riscv_xlen == 64 + return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48); +#else // return __builtin_bswap16((upx_uint16_t) (v & 0xffff)); - // return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48); return __builtin_bswap32(v << 16); +#endif } static forceinline constexpr unsigned bswap32(unsigned v) noexcept { - // return (unsigned) __builtin_bswap64((upx_uint64_t) v << 32); +#if defined(__riscv) && __riscv_xlen == 64 + return (unsigned) __builtin_bswap64((upx_uint64_t) v << 32); +#else return __builtin_bswap32(v); +#endif } static forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) noexcept { return __builtin_bswap64(v); diff --git a/src/check/dt_check.cpp b/src/check/dt_check.cpp index 8f2251e3..fc4486d8 100644 --- a/src/check/dt_check.cpp +++ b/src/check/dt_check.cpp @@ -43,6 +43,8 @@ int upx_doctest_check(int argc, char **argv) { return 0; #else const char *e = getenv("UPX_DEBUG_DOCTEST_DISABLE"); + if (!e) + e = getenv("UPX_DEBUG_DISABLE_DOCTEST"); // allow alternate spelling if (e && e[0] && strcmp(e, "0") != 0) return 0; bool minimal = true; // don't show summary @@ -319,7 +321,7 @@ struct TestIntegerWrap { static inline bool neg_eq(const T x) noexcept { return T(0) - x == x; } }; -static noinline void throwSomeValue(int x) { +static noinline void throwSomeValue(int x) may_throw { if (x < 0) throw int(x); else @@ -346,6 +348,8 @@ static noinline void check_basic_cxx_exception_handling(void (*func)(int)) noexc void upx_compiler_sanity_check(void) noexcept { const char *e = getenv("UPX_DEBUG_DOCTEST_DISABLE"); + if (!e) + e = getenv("UPX_DEBUG_DISABLE_DOCTEST"); // allow alternate spelling if (e && e[0] && strcmp(e, "0") != 0) { // If UPX_DEBUG_DOCTEST_DISABLE is set then we don't want to throw any // exceptions in order to improve debugging experience. @@ -622,4 +626,36 @@ TEST_CASE("libc snprintf") { CHECK_EQ(strcmp(buf, "-7.0.0.0.0.0.0.0.7.0xffffffffffffffff"), 0); } +TEST_CASE("libc qsort") { + // runtime check that libc qsort() never compares identical objects + struct Elem { + upx_uint16_t id; + upx_uint16_t value; + static int compare(const void *aa, const void *bb) noexcept { + const Elem *a = (const Elem *) aa; + const Elem *b = (const Elem *) bb; + assert_noexcept(a->id != b->id); // check not IDENTICAL + return a->value < b->value ? -1 : (a->value == b->value ? 0 : 1); + } + static bool qsort_check(Elem *e, size_t n) { + upx_uint32_t x = n + 5381; + for (size_t i = 0; i < n; i++) { + e[i].id = (upx_uint16_t) i; + x = x * 33 + (i & 255); + e[i].value = (upx_uint16_t) x; + } + qsort(e, n, sizeof(*e), Elem::compare); + bool sorted_ok = true; + for (size_t i = 1; i < n; i++) + sorted_ok &= e[i - 1].value <= e[i].value; + return sorted_ok; + } + }; + + constexpr size_t N = 4096; + Elem e[N]; + for (size_t n = 1; n <= N; n <<= 1) + CHECK(Elem::qsort_check(e, n)); +} + /* vim:set ts=4 sw=4 et: */ diff --git a/src/except.h b/src/except.h index f8e59f1b..ac7fcd42 100644 --- a/src/except.h +++ b/src/except.h @@ -186,32 +186,32 @@ public: #define NORET noinline #endif -NORET void throwCantPack(const char *msg); -NORET void throwCantPackExact(); -NORET void throwUnknownExecutableFormat(const char *msg = nullptr, bool warn = false); -NORET void throwNotCompressible(const char *msg = nullptr); -NORET void throwAlreadyPacked(const char *msg = nullptr); -NORET void throwAlreadyPackedByUPX(const char *msg = nullptr); -NORET void throwCantUnpack(const char *msg); -NORET void throwNotPacked(const char *msg = nullptr); -NORET void throwFilterException(); -NORET void throwBadLoader(); -NORET void throwChecksumError(); -NORET void throwCompressedDataViolation(); -NORET void throwInternalError(const char *msg); -NORET void throwOutOfMemoryException(const char *msg = nullptr); -NORET void throwIOException(const char *msg = nullptr, int e = 0); -NORET void throwEOFException(const char *msg = nullptr, int e = 0); +NORET void throwCantPack(const char *msg) may_throw; +NORET void throwCantPackExact() may_throw; +NORET void throwUnknownExecutableFormat(const char *msg = nullptr, bool warn = false) may_throw; +NORET void throwNotCompressible(const char *msg = nullptr) may_throw; +NORET void throwAlreadyPacked(const char *msg = nullptr) may_throw; +NORET void throwAlreadyPackedByUPX(const char *msg = nullptr) may_throw; +NORET void throwCantUnpack(const char *msg) may_throw; +NORET void throwNotPacked(const char *msg = nullptr) may_throw; +NORET void throwFilterException() may_throw; +NORET void throwBadLoader() may_throw; +NORET void throwChecksumError() may_throw; +NORET void throwCompressedDataViolation() may_throw; +NORET void throwInternalError(const char *msg) may_throw; +NORET void throwOutOfMemoryException(const char *msg = nullptr) may_throw; +NORET void throwIOException(const char *msg = nullptr, int e = 0) may_throw; +NORET void throwEOFException(const char *msg = nullptr, int e = 0) may_throw; // some C++ template wizardry is needed to overload throwCantPack() for varargs template void throwCantPack(const T *, ...) DELETED_FUNCTION; template <> -NORET void throwCantPack(const char *format, ...) attribute_format(1, 2); +NORET void throwCantPack(const char *format, ...) may_throw attribute_format(1, 2); template void throwCantUnpack(const T *, ...) DELETED_FUNCTION; template <> -NORET void throwCantUnpack(const char *format, ...) attribute_format(1, 2); +NORET void throwCantUnpack(const char *format, ...) may_throw attribute_format(1, 2); #undef NORET diff --git a/src/p_vmlinx.cpp b/src/p_vmlinx.cpp index be5701a2..57170f50 100644 --- a/src/p_vmlinx.cpp +++ b/src/p_vmlinx.cpp @@ -1238,8 +1238,9 @@ Linker* PackVmlinuxAMD64::newLinker() const // instantiate instances -template class PackVmlinuxBase; template class PackVmlinuxBase; +// template class PackVmlinuxBase; // not used +template class PackVmlinuxBase; template class PackVmlinuxBase; /* vim:set ts=4 sw=4 et: */ diff --git a/src/packmast.cpp b/src/packmast.cpp index aee03e60..94b4f8a9 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -91,7 +91,7 @@ PackMaster::~PackMaster() noexcept { // **************************************************************************/ -static tribool try_can_pack(PackerBase *pb, void *user) may_throw { +static noinline tribool try_can_pack(PackerBase *pb, void *user) may_throw { InputFile *f = (InputFile *) user; try { pb->initPackHeader(); @@ -111,7 +111,7 @@ static tribool try_can_pack(PackerBase *pb, void *user) may_throw { return false; } -static tribool try_can_unpack(PackerBase *pb, void *user) may_throw { +static noinline tribool try_can_unpack(PackerBase *pb, void *user) may_throw { InputFile *f = (InputFile *) user; try { pb->initPackHeader(); diff --git a/src/packmast.h b/src/packmast.h index 1508b39c..36958227 100644 --- a/src/packmast.h +++ b/src/packmast.h @@ -40,11 +40,11 @@ public: explicit PackMaster(InputFile *f, Options *o = nullptr) noexcept; ~PackMaster() noexcept; - void pack(OutputFile *fo); - void unpack(OutputFile *fo); - void test(); - void list(); - void fileInfo(); + void pack(OutputFile *fo) may_throw; + void unpack(OutputFile *fo) may_throw; + void test() may_throw; + void list() may_throw; + void fileInfo() may_throw; typedef tribool (*visit_func_t)(PackerBase *pb, void *user); static PackerBase *visitAllPackers(visit_func_t, InputFile *f, const Options *, void *user) @@ -54,8 +54,8 @@ private: OwningPointer(PackerBase) packer = nullptr; // owner InputFile *const fi; // reference, required - static PackerBase *getPacker(InputFile *f); - static PackerBase *getUnpacker(InputFile *f); + static PackerBase *getPacker(InputFile *f) may_throw; + static PackerBase *getUnpacker(InputFile *f) may_throw; // setup local options for each file Options local_options; diff --git a/src/pefile.cpp b/src/pefile.cpp index f5e3ed71..0dd745be 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -704,8 +704,9 @@ class PeFile::ImportLinker final : public ElfLinkerAMD64 { if (rc != 0) return rc; // What could remain? + // make sort order deterministic assert_noexcept(a->sort_id != b->sort_id); - return a->sort_id < b->sort_id ? -1 : 1; // make sort order deterministic + return a->sort_id < b->sort_id ? -1 : 1; } virtual void alignCode(unsigned len) override { alignWithByte(len, 0); } diff --git a/src/util/xspan_impl.h b/src/util/xspan_impl.h index 2ddec6f6..ea3d3bbd 100644 --- a/src/util/xspan_impl.h +++ b/src/util/xspan_impl.h @@ -42,13 +42,13 @@ XSPAN_NAMESPACE_BEGIN // HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience -noinline void xspan_fail_nullptr(void); -noinline void xspan_fail_nullbase(void); -noinline void xspan_fail_not_same_base(void); -noinline void xspan_fail_range_nullptr(void); -noinline void xspan_fail_range_nullbase(void); -noinline void xspan_fail_range_range(void); -void xspan_check_range(const void *ptr, const void *base, ptrdiff_t size_in_bytes); +noinline void xspan_fail_nullptr(void) may_throw; +noinline void xspan_fail_nullbase(void) may_throw; +noinline void xspan_fail_not_same_base(void) may_throw; +noinline void xspan_fail_range_nullptr(void) may_throw; +noinline void xspan_fail_range_nullbase(void) may_throw; +noinline void xspan_fail_range_range(void) may_throw; +void xspan_check_range(const void *ptr, const void *base, ptrdiff_t size_in_bytes) may_throw; // help constructor to distinguish between number of elements and bytes struct XSpanCount {