From e6336942554239f6a0d6ba7def7c70bd07b08673 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Thu, 20 Apr 2023 20:10:12 +0200 Subject: [PATCH 1/3] cmake: use MSVC_FRONTEND --- CMakeLists.txt | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef193f9c..724de2ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,11 @@ elseif(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE) endif() +set(MSVC_FRONTEND 0) +if(MSVC OR ",${CMAKE_C_COMPILER_FRONTEND_VARIANT}," STREQUAL ",MSVC,") + set(MSVC_FRONTEND 1) +endif() + #*********************************************************************** # targets #*********************************************************************** @@ -166,14 +171,14 @@ if(NOT MSVC) set(CMAKE_CXX_FLAGS_RELEASE "${b}" CACHE STRING "Flags used by the CXX compiler during RELEASE builds." FORCE) endif() -if(MSVC) +if(MSVC_FRONTEND) # disable silly warnings about using "deprecated" POSIX functions like fopen() add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) add_definitions(-D_CRT_NONSTDC_NO_WARNINGS) add_definitions(-D_CRT_SECURE_NO_DEPRECATE) add_definitions(-D_CRT_SECURE_NO_WARNINGS) # set __cplusplus according to selected C++ standard; use new preprocessor - add_definitions(-Zc:__cplusplus -Zc:preprocessor) + add_definitions(-J -Zc:__cplusplus -Zc:preprocessor) else() # protect against security threats caused by misguided compiler "optimizations" if(CMAKE_C_COMPILER_ID STREQUAL "GNU") @@ -186,7 +191,7 @@ endif() # compile a target with -O2 even in Debug build function(upx_compile_target_debug_with_O2 t) - if(MSVC) + if(MSVC_FRONTEND) # MSVC uses some Debug compile options like -RTC1 that are incompatible with -O2 else() target_compile_options(${t} PRIVATE $<$:-O2>) @@ -195,7 +200,7 @@ endfunction() function(upx_sanitize_target t) if(NOT UPX_CONFIG_DISABLE_SANITIZE) - if(MSVC) + if(MSVC_FRONTEND) # MSVC uses -GS (similar to -fstack-protector) by default elseif(CMAKE_C_PLATFORM_ID MATCHES "^MinGW" OR MINGW OR CYGWIN) # avoid link errors with current MinGW-w64 versions @@ -213,8 +218,8 @@ set(t upx_vendor_ucl) target_include_directories(${t} PRIVATE vendor/ucl/include vendor/ucl) upx_compile_target_debug_with_O2(${t}) upx_sanitize_target(${t}) -if(MSVC) - target_compile_options(${t} PRIVATE -J ${warn_WN} ${warn_WX}) +if(MSVC_FRONTEND) + target_compile_options(${t} PRIVATE ${warn_WN} ${warn_WX}) else() target_compile_options(${t} PRIVATE ${warn_Wall} ${warn_Werror}) endif() @@ -223,8 +228,8 @@ set(t upx_vendor_zlib) upx_compile_target_debug_with_O2(${t}) upx_sanitize_target(${t}) target_compile_definitions(${t} PRIVATE HAVE_STDARG_H=1 HAVE_VSNPRINTF=1) -if(MSVC) - target_compile_options(${t} PRIVATE -J -W3 ${warn_WX}) +if(MSVC_FRONTEND) + target_compile_options(${t} PRIVATE -W3 ${warn_WX}) else() target_compile_definitions(${t} PRIVATE HAVE_UNISTD_H=1) # clang-15: -Wno-strict-prototypes is needed to silence the new -Wdeprecated-non-prototype warning @@ -237,8 +242,8 @@ set(t upx_vendor_zstd) upx_compile_target_debug_with_O2(${t}) upx_sanitize_target(${t}) target_compile_definitions(${t} PRIVATE DYNAMIC_BMI2=0 ZSTD_DISABLE_ASM=1) -if(MSVC) - target_compile_options(${t} PRIVATE -J ${warn_WN} ${warn_WX}) +if(MSVC_FRONTEND) + target_compile_options(${t} PRIVATE ${warn_WN} ${warn_WX}) else() target_compile_options(${t} PRIVATE ${warn_Wall} ${warn_Werror}) endif() @@ -267,8 +272,8 @@ if(NOT UPX_CONFIG_DISABLE_ZSTD) endif() #upx_compile_target_debug_with_O2(${t}) upx_sanitize_target(${t}) -if(MSVC) - target_compile_options(${t} PRIVATE -EHsc -J ${warn_WN} ${warn_WX}) +if(MSVC_FRONTEND) + target_compile_options(${t} PRIVATE -EHsc ${warn_WN} ${warn_WX}) else() target_compile_options(${t} PRIVATE ${warn_Wall} ${warn_Werror}) endif() From c03b382d613afed1954d66c472fa7384ff0ca316 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Thu, 20 Apr 2023 20:58:19 +0200 Subject: [PATCH 2/3] src: some more "noexcept" --- src/conf.h | 4 ++-- src/util/membuffer.cpp | 10 +++++----- src/util/membuffer.h | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/conf.h b/src/conf.h index b4360508..dd4f0c0a 100644 --- a/src/conf.h +++ b/src/conf.h @@ -774,8 +774,8 @@ class Throwable; // util/membuffer.h class MemBuffer; -void *membuffer_get_void_ptr(MemBuffer &mb); -unsigned membuffer_get_size(MemBuffer &mb); +void *membuffer_get_void_ptr(MemBuffer &mb) noexcept; +unsigned membuffer_get_size(MemBuffer &mb) noexcept; // util/dt_check.cpp void upx_compiler_sanity_check(); diff --git a/src/util/membuffer.cpp b/src/util/membuffer.cpp index 933d0616..1da7ca5e 100644 --- a/src/util/membuffer.cpp +++ b/src/util/membuffer.cpp @@ -29,8 +29,8 @@ #include "membuffer.h" // extra functions to reduce dependency on membuffer.h -void *membuffer_get_void_ptr(MemBuffer &mb) { return mb.getVoidPtr(); } -unsigned membuffer_get_size(MemBuffer &mb) { return mb.getSize(); } +void *membuffer_get_void_ptr(MemBuffer &mb) noexcept { return mb.getVoidPtr(); } +unsigned membuffer_get_size(MemBuffer &mb) noexcept { return mb.getSize(); } /*static*/ MemBuffer::Stats MemBuffer::stats; @@ -45,7 +45,7 @@ unsigned membuffer_get_size(MemBuffer &mb) { return mb.getSize(); } **************************************************************************/ #if defined(__SANITIZE_ADDRESS__) -static forceinline constexpr bool use_simple_mcheck() { return false; } +static forceinline constexpr bool use_simple_mcheck() noexcept { return false; } #elif (WITH_VALGRIND) && defined(RUNNING_ON_VALGRIND) static bool use_simple_mcheck_flag; static noinline void init_use_simple_mcheck() noexcept { @@ -56,13 +56,13 @@ static noinline void init_use_simple_mcheck() noexcept { } use_simple_mcheck_flag = r; } -static bool use_simple_mcheck() { +static bool use_simple_mcheck() noexcept { static upx_std_once_flag init_done; upx_std_call_once(init_done, init_use_simple_mcheck); return use_simple_mcheck_flag; } #else -static forceinline constexpr bool use_simple_mcheck() { return true; } +static forceinline constexpr bool use_simple_mcheck() noexcept { return true; } #endif /************************************************************************* diff --git a/src/util/membuffer.h b/src/util/membuffer.h index da2e6f29..895b9bba 100644 --- a/src/util/membuffer.h +++ b/src/util/membuffer.h @@ -96,11 +96,11 @@ public: void dealloc() noexcept; void checkState() const; - unsigned getSize() const { return size_in_bytes; } + unsigned getSize() const noexcept { return size_in_bytes; } // explicit conversion - void *getVoidPtr() { return (void *) ptr; } - const void *getVoidPtr() const { return (const void *) ptr; } + void *getVoidPtr() noexcept { return (void *) ptr; } + const void *getVoidPtr() const noexcept { return (const void *) ptr; } // util void fill(unsigned off, unsigned len, int value); From 726f5de778db165c1980a3f13d3c5b96b79540c2 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Wed, 26 Apr 2023 08:13:32 +0200 Subject: [PATCH 3/3] src: minor cleanups --- .github/workflows/ci.yml | 4 +- src/check/dt_check.cpp | 19 +++++++-- src/conf.h | 10 +---- src/except.h | 1 + src/main.cpp | 5 +-- src/packer.h | 20 +++++----- src/util/util.cpp | 86 +++++++++++++++++++++++++--------------- 7 files changed, 86 insertions(+), 59 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b78fd510..0abab908 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -377,8 +377,8 @@ jobs: - { zig_target: x86_64-macos.13-none } - { zig_target: x86_64-windows-gnu } env: - # 2023-04-17 - ZIG_DIST_VERSION: 0.11.0-dev.2624+bc804eb84 + # 2023-04-24 + ZIG_DIST_VERSION: 0.11.0-dev.2777+b95cdf0ae # for zig-cc wrapper scripts (see below): ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING ZIG_FLAGS: ${{ matrix.zig_flags }} diff --git a/src/check/dt_check.cpp b/src/check/dt_check.cpp index cf268f3c..a999cbee 100644 --- a/src/check/dt_check.cpp +++ b/src/check/dt_check.cpp @@ -165,6 +165,12 @@ template struct CheckIntegral { template static void checkU(void) { + U a = {}; + const U b = {}; + constexpr U c = {}; + UNUSED(a); + UNUSED(b); + UNUSED(c); #if __cplusplus < 202002L COMPILE_TIME_ASSERT(std::is_pod::value) // deprecated in C++20 #endif @@ -217,15 +223,18 @@ struct TestBELE { static noinline bool test(void) { CheckIntegral::check(); CheckAlignment::check(); + // array init + T array[2] = {}; + assert(array[0] == 0 && array[1] == 0); // arithmetic checks (modern compilers will optimize this away) - T allbits; - allbits = 0; + T allbits = {}; + assert(allbits == 0); allbits += 1; allbits -= 2; T v1; v1 = 1; - v1 *= 2; - v1 /= 1; + v1 *= 4; + v1 /= 2; v1 -= 1; T v2; v2 = 1; @@ -251,6 +260,8 @@ struct TestBELE { v2 &= v1; v2 /= v1; v2 *= v1; + v1 += v2; + v1 -= v2; assert(v1 == 1); assert(v2 == 0); if ((v1 ^ v2) != 1) diff --git a/src/conf.h b/src/conf.h index dd4f0c0a..711a3659 100644 --- a/src/conf.h +++ b/src/conf.h @@ -65,14 +65,8 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char // 51:32: error: zero as null pointer constant # pragma GCC diagnostic error "-Wzero-as-null-pointer-constant" #endif -#if (ACC_CC_MSC) -# pragma warning(error: 4127) -# pragma warning(error: 4146) -# pragma warning(error: 4319) -# pragma warning(error: 4805) -#endif -#endif // UPX_CONFIG_DISABLE_WSTRICT #endif // UPX_CONFIG_DISABLE_WERROR +#endif // UPX_CONFIG_DISABLE_WSTRICT // multithreading (UPX currently does not use multithreading) #if (WITH_THREADS) @@ -346,7 +340,7 @@ inline void NO_fprintf(FILE *, const char *, ...) {} # define upx_return_address() nullptr #endif -// TODO cleanup: we now require C++14, so remove all __packed_struct usage +// TODO cleanup: we now require C++17, so remove all __packed_struct usage #define __packed_struct(s) struct alignas(1) s { #define __packed_struct_end() }; diff --git a/src/except.h b/src/except.h index 5fc8cb2a..7713ba05 100644 --- a/src/except.h +++ b/src/except.h @@ -211,6 +211,7 @@ 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); +// some C++ template wizardry is needed to overload throwCantPack() for varargs template void throwCantPack(const T *, ...) = delete; template <> diff --git a/src/main.cpp b/src/main.cpp index b0c99961..0a749df1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,9 +28,8 @@ // main entry, mostly boring stuff; see work.cpp for actual action #include "conf.h" -#include "file.h" -#include "packer.h" -#include "p_elf.h" +#include "packer.h" // Packer::isValidCompressionMethod() +#include "p_elf.h" // ELFOSABI_xxx #include "compress/compress.h" // upx_ucl_init() /************************************************************************* diff --git a/src/packer.h b/src/packer.h index 0102df0c..9c36cda3 100644 --- a/src/packer.h +++ b/src/packer.h @@ -278,8 +278,16 @@ protected: unsigned image_size, int bits, bool bswap); // Target Endianness abstraction -#if 1 - // try to detect TE16 vs TE32 vs TE64 size mismatches; note that "byte" is explicitly allowed +#if 0 + // 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 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); } + inline void set_te64(void *p, upx_uint64_t v) noexcept { bele->set64(p, v); } +#else + // try to detect TE16 vs TE32 vs TE64 size mismatches; note that byte is explicitly allowed template static inline constexpr bool is_te16_type = is_same_any_v; template @@ -312,14 +320,6 @@ protected: inline void set_te64(T *p, upx_uint64_t v) noexcept { bele->set64(p, v); } -#else - // 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 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); } - inline void set_te64(void *p, upx_uint64_t v) noexcept { bele->set64(p, v); } #endif protected: diff --git a/src/util/util.cpp b/src/util/util.cpp index cd21c0ce..7c19324f 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -247,20 +247,6 @@ TEST_CASE("ptr_check_no_overlap 3") { } #endif // DEBUG -/************************************************************************* -// bele.h -**************************************************************************/ - -namespace N_BELE_CTP { -const BEPolicy be_policy; -const LEPolicy le_policy; -} // namespace N_BELE_CTP - -namespace N_BELE_RTP { -const BEPolicy be_policy; -const LEPolicy le_policy; -} // namespace N_BELE_RTP - /************************************************************************* // stdlib **************************************************************************/ @@ -312,25 +298,47 @@ TEST_CASE("upx_stable_sort") { CHECK((a[0] == 0 && a[1] == 1)); } { - LE64 a[3]; - a[0] = 2; - a[1] = 1; - a[2] = 0; - upx_stable_sort(a, 3, sizeof(*a), le64_compare); - CHECK((a[0] == 0 && a[1] == 1 && a[2] == 2)); + BE64 a[3]; + a[0] = 257; + a[1] = 256; + a[2] = 255; + upx_stable_sort(a, 3, sizeof(*a), be64_compare); + CHECK((a[0] == 255 && a[1] == 256 && a[2] == 257)); } -#if __cplusplus >= 202002L // use C++20 std::next_permutation() to test all permutations - { - upx_uint16_t perm[5] = {0, 1, 2, 3, 4}; // 120 permutations - do { - upx_uint16_t a[5] = {}; - memcpy(a, perm, sizeof(perm)); - upx_stable_sort(a, 5, sizeof(*a), ne16_compare); - CHECK((a[0] == 0 && a[1] == 1 && a[2] == 2 && a[3] == 3 && a[4] == 4)); - } while (std::next_permutation(perm, perm + 5)); - } -#endif } + +#if __cplusplus >= 202002L // use C++20 std::next_permutation() to test all permutations +namespace { +struct TestSortAllPermutations { + static upx_uint64_t test(size_t n) { + constexpr size_t N = 16; + assert(n > 0 && n <= N); + LE16 perm[N]; + for (size_t i = 0; i < n; i++) + perm[i] = 255 + i; + upx_uint64_t num_perms = 0; + do { + LE16 a[N]; + memcpy(a, perm, sizeof(*a) * n); + upx_stable_sort(a, n, sizeof(*a), le16_compare); + for (size_t i = 0; i < n; i++) + CHECK((a[i] == 255 + i)); + num_perms += 1; + } while (std::next_permutation(perm, perm + n)); + return num_perms; + } +}; +} // namespace +TEST_CASE("upx_stable_sort") { + CHECK(TestSortAllPermutations::test(1) == 1); + CHECK(TestSortAllPermutations::test(2) == 2); + CHECK(TestSortAllPermutations::test(3) == 6); + CHECK(TestSortAllPermutations::test(4) == 24); + CHECK(TestSortAllPermutations::test(5) == 120); + // CHECK(TestSortAllPermutations::test(6) == 720); + // CHECK(TestSortAllPermutations::test(7) == 5040); +} +#endif // C++20 #endif // DEBUG /************************************************************************* @@ -537,6 +545,20 @@ TEST_CASE("mem_replace") { CHECK(strcmp(b, "cdcdcdcdefgefghh") == 0); } +/************************************************************************* +// bele.h globals +**************************************************************************/ + +namespace N_BELE_CTP { +const BEPolicy be_policy; +const LEPolicy le_policy; +} // namespace N_BELE_CTP + +namespace N_BELE_RTP { +const BEPolicy be_policy; +const LEPolicy le_policy; +} // namespace N_BELE_RTP + /************************************************************************* // fn - FileName util **************************************************************************/ @@ -736,7 +758,7 @@ bool makebakname(char *ofilename, size_t size, const char *ifilename, bool force **************************************************************************/ unsigned get_ratio(upx_uint64_t u_len, upx_uint64_t c_len) { - const unsigned n = 1000 * 1000; + constexpr unsigned n = 1000 * 1000; if (u_len == 0) return c_len == 0 ? 0 : n; upx_uint64_t x = c_len * n;