diff --git a/.gitattributes b/.gitattributes index 9b127bc2..451b824d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,6 +3,10 @@ # # HINT: check settings with # git ls-files | git check-attr --stdin --all +# git ls-files --eol + +# disable all line ending conversions +* -text # # tell diff tools that these files are generated automatically diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 510f1a86..6965c9f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,8 +16,9 @@ env: UPX_CMAKE_BUILD_FLAGS: --verbose UPX_CMAKE_CONFIG_FLAGS: -Wdev --warn-uninitialized UPX_DEBUG_TEST_FLOAT_DIVISION_BY_ZERO: 1 - # 2024-03-29 - ZIG_DIST_VERSION: 0.12.0-dev.3484+7aa42f47b + UPX_DEBUG_TEST_LIBC_QSORT: 1 + # 2024-04-01 + ZIG_DIST_VERSION: 0.12.0-dev.3508+a6ed3e6d2 jobs: job-rebuild-and-verify-stubs: @@ -183,7 +184,7 @@ jobs: job-macos-cmake: # uses cmake + make if: true needs: [ job-rebuild-and-verify-stubs ] - name: ${{ format('{0} {1}', matrix.os, matrix.xcode_version) }} + name: ${{ format('{0} {1}{2}', matrix.os, matrix.xcode_version && 'xcode-' || '', matrix.xcode_version) }} runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -193,8 +194,8 @@ jobs: # NOTE: macos-11 does not have "readlink -f"; only on macos >= 12 or with brew coreutils - { os: macos-11, gcc: gcc-10, gxx: 'g++-10', testsuite: true } - { os: macos-12, gcc: gcc-11, gxx: 'g++-11', testsuite: true } - - { os: macos-13, gcc: gcc-12, gxx: 'g++-12', testsuite: true, xcode_version: 14.3.1 } - { os: macos-13, testsuite: true } # use default Xcode-15 + - { os: macos-13, gcc: gcc-12, gxx: 'g++-12', testsuite: true, xcode_version: 14.3.1 } # { os: macos-14, gcc: gcc-13, gxx: 'g++-13', testsuite: true } # gcc-13: INTERNAL ERROR in ld64 # { os: macos-14, gcc: gcc-13, gxx: 'g++-13', testsuite: true, xcode_version: 14.3.1 } # gcc-13: MISSING HEADER FILES - { os: macos-14, gcc: gcc-12, gxx: 'g++-12', testsuite: true } # => use gcc-12 for now @@ -465,16 +466,18 @@ jobs: - { zig_target: aarch64-windows-gnu } - { zig_target: arm-linux-musleabihf, qemu: qemu-arm } # { zig_target: arm-linux-musleabihf, qemu: qemu-arm, zig_pic: -fPIE } - - { zig_target: i386-linux-musl, qemu: qemu-i386 } - # { zig_target: i386-linux-musl, qemu: qemu-i386, zig_pic: -fPIE } + - { zig_target: i386-linux-gnu.2.3.4, zig_flags: -march=i586 } + - { zig_target: i386-linux-musl, zig_flags: -march=i586, qemu: qemu-i386 } + # { zig_target: i386-linux-musl, zig_flags: -march=i586, qemu: qemu-i386, zig_pic: -fPIE } - { zig_target: i386-windows-gnu } # mips and mipsel: bad hard-float code generation(??); or QEMU bug; or UPX bug; see https://github.com/upx/upx/issues/788 - { zig_target: mips-linux-musl, zig_flags: -msoft-float, qemu: qemu-mips } - { zig_target: mipsel-linux-musl, zig_flags: -msoft-float, qemu: qemu-mipsel } - { zig_target: powerpc-linux-musl, qemu: qemu-ppc } - # powerpc64: obscure problem with C++ exceptions in doctest checks when *NOT* using -fstack-protector + # powerpc64: obscure problem with C++ exceptions in UPX doctest checks when *NOT* using -fstack-protector - { zig_target: powerpc64-linux-musl, zig_flags: -fstack-protector, qemu: qemu-ppc64 } - { zig_target: powerpc64le-linux-musl, qemu: qemu-ppc64le } + - { zig_target: x86_64-linux-gnu.2.3.4 } - { zig_target: x86_64-linux-musl, qemu: qemu-x86_64 } # { zig_target: x86_64-linux-musl, qemu: qemu-x86_64, zig_pic: -fPIE } # { zig_target: x86_64-macos-none } diff --git a/CMakeLists.txt b/CMakeLists.txt index b1cee4b7..8e890830 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -516,7 +516,7 @@ if(Threads_FOUND) elseif(UPX_CONFIG_REQUIRE_THREADS) message(FATAL_ERROR "ERROR: WITH_THREADS required") elseif(UPX_CONFIG_EXPECT_THREADS AND NOT UPX_CONFIG_DISABLE_THREADS) - message(FATAL_ERROR "ERROR: WITH_THREADS expected") + message(FATAL_ERROR "ERROR: WITH_THREADS expected; set UPX_CONFIG_EXPECT_THREADS=OFF to disable") endif() if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|None|Release)$") message(WARNING "WARNING: unsupported CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}; please use \"Debug\" or \"Release\"") diff --git a/misc/make/Makefile-extra.mk b/misc/make/Makefile-extra.mk index ce7b956a..9fc917c5 100644 --- a/misc/make/Makefile-extra.mk +++ b/misc/make/Makefile-extra.mk @@ -236,8 +236,8 @@ build/analyze/clang-tidy/debug build/analyze/clang-tidy/release: build/analyze/c build/analyze/clang-tidy/debug build/analyze/clang-tidy/release: build/analyze/clang-tidy-zstd/$$(notdir $$@) # OLD names [deprecated] -build/extra/scan-build/debug: build/analyze/clang-analyzer/debug -build/extra/scan-build/release: build/analyze/clang-analyzer/release +build/extra/scan-build/debug: build/analyze/clang-analyzer/debug PHONY +build/extra/scan-build/release: build/analyze/clang-analyzer/release PHONY #*********************************************************************** # advanced: generic eXtra target diff --git a/src/Makefile b/src/Makefile index c7ebc97a..630ebcc7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -33,10 +33,6 @@ debug+test release+test all+test: PHONY; $(MAKE) -C $(top_srcd test:: build/all+test PHONY -# OLD target names [deprecated] -$(top_srcdir)/build/debug: build/debug PHONY -$(top_srcdir)/build/release: build/release PHONY - #*********************************************************************** # make run-testsuite # git clone https://github.com/upx/upx-testsuite.git diff --git a/src/bele.h b/src/bele.h index 0e97a241..23f3299b 100644 --- a/src/bele.h +++ b/src/bele.h @@ -785,6 +785,26 @@ inline unsigned UPX_MIN(const LE32 &a, unsigned b) { return UPX_MIN(unsigned(a), // misc support **************************************************************************/ +// for use with qsort() +extern "C" { +int __acc_cdecl_qsort be16_compare(const void *, const void *); +int __acc_cdecl_qsort be24_compare(const void *, const void *); +int __acc_cdecl_qsort be32_compare(const void *, const void *); +int __acc_cdecl_qsort be64_compare(const void *, const void *); +int __acc_cdecl_qsort le16_compare(const void *, const void *); +int __acc_cdecl_qsort le24_compare(const void *, const void *); +int __acc_cdecl_qsort le32_compare(const void *, const void *); +int __acc_cdecl_qsort le64_compare(const void *, const void *); +int __acc_cdecl_qsort be16_compare_signed(const void *, const void *); +int __acc_cdecl_qsort be24_compare_signed(const void *, const void *); +int __acc_cdecl_qsort be32_compare_signed(const void *, const void *); +int __acc_cdecl_qsort be64_compare_signed(const void *, const void *); +int __acc_cdecl_qsort le16_compare_signed(const void *, const void *); +int __acc_cdecl_qsort le24_compare_signed(const void *, const void *); +int __acc_cdecl_qsort le32_compare_signed(const void *, const void *); +int __acc_cdecl_qsort le64_compare_signed(const void *, const void *); +} // extern "C" + // upx_is_integral; see conf.h #define TT_UPX_IS_INTEGRAL(T) \ template <> \ @@ -826,26 +846,6 @@ typedef LE64 NE64; #define ne64_compare_signed le64_compare_signed #endif -// for use with qsort() -extern "C" { -int __acc_cdecl_qsort be16_compare(const void *, const void *); -int __acc_cdecl_qsort be24_compare(const void *, const void *); -int __acc_cdecl_qsort be32_compare(const void *, const void *); -int __acc_cdecl_qsort be64_compare(const void *, const void *); -int __acc_cdecl_qsort le16_compare(const void *, const void *); -int __acc_cdecl_qsort le24_compare(const void *, const void *); -int __acc_cdecl_qsort le32_compare(const void *, const void *); -int __acc_cdecl_qsort le64_compare(const void *, const void *); -int __acc_cdecl_qsort be16_compare_signed(const void *, const void *); -int __acc_cdecl_qsort be24_compare_signed(const void *, const void *); -int __acc_cdecl_qsort be32_compare_signed(const void *, const void *); -int __acc_cdecl_qsort be64_compare_signed(const void *, const void *); -int __acc_cdecl_qsort le16_compare_signed(const void *, const void *); -int __acc_cdecl_qsort le24_compare_signed(const void *, const void *); -int __acc_cdecl_qsort le32_compare_signed(const void *, const void *); -int __acc_cdecl_qsort le64_compare_signed(const void *, const void *); -} // extern "C" - /************************************************************************* // Provide namespaces and classes to abstract endianness policies. // diff --git a/src/bele_policy.h b/src/bele_policy.h index b3b36e19..f03f8d07 100644 --- a/src/bele_policy.h +++ b/src/bele_policy.h @@ -92,9 +92,9 @@ private: #define C const noexcept override #endif -struct BEPolicy +struct BEPolicy final #if defined(BELE_RTP) - final : public AbstractPolicy + : public AbstractPolicy #endif { explicit inline BEPolicy() noexcept {} @@ -151,9 +151,9 @@ private: UPX_CXX_DISABLE_NEW_DELETE(BEPolicy) }; -struct LEPolicy +struct LEPolicy final #if defined(BELE_RTP) - final : public AbstractPolicy + : public AbstractPolicy #endif { explicit inline LEPolicy() noexcept {} diff --git a/src/check/dt_check.cpp b/src/check/dt_check.cpp index 6c47409a..bc001a66 100644 --- a/src/check/dt_check.cpp +++ b/src/check/dt_check.cpp @@ -24,6 +24,9 @@ */ +// doctest checks, and various tests to catch toolchain/qemu/sanitizer/valgrind/wine/etc +// problems; grown historically + #include "../util/system_headers.h" #include // std::isinf std::isnan #include "../conf.h" @@ -376,6 +379,7 @@ struct TestFloat { static noinline Float add_div_x(Int a, Int b) { return Float(a + b) / Float(X); } static noinline Float sub_div_x(Int a, Int b) { return Float(a - b) / Float(X); } static noinline void check() noexcept { + assert_noexcept(div(2 * X, Float(X)) == Float(2)); assert_noexcept(add_div(X, X, Float(X)) == Float(2)); assert_noexcept(add_div_x(X, X) == Float(2)); assert_noexcept(sub_div(3 * X, X, Float(X)) == Float(2)); @@ -391,6 +395,7 @@ struct TestFloat { #else assert_noexcept(std::isnan(div(0, Float(0)))); assert_noexcept(std::isinf(div(1, Float(0)))); + assert_noexcept(std::isinf(div(Int(-1), Float(0)))); #endif } } @@ -432,6 +437,19 @@ void upx_compiler_sanity_check(void) noexcept { check_basic_floating_point(); + // check_basic_decltype() + { + auto a = +0; + constexpr auto b = -0; + const auto &c = -1; + COMPILE_TIME_ASSERT((std::is_same::value)) + COMPILE_TIME_ASSERT((std::is_same::value)) + COMPILE_TIME_ASSERT((std::is_same::value)) + UNUSED(a); + UNUSED(b); + UNUSED(c); + } + #define ACC_WANT_ACC_CHK_CH 1 #undef ACCCHK_ASSERT #define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT(expr) @@ -646,7 +664,7 @@ void upx_compiler_sanity_check(void) noexcept { **************************************************************************/ TEST_CASE("assert_noexcept") { - // just to make sure that our own assert() macros don't generate any warnings + // just to make sure that our own assert() macros do not trigger any compiler warnings byte dummy = 0; byte *ptr1 = &dummy; const byte *const ptr2 = &dummy; @@ -668,10 +686,13 @@ TEST_CASE("acc_vget") { CHECK_EQ(acc_vget_long(1, -1), 1); CHECK_EQ(acc_vget_acc_int64l_t(2, 1), 2); CHECK_EQ(acc_vget_acc_hvoid_p(nullptr, 0), nullptr); + if (acc_vget_int(1, 0) > 0) + return; + assert_noexcept(false); } TEST_CASE("ptr_invalidate_and_poison") { - int *ip = nullptr; + int *ip = nullptr; // initialized ptr_invalidate_and_poison(ip); assert(ip != nullptr); (void) ip; @@ -751,11 +772,13 @@ TEST_CASE("libc snprintf") { CHECK_EQ(strcmp(buf, "0X1A 0x1b 0x1c "), 0); } -#if 0 TEST_CASE("libc qsort") { // runtime check that libc qsort() never compares identical objects - // UPDATE: while only poor implementations of qsort() would actually do - // this, it is probably allowed by the standard; so skip this test case + // UPDATE: while only poor implementations of qsort() would actually do this + // it is probably allowed by the standard, so skip this test by default + if (!is_envvar_true("UPX_DEBUG_TEST_LIBC_QSORT")) + return; + struct Elem { upx_uint16_t id; upx_uint16_t value; @@ -765,8 +788,8 @@ TEST_CASE("libc qsort") { assert_noexcept(a->id != b->id); // check not IDENTICAL return a->value < b->value ? -1 : (a->value == b->value ? 0 : 1); } - static bool check_sort(upx_sort_func_t sort, Elem *e, size_t n) { - upx_uint32_t x = 5381 + n + ((upx_uintptr_t) e & 0xff); + static noinline bool check_sort(upx_sort_func_t sort, Elem *e, size_t n) { + upx_uint32_t x = 5381 + n + (upx_rand() & 0xff); for (size_t i = 0; i < n; i++) { e[i].id = (upx_uint16_t) i; x = x * 33 + 1 + (i & 255); @@ -782,18 +805,19 @@ TEST_CASE("libc qsort") { constexpr size_t N = 4096; Elem e[N]; for (size_t n = 0; n <= N; n = 2 * n + 1) { - // CHECK(Elem::check_sort(qsort, e, n)); // libc qsort() - CHECK(Elem::check_sort(upx_gnomesort, e, n)); - CHECK(Elem::check_sort(upx_shellsort_memswap, e, n)); - CHECK(Elem::check_sort(upx_shellsort_memcpy, e, n)); + // system sort functions + CHECK(Elem::check_sort(::qsort, e, n)); // libc qsort() #if UPX_CONFIG_USE_STABLE_SORT upx_sort_func_t wrap_stable_sort = [](void *aa, size_t nn, size_t, upx_compare_func_t cc) { upx_std_stable_sort(aa, nn, cc); }; - CHECK(Elem::check_sort(wrap_stable_sort, e, n)); + CHECK(Elem::check_sort(wrap_stable_sort, e, n)); // std::stable_sort() #endif + // UPX sort functions + CHECK(Elem::check_sort(upx_gnomesort, e, n)); + CHECK(Elem::check_sort(upx_shellsort_memswap, e, n)); + CHECK(Elem::check_sort(upx_shellsort_memcpy, e, n)); } } -#endif /* vim:set ts=4 sw=4 et: */ diff --git a/src/check/dt_cxxlib.cpp b/src/check/dt_cxxlib.cpp index c4ba68b8..15b3426b 100644 --- a/src/check/dt_cxxlib.cpp +++ b/src/check/dt_cxxlib.cpp @@ -27,24 +27,8 @@ // lots of tests (and probably quite a number of redundant tests) // modern compilers will optimize away much of this code -#if 0 // TODO later -// libc++ hardenining -#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ + 0 >= 18) -#if DEBUG -#define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEBUG -#else -#define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_EXTENSIVE -#endif -#endif -#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ + 0 < 18) -#if DEBUG -#define _LIBCPP_ENABLE_ASSERTIONS 1 -#endif -#endif -#endif // TODO later - #include "../util/system_headers.h" -#include +#include // std::vector #include "../conf.h" /************************************************************************* @@ -125,7 +109,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_le("abc", "abz")) // **************************************************************************/ -TEST_CASE("libc++") { +TEST_CASE("std::vector") { constexpr size_t N = 16; std::vector v(N); CHECK(v.end() - v.begin() == N); @@ -298,7 +282,7 @@ TEST_CASE("upx::ObjectDeleter 2") { } TEST_CASE("upx::ptr_static_cast") { - // check that we don't trigger any -Wcast-align warnings + // check that we do not trigger any -Wcast-align warnings using upx::ptr_static_cast; void *vp = nullptr; byte *bp = nullptr; diff --git a/src/conf.h b/src/conf.h index 70f3422a..44521979 100644 --- a/src/conf.h +++ b/src/conf.h @@ -162,7 +162,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(upx_charptr_unit_type) == 1) typedef upx_int64_t upx_off_t; #undef off_t #if 0 -// TODO cleanup: at some future point we can do this: +// TODO later cleanup: at some future point we can do this: #define off_t DO_NOT_USE_off_t #else #define off_t upx_off_t @@ -230,12 +230,6 @@ typedef upx_int64_t upx_off_t; #undef sopen #endif -#if defined(HAVE_DUP) && (HAVE_DUP + 0 == 0) -// TODO later: add upx_fd_dup() util -#undef dup -#define dup(x) (-1) -#endif - #ifndef STDIN_FILENO #define STDIN_FILENO (fileno(stdin)) #endif @@ -338,7 +332,7 @@ typedef upx_int64_t upx_off_t; // TODO later: check __MINGW_PRINTF_FORMAT #if defined(_WIN32) && defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__) #define attribute_format(a, b) __attribute__((__format__(__gnu_printf__, a, b))) -#elif (ACC_CC_CLANG || ACC_CC_GNUC) +#elif defined(__clang__) || defined(__GNUC__) #define attribute_format(a, b) __attribute__((__format__(__printf__, a, b))) #else #define attribute_format(a, b) /*empty*/ @@ -442,6 +436,7 @@ inline void mem_clear(T *object) noexcept { static_assert(size >= 1 && size <= UPX_RSIZE_MAX_MEM); memset((void *) object, 0, size); } +// disable some overloads #if defined(__clang__) || __GNUC__ != 7 template inline void mem_clear(T (&array)[]) noexcept DELETED_FUNCTION; diff --git a/src/except.cpp b/src/except.cpp index 00bb8951..acf8d0c9 100644 --- a/src/except.cpp +++ b/src/except.cpp @@ -203,7 +203,7 @@ const char *prettyName(const char *n) noexcept { n++; else if (*n == ' ') n++; - else if (strncmp(n, "class ", 6) == 0) // Visual C++ (msvc) + else if (strncmp(n, "class ", 6) == 0) // Visual C++ (MSVC) n += 6; else break; diff --git a/src/file.cpp b/src/file.cpp index 735378e8..2cfc9026 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -40,6 +40,7 @@ #else UNUSED(name); UNUSED(mode); + // no error #endif } @@ -88,7 +89,7 @@ bool FileBase::do_sopen() { else { #if (ACC_OS_DOS32) && defined(__DJGPP__) _fd = ::open(_name, _flags | _shflags, _mode); -#elif defined(__MINT__) +#elif (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__) _fd = ::open(_name, _flags | (_shflags & O_SHMODE), _mode); #elif defined(SH_DENYRW) _fd = ::sopen(_name, _flags, _shflags, _mode); @@ -98,6 +99,7 @@ bool FileBase::do_sopen() { } if (_fd < 0) return false; + st.st_size = 0; if (::fstat(_fd, &st) != 0) throwIOException(_name, errno); _length = st.st_size; @@ -212,6 +214,20 @@ upx_off_t InputFile::seek(upx_off_t off, int whence) { upx_off_t InputFile::st_size_orig() const { return _length_orig; } +int InputFile::dup() may_throw { + if (!isOpen()) + throwIOException("bad dup"); +#if defined(HAVE_DUP) && (HAVE_DUP + 0 == 0) + errno = ENOSYS; + int r = -1; +#else + int r = ::dup(getFd()); +#endif + if (r < 0) + throwIOException("dup", errno); + return r; +} + /************************************************************************* // OutputFile **************************************************************************/ @@ -333,6 +349,7 @@ void OutputFile::set_extent(upx_off_t offset, upx_off_t length) { super::set_extent(offset, length); bytes_written = 0; if (0 == offset && 0xffffffffLL == length) { // TODO: check all callers of this method + st.st_size = 0; if (::fstat(_fd, &st) != 0) throwIOException(_name, errno); _length = st.st_size - offset; diff --git a/src/file.h b/src/file.h index 435b5ba3..cca45e92 100644 --- a/src/file.h +++ b/src/file.h @@ -88,6 +88,8 @@ public: virtual upx_off_t seek(upx_off_t off, int whence) override; upx_off_t st_size_orig() const; + noinline int dup() may_throw; + protected: upx_off_t _length_orig = 0; }; diff --git a/src/linker.cpp b/src/linker.cpp index 7775569e..4a8efaa4 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -60,7 +60,7 @@ ElfLinker::Section::Section(const char *n, const void *i, unsigned s, unsigned a : name(nullptr), output(nullptr), size(s), offset(0), p2align(a), next(nullptr) { name = strdup(n); assert(name != nullptr); - input = malloc(s + 1); + input = ::malloc(s + 1); assert(input != nullptr); if (s != 0) { assert(i != nullptr); @@ -70,8 +70,8 @@ ElfLinker::Section::Section(const char *n, const void *i, unsigned s, unsigned a } ElfLinker::Section::~Section() noexcept { - free(name); - free(input); + ::free(name); + ::free(input); } /************************************************************************* @@ -85,7 +85,7 @@ ElfLinker::Symbol::Symbol(const char *n, Section *s, upx_uint64_t o) assert(section != nullptr); } -ElfLinker::Symbol::~Symbol() noexcept { free(name); } +ElfLinker::Symbol::~Symbol() noexcept { ::free(name); } /************************************************************************* // Relocation @@ -110,13 +110,13 @@ ElfLinker::~ElfLinker() noexcept { unsigned ic; for (ic = 0; ic < nsections; ic++) delete sections[ic]; - free(sections); + ::free(sections); for (ic = 0; ic < nsymbols; ic++) delete symbols[ic]; - free(symbols); + ::free(symbols); for (ic = 0; ic < nrelocations; ic++) delete relocations[ic]; - free(relocations); + ::free(relocations); } void ElfLinker::init(const void *pdata_v, int plen, unsigned pxtra) { @@ -425,7 +425,7 @@ int ElfLinker::addLoader(const char *sname) { } sect += strlen(sect) + 1; } - free(begin); + ::free(begin); return outputlen; } diff --git a/src/main.cpp b/src/main.cpp index 9f99ba12..069fc9bb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -923,7 +923,7 @@ int main_get_options(int argc, char **argv) { // atari/tos {"split-segments", 0x90, N, 650}, // darwin/macho - {"force-macos", 0x90, N, 690}, // undocumented temporary until we fix macOS 13+ + {"force-macos", 0x90, N, 690}, // undocumented temporary option until we do fix macOS 13+ // djgpp2/coff {"coff", 0x90, N, 610}, // produce COFF output // dos/exe @@ -1355,9 +1355,9 @@ int __acc_cdecl_main main(int argc, char *argv[]) /*noexcept*/ { #endif acc_wildargv(&argc, &argv); #if defined(__wasi__) - srand((int) time(nullptr)); + ::srand((unsigned) time(nullptr)); #else - srand((int) clock()); + ::srand((unsigned) clock()); #endif // info: main() is implicitly "noexcept", so we need a try block diff --git a/src/options.h b/src/options.h index a01d6398..65709620 100644 --- a/src/options.h +++ b/src/options.h @@ -28,9 +28,10 @@ #pragma once struct Options; -extern Options *opt; // global options, see class PackMaster for per-file local options #define options_t Options // old name +extern Options *opt; // global options, see class PackMaster for per-file local options + #if WITH_THREADS extern std::mutex opt_lock_mutex; #endif @@ -177,6 +178,9 @@ struct Options final { int strip_relocs; const char *keep_resource; } win32_pe; + +private: // UPX conventions + UPX_CXX_DISABLE_NEW_DELETE(Options) }; /* vim:set ts=4 sw=4 et: */ diff --git a/src/p_vmlinz.cpp b/src/p_vmlinz.cpp index 7123967d..62aec6e8 100644 --- a/src/p_vmlinz.cpp +++ b/src/p_vmlinz.cpp @@ -267,7 +267,7 @@ int PackVmlinuzI386::decompressKernel() fd_pos = -1; // open fi->seek(gzoff, SEEK_SET); - fd = dup(fi->getFd()); + fd = fi->dup(); if (fd < 0) break; gzFile zf = gzdopen(fd, "rb"); @@ -849,7 +849,7 @@ int PackVmlinuzARMEL::decompressKernel() fd_pos = -1; // open fi->seek(gzoff, SEEK_SET); - fd = dup(fi->getFd()); + fd = fi->dup(); if (fd < 0) break; gzFile zf = gzdopen(fd, "rb"); diff --git a/src/p_wcle.cpp b/src/p_wcle.cpp index ab7c9bbc..54cb0c23 100644 --- a/src/p_wcle.cpp +++ b/src/p_wcle.cpp @@ -743,6 +743,7 @@ tribool PackWcle::canUnpack() { return readPackHeader(len) ? 1 : -1; } +/*static*/ void PackWcle::virt2rela(const le_object_table_entry_t *entr, unsigned *objn, unsigned *addr) { for (; *objn > 1; objn[0]--) { if (entr[*objn - 1].my_base_address > *addr) diff --git a/src/packer.cpp b/src/packer.cpp index 30f729e7..795503ef 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -495,7 +495,7 @@ unsigned Packer::getRandomId() const { #endif id ^= (unsigned) fi->st.st_ino; id ^= (unsigned) fi->st.st_atime; - id ^= (unsigned) rand(); + id ^= (unsigned) upx_rand(); } return id; } @@ -947,7 +947,7 @@ int Packer::prepareMethods(int *methods, int ph_method, const int *all_methods) } // debug if (opt->debug.use_random_method && nmethods >= 2) { - int method = methods[rand() % nmethods]; + int method = methods[upx_rand() % nmethods]; methods[0] = method; nmethods = 1; NO_printf("\nuse_random_method = %d\n", method); @@ -1015,7 +1015,7 @@ done: filters[nfilters++] = 0; // debug if (opt->debug.use_random_filter && nfilters >= 3 && filters[nfilters - 1] == 0) { - int filter_id = filters[rand() % (nfilters - 1)]; + int filter_id = filters[upx_rand() % (nfilters - 1)]; if (filter_id > 0) { filters[0] = filter_id; filters[1] = 0; diff --git a/src/packhead.h b/src/packhead.h index bf97f612..dd8d137b 100644 --- a/src/packhead.h +++ b/src/packhead.h @@ -84,10 +84,14 @@ struct PackHeader final { // info fields set by Packer::compressWithFilters() unsigned overlap_overhead; + +private: // UPX conventions + UPX_CXX_DISABLE_ADDRESS(PackHeader) + UPX_CXX_DISABLE_NEW_DELETE(PackHeader) }; /************************************************************************* -// ph default util functions +// PackHeader ph util functions **************************************************************************/ bool ph_is_forced_method(int method) noexcept; // predicate diff --git a/src/packmast.h b/src/packmast.h index d47ad01d..98337e12 100644 --- a/src/packmast.h +++ b/src/packmast.h @@ -59,6 +59,11 @@ private: // setup local options for each file Options local_options; Options *saved_opt = nullptr; + +private: // UPX conventions + UPX_CXX_DISABLE_ADDRESS(PackMaster) + UPX_CXX_DISABLE_COPY_MOVE(PackMaster) + UPX_CXX_DISABLE_NEW_DELETE(PackMaster) }; /* vim:set ts=4 sw=4 et: */ diff --git a/src/pefile.cpp b/src/pefile.cpp index 0144a88f..b161ed20 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -215,7 +215,7 @@ int PeFile::readFileHeader() { PeFile::Interval::Interval(SPAN_P(byte) b) : base(b) {} -PeFile::Interval::~Interval() noexcept { free(ivarr); } +PeFile::Interval::~Interval() noexcept { ::free(ivarr); } int __acc_cdecl_qsort PeFile::Interval::compare(const void *p1, const void *p2) { const interval *i1 = (const interval *) p1; @@ -1175,14 +1175,14 @@ PeFile::Export::Export(char *_base) : base(_base), iv((byte *) _base) { } PeFile::Export::~Export() noexcept { - free(ename); + ::free(ename); delete[] functionptrs; delete[] ordinals; if (names) { const unsigned limit = edir.names + edir.functions; for (unsigned ic = 0; ic < limit; ic++) if (names[ic]) - free(names[ic]); // allocated by strdup() + ::free(names[ic]); // allocated by strdup() delete[] names; } } diff --git a/src/ui.h b/src/ui.h index 51407636..e41b2289 100644 --- a/src/ui.h +++ b/src/ui.h @@ -104,6 +104,10 @@ protected: static unsigned update_u_len; static unsigned update_fc_len; static unsigned update_fu_len; + +private: // UPX conventions + UPX_CXX_DISABLE_ADDRESS(UiPacker) + UPX_CXX_DISABLE_COPY_MOVE(UiPacker) }; /* vim:set ts=4 sw=4 et: */ diff --git a/src/util/cxxlib.h b/src/util/cxxlib.h index 6cd85f01..2b88b5cf 100644 --- a/src/util/cxxlib.h +++ b/src/util/cxxlib.h @@ -427,7 +427,7 @@ template inline void owner_free(OwningPointer(T)(&object)) noexcept { static_assert(!std::is_class_v); // UPX convention if (object != nullptr) { - free((T *) object); + ::free((T *) object); object = nullptr; } assert_noexcept((T *) object == nullptr); diff --git a/src/util/snprintf.cpp b/src/util/snprintf.cpp index 22085bf2..81d4d938 100644 --- a/src/util/snprintf.cpp +++ b/src/util/snprintf.cpp @@ -128,7 +128,7 @@ int upx_safe_vasprintf(char **ptr, const char *format, va_list ap) { va_end(ap_copy); if (len >= 0) { - *ptr = (char *) malloc(len + 1); + *ptr = (char *) ::malloc(len + 1); assert(*ptr != nullptr); if (*ptr == nullptr) return -1; diff --git a/src/util/system_features.h b/src/util/system_features.h index 1b2bc864..b8233a1f 100644 --- a/src/util/system_features.h +++ b/src/util/system_features.h @@ -55,7 +55,7 @@ #if DEBUG #define _LIBCPP_ENABLE_ASSERTIONS 1 #endif -#endif +#endif // clang >= 18 #endif // TODO later /* vim:set ts=4 sw=4 et: */ diff --git a/src/util/util.cpp b/src/util/util.cpp index 34d6eb6e..7644e771 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -254,17 +254,19 @@ TEST_CASE("ptr_check_no_overlap 3") { // stdlib **************************************************************************/ +int upx_rand(void) noexcept { return ::rand(); } + void *upx_calloc(size_t n, size_t element_size) may_throw { size_t bytes = mem_size(element_size, n); // assert size - void *p = malloc(bytes); + void *p = ::malloc(bytes); if (p != nullptr) memset(p, 0, bytes); return p; } // simple unoptimized memswap() -void upx_memswap(void *a, void *b, size_t n) noexcept { - if (a != b && n != 0) { +void upx_memswap(void *a, void *b, size_t bytes) noexcept { + if (a != b && bytes != 0) { byte *x = (byte *) a; byte *y = (byte *) b; do { @@ -273,16 +275,16 @@ void upx_memswap(void *a, void *b, size_t n) noexcept { byte tmp = *x; // NOLINT(*core.uninitialized.Assign) // bogus clang-analyzer warning *x++ = *y; *y++ = tmp; - } while (--n != 0); + } while (--bytes != 0); } } // much better memswap(), optimized for our use case in sort functions below -static void memswap_no_overlap(byte *a, byte *b, size_t n) noexcept { +static inline void memswap_no_overlap(byte *a, byte *b, size_t bytes) noexcept { #if defined(__clang__) && __clang_major__ < 15 // work around a clang < 15 ICE (Internal Compiler Error) // @COMPILER_BUG @CLANG_BUG - upx_memswap(a, b, n); + upx_memswap(a, b, bytes); #else // clang bug upx_alignas_max byte tmp_buf[16]; #define SWAP(x) \ @@ -294,15 +296,15 @@ static void memswap_no_overlap(byte *a, byte *b, size_t n) noexcept { b += x; \ } while (0) - for (; n >= 16; n -= 16) + for (; bytes >= 16; bytes -= 16) SWAP(16); - if (n & 8) + if (bytes & 8) SWAP(8); - if (n & 4) + if (bytes & 4) SWAP(4); - if (n & 2) + if (bytes & 2) SWAP(2); - if (n & 1) { + if (bytes & 1) { byte tmp = *a; *a = *b; *b = tmp; @@ -347,7 +349,7 @@ void upx_shellsort_memcpy(void *array, size_t n, size_t element_size, upx_compar upx_alignas_max byte tmp_buf[MAX_INLINE_ELEMENT_SIZE]; // buffer for one element byte *tmp = tmp_buf; if (element_size > MAX_INLINE_ELEMENT_SIZE) { - tmp = (byte *) malloc(element_size); + tmp = (byte *) ::malloc(element_size); assert(tmp != nullptr); } size_t gap = 0; // 0, 1, 4, 13, 40, 121, 364, 1093, ... @@ -368,7 +370,7 @@ void upx_shellsort_memcpy(void *array, size_t n, size_t element_size, upx_compar } } if (element_size > MAX_INLINE_ELEMENT_SIZE) - free(tmp); + ::free(tmp); } // wrap std::stable_sort() @@ -391,9 +393,10 @@ void upx_std_stable_sort(void *array, size_t n, upx_compare_func_t compare) { } #if UPX_CONFIG_USE_STABLE_SORT -// instantiate function templates for all element sizes we need; efficient run time, but code size -// bloat (about 4KiB code size for each function with my current libstdc++); not really needed as -// libc qsort() is good enough for our use cases +// instantiate function templates for all element sizes we need; efficient +// run-time, but code size bloat (about 4KiB code size for each function +// with my current libstdc++); not really needed as libc qsort() is +// good enough for our use cases template void upx_std_stable_sort<1>(void *, size_t, upx_compare_func_t); template void upx_std_stable_sort<2>(void *, size_t, upx_compare_func_t); template void upx_std_stable_sort<4>(void *, size_t, upx_compare_func_t); @@ -405,7 +408,7 @@ template void upx_std_stable_sort<56>(void *, size_t, upx_compare_func_t); template void upx_std_stable_sort<72>(void *, size_t, upx_compare_func_t); #endif -#if !defined(DOCTEST_CONFIG_DISABLE) && DEBUG >= 1 +#if !defined(DOCTEST_CONFIG_DISABLE) && DEBUG #if __cplusplus >= 202002L // use C++20 std::next_permutation() to test all permutations namespace { template @@ -588,7 +591,7 @@ int find(const void *buf, int blen, const void *what, int wlen) noexcept { return -1; const byte *b = (const byte *) buf; - byte first_byte = *(const byte *) what; + const byte first_byte = *(const byte *) what; blen -= wlen; for (int i = 0; i <= blen; i++, b++) @@ -769,8 +772,8 @@ int fn_strcmp(const char *n1, const char *n2) { // misc **************************************************************************/ +// UPX convention: any environment variable that is set and is not strictly equal to "0" is true bool is_envvar_true(const char *envvar, const char *alternate_name) noexcept { - // UPX convention: any environment variable that is set and is not strictly equal to "0" is true const char *e = getenv(envvar); if (e != nullptr && e[0]) return strcmp(e, "0") != 0; diff --git a/src/util/util.h b/src/util/util.h index 26d8bc4b..adf183c8 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -143,9 +143,11 @@ inline void ptr_invalidate_and_poison(T *(&ptr)) noexcept { // stdlib **************************************************************************/ -void *upx_calloc(size_t n, size_t element_size) may_throw; +noinline void *upx_calloc(size_t n, size_t element_size) may_throw; -void upx_memswap(void *a, void *b, size_t n) noexcept; +void upx_memswap(void *a, void *b, size_t bytes) noexcept; + +noinline int upx_rand(void) noexcept; typedef int(__acc_cdecl_qsort *upx_compare_func_t)(const void *, const void *); typedef void (*upx_sort_func_t)(void *array, size_t n, size_t element_size, upx_compare_func_t); @@ -165,7 +167,7 @@ void upx_std_stable_sort(void *array, size_t n, upx_compare_func_t compare); upx_std_stable_sort<(element_size)>((a), (n), (compare)) #else // use libc qsort(); good enough for our use cases -#define upx_qsort qsort +#define upx_qsort ::qsort #endif /************************************************************************* diff --git a/src/work.cpp b/src/work.cpp index 9bed93b2..3f4bf6c1 100644 --- a/src/work.cpp +++ b/src/work.cpp @@ -30,7 +30,7 @@ // of class PackerBase which then does the actual work. // And see p_com.cpp for a simple executable format. // -// This file also has the burden to deal with all those pesky low-level +// And this file also has the burden to deal with all those pesky low-level // file handling issues. #define WANT_WINDOWS_LEAN_H 1 // _get_osfhandle, GetFileTime, SetFileTime @@ -47,7 +47,7 @@ #include "util/membuffer.h" #if USE_UTIMENSAT && defined(AT_FDCWD) -#elif (defined(_WIN32) || defined(__CYGWIN__)) && 1 +#elif defined(_WIN32) || defined(__CYGWIN__) #define USE_SETFILETIME 1 #elif (ACC_OS_DOS32) && defined(__DJGPP__) #define USE_FTIME 1