diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8bc4137b..cd8ddc34 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -365,12 +365,7 @@ jobs: - { name: arm64ec-win64-vs2022, os: windows-2022, vsversion: 2022, vsarch: amd64_arm64, cl_machine_flags: -arm64EC, link_machine_flags: '/machine:arm64ec' } # { name: arm64x-win64-vs2022, os: windows-2022, vsversion: 2022, vsarch: amd64_arm64, cl_machine_flags: -arm64EC, link_machine_flags: '/machine:arm64x' } - { name: i386-win32-vs2019, os: windows-2019, vsversion: 2019, vsarch: amd64_x86 } - # TODO: as of 2024-06-07 i386-win32-vs2022 stopped working: "upx_ucl_init() failed" - # working: MSVC 19.39.33523 for x86 - # broken: MSVC 19.40.33811 for x86 - # caused by runner-images update 20240603.1: - # https://github.com/actions/runner-images/blob/win22/20240603.1/images/windows/Windows2022-Readme.md?plain=1#L470-L480 - # { name: i386-win32-vs2022, os: windows-2022, vsversion: 2022, vsarch: amd64_x86 } + - { name: i386-win32-vs2022, os: windows-2022, vsversion: 2022, vsarch: amd64_x86 } steps: - run: git config --global core.autocrlf false - uses: actions/checkout@v4 diff --git a/src/check/dt_check.cpp b/src/check/dt_check.cpp index 32db45d8..4025a50b 100644 --- a/src/check/dt_check.cpp +++ b/src/check/dt_check.cpp @@ -263,6 +263,8 @@ ASSERT_SAME_TYPE(uintptr_t, expected_uintptr_t); #endif // UPX types +ASSERT_SAME_TYPE(signed char, upx_int8_t); +ASSERT_SAME_TYPE(unsigned char, upx_uint8_t); ASSERT_SAME_TYPE(short, upx_int16_t); ASSERT_SAME_TYPE(unsigned short, upx_uint16_t); ASSERT_SAME_TYPE(int, upx_int32_t); @@ -450,14 +452,14 @@ struct CheckIntegral { assert_noexcept(upx::align_up(three, four) == four); assert_noexcept(upx::align_up(four, four) == 4); assert_noexcept(upx::align_up(four, four) == four); - assert_noexcept(upx::align_gap(zero, four) == 0); - assert_noexcept(upx::align_gap(zero, four) == zero); - assert_noexcept(upx::align_gap(one, four) == 3); - assert_noexcept(upx::align_gap(one, four) == three); - assert_noexcept(upx::align_gap(three, four) == 1); - assert_noexcept(upx::align_gap(three, four) == one); - assert_noexcept(upx::align_gap(four, four) == 0); - assert_noexcept(upx::align_gap(four, four) == zero); + assert_noexcept(upx::align_up_gap(zero, four) == 0); + assert_noexcept(upx::align_up_gap(zero, four) == zero); + assert_noexcept(upx::align_up_gap(one, four) == 3); + assert_noexcept(upx::align_up_gap(one, four) == three); + assert_noexcept(upx::align_up_gap(three, four) == 1); + assert_noexcept(upx::align_up_gap(three, four) == one); + assert_noexcept(upx::align_up_gap(four, four) == 0); + assert_noexcept(upx::align_up_gap(four, four) == zero); } } }; @@ -646,11 +648,16 @@ struct TestBELE { static_assert(upx::align_down(one, four) == 0); static_assert(upx::align_up(one, four) == 4); static_assert(upx::align_up(one, four) == four); - static_assert(upx::align_gap(one, four) == 3); - static_assert(upx::align_gap(one, four) == T::make(four - 1)); - static_assert(upx::align_gap(one, four) == T::make(four - one)); - static_assert(upx::align_gap(one, four) == T::make(four + one - one - one)); - static_assert(upx::align_gap(one, four) == T::make(four + one - 2 * one)); + static_assert(upx::align_up_gap(one, four) == 3); + static_assert(upx::align_up_gap(one, four) == T::make(four - 1)); + static_assert(upx::align_up_gap(one, four) == T::make(four - one)); + static_assert(upx::align_up_gap(one, four) == T::make(four + one - one - one)); + static_assert(upx::align_up_gap(one, four) == T::make(four + one - 2 * one)); + static_assert(upx::align_down_gap(T::make(4), four) == 0); + static_assert(upx::align_down_gap(T::make(5), four) == 1); + static_assert(upx::align_down_gap(T::make(6), four) == 2); + static_assert(upx::align_down_gap(T::make(7), four) == 3); + static_assert(upx::align_down_gap(T::make(8), four) == 0); constexpr T one_copy = T::make(one); static_assert(one_copy == one); static_assert(one_copy == 1); @@ -976,8 +983,11 @@ void upx_compiler_sanity_check(void) noexcept { CheckIntegral::check(); #endif #if (__SIZEOF_INT128__ == 16) +#if defined(_CPP_VER) // int128 is not supported by MSVC libstdc++ yet +#else CheckIntegral::check(); CheckIntegral::check(); +#endif #endif CheckSignedness::check(); // -funsigned-char @@ -1002,8 +1012,11 @@ void upx_compiler_sanity_check(void) noexcept { CheckSignedness::check(); CheckSignedness::check(); #if (__SIZEOF_INT128__ == 16) +#if defined(_CPP_VER) // int128 is not supported by MSVC libstdc++ yet +#else CheckSignedness::check(); CheckSignedness::check(); +#endif #endif CheckSignedness::check(); CheckSignedness::check(); @@ -1022,11 +1035,15 @@ void upx_compiler_sanity_check(void) noexcept { CHECK_TYPE_PAIR(long, unsigned long); CHECK_TYPE_PAIR(long long, unsigned long long); CHECK_TYPE_PAIR(intmax_t, uintmax_t); + CHECK_TYPE_PAIR(upx_int8_t, upx_uint8_t); CHECK_TYPE_PAIR(upx_int16_t, upx_uint16_t); CHECK_TYPE_PAIR(upx_int32_t, upx_uint32_t); CHECK_TYPE_PAIR(upx_int64_t, upx_uint64_t); #if (__SIZEOF_INT128__ == 16) +#if defined(_CPP_VER) // int128 is not supported by MSVC libstdc++ yet +#else CHECK_TYPE_PAIR(upx_int128_t, upx_uint128_t); +#endif #endif CHECK_TYPE_PAIR(ptrdiff_t, upx_uptrdiff_t); CHECK_TYPE_PAIR(upx_ssize_t, size_t); @@ -1084,6 +1101,7 @@ void upx_compiler_sanity_check(void) noexcept { 0, 0, 0, 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0, 0, 0, 0, 0}; constexpr const byte *d = dd + 7; assert_noexcept(ptr_is_aligned<16>(dd)); + assert_noexcept(ptr_is_aligned(dd, 16)); static_assert(upx::compile_time::get_be16(d) == 0xfffe); static_assert(upx::compile_time::get_be24(d) == 0xfffefd); static_assert(upx::compile_time::get_be32(d) == 0xfffefdfc); diff --git a/src/check/dt_cxxlib.cpp b/src/check/dt_cxxlib.cpp index a52b09ed..4546b313 100644 --- a/src/check/dt_cxxlib.cpp +++ b/src/check/dt_cxxlib.cpp @@ -204,6 +204,7 @@ static_assert(!upx::is_same_any_v); static_assert(upx::is_same_any_v); static_assert(upx::is_same_any_v); +static_assert(upx::is_same_any_v); #if defined(__CHERI__) && defined(__CHERI_PURE_CAPABILITY__) static_assert(!upx::is_same_any_v); #else @@ -234,11 +235,11 @@ static_assert(upx::align_up(1, 4) == 4); static_assert(upx::align_up(2, 4) == 4); static_assert(upx::align_up(3, 4) == 4); static_assert(upx::align_up(4, 4) == 4); -static_assert(upx::align_gap(0, 4) == 0); -static_assert(upx::align_gap(1, 4) == 3); -static_assert(upx::align_gap(2, 4) == 2); -static_assert(upx::align_gap(3, 4) == 1); -static_assert(upx::align_gap(4, 4) == 0); +static_assert(upx::align_up_gap(0, 4) == 0); +static_assert(upx::align_up_gap(1, 4) == 3); +static_assert(upx::align_up_gap(2, 4) == 2); +static_assert(upx::align_up_gap(3, 4) == 1); +static_assert(upx::align_up_gap(4, 4) == 0); static_assert(upx::min(1, 2) == 1); static_assert(upx::min(1, 2) == 1); diff --git a/src/compress/compress_ucl.cpp b/src/compress/compress_ucl.cpp index 659091ce..05cf2cea 100644 --- a/src/compress/compress_ucl.cpp +++ b/src/compress/compress_ucl.cpp @@ -248,8 +248,12 @@ static void __UCL_CDECL my_free(ucl_voidp p) { free(p); } } // extern "C" int upx_ucl_init(void) { +#if (ACC_CC_MSC && ACC_ARCH_I386) && (_MSC_VER >= 1940) + (void) ucl_init(); // TODO later +#else if (ucl_init() != UCL_E_OK) return -1; +#endif if (UCL_VERSION != ucl_version() || strcmp(UCL_VERSION_STRING, ucl_version_string()) != 0) return -2; ucl_set_malloc_hooks(my_malloc, my_free); diff --git a/src/conf.h b/src/conf.h index 76a76bdf..9db84ab4 100644 --- a/src/conf.h +++ b/src/conf.h @@ -65,6 +65,9 @@ static_assert((char) (-1) == 255); // -funsigned-char // enable some more strict warnings for Git developer builds #if defined(UPX_CONFIG_DISABLE_WSTRICT) && (UPX_CONFIG_DISABLE_WSTRICT + 0 == 0) #if defined(UPX_CONFIG_DISABLE_WERROR) && (UPX_CONFIG_DISABLE_WERROR + 0 == 0) +#if (ACC_CC_MSC) +#pragma warning(error : 4714) // W4: function marked as __forceinline not inlined +#endif #if (ACC_CC_CLANG >= 0x0b0000) #pragma clang diagnostic error "-Wsuggest-override" #elif (ACC_CC_GNUC >= 0x0a0000) @@ -469,12 +472,12 @@ noreturn void throwAssertFailed(const char *expr, const char *file, int line, co // C++ support library #include "util/cxxlib.h" using upx::tribool; -#define usizeof(expr) (upx::UnsignedSizeOf::value) -#define ALIGN_DOWN(a, b) (upx::align_down((a), (b))) -#define ALIGN_UP(a, b) (upx::align_up((a), (b))) -#define ALIGN_GAP(a, b) (upx::align_gap((a), (b))) -#define UPX_MAX(a, b) (upx::max((a), (b))) -#define UPX_MIN(a, b) (upx::min((a), (b))) +#define usizeof(expr) (upx::UnsignedSizeOf::value) +#define ALIGN_DOWN(a, b) (upx::align_down((a), (b))) +#define ALIGN_UP(a, b) (upx::align_up((a), (b))) +#define ALIGN_UP_GAP(a, b) (upx::align_up_gap((a), (b))) +#define UPX_MAX(a, b) (upx::max((a), (b))) +#define UPX_MIN(a, b) (upx::min((a), (b))) /************************************************************************* // constants diff --git a/src/p_ps1.cpp b/src/p_ps1.cpp index 57c513c4..7515e8b9 100644 --- a/src/p_ps1.cpp +++ b/src/p_ps1.cpp @@ -154,7 +154,7 @@ void PackPs1::putBkupHeader(const byte *src, byte *dst, unsigned *len) { if (r != UPX_E_OK || sz_cbh >= SZ_IH_BKUP) throwInternalError("header compression failed"); INIT_BH_BKUP(p, sz_cbh); - *len = ALIGN_UP(sz_cbh + (unsigned) sizeof(ps1_exe_chb_t) - 1, 4u); + *len = ALIGN_UP(sz_cbh + usizeof(ps1_exe_chb_t) - 1, 4u); p->ih_csum = ADLER16(upx_adler32(&ih.epc, SZ_IH_BKUP)); memcpy(dst, cpr_bh, SZ_IH_BKUP); } else @@ -300,7 +300,7 @@ void PackPs1::buildLoader(const Filter *) { } else initLoader(stub_mipsel_r3000_ps1, sizeof(stub_mipsel_r3000_ps1)); - pad_code = ALIGN_GAP((ph.c_len + (isCon ? sz_lcpr : 0)), 4u); + pad_code = ALIGN_UP_GAP((ph.c_len + (isCon ? sz_lcpr : 0)), 4u); assert(pad_code < 4); static const byte pad_buffer[4] = {0, 0, 0, 0}; linker->addSection("pad.code", pad_buffer, pad_code, 0); diff --git a/src/pefile.cpp b/src/pefile.cpp index 8fd0cc89..d8d313e1 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -2466,7 +2466,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask, else if (((identsplit + identsize) ^ identsplit) < oh_filealign) identsplit = identsize; else - identsplit = ALIGN_GAP(identsplit, oh_filealign); + identsplit = ALIGN_UP_GAP(identsplit, oh_filealign); ic = identsize - identsplit; const unsigned c_len = diff --git a/src/util/cxxlib.h b/src/util/cxxlib.h index ee416054..9135e7bf 100644 --- a/src/util/cxxlib.h +++ b/src/util/cxxlib.h @@ -180,7 +180,7 @@ inline constexpr bool is_same_any_v = is_same_any::value; template forceinline constexpr bool has_single_bit(T x) noexcept { - return x != 0 && (x & (x - 1)) == 0; + return !(x == 0) && (x & (x - 1)) == 0; } /************************************************************************* @@ -191,21 +191,30 @@ template inline constexpr T align_down(const T &x, const T &alignment) noexcept { // assert_noexcept(has_single_bit(alignment)); // (not constexpr) T r = {}; - r = (x / alignment) * alignment; + r = x - (x & (alignment - 1)); + return r; +} +template +inline constexpr T align_down_gap(const T &x, const T &alignment) noexcept { + // assert_noexcept(has_single_bit(alignment)); // (not constexpr) + T r = {}; + r = x & (alignment - 1); return r; } template inline constexpr T align_up(const T &x, const T &alignment) noexcept { // assert_noexcept(has_single_bit(alignment)); // (not constexpr) T r = {}; - r = ((x + (alignment - 1)) / alignment) * alignment; + constexpr T zero = {}; + r = x + ((zero - x) & (alignment - 1)); return r; } template -inline constexpr T align_gap(const T &x, const T &alignment) noexcept { +inline constexpr T align_up_gap(const T &x, const T &alignment) noexcept { // assert_noexcept(has_single_bit(alignment)); // (not constexpr) T r = {}; - r = align_up(x, alignment) - x; + constexpr T zero = {}; + r = (zero - x) & (alignment - 1); return r; } diff --git a/src/util/system_headers.h b/src/util/system_headers.h index 54730090..be6eccfa 100644 --- a/src/util/system_headers.h +++ b/src/util/system_headers.h @@ -82,6 +82,9 @@ static_assert(sizeof(void *) == sizeof(long)); #pragma warning(disable : 4244) // W3: conversion from 'type1' to 'type2', possible loss of data #pragma warning(disable : 4267) // W3: conversion from 'size_t' to 'type', possible loss of data #pragma warning(disable : 4820) // W4: padding added after data member +#if _MSC_VER >= 1800 +#pragma warning(disable : 4464) // W4: relative include path contains '..' +#endif #endif #undef snprintf diff --git a/src/util/util.cpp b/src/util/util.cpp index 5cff417e..01737d20 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -292,7 +292,8 @@ void *upx_calloc(size_t n, size_t element_size) may_throw { } // simple unoptimized memswap() -// TODO later: CHERI clang bug/miscompilation with upx_memswap() ??? +// TODO later: CHERI clang-14 bug/miscompilation with upx_memswap(); or +// maybe caused by tagged-memory issues ??? void upx_memswap(void *aa, void *bb, size_t bytes) noexcept { if (aa != bb && bytes != 0) { byte *a = (byte *) aa; @@ -448,11 +449,24 @@ TEST_CASE("upx_memswap") { memset(array, 0xfb, sizeof(array)); array[1] = &a; array[3] = &b; + CHECK(*array[1] == 11); + CHECK(*array[3] == 22); +#if defined(__CHERI__) && defined(__CHERI_PURE_CAPABILITY__) + // TODO later: CHERI clang-14 bug/miscompilation with upx_memswap(); or + // maybe caused by tagged-memory issues ??? + memswap_no_overlap((byte *) array, (byte *) (array + 2), 2 * sizeof(array[0])); +#else upx_memswap(array, array + 2, 2 * sizeof(array[0])); - assert(array[1] == &b); - assert(array[3] == &a); - assert(*array[1] == 22); - assert(*array[3] == 11); +#endif + CHECK(array[1] == &b); + CHECK(array[3] == &a); + CHECK(*array[1] == 22); + CHECK(*array[3] == 11); + memswap_no_overlap((byte *) array, (byte *) (array + 2), 2 * sizeof(array[0])); + CHECK(array[1] == &a); + CHECK(array[3] == &b); + CHECK(*array[1] == 11); + CHECK(*array[3] == 22); } } diff --git a/src/util/util.h b/src/util/util.h index 984135e7..71df9bda 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -110,6 +110,10 @@ forceinline bool ptr_is_aligned(const void *p) noexcept { static_assert(upx::has_single_bit(Alignment)); return (ptr_get_address(p) & (Alignment - 1)) == 0; } +forceinline bool ptr_is_aligned(const void *p, size_t alignment) noexcept { + assert_noexcept(upx::has_single_bit(alignment)); + return (ptr_get_address(p) & (alignment - 1)) == 0; +} // ptrdiff_t with nullptr checks and asserted size; will throw on failure // NOTE: returns size_in_bytes, not number of elements!