From 344246725b46313d42bef9b031d9833146f22a7b Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Wed, 22 May 2024 09:49:20 +0200 Subject: [PATCH] src: more upx::max cleanups --- src/bele.h | 110 +++++++++++++++++++++--------- src/check/dt_check.cpp | 149 ++++++++++++++++++++++++++++++----------- src/p_w32pe_i386.cpp | 3 +- src/p_w64pe_amd64.cpp | 3 +- src/pefile.cpp | 12 ++-- 5 files changed, 198 insertions(+), 79 deletions(-) diff --git a/src/bele.h b/src/bele.h index 93f75a7f..d6e35cce 100644 --- a/src/bele.h +++ b/src/bele.h @@ -42,6 +42,14 @@ #define bswap64 upx_bswap64 #endif +// forward declarations +struct BE16; +struct BE32; +struct BE64; +struct LE16; +struct LE32; +struct LE64; + /************************************************************************* // XE - eXtended Endian compatibility // try to detect XX16 vs XX32 vs XX64 size mismatches @@ -61,14 +69,6 @@ typedef void XE64; #else // permissive version -// forward declarations -struct BE16; -struct BE32; -struct BE64; -struct LE16; -struct LE32; -struct LE64; - namespace bele_detail { // Note: @@ -755,35 +755,81 @@ T *operator+(const LE64 &v, T *ptr) noexcept DELETED_FUNCTION; namespace upx { -inline unsigned align_down(unsigned a, const BE32 &b) { return align_down(a, unsigned(b)); } -inline unsigned align_down(const BE32 &a, unsigned b) { return align_down(unsigned(a), b); } -inline unsigned align_up(unsigned a, const BE32 &b) { return align_up(a, unsigned(b)); } -inline unsigned align_up(const BE32 &a, unsigned b) { return align_up(unsigned(a), b); } +#define REQUIRE_UINT32 \ + template , T> > +#define REQUIRE_UINT64 \ + template , T> > -inline unsigned align_down(unsigned a, const LE32 &b) { return align_down(a, unsigned(b)); } -inline unsigned align_down(const LE32 &a, unsigned b) { return align_down(unsigned(a), b); } -inline unsigned align_up(unsigned a, const LE32 &b) { return align_up(a, unsigned(b)); } -inline unsigned align_up(const LE32 &a, unsigned b) { return align_up(unsigned(a), b); } +REQUIRE_UINT32 +inline T align_down(const T &a, const BE32 &b) noexcept { return align_down(a, T(b)); } +REQUIRE_UINT32 +inline T align_down(const BE32 &a, const T &b) noexcept { return align_down(T(a), b); } +REQUIRE_UINT32 +inline T align_down(const T &a, const LE32 &b) noexcept { return align_down(a, T(b)); } +REQUIRE_UINT32 +inline T align_down(const LE32 &a, const T &b) noexcept { return align_down(T(a), b); } -inline unsigned max(unsigned a, const BE16 &b) { return max(a, unsigned(b)); } -inline unsigned max(const BE16 &a, unsigned b) { return max(unsigned(a), b); } -inline unsigned min(unsigned a, const BE16 &b) { return min(a, unsigned(b)); } -inline unsigned min(const BE16 &a, unsigned b) { return min(unsigned(a), b); } +REQUIRE_UINT32 +inline T align_up(const T &a, const LE32 &b) noexcept { return align_up(a, T(b)); } +REQUIRE_UINT32 +inline T align_up(const LE32 &a, const T &b) noexcept { return align_up(T(a), b); } +REQUIRE_UINT32 +inline T align_up(const T &a, const BE32 &b) noexcept { return align_up(a, T(b)); } +REQUIRE_UINT32 +inline T align_up(const BE32 &a, const T &b) noexcept { return align_up(T(a), b); } -inline unsigned max(unsigned a, const BE32 &b) { return max(a, unsigned(b)); } -inline unsigned max(const BE32 &a, unsigned b) { return max(unsigned(a), b); } -inline unsigned min(unsigned a, const BE32 &b) { return min(a, unsigned(b)); } -inline unsigned min(const BE32 &a, unsigned b) { return min(unsigned(a), b); } +REQUIRE_UINT32 +inline T min(const T &a, const BE16 &b) noexcept { return min(a, T(b)); } +REQUIRE_UINT32 +inline T min(const BE16 &a, const T &b) noexcept { return min(T(a), b); } +REQUIRE_UINT32 +inline T min(const T &a, const BE32 &b) noexcept { return min(a, T(b)); } +REQUIRE_UINT32 +inline T min(const BE32 &a, const T &b) noexcept { return min(T(a), b); } +REQUIRE_UINT64 +inline T min(const T &a, const BE64 &b) noexcept { return min(a, T(b)); } +REQUIRE_UINT64 +inline T min(const BE64 &a, const T &b) noexcept { return min(T(a), b); } +REQUIRE_UINT32 +inline T min(const T &a, const LE16 &b) noexcept { return min(a, T(b)); } +REQUIRE_UINT32 +inline T min(const LE16 &a, const T &b) noexcept { return min(T(a), b); } +REQUIRE_UINT32 +inline T min(const T &a, const LE32 &b) noexcept { return min(a, T(b)); } +REQUIRE_UINT32 +inline T min(const LE32 &a, const T &b) noexcept { return min(T(a), b); } +REQUIRE_UINT64 +inline T min(const T &a, const LE64 &b) noexcept { return min(a, T(b)); } +REQUIRE_UINT64 +inline T min(const LE64 &a, const T &b) noexcept { return min(T(a), b); } -inline unsigned max(unsigned a, const LE16 &b) { return max(a, unsigned(b)); } -inline unsigned max(const LE16 &a, unsigned b) { return max(unsigned(a), b); } -inline unsigned min(unsigned a, const LE16 &b) { return min(a, unsigned(b)); } -inline unsigned min(const LE16 &a, unsigned b) { return min(unsigned(a), b); } +REQUIRE_UINT32 +inline T max(const T &a, const BE16 &b) noexcept { return max(a, T(b)); } +REQUIRE_UINT32 +inline T max(const BE16 &a, const T &b) noexcept { return max(T(a), b); } +REQUIRE_UINT32 +inline T max(const T &a, const BE32 &b) noexcept { return max(a, T(b)); } +REQUIRE_UINT32 +inline T max(const BE32 &a, const T &b) noexcept { return max(T(a), b); } +REQUIRE_UINT64 +inline T max(const T &a, const BE64 &b) noexcept { return max(a, T(b)); } +REQUIRE_UINT64 +inline T max(const BE64 &a, const T &b) noexcept { return max(T(a), b); } +REQUIRE_UINT32 +inline T max(const T &a, const LE16 &b) noexcept { return max(a, T(b)); } +REQUIRE_UINT32 +inline T max(const LE16 &a, const T &b) noexcept { return max(T(a), b); } +REQUIRE_UINT32 +inline T max(const T &a, const LE32 &b) noexcept { return max(a, T(b)); } +REQUIRE_UINT32 +inline T max(const LE32 &a, const T &b) noexcept { return max(T(a), b); } +REQUIRE_UINT64 +inline T max(const T &a, const LE64 &b) noexcept { return max(a, T(b)); } +REQUIRE_UINT64 +inline T max(const LE64 &a, const T &b) noexcept { return max(T(a), b); } -inline unsigned max(unsigned a, const LE32 &b) { return max(a, unsigned(b)); } -inline unsigned max(const LE32 &a, unsigned b) { return max(unsigned(a), b); } -inline unsigned min(unsigned a, const LE32 &b) { return min(a, unsigned(b)); } -inline unsigned min(const LE32 &a, unsigned b) { return min(unsigned(a), b); } +#undef REQUIRE_UINT32 +#undef REQUIRE_UINT64 } // namespace upx diff --git a/src/check/dt_check.cpp b/src/check/dt_check.cpp index 6c59b6b4..c0d53f72 100644 --- a/src/check/dt_check.cpp +++ b/src/check/dt_check.cpp @@ -298,48 +298,119 @@ struct CheckAlignment { template struct TestBELE { static noinline bool test(void) noexcept { + static_assert(upx::is_same_any_v); + static_assert( + upx::is_same_any_v); CheckIntegral::check(); CheckAlignment::check(); // arithmetic checks - T all_bits = {}; - assert_noexcept(all_bits == 0); - all_bits += 1; - all_bits -= 2; - T v1; - v1 = 1; - v1 *= 4; - v1 /= 2; - v1 -= 1; - T v2; - v2 = 1; - assert_noexcept((v1 == v2)); - assert_noexcept(!(v1 != v2)); - assert_noexcept((v1 <= v2)); - assert_noexcept((v1 >= v2)); - assert_noexcept(!(v1 < v2)); - assert_noexcept(!(v1 > v2)); - v2 ^= all_bits; - assert_noexcept(!(v1 == v2)); - assert_noexcept((v1 != v2)); - assert_noexcept((v1 <= v2)); - assert_noexcept(!(v1 >= v2)); - assert_noexcept((v1 < v2)); - assert_noexcept(!(v1 > v2)); - v2 += 2; - assert_noexcept(v1 == 1); - assert_noexcept(v2 == 0); - v1 <<= 1; - v1 |= v2; - v1 >>= 1; - v2 &= v1; - v2 /= v1; - v2 *= v1; - v1 += v2; - v1 -= v2; - assert_noexcept(v1 == 1); - assert_noexcept(v2 == 0); - if ((v1 ^ v2) != 1) - return false; + { + T all_bits = {}; // == zero + assert_noexcept(all_bits == 0); + assert_noexcept(!upx::has_single_bit(all_bits)); + all_bits += 1; + assert_noexcept(upx::has_single_bit(all_bits)); + all_bits -= 2; + assert_noexcept(!upx::has_single_bit(all_bits)); + T v1; + v1 = 1; + v1 *= 4; + v1 /= 2; + v1 -= 1; + T v2; + v2 = 1; + assert_noexcept((v1 == v2)); + assert_noexcept(!(v1 != v2)); + assert_noexcept((v1 <= v2)); + assert_noexcept((v1 >= v2)); + assert_noexcept(!(v1 < v2)); + assert_noexcept(!(v1 > v2)); + v2 ^= all_bits; + assert_noexcept(!(v1 == v2)); + assert_noexcept((v1 != v2)); + assert_noexcept((v1 <= v2)); + assert_noexcept(!(v1 >= v2)); + assert_noexcept((v1 < v2)); + assert_noexcept(!(v1 > v2)); + v2 += 2; + assert_noexcept(v1 == 1); + assert_noexcept(v2 == 0); + v1 <<= 1; + v1 |= v2; + v1 >>= 1; + v2 &= v1; + v2 /= v1; + v2 *= v1; + v1 += v2; + v1 -= v2; + assert_noexcept(v1 == 1); + assert_noexcept(v2 == 0); + if ((v1 ^ v2) != 1) + return false; + } + // min/max + { + constexpr T a = {}; // == zero + typedef typename T::integral_conversion_type U; + constexpr U b = 1; + assert_noexcept(upx::min(a, a) == 0); + assert_noexcept(upx::min(a, a) == a); + assert_noexcept(upx::min(a, b) == 0); + assert_noexcept(upx::min(a, b) == a); + assert_noexcept(upx::min(b, a) == 0); + assert_noexcept(upx::min(b, a) == a); + assert_noexcept(upx::min(b, b) == 1); + assert_noexcept(upx::min(b, b) == b); + assert_noexcept(upx::max(a, a) == 0); + assert_noexcept(upx::max(a, a) == a); + assert_noexcept(upx::max(a, b) == 1); + assert_noexcept(upx::max(a, b) == b); + assert_noexcept(upx::max(b, a) == 1); + assert_noexcept(upx::max(b, a) == b); + assert_noexcept(upx::max(b, b) == 1); + assert_noexcept(upx::max(b, b) == b); + T minus_one_t = {}, minus_two_t = {}; + minus_one_t -= 1; + minus_two_t -= 2; + const U minus_one_u = minus_one_t; + const U minus_two_u = minus_two_t; + assert_noexcept(upx::min(minus_one_t, minus_one_t) == minus_one_t); + assert_noexcept(upx::min(minus_one_t, minus_one_t) == minus_one_u); + assert_noexcept(upx::min(minus_one_u, minus_one_t) == minus_one_t); + assert_noexcept(upx::min(minus_one_u, minus_one_t) == minus_one_u); + assert_noexcept(upx::min(minus_one_t, minus_one_u) == minus_one_t); + assert_noexcept(upx::min(minus_one_t, minus_one_u) == minus_one_u); + assert_noexcept(upx::min(minus_two_t, minus_one_t) == minus_two_t); + assert_noexcept(upx::min(minus_two_t, minus_one_t) == minus_two_u); + assert_noexcept(upx::min(minus_two_u, minus_one_t) == minus_two_t); + assert_noexcept(upx::min(minus_two_u, minus_one_t) == minus_two_u); + assert_noexcept(upx::min(minus_two_t, minus_one_u) == minus_two_t); + assert_noexcept(upx::min(minus_two_t, minus_one_u) == minus_two_u); + assert_noexcept(upx::min(minus_one_t, minus_two_t) == minus_two_t); + assert_noexcept(upx::min(minus_one_t, minus_two_t) == minus_two_u); + assert_noexcept(upx::min(minus_one_u, minus_two_t) == minus_two_t); + assert_noexcept(upx::min(minus_one_u, minus_two_t) == minus_two_u); + assert_noexcept(upx::min(minus_one_t, minus_two_u) == minus_two_t); + assert_noexcept(upx::min(minus_one_t, minus_two_u) == minus_two_u); + assert_noexcept(upx::max(minus_one_t, minus_one_t) == minus_one_t); + assert_noexcept(upx::max(minus_one_t, minus_one_t) == minus_one_u); + assert_noexcept(upx::max(minus_one_u, minus_one_t) == minus_one_t); + assert_noexcept(upx::max(minus_one_u, minus_one_t) == minus_one_u); + assert_noexcept(upx::max(minus_one_t, minus_one_u) == minus_one_t); + assert_noexcept(upx::max(minus_one_t, minus_one_u) == minus_one_u); + assert_noexcept(upx::max(minus_two_t, minus_one_t) == minus_one_t); + assert_noexcept(upx::max(minus_two_t, minus_one_t) == minus_one_u); + assert_noexcept(upx::max(minus_two_u, minus_one_t) == minus_one_t); + assert_noexcept(upx::max(minus_two_u, minus_one_t) == minus_one_u); + assert_noexcept(upx::max(minus_two_t, minus_one_u) == minus_one_t); + assert_noexcept(upx::max(minus_two_t, minus_one_u) == minus_one_u); + assert_noexcept(upx::max(minus_one_t, minus_two_t) == minus_one_t); + assert_noexcept(upx::max(minus_one_t, minus_two_t) == minus_one_u); + assert_noexcept(upx::max(minus_one_u, minus_two_t) == minus_one_t); + assert_noexcept(upx::max(minus_one_u, minus_two_t) == minus_one_u); + assert_noexcept(upx::max(minus_one_t, minus_two_u) == minus_one_t); + assert_noexcept(upx::max(minus_one_t, minus_two_u) == minus_one_u); + } return true; } }; diff --git a/src/p_w32pe_i386.cpp b/src/p_w32pe_i386.cpp index 72e5a07a..82d8dee1 100644 --- a/src/p_w32pe_i386.cpp +++ b/src/p_w32pe_i386.cpp @@ -243,7 +243,8 @@ void PackW32PeI386::setOhDataBase(const pe_section_t *osection) { oh.database = void PackW32PeI386::setOhHeaderSize(const pe_section_t *osection) { // SizeOfHeaders - oh.headersize = ALIGN_UP(pe_offset + sizeof(oh) + sizeof(*osection) * oh.objects, oh.filealign); + oh.headersize = + ALIGN_UP(pe_offset + usizeof(oh) + usizeof(*osection) * oh.objects, oh.filealign); } void PackW32PeI386::pack(OutputFile *fo) { diff --git a/src/p_w64pe_amd64.cpp b/src/p_w64pe_amd64.cpp index 77c7855d..e94b1a12 100644 --- a/src/p_w64pe_amd64.cpp +++ b/src/p_w64pe_amd64.cpp @@ -236,7 +236,8 @@ void PackW64PeAmd64::defineSymbols(unsigned ncsection, unsigned upxsection, unsi void PackW64PeAmd64::setOhHeaderSize(const pe_section_t *osection) { // SizeOfHeaders - oh.headersize = ALIGN_UP(pe_offset + sizeof(oh) + sizeof(*osection) * oh.objects, oh.filealign); + oh.headersize = + ALIGN_UP(pe_offset + usizeof(oh) + usizeof(*osection) * oh.objects, oh.filealign); } void PackW64PeAmd64::pack(OutputFile *fo) { diff --git a/src/pefile.cpp b/src/pefile.cpp index 0dca1a79..88da0274 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -1417,7 +1417,7 @@ void PeFile::processTls1(Interval *iv, typename tls_traits::cb_value_t ima // ... and those dwords should be correctly aligned if (use_tls_callbacks) sotls = ALIGN_UP(sotls, cb_size) + 2 * cb_size; - const unsigned aligned_sotls = ALIGN_UP(sotls, (unsigned) sizeof(LEXX)); + const unsigned aligned_sotls = ALIGN_UP(sotls, usizeof(LEXX)); // the PE loader wants this stuff uncompressed mb_otls.alloc(aligned_sotls); @@ -2140,7 +2140,7 @@ void PeFile::checkHeaderValues(unsigned subsystem, unsigned mask, unsigned ih_en throwCantPack("run a virus scanner on this file!"); const unsigned fam1 = ih_filealign - 1; - if (!(1 + fam1) || (1 + fam1) & fam1) { // ih_filealign is not a power of 2 + if (!upx::has_single_bit(ih_filealign)) { // ih_filealign is not a power of 2 char buf[32]; snprintf(buf, sizeof(buf), "bad file alignment %#x", 1 + fam1); throwCantPack(buf); @@ -2338,7 +2338,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask, allow_filter = false; const unsigned oam1 = ih.objectalign - 1; - if (!(1 + oam1) || (1 + oam1) & oam1) { // ih.objectalign is not a power of 2 + if (!upx::has_single_bit(ih.objectalign)) { // ih.objectalign is not a power of 2 char buf[32]; snprintf(buf, sizeof(buf), "bad object alignment %#x", 1 + oam1); throwCantPack(buf); @@ -2414,7 +2414,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask, if (tlsindex && ((newvsize - ph.c_len - 1024 + oam1) & ~oam1) > tlsindex + 4) tlsindex = 0; - const int oh_filealign = UPX_MIN(ih.filealign, 0x200); + const int oh_filealign = UPX_MIN(ih.filealign, 0x200u); const unsigned fam1 = oh_filealign - 1; int identsize = 0; @@ -2456,9 +2456,9 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask, ((ph.c_len + ic) & 15) == 0 ? ph.c_len : ph.c_len + 16 - ((ph.c_len + ic) & 15); obuf.clear(ph.c_len, c_len - ph.c_len); - const unsigned aligned_sotls = ALIGN_UP(sotls, (unsigned) sizeof(LEXX)); + const unsigned aligned_sotls = ALIGN_UP(sotls, usizeof(LEXX)); const unsigned s1size = - ALIGN_UP(ic + c_len + codesize, (unsigned) sizeof(LEXX)) + aligned_sotls + soloadconf; + ALIGN_UP(ic + c_len + codesize, usizeof(LEXX)) + aligned_sotls + soloadconf; const unsigned s1addr = (newvsize - (ic + c_len) + oam1) & ~oam1; const unsigned ncsection = (s1addr + s1size + oam1) & ~oam1;