diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3a670a8..392d69d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -633,9 +633,9 @@ jobs: - { zig_target: x86_64-windows-gnu } name: ${{ format('zigcc {0} {1}', matrix.zig_target, matrix.zig_pic) }} runs-on: ubuntu-latest - container: ${{ matrix.container || 'alpine:3.22' }} + container: ${{ matrix.container || 'alpine:3.23' }} env: - container: ${{ matrix.container || 'alpine:3.22' }} + container: ${{ matrix.container || 'alpine:3.23' }} UPX_CONFIG_HAVE_WORKING_BUILD_RPATH: '' # for zig-cc wrapper scripts (see below): ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING diff --git a/misc/make/Makefile-extra.mk b/misc/make/Makefile-extra.mk index fda36ef5..a7afd9f9 100644 --- a/misc/make/Makefile-extra.mk +++ b/misc/make/Makefile-extra.mk @@ -378,7 +378,7 @@ UPX_CMAKE_CONFIG_FLAGS += $(call __add_cmake_config,UPX_CONFIG_EXTRA_COMPILE_OPT SUBMODULES = doctest lzma-sdk ucl valgrind zlib $(foreach 1,$(SUBMODULES),$(if $(wildcard vendor/$1/[CL]*),,\ - $(error ERROR: missing git submodule '$1'; run 'git submodule update --init'))) + $(error ERROR: missing git submodule '$1'; run 'git submodule update --init'))) endif # UPX_MAKEFILE_EXTRA_MK_INCLUDED diff --git a/src/check/dt_xspan.cpp b/src/check/dt_xspan.cpp index d9bffd47..c30ee408 100644 --- a/src/check/dt_xspan.cpp +++ b/src/check/dt_xspan.cpp @@ -878,7 +878,7 @@ TEST_CASE("PtrOrSpan int") { namespace { template -static noinline void check_bele(const T &mb, size_t i) { +static noinline void check_bele_a(const T &mb, size_t i) { if (i < 2) { CHECK_THROWS(get_ne16(mb)); CHECK_THROWS(get_be16(mb)); @@ -940,32 +940,95 @@ static noinline void check_bele(const T &mb, size_t i) { CHECK_NOTHROW(set_le64(mb, 0)); } } +template +static noinline void check_bele_c(const T &mb, size_t i) { + if (i < 2) { + CHECK_THROWS(get_ne16(mb)); + CHECK_THROWS(get_be16(mb)); + CHECK_THROWS(get_le16(mb)); + } else { + CHECK_NOTHROW(get_ne16(mb)); + CHECK_NOTHROW(get_be16(mb)); + CHECK_NOTHROW(get_le16(mb)); + } + if (i < 3) { + CHECK_THROWS(get_ne24(mb)); + CHECK_THROWS(get_be24(mb)); + CHECK_THROWS(get_le24(mb)); + } else { + CHECK_NOTHROW(get_ne24(mb)); + CHECK_NOTHROW(get_be24(mb)); + CHECK_NOTHROW(get_le24(mb)); + } + if (i < 4) { + CHECK_THROWS(get_ne32(mb)); + CHECK_THROWS(get_be32(mb)); + CHECK_THROWS(get_le32(mb)); + } else { + CHECK_NOTHROW(get_ne32(mb)); + CHECK_NOTHROW(get_be32(mb)); + CHECK_NOTHROW(get_le32(mb)); + } + if (i < 8) { + CHECK_THROWS(get_ne64(mb)); + CHECK_THROWS(get_be64(mb)); + CHECK_THROWS(get_le64(mb)); + } else { + CHECK_NOTHROW(get_ne64(mb)); + CHECK_NOTHROW(get_be64(mb)); + CHECK_NOTHROW(get_le64(mb)); + } +} } // namespace #endif // UPX_VERSION_HEX TEST_CASE("xspan global overloads") { - byte buf[16] = {}; + byte buf_a[16] = {}; + const byte buf_c[16] = {}; for (size_t i = 0; i < 16; i++) { - XSPAN_0_VAR(byte, a0, buf, i); - XSPAN_P_VAR(byte, ap, buf, i); - XSPAN_S_VAR(byte, as, buf, i); + XSPAN_0_VAR(byte, a0, buf_a, i); + XSPAN_P_VAR(byte, ap, buf_a, i); + XSPAN_S_VAR(byte, as, buf_a, i); + + XSPAN_0_VAR(const byte, c0, buf_c, i); + XSPAN_P_VAR(const byte, cp, buf_c, i); + XSPAN_S_VAR(const byte, cs, buf_c, i); #ifdef UPX_VERSION_HEX - check_bele(a0, i); - check_bele(ap, i); - check_bele(as, i); + check_bele_a(a0, i); + check_bele_a(ap, i); + check_bele_a(as, i); + + check_bele_c(c0, i); + check_bele_c(cp, i); + check_bele_c(cs, i); + CHECK_THROWS(upx_adler32(a0, i + 1)); CHECK_THROWS(upx_adler32(ap, i + 1)); CHECK_THROWS(upx_adler32(as, i + 1)); + CHECK_THROWS(upx_adler32(c0, i + 1)); + CHECK_THROWS(upx_adler32(cp, i + 1)); + CHECK_THROWS(upx_adler32(cs, i + 1)); + if (i == 0) { CHECK_THROWS(upx_safe_strlen(a0)); CHECK_THROWS(upx_safe_strlen(ap)); CHECK_THROWS(upx_safe_strlen(as)); + CHECK_THROWS(upx_safe_strlen(c0)); + CHECK_THROWS(upx_safe_strlen(cp)); + CHECK_THROWS(upx_safe_strlen(cs)); } #endif + CHECK_THROWS(memchr(a0, 0, i + 1)); // NOLINT(bugprone-unused-return-value) + CHECK_THROWS(memchr(ap, 0, i + 1)); // NOLINT(bugprone-unused-return-value) + CHECK_THROWS(memchr(as, 0, i + 1)); // NOLINT(bugprone-unused-return-value) + CHECK_THROWS(memchr(c0, 0, i + 1)); // NOLINT(bugprone-unused-return-value) + CHECK_THROWS(memchr(cp, 0, i + 1)); // NOLINT(bugprone-unused-return-value) + CHECK_THROWS(memchr(cs, 0, i + 1)); // NOLINT(bugprone-unused-return-value) + CHECK(memcmp(a0, a0, i) == 0); CHECK(memcmp(ap, a0, i) == 0); CHECK(memcmp(as, a0, i) == 0); @@ -973,6 +1036,20 @@ TEST_CASE("xspan global overloads") { CHECK_THROWS(memcmp(ap, a0, i + 1)); // NOLINT(bugprone-unused-return-value) CHECK_THROWS(memcmp(as, a0, i + 1)); // NOLINT(bugprone-unused-return-value) + CHECK_NOTHROW(memcpy(a0, c0, i)); + CHECK_NOTHROW(memcpy(ap, cp, i)); + CHECK_NOTHROW(memcpy(as, cs, i)); + CHECK_THROWS(memcpy(a0, c0, i + 1)); + CHECK_THROWS(memcpy(ap, cp, i + 1)); + CHECK_THROWS(memcpy(as, cs, i + 1)); + + CHECK_NOTHROW(memmove(a0, c0, i)); + CHECK_NOTHROW(memmove(ap, cp, i)); + CHECK_NOTHROW(memmove(as, cs, i)); + CHECK_THROWS(memmove(a0, c0, i + 1)); + CHECK_THROWS(memmove(ap, cp, i + 1)); + CHECK_THROWS(memmove(as, cs, i + 1)); + CHECK_NOTHROW(memset(a0, 255, i)); CHECK_NOTHROW(memset(ap, 255, i)); CHECK_NOTHROW(memset(as, 255, i)); diff --git a/src/conf.h b/src/conf.h index cdd0d6f8..06dab311 100644 --- a/src/conf.h +++ b/src/conf.h @@ -377,6 +377,7 @@ inline void NO_printf(const char *, ...) noexcept {} inline void NO_fprintf(FILE *, const char *, ...) noexcept attribute_format(2, 3); inline void NO_fprintf(FILE *, const char *, ...) noexcept {} +// upx_memcmp_inline #if __has_builtin(__builtin_memcmp) #define upx_memcmp_inline __builtin_memcmp #elif defined(__clang__) || defined(__GNUC__) @@ -384,6 +385,8 @@ inline void NO_fprintf(FILE *, const char *, ...) noexcept {} #else #define upx_memcmp_inline memcmp #endif + +// upx_memcpy_inline #if __has_builtin(__builtin_memcpy_inline) && 0 // TODO later: clang constexpr limitation? #define upx_memcpy_inline __builtin_memcpy_inline #elif __has_builtin(__builtin_memcpy) @@ -394,6 +397,7 @@ inline void NO_fprintf(FILE *, const char *, ...) noexcept {} #define upx_memcpy_inline memcpy #endif +// upx_return_address() #if defined(__wasi__) #define upx_return_address() nullptr #elif __has_builtin(__builtin_return_address) @@ -803,7 +807,8 @@ int upx_doctest_check(); // util/membuffer.h class MemBuffer; void *membuffer_get_void_ptr(MemBuffer &mb) noexcept; -unsigned membuffer_get_size_in_bytes(MemBuffer &mb) noexcept; +const void *membuffer_get_void_ptr(const MemBuffer &mb) noexcept; +unsigned membuffer_get_size_in_bytes(const MemBuffer &mb) noexcept; // main.cpp extern const char *progname; diff --git a/src/help.cpp b/src/help.cpp index e63e7a52..061ff6d7 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -49,7 +49,7 @@ const char gitrev[] = UPX_VERSION_GITREV; const char gitrev[1] = {0}; #endif -void show_header(void) { +void show_header() { FILE *f = con_term; int fg; @@ -85,7 +85,7 @@ void show_header(void) { // usage **************************************************************************/ -void show_usage(void) { +void show_usage() { FILE *f = con_term; con_fprintf(f, "Usage: %s [-123456789dlthVL] [-qvfk] [-o file] %sfile..\n", progname, @@ -381,7 +381,7 @@ void show_help(int verbose) { // license **************************************************************************/ -void show_license(void) { +void show_license() { FILE *f = con_term; show_header(); diff --git a/src/linker.cpp b/src/linker.cpp index 0a1b7648..b6a0fefd 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -367,6 +367,8 @@ int ElfLinker::addLoader(const char *sname) { return outputlen; char *begin = strdup(sname); + assert(begin != nullptr); + auto begin_deleter = upx::MallocDeleter(&begin, 1); char *end = begin + strlen(begin); for (char *sect = begin; sect < end;) { for (char *tokend = sect; *tokend; tokend++) @@ -418,7 +420,6 @@ int ElfLinker::addLoader(const char *sname) { } sect += strlen(sect) + 1; } - ::free(begin); return outputlen; } diff --git a/src/main.cpp b/src/main.cpp index 12fb3811..044e1deb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -67,12 +67,9 @@ static void handle_opterr(acc_getopt_p g, const char *f, void *v) { static int exit_code = EXIT_OK; #if (WITH_GUI) -static noinline void do_exit(void) { throw exit_code; } +static noreturn void do_exit() { throw exit_code; } #else -#if defined(__GNUC__) -static void do_exit(void) __attribute__((__noreturn__)); -#endif -static void do_exit(void) { +static noreturn void do_exit() { static bool in_exit = false; if (in_exit) @@ -115,7 +112,7 @@ static noinline void e_exit(int ec) { do_exit(); } -static noinline void e_usage(void) { +static noinline void e_usage() { if (opt->debug.getopt_throw_instead_of_exit) throw EXIT_USAGE; show_usage(); @@ -217,7 +214,7 @@ static void check_and_update_options(int i, int argc) { // misc **************************************************************************/ -static void e_help(void) { +static void e_help() { show_help(0); e_exit(EXIT_USAGE); } diff --git a/src/packer.h b/src/packer.h index d66f6665..f2169bc5 100644 --- a/src/packer.h +++ b/src/packer.h @@ -260,7 +260,7 @@ protected: // permissive version using "void *" inline unsigned get_te16(const void *p) const noexcept { return bele->get16(p); } inline unsigned get_te32(const void *p) const noexcept { return bele->get32(p); } - inline unsigned get_te64_32(const void *p) const { return (unsigned) bele->get64(p); } + inline unsigned get_te64_32(const void *p) const may_throw { return (unsigned) bele->get64(p); } inline upx_uint64_t get_te64(const void *p) const noexcept { return bele->get64(p); } inline void set_te16(void *p, unsigned v) noexcept { bele->set16(p, v); } inline void set_te32(void *p, unsigned v) noexcept { bele->set32(p, v); } @@ -293,7 +293,7 @@ protected: return bele->get32(p); } template > - inline unsigned get_te64_32(const T *p) const { + inline unsigned get_te64_32(const T *p) const may_throw { upx_uint64_t v = bele->get64(p); if ((v >> 32) != 0) throwCantPack("64-bit value too big %#llx", v); diff --git a/src/util/membuffer.cpp b/src/util/membuffer.cpp index 4af2ef57..28bd9224 100644 --- a/src/util/membuffer.cpp +++ b/src/util/membuffer.cpp @@ -33,7 +33,8 @@ // extra functions to reduce dependency on membuffer.h void *membuffer_get_void_ptr(MemBuffer &mb) noexcept { return mb.getVoidPtr(); } -unsigned membuffer_get_size_in_bytes(MemBuffer &mb) noexcept { return mb.getSizeInBytes(); } +const void *membuffer_get_void_ptr(const MemBuffer &mb) noexcept { return mb.getVoidPtr(); } +unsigned membuffer_get_size_in_bytes(const MemBuffer &mb) noexcept { return mb.getSizeInBytes(); } /*static*/ MemBuffer::Stats MemBuffer::stats; @@ -169,7 +170,7 @@ void MemBuffer::checkState() const may_throw { } } -void MemBuffer::alloc(upx_uint64_t bytes) may_throw { +void MemBuffer::alloc(const upx_uint64_t bytes) may_throw { // INFO: we don't automatically free a used buffer assert(ptr == nullptr); assert(size_in_bytes == 0); @@ -185,7 +186,7 @@ void MemBuffer::alloc(upx_uint64_t bytes) may_throw { NO_printf("MemBuffer::alloc %llu: %p\n", bytes, p); if (!p) throwOutOfMemoryException(); - size_in_bytes = ACC_ICONV(unsigned, bytes); + size_in_bytes = size_type(bytes); if (use_simple_mcheck()) { p += 16; // store magic constants to detect buffer overruns @@ -323,6 +324,7 @@ TEST_CASE("MemBuffer global overloads") { 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)); diff --git a/src/util/membuffer.h b/src/util/membuffer.h index 1a3f21f9..cb0f5377 100644 --- a/src/util/membuffer.h +++ b/src/util/membuffer.h @@ -62,7 +62,7 @@ public: // array access reference operator[](ptrdiff_t i) const may_throw { // NOTE: &array[SIZE] is *not* legal for containers like std::vector and MemBuffer ! - if very_unlikely (i < 0 || mem_size(element_size, i) + element_size > size_in_bytes) + if very_unlikely (i < 0 || mem_size(element_size, i) >= size_in_bytes) throwCantPack("MemBuffer invalid array index %td (%zu bytes)", i, size_in_bytes); return ptr[i]; } @@ -169,8 +169,8 @@ inline typename MemBufferBase::pointer raw_index_bytes(const MemBufferBase #define XSPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION(A, B, RType) \ typename std::enable_if::value, RType>::type #endif -#define C MemBufferBase #define XSPAN_FWD_C_IS_MEMBUFFER 1 +#define C MemBufferBase #if WITH_XSPAN >= 1 #define D XSPAN_NS(Ptr) #endif @@ -198,8 +198,8 @@ public: void allocForCompression(unsigned uncompressed_size, unsigned extra = 0) may_throw; void allocForDecompression(unsigned uncompressed_size, unsigned extra = 0) may_throw; - noinline void dealloc() noexcept; noinline void checkState() const may_throw; + noinline void dealloc() noexcept; // explicit conversion void *getVoidPtr() noexcept { return (void *) ptr; } diff --git a/src/util/util.h b/src/util/util.h index a9d7422a..e0627dd6 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -121,18 +121,17 @@ forceinline bool ptr_is_aligned(const void *p, size_t alignment) noexcept { // ptrdiff_t with nullptr checks and asserted size; will throw on failure // NOTE: returns size_in_bytes, not number of elements! -int ptr_diff_bytes(const void *a, const void *b) may_throw; -unsigned ptr_udiff_bytes(const void *a, const void *b) may_throw; // asserts a >= b +noinline int ptr_diff_bytes(const void *a, const void *b) may_throw; +noinline unsigned ptr_udiff_bytes(const void *a, const void *b) may_throw; // asserts a >= b // short names "ptr_diff" and "ptr_udiff" for types with sizeof(X) == 1 template -inline typename std::enable_if::type ptr_diff(const T *a, - const U *b) - may_throw { +forceinline typename std::enable_if::type +ptr_diff(const T *a, const U *b) may_throw { return ptr_diff_bytes(a, b); } template -inline typename std::enable_if::type +forceinline typename std::enable_if::type ptr_udiff(const T *a, const U *b) may_throw { return ptr_udiff_bytes(a, b); } @@ -229,7 +228,7 @@ bool maketempname(char *ofilename, size_t size, const char *ifilename, const cha bool force = true); bool makebakname(char *ofilename, size_t size, const char *ifilename, bool force = true); -bool is_envvar_true(const char *envvar, const char *alternate_name = nullptr) noexcept; +noinline bool is_envvar_true(const char *envvar, const char *alternate_name = nullptr) noexcept; unsigned get_ratio(upx_uint64_t u_len, upx_uint64_t c_len); bool set_method_name(char *buf, size_t size, int method, int level); diff --git a/src/util/xspan.cpp b/src/util/xspan.cpp index 6e1729c4..a6666afd 100644 --- a/src/util/xspan.cpp +++ b/src/util/xspan.cpp @@ -44,33 +44,33 @@ struct XSpanStats { static XSpanStats xspan_stats; // HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience -void xspan_fail_nullptr() { +void xspan_fail_nullptr() may_throw { xspan_stats.fail_nullptr += 1; throwCantPack("xspan unexpected NULL pointer; take care!"); } -void xspan_fail_nullbase() { +void xspan_fail_nullbase() may_throw { xspan_stats.fail_nullbase += 1; throwCantPack("xspan unexpected NULL base; take care!"); } -void xspan_fail_not_same_base() { +void xspan_fail_not_same_base() may_throw { xspan_stats.fail_not_same_base += 1; throwCantPack("xspan unexpected base pointer; take care!"); } -void xspan_fail_range_nullptr() { +void xspan_fail_range_nullptr() may_throw { xspan_stats.fail_range_nullptr += 1; throwCantPack("xspan_check_range: unexpected NULL pointer; take care!"); } -void xspan_fail_range_nullbase() { +void xspan_fail_range_nullbase() may_throw { xspan_stats.fail_range_nullbase += 1; throwCantPack("xspan_check_range: unexpected NULL base; take care!"); } -void xspan_fail_range_range() { +void xspan_fail_range_range() may_throw { xspan_stats.fail_range_range += 1; throwCantPack("xspan_check_range: pointer out of range; take care!"); } -void xspan_check_range(const void *ptr, const void *base, ptrdiff_t size_in_bytes) { +void xspan_check_range(const void *ptr, const void *base, ptrdiff_t size_in_bytes) may_throw { xspan_stats.check_range_counter += 1; if very_unlikely (ptr == nullptr) xspan_fail_range_nullptr();