diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 451a6f78..6d626df8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -455,8 +455,8 @@ jobs: - { zig_target: i386-linux-musl, qemu: qemu-i386 } # { zig_target: i386-linux-musl, qemu: qemu-i386, zig_pic: -fPIE } - { zig_target: i386-windows-gnu } - - { zig_target: mips-linux-musl } - - { zig_target: mipsel-linux-musl } + - { zig_target: mips-linux-musl } # TODO: qemu + - { zig_target: mipsel-linux-musl } # TODO: qemu - { zig_target: powerpc-linux-musl, qemu: qemu-ppc } - { zig_target: powerpc64-linux-musl, qemu: qemu-ppc64 } - { zig_target: powerpc64le-linux-musl, qemu: qemu-ppc64le } diff --git a/src/check/dt_cxxlib.cpp b/src/check/dt_cxxlib.cpp index 3657401f..bb3c435c 100644 --- a/src/check/dt_cxxlib.cpp +++ b/src/check/dt_cxxlib.cpp @@ -131,6 +131,7 @@ TEST_CASE("libc++") { CHECK(v.end() - v.begin() == N); CHECK(&v[0] == &(*(v.begin()))); // CHECK(&v[0] + N == &(*(v.end()))); // TODO later: is this legal?? + // TODO later #if defined(_LIBCPP_HARDENING_MODE_DEBUG) && \ (_LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG) CHECK_THROWS((void) &v[N]); @@ -259,6 +260,41 @@ struct Z2_X2 : public X2 { // util **************************************************************************/ +TEST_CASE("Deleter") { + LE16 *o = {}; // object + LE32 *a = {}; // array + { + const upx::ObjectDeleter o_deleter{&o, 1}; + o = new LE16; + assert(o != nullptr); + const upx::ArrayDeleter a_deleter{&a, 1}; + a = New(LE32, 1); + assert(a != nullptr); + } + assert(o == nullptr); + assert(a == nullptr); +} + +TEST_CASE("Deleter") { + constexpr size_t N = 2; + BE16 *o[N]; // multiple objects + BE32 *a[N]; // multiple arrays + { + upx::ObjectDeleter o_deleter{o, 0}; + upx::ArrayDeleter a_deleter{a, 0}; + for (size_t i = 0; i < N; i++) { + o[i] = new BE16; + o_deleter.count += 1; + a[i] = New(BE32, 1 + i); + a_deleter.count += 1; + } + } + for (size_t i = 0; i < N; i++) { + assert(o[i] == nullptr); + assert(a[i] == nullptr); + } +} + TEST_CASE("ptr_static_cast") { // check that we don't trigger any -Wcast-align warnings using upx::ptr_static_cast; diff --git a/src/compress/compress_bzip2.cpp b/src/compress/compress_bzip2.cpp index 23362e36..e170a380 100644 --- a/src/compress/compress_bzip2.cpp +++ b/src/compress/compress_bzip2.cpp @@ -24,6 +24,10 @@ */ +#include "../headers.h" +#if WITH_BZIP2 +#include +#endif #include "../conf.h" void bzip2_compress_config_t::reset() noexcept { mem_clear(this); } @@ -31,7 +35,6 @@ void bzip2_compress_config_t::reset() noexcept { mem_clear(this); } #if WITH_BZIP2 #include "compress.h" #include "../util/membuffer.h" -#include #if defined(BZ_NO_STDIO) || 1 // we need to supply bz_internal_error() when building with BZ_NO_STDIO diff --git a/src/compress/compress_zstd.cpp b/src/compress/compress_zstd.cpp index 82cd90e9..2de17f74 100644 --- a/src/compress/compress_zstd.cpp +++ b/src/compress/compress_zstd.cpp @@ -24,6 +24,12 @@ */ +#include "../headers.h" +#if WITH_ZSTD +#include +#include +#include +#endif #include "../conf.h" void zstd_compress_config_t::reset() noexcept { mem_clear(this); } @@ -31,9 +37,6 @@ void zstd_compress_config_t::reset() noexcept { mem_clear(this); } #if WITH_ZSTD #include "compress.h" #include "../util/membuffer.h" -#include -#include -#include static int convert_errno_from_zstd(size_t zr) { const ZSTD_ErrorCode ze = ZSTD_getErrorCode(zr); diff --git a/src/conf.h b/src/conf.h index a178be84..d84fbaa9 100644 --- a/src/conf.h +++ b/src/conf.h @@ -190,7 +190,7 @@ typedef upx_int64_t upx_off_t; #define unlikely __acc_unlikely #define very_likely __acc_very_likely #define very_unlikely __acc_very_unlikely -// cosmetic: explictly annotate some functions which may throw exceptions +// cosmetic: explicitly annotate some functions which may throw exceptions // note: noexcept(false) is the default for all C++ functions anyway #define may_throw noexcept(false) diff --git a/src/except.cpp b/src/except.cpp index ba04d749..00bb8951 100644 --- a/src/except.cpp +++ b/src/except.cpp @@ -41,8 +41,8 @@ Throwable::Throwable(const char *m, int e, bool w) noexcept : super(), msg = strdup(m); assert_noexcept(msg != nullptr); } - NO_fprintf(stderr, "construct exception: %zu %zu %s\n", stats.counter_current, - stats.counter_total, (const char *) msg); + NO_fprintf(stderr, "construct exception: %zu %zu %s\n", size_t(stats.counter_current), + size_t(stats.counter_total), (const char *) msg); stats.counter_current += 1; stats.counter_total += 1; } @@ -55,16 +55,16 @@ Throwable::Throwable(const Throwable &other) noexcept : super(other), msg = strdup(other.msg); assert_noexcept(msg != nullptr); } - NO_fprintf(stderr, "copy construct exception: %zu %zu %s\n", stats.counter_current, - stats.counter_total, (const char *) msg); + NO_fprintf(stderr, "copy construct exception: %zu %zu %s\n", size_t(stats.counter_current), + size_t(stats.counter_total), (const char *) msg); stats.counter_current += 1; stats.counter_total += 1; } Throwable::~Throwable() noexcept { stats.counter_current -= 1; - NO_fprintf(stderr, "destruct exception: %zu %zu %s\n", stats.counter_current, - stats.counter_total, (const char *) msg); + NO_fprintf(stderr, "destruct exception: %zu %zu %s\n", size_t(stats.counter_current), + size_t(stats.counter_total), (const char *) msg); upx::owner_free(msg); } diff --git a/src/headers.h b/src/headers.h index 3d2be561..84c65501 100644 --- a/src/headers.h +++ b/src/headers.h @@ -106,12 +106,14 @@ static_assert(sizeof(void *) == 8); #include #endif -// C++ system headers +// C++ freestanding headers #include #include #include #include - +#include +// C++ system headers +#include // std::unique_ptr // C++ multithreading (UPX currently does not use multithreading) #if __STDC_NO_ATOMICS__ #undef WITH_THREADS diff --git a/src/p_lx_elf.h b/src/p_lx_elf.h index 55b0ac9d..58723b5d 100644 --- a/src/p_lx_elf.h +++ b/src/p_lx_elf.h @@ -44,7 +44,7 @@ public: PackLinuxElf(InputFile *f); virtual ~PackLinuxElf(); /*virtual void buildLoader(const Filter *);*/ - virtual int getVersion() const override { return 14; } // upx-3.96 cannot upack, for instance + virtual int getVersion() const override { return 14; } // upx-3.96 cannot unpack, for instance virtual bool canUnpackVersion(int version) const override { return (version >= 11); } virtual tribool canUnpack() override { return super::canUnpack(); } // bool, except -1: format known, but not packed diff --git a/src/packmast.cpp b/src/packmast.cpp index d5046719..3b608558 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -25,8 +25,6 @@ */ -#include "headers.h" -#include // std::unique_ptr #include "conf.h" #include "file.h" #include "packmast.h" diff --git a/src/pefile.cpp b/src/pefile.cpp index cd7af70e..f6333f5b 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -282,19 +282,6 @@ void PeFile::Interval::dump() const { // relocation handling **************************************************************************/ -namespace { -struct FixDeleter final { // helper so we don't leak memory on exceptions - LE32 **fix; - size_t count; - ~FixDeleter() noexcept { - for (size_t i = 0; i < count; i++) { - delete[] fix[i]; - fix[i] = nullptr; - } - } -}; -} // namespace - void PeFile::Reloc::RelocationBlock::reset() noexcept { rel = nullptr; // SPAN_0 rel1 = nullptr; // SPAN_0 @@ -489,7 +476,7 @@ void PeFile32::processRelocs() // pass1 infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]); LE32 *fix[4]; - FixDeleter fixdel{fix, 0}; // don't leak memory + upx::ArrayDeleter fixdel{fix, 0}; // don't leak memory for (ic = 0; ic < 4; ic++) { fix[ic] = New(LE32, counts[ic]); fixdel.count += 1; @@ -591,7 +578,7 @@ void PeFile64::processRelocs() // pass1 infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]); LE32 *fix[16]; - FixDeleter fixdel{fix, 0}; // don't leak memory + upx::ArrayDeleter fixdel{fix, 0}; // don't leak memory for (ic = 0; ic < 16; ic++) { fix[ic] = New(LE32, counts[ic]); fixdel.count += 1; @@ -1919,11 +1906,14 @@ void PeFile::processResources(Resource *res) { SPAN_S_VAR(byte, ores, oresources + res->dirsize()); char *keep_icons = nullptr; // icon ids in the first icon group + upx::ArrayDeleter keep_icons_deleter{&keep_icons, 1}; // don't leak memory unsigned iconsin1stdir = 0; if (opt->win32_pe.compress_icons == 2) while (res->next()) // there is no rewind() in Resource if (res->itype() == RT_GROUP_ICON && iconsin1stdir == 0) { iconsin1stdir = get_le16(ibuf.subref("bad resoff %#x", res->offs() + 4, 2)); + delete[] keep_icons; + keep_icons = nullptr; keep_icons = New(char, 1 + iconsin1stdir * 9); *keep_icons = 0; for (unsigned ic = 0; ic < iconsin1stdir; ic++) @@ -2007,8 +1997,6 @@ void PeFile::processResources(Resource *res) { } soresources = ptr_diff_bytes(ores, oresources); - delete[] keep_icons; - keep_icons = nullptr; if (!res->clear()) { // The area occupied by the resource directory is not continuous // so to still support uncompression, I can't zero this area. diff --git a/src/util/cxxlib.h b/src/util/cxxlib.h index c4043942..55560b35 100644 --- a/src/util/cxxlib.h +++ b/src/util/cxxlib.h @@ -179,6 +179,38 @@ forceinline Result ptr_static_cast(const From *ptr) noexcept { return static_cast(static_cast(ptr)); } +// helper classes so we don't leak memory on exceptions +template // T is "Type **" +struct ObjectDeleter final { + static_assert(std::is_pointer_v); + static_assert(std::is_pointer_v >); + T items; // public + size_t count; // public + ~ObjectDeleter() noexcept { delete_items(); } + void delete_items() noexcept { + for (size_t i = 0; i < count; i++) { + auto item = items[i]; + items[i] = nullptr; + delete item; // single object delete + } + } +}; +template // T is "Type **" +struct ArrayDeleter final { + static_assert(std::is_pointer_v); + static_assert(std::is_pointer_v >); + T items; // public + size_t count; // public + ~ArrayDeleter() noexcept { delete_items(); } + void delete_items() noexcept { + for (size_t i = 0; i < count; i++) { + auto item = items[i]; + items[i] = nullptr; + delete[] item; // array delete + } + } +}; + class noncopyable { protected: forceinline constexpr noncopyable() noexcept {} diff --git a/src/util/xspan_impl_common.h b/src/util/xspan_impl_common.h index 9ca2aa7a..8d706980 100644 --- a/src/util/xspan_impl_common.h +++ b/src/util/xspan_impl_common.h @@ -457,7 +457,7 @@ public: // raw access // like C++20 std::span pointer data() const noexcept { return ptr; } pointer data(size_t bytes) const { return raw_bytes(bytes); } // UPX extra - size_type size() const noexcept { return size_bytes() / sizeof(element_type); } + size_type size() const { return size_bytes() / sizeof(element_type); } size_type size_bytes() const { assertInvariants(); if __acc_cte (!configRequirePtr && ptr == nullptr)