diff --git a/src/bele.h b/src/bele.h index 8cdb20b2..93f75a7f 100644 --- a/src/bele.h +++ b/src/bele.h @@ -750,40 +750,42 @@ template T *operator+(const LE64 &v, T *ptr) noexcept DELETED_FUNCTION; /************************************************************************* -// global overloads +// some global overloads **************************************************************************/ -// TODO later: move these to upx namespace in util/cxxlib.h; see conf.h -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); } +namespace upx { -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); } +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); } -// TODO later: introduce upx::umax() and upx::umin() -inline unsigned UPX_MAX(unsigned a, const BE16 &b) { return UPX_MAX(a, unsigned(b)); } -inline unsigned UPX_MAX(const BE16 &a, unsigned b) { return UPX_MAX(unsigned(a), b); } -inline unsigned UPX_MIN(unsigned a, const BE16 &b) { return UPX_MIN(a, unsigned(b)); } -inline unsigned UPX_MIN(const BE16 &a, unsigned b) { return UPX_MIN(unsigned(a), b); } +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); } -inline unsigned UPX_MAX(unsigned a, const BE32 &b) { return UPX_MAX(a, unsigned(b)); } -inline unsigned UPX_MAX(const BE32 &a, unsigned b) { return UPX_MAX(unsigned(a), b); } -inline unsigned UPX_MIN(unsigned a, const BE32 &b) { return UPX_MIN(a, unsigned(b)); } -inline unsigned UPX_MIN(const BE32 &a, unsigned b) { return UPX_MIN(unsigned(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); } -inline unsigned UPX_MAX(unsigned a, const LE16 &b) { return UPX_MAX(a, unsigned(b)); } -inline unsigned UPX_MAX(const LE16 &a, unsigned b) { return UPX_MAX(unsigned(a), b); } -inline unsigned UPX_MIN(unsigned a, const LE16 &b) { return UPX_MIN(a, unsigned(b)); } -inline unsigned UPX_MIN(const LE16 &a, unsigned b) { return UPX_MIN(unsigned(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); } -inline unsigned UPX_MAX(unsigned a, const LE32 &b) { return UPX_MAX(a, unsigned(b)); } -inline unsigned UPX_MAX(const LE32 &a, unsigned b) { return UPX_MAX(unsigned(a), b); } -inline unsigned UPX_MIN(unsigned a, const LE32 &b) { return UPX_MIN(a, unsigned(b)); } -inline unsigned UPX_MIN(const LE32 &a, unsigned b) { return UPX_MIN(unsigned(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); } + +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); } + +} // namespace upx /************************************************************************* // misc support diff --git a/src/check/dt_check.cpp b/src/check/dt_check.cpp index bf93a22f..6c59b6b4 100644 --- a/src/check/dt_check.cpp +++ b/src/check/dt_check.cpp @@ -230,6 +230,43 @@ struct CheckIntegral { } checkU(); checkU::type>(); + { + T zero, one, three, four; + zero = 0; + one = 1; + three = 3; + four = 4; + // min / max + assert_noexcept(upx::min(one, four) == 1); + assert_noexcept(upx::min(one, four) == one); + assert_noexcept(upx::max(one, four) == 4); + assert_noexcept(upx::max(one, four) == four); + // align + assert_noexcept(upx::align_down(zero, four) == 0); + assert_noexcept(upx::align_down(zero, four) == zero); + assert_noexcept(upx::align_down(one, four) == 0); + assert_noexcept(upx::align_down(one, four) == zero); + assert_noexcept(upx::align_down(three, four) == 0); + assert_noexcept(upx::align_down(three, four) == zero); + assert_noexcept(upx::align_down(four, four) == 4); + assert_noexcept(upx::align_down(four, four) == four); + assert_noexcept(upx::align_up(zero, four) == 0); + assert_noexcept(upx::align_up(zero, four) == zero); + assert_noexcept(upx::align_up(one, four) == 4); + assert_noexcept(upx::align_up(one, four) == four); + assert_noexcept(upx::align_up(three, four) == 4); + 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); + } } }; diff --git a/src/check/dt_cxxlib.cpp b/src/check/dt_cxxlib.cpp index 0a700ee8..1192403e 100644 --- a/src/check/dt_cxxlib.cpp +++ b/src/check/dt_cxxlib.cpp @@ -122,10 +122,10 @@ TEST_CASE("std::vector") { CHECK(v.end() - v.begin() == N); CHECK(&v[0] == &(*(v.begin()))); // CHECK(&v[0] + N == &(*(v.end()))); // TODO later: is this legal?? - // TODO later: make sure that this throws -#if defined(_LIBCPP_HARDENING_MODE_DEBUG) && \ +#if defined(_LIBCPP_HARDENING_MODE) && defined(_LIBCPP_HARDENING_MODE_DEBUG) && \ (_LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG) - CHECK_THROWS((void) &v[N]); + // unfortunately this does not throw but aborts + ////CHECK_THROWS((void) &v[N]); #endif UNUSED(v); } @@ -251,6 +251,36 @@ struct Z2_X2 : public X2 { // util **************************************************************************/ +TEST_CASE("upx::min_max") { + static_assert(upx::min(0, 0) == 0); + static_assert(upx::min(0, 1) == 0); + static_assert(upx::min(1, 0) == 0); + static_assert(upx::max(0, 0) == 0); + static_assert(upx::max(0, 1) == 1); + static_assert(upx::max(1, 0) == 1); + static_assert(upx::umin(0u, 0u) == 0u); + static_assert(upx::umin(0u, 1u) == 0u); + static_assert(upx::umin(1u, 0u) == 0u); + static_assert(upx::umax(0u, 0u) == 0u); + static_assert(upx::umax(0u, 1u) == 1u); + static_assert(upx::umax(1u, 0u) == 1u); + CHECK_EQ(upx::align_down(0, 4), 0); + CHECK_EQ(upx::align_down(1, 4), 0); + CHECK_EQ(upx::align_down(2, 4), 0); + CHECK_EQ(upx::align_down(3, 4), 0); + CHECK_EQ(upx::align_down(4, 4), 4); + CHECK_EQ(upx::align_up(0, 4), 0); + CHECK_EQ(upx::align_up(1, 4), 4); + CHECK_EQ(upx::align_up(2, 4), 4); + CHECK_EQ(upx::align_up(3, 4), 4); + CHECK_EQ(upx::align_up(4, 4), 4); + CHECK_EQ(upx::align_gap(0, 4), 0); + CHECK_EQ(upx::align_gap(1, 4), 3); + CHECK_EQ(upx::align_gap(2, 4), 2); + CHECK_EQ(upx::align_gap(3, 4), 1); + CHECK_EQ(upx::align_gap(4, 4), 0); +} + #if WITH_THREADS TEST_CASE("upx::ptr_std_atomic_cast") { // pointer-size diff --git a/src/compress/compress_zlib.cpp b/src/compress/compress_zlib.cpp index 3df92dda..95f5a504 100644 --- a/src/compress/compress_zlib.cpp +++ b/src/compress/compress_zlib.cpp @@ -25,13 +25,6 @@ */ #include "../conf.h" -#include "compress.h" -#include "../util/membuffer.h" -// NOLINTBEGIN(clang-analyzer-optin.performance.Padding) -#define ZLIB_CONST 1 -#include -#include -// NOLINTEND(clang-analyzer-optin.performance.Padding) void zlib_compress_config_t::reset() noexcept { mem_clear(this); @@ -40,6 +33,15 @@ void zlib_compress_config_t::reset() noexcept { strategy.reset(); } +#if WITH_ZLIB +#include "compress.h" +#include "../util/membuffer.h" +// NOLINTBEGIN(clang-analyzer-optin.performance.Padding) +#define ZLIB_CONST 1 +#include +#include +// NOLINTEND(clang-analyzer-optin.performance.Padding) + static int convert_errno_from_zlib(int zr) { switch (zr) { case Z_OK: @@ -307,4 +309,6 @@ TEST_CASE("upx_zlib_decompress") { UNUSED(r); } +#endif // WITH_ZLIB + /* vim:set ts=4 sw=4 et: */ diff --git a/src/conf.h b/src/conf.h index c1321a68..a0d8c116 100644 --- a/src/conf.h +++ b/src/conf.h @@ -397,39 +397,6 @@ inline void NO_fprintf(FILE *, const char *, ...) noexcept {} #define TABLESIZE(table) ((sizeof(table) / sizeof((table)[0]))) -// TODO later: move these to upx namespace in util/cxxlib.h; also see bele.h -template -inline T ALIGN_DOWN(const T &a, const T &b) { - T r; - r = (a / b) * b; - return r; -} -template -inline T ALIGN_UP(const T &a, const T &b) { - T r; - r = ((a + b - 1) / b) * b; - return r; -} -template -inline T ALIGN_GAP(const T &a, const T &b) { - T r; - r = ALIGN_UP(a, b) - a; - return r; -} - -template -inline const T &UPX_MAX(const T &a, const T &b) { - if (a < b) - return b; - return a; -} -template -inline const T &UPX_MIN(const T &a, const T &b) { - if (a < b) - return a; - return b; -} - template inline void mem_clear(T *object) noexcept { static_assert(std::is_class_v); // UPX convention @@ -483,6 +450,12 @@ using upx::OptVar; 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)) + /************************************************************************* // constants **************************************************************************/ @@ -623,7 +596,9 @@ using upx::tribool; #define WITH_LZMA 1 #define WITH_UCL 1 +#ifndef WITH_ZLIB #define WITH_ZLIB 1 +#endif #if (WITH_UCL) #define ucl_compress_config_t REAL_ucl_compress_config_t #include diff --git a/src/main.cpp b/src/main.cpp index 4e9f2ccb..a322eb44 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1246,7 +1246,9 @@ int upx_main(int argc, char *argv[]) may_throw { assert(upx_nrv_init() == 0); #endif assert(upx_ucl_init() == 0); +#if (WITH_ZLIB) assert(upx_zlib_init() == 0); +#endif #if (WITH_ZSTD) assert(upx_zstd_init() == 0); #endif diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 9aa664f2..00c58733 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -43,6 +43,8 @@ #include "p_lx_elf.h" #include "ui.h" +using upx::umax, upx::umin; + #define PT_LOAD32 Elf32_Phdr::PT_LOAD #define PT_LOAD64 Elf64_Phdr::PT_LOAD #define PT_NOTE32 Elf32_Phdr::PT_NOTE @@ -66,18 +68,6 @@ static unsigned const EF_ARM_EABI_VER5 = 0x05000000; /*offset 20*/ '.','s','h','s','t','r','t','a','b','\0' }; -static unsigned -umin(unsigned a, unsigned b) -{ - return (a < b) ? a : b; -} - -static upx_uint64_t -umin64(upx_uint64_t a, upx_uint64_t b) -{ - return (a < b) ? a : b; -} - static unsigned up4(unsigned x) { @@ -357,7 +347,7 @@ PackLinuxElf32::PackLinuxElf32help1(InputFile *f) unsigned offset = check_pt_dynamic(phdr); dynseg= (Elf32_Dyn *)(offset + file_image); invert_pt_dynamic(dynseg, - umin(get_te32(&phdr->p_filesz), file_size - offset)); + umin(get_te32(&phdr->p_filesz), (unsigned)(file_size_u - offset))); } else if (is_LOAD32(phdr)) { check_pt_load(phdr); @@ -1069,7 +1059,7 @@ PackLinuxElf64::PackLinuxElf64help1(InputFile *f) upx_uint64_t offset = check_pt_dynamic(phdr); dynseg= (Elf64_Dyn *)(offset + file_image); invert_pt_dynamic(dynseg, - umin(get_te64(&phdr->p_filesz), file_size - offset)); + umin(get_te64(&phdr->p_filesz), file_size_u - offset)); } else if (PT_LOAD64==get_te32(&phdr->p_type)) { check_pt_load(phdr); @@ -2699,7 +2689,7 @@ tribool PackLinuxElf32::canPack() unsigned offset = check_pt_dynamic(phdr); dynseg= (Elf32_Dyn *)(offset + file_image); invert_pt_dynamic(dynseg, - umin(get_te32(&phdr->p_filesz), file_size - offset)); + umin(get_te32(&phdr->p_filesz), (unsigned)(file_size_u - offset))); } else if (is_LOAD32(phdr)) { if (!pload_x0 @@ -2773,7 +2763,7 @@ tribool PackLinuxElf32::canPack() for (int j= e_shnum; --j>=0; ++shdr) { unsigned const sh_type = get_te32(&shdr->sh_type); if (Elf32_Shdr::SHF_EXECINSTR & get_te32(&shdr->sh_flags)) { - xct_va = umin(xct_va, get_te32(&shdr->sh_addr)); + xct_va = umin((unsigned) xct_va, get_te32(&shdr->sh_addr)); } // Hook the first slot of DT_PREINIT_ARRAY or DT_INIT_ARRAY. if (!user_init_rp && ( @@ -3797,7 +3787,7 @@ PackLinuxElf64::generateElfHdr( for (int j= e_phnum; --j>=0; ) { if (PT_LOAD64 == get_te32(&phdri[j].p_type)) { upx_uint64_t const vaddr = get_te64(&phdri[j].p_vaddr); - lo_va_user = umin64(lo_va_user, vaddr); + lo_va_user = umin(lo_va_user, vaddr); } } set_te64( &h2->phdr[C_BASE].p_vaddr, lo_va_user); @@ -5108,7 +5098,7 @@ int PackLinuxElf32::pack2(OutputFile *fo, Filter &ft) asl_pack2_Shdrs(fo, pre_xct_top); } else { // Just copy up to xct_off - x.size = umin(x.size, xct_off - x.offset); + x.size = umin(0ull + x.size, 0ull + xct_off - x.offset); if (0) { // DEBUG paranoia fi->seek(x.offset, SEEK_SET); fi->readx(ibuf, x.size); @@ -5366,7 +5356,7 @@ int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft) asl_pack2_Shdrs(fo, pre_xct_top); } else { // Just copy up to xct_off - x.size = umin(x.size, xct_off - x.offset); + x.size = umin(0ull + x.size, 0ull + xct_off - x.offset); if (0) { // DEBUG paranoia fi->seek(x.offset, SEEK_SET); fi->readx(ibuf, x.size); @@ -6444,7 +6434,7 @@ void PackLinuxElf64::un_shlib_1( // Below xct_off is not compressed (for benefit of rtld.) fi->seek(0, SEEK_SET); - fi->readx(ibuf, umin(blocksize, file_size)); + fi->readx(ibuf, umin(blocksize, file_size_u32)); // Determine if the extra page with copy of _Shdrs was spliced in. // This used to be the result of --android-shlib. @@ -6457,7 +6447,7 @@ void PackLinuxElf64::un_shlib_1( if (e_shoff && e_shnum // +36: (sizeof(PackHeader) + sizeof(overlay_offset)) // after Shdrs for ARM_ATTRIBUTES - && (((e_shoff + sizeof(Elf64_Shdr) * e_shnum) + 36) < (upx_uint64_t)file_size) + && (((e_shoff + sizeof(Elf64_Shdr) * e_shnum) + 36) < file_size_u) ) { // possible --android-shlib unsigned x = get_te32(&file_image[get_te64(&ehdri.e_entry) - (1+ 4)*sizeof(int)]); if (1 & x) { // the clincher @@ -6644,7 +6634,7 @@ void PackLinuxElf32::un_shlib_1( // Below xct_off is not compressed (for benefit of rtld.) fi->seek(0, SEEK_SET); - fi->readx(ibuf, umin(blocksize, file_size)); + fi->readx(ibuf, umin(blocksize, file_size_u32)); // Determine if the extra page with copy of _Shdrs was spliced in. // This used to be the result of --android-shlib. @@ -6657,7 +6647,7 @@ void PackLinuxElf32::un_shlib_1( if (e_shoff && e_shnum // +36: (sizeof(PackHeader) + sizeof(overlay_offset)) // after Shdrs for ARM_ATTRIBUTES - && (((e_shoff + sizeof(Elf32_Shdr) * e_shnum) + 36) < (upx_uint32_t)file_size) + && (((e_shoff + sizeof(Elf32_Shdr) * e_shnum) + 36) < file_size_u32) ) { // possible --android-shlib unsigned x = get_te32(&file_image[get_te32(&ehdri.e_entry) - (1+ 4)*sizeof(int)]); if (1 & x) { // the clincher @@ -6844,7 +6834,7 @@ void PackLinuxElf32::un_DT_INIT( upx_uint32_t dt_relsz(0), dt_rel(0); upx_uint32_t const dyn_len = get_te32(&dynhdr->p_filesz); upx_uint32_t const dyn_off = get_te32(&dynhdr->p_offset); - if ((unsigned long)file_size < (dyn_len + dyn_off)) { + if (file_size_u32 < (dyn_len + dyn_off)) { char msg[50]; snprintf(msg, sizeof(msg), "bad PT_DYNAMIC .p_filesz %#lx", (long unsigned)dyn_len); throwCantUnpack(msg); @@ -6853,7 +6843,7 @@ void PackLinuxElf32::un_DT_INIT( fi->readx(ibuf, dyn_len); Elf32_Dyn *dyn = (Elf32_Dyn *)(void *)ibuf; dynseg = dyn; invert_pt_dynamic(dynseg, - umin(dyn_len, file_size - dyn_off)); + umin(dyn_len, file_size_u32 - dyn_off)); for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) { upx_uint32_t const tag = get_te32(&dyn->d_tag); upx_uint32_t val = get_te32(&dyn->d_val); @@ -7023,7 +7013,7 @@ void PackLinuxElf64::un_DT_INIT( upx_uint64_t dt_relasz(0), dt_rela(0); upx_uint64_t const dyn_len = get_te64(&dynhdr->p_filesz); upx_uint64_t const dyn_off = get_te64(&dynhdr->p_offset); - if ((unsigned long)file_size < (dyn_len + dyn_off)) { + if (file_size_u < (dyn_len + dyn_off)) { char msg[50]; snprintf(msg, sizeof(msg), "bad PT_DYNAMIC .p_filesz %#lx", (long unsigned)dyn_len); throwCantUnpack(msg); @@ -7032,7 +7022,7 @@ void PackLinuxElf64::un_DT_INIT( fi->readx(ibuf, dyn_len); Elf64_Dyn *dyn = (Elf64_Dyn *)(void *)ibuf; dynseg = dyn; invert_pt_dynamic(dynseg, - umin(dyn_len, file_size - dyn_off)); + umin(dyn_len, file_size_u - dyn_off)); for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) { upx_uint64_t const tag = get_te64(&dyn->d_tag); upx_uint64_t val = get_te64(&dyn->d_val); @@ -7238,7 +7228,7 @@ void PackLinuxElf64::unpack(OutputFile *fo) fi->readx(&bhdr, szb_info); ph.u_len = get_te32(&bhdr.sz_unc); ph.c_len = get_te32(&bhdr.sz_cpr); - if (ph.c_len > (unsigned)file_size || ph.c_len == 0 || ph.u_len == 0 + if (ph.c_len > file_size_u || ph.c_len == 0 || ph.u_len == 0 || ph.u_len > orig_file_size) throwCantUnpack("b_info corrupted"); ph.filter_cto = bhdr.b_cto8; @@ -7306,7 +7296,7 @@ void PackLinuxElf64::unpack(OutputFile *fo) fi->seek(- (off_t) (szb_info + ph.c_len), SEEK_CUR); u_phnum = get_te16(&ehdr->e_phnum); - if ((umin64(MAX_ELF_HDR_64, ph.u_len) - sizeof(Elf64_Ehdr))/sizeof(Elf64_Phdr) < u_phnum) { + if ((umin(MAX_ELF_HDR_64, ph.u_len) - sizeof(Elf64_Ehdr))/sizeof(Elf64_Phdr) < u_phnum) { throwCantUnpack("bad compressed e_phnum"); } o_elfhdrs.alloc(sizeof(Elf64_Ehdr) + u_phnum * sizeof(Elf64_Phdr)); @@ -7681,7 +7671,7 @@ PackLinuxElf32::elf_get_offset_from_Phdrs(unsigned addr, Elf32_Phdr const *phdr0 unsigned const t = addr - get_te32(&phdr->p_vaddr); if (t < get_te32(&phdr->p_filesz)) { unsigned const p_offset = get_te32(&phdr->p_offset); - if ((u32_t)file_size <= p_offset) { // FIXME: weak + if (file_size_u <= p_offset) { // FIXME: weak char msg[40]; snprintf(msg, sizeof(msg), "bad Elf32_Phdr[%d].p_offset %x", -1+ e_phnum - j, p_offset); @@ -7703,9 +7693,9 @@ PackLinuxElf32::check_pt_load(Elf32_Phdr const *const phdr) u32_t align = get_te32(&phdr->p_align); if ((-1+ align) & (paddr ^ vaddr) - || (u32_t)file_size <= (u32_t)offset - || (u32_t)file_size < (u32_t)offend - || (u32_t)file_size < (u32_t)filesz) { + || file_size_u32 <= (u32_t)offset + || file_size_u32 < (u32_t)offend + || file_size_u32 < (u32_t)filesz) { char msg[50]; snprintf(msg, sizeof(msg), "bad PT_LOAD phdr[%u]", (unsigned)(phdr - phdri)); throwCantPack(msg); @@ -7789,7 +7779,7 @@ PackLinuxElf32::elf_find_dynamic(unsigned int key) const Elf32_Dyn const *dynp= elf_find_dynptr(key); if (dynp) { unsigned const t= elf_get_offset_from_address(get_te32(&dynp->d_val)); - if (t && t < (unsigned)file_size) { + if (t && t < file_size_u) { return t + file_image; } } @@ -7802,7 +7792,7 @@ PackLinuxElf64::elf_find_dynamic(unsigned int key) const Elf64_Dyn const *dynp= elf_find_dynptr(key); if (dynp) { upx_uint64_t const t= elf_get_offset_from_address(get_te64(&dynp->d_val)); - if (t && t < (upx_uint64_t)file_size) { + if (t && t < file_size_u) { return t + file_image; } } @@ -7838,7 +7828,7 @@ PackLinuxElf64::elf_get_offset_from_address(upx_uint64_t addr) const upx_uint64_t const t = addr - get_te64(&phdr->p_vaddr); if (t < get_te64(&phdr->p_filesz)) { upx_uint64_t const p_offset = get_te64(&phdr->p_offset); - if ((u64_t)file_size <= p_offset) { // FIXME: weak + if (file_size_u <= p_offset) { // FIXME: weak char msg[40]; snprintf(msg, sizeof(msg), "bad Elf64_Phdr[%d].p_offset %#lx", -1+ e_phnum - j, (long unsigned)p_offset); @@ -7860,9 +7850,9 @@ PackLinuxElf64::check_pt_load(Elf64_Phdr const *const phdr) u64_t align = get_te64(&phdr->p_align); if ((-1+ align) & (paddr ^ vaddr) - || (u64_t)file_size <= (u64_t)offset - || (u64_t)file_size < (u64_t)offend - || (u64_t)file_size < (u64_t)filesz) { + || file_size_u <= (u64_t)offset + || file_size_u < (u64_t)offend + || file_size_u < (u64_t)filesz) { char msg[50]; snprintf(msg, sizeof(msg), "bad PT_LOAD phdr[%u]", (unsigned)(phdr - phdri)); throwCantPack(msg); @@ -8072,7 +8062,7 @@ PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp, upx_uint64_t headway) unsigned const v_sym = !x_sym ? 0 : get_te64(&dynp0[-1+ x_sym].d_val); // UPX_RSIZE_MAX_MEM if ((unsigned)(hashend - buckets) < nbucket - || !v_sym || (unsigned)file_size <= v_sym + || !v_sym || file_size_u <= v_sym || ((v_hsh < v_sym) && (v_sym - v_hsh) < sizeof(*buckets)*(2+ nbucket)) ) { char msg[80]; snprintf(msg, sizeof(msg), diff --git a/src/p_lx_exc.cpp b/src/p_lx_exc.cpp index dab1607b..f49671a7 100644 --- a/src/p_lx_exc.cpp +++ b/src/p_lx_exc.cpp @@ -279,15 +279,6 @@ PackLinuxI386::pack4(OutputFile *fo, Filter &ft) fo->rewrite(&elfout, overlay_offset); } -static unsigned -umax(unsigned a, unsigned b) -{ - if (a <= b) { - return b; - } - return a; -} - Linker *PackLinuxI386::newLinker() const { return new ElfLinkerX86; @@ -311,7 +302,7 @@ PackLinuxI386::buildLinuxLoader( usizeof(l_info); if (0 == get_le32(fold_hdrlen + fold)) { // inconsistent SIZEOF_HEADERS in *.lds (ld, binutils) - fold_hdrlen = umax(0x80, fold_hdrlen); + fold_hdrlen = upx::umax(0x80u, fold_hdrlen); } } // This adds the definition to the "library", to be used later. diff --git a/src/p_lx_sh.cpp b/src/p_lx_sh.cpp index d2902c57..b89eebdd 100644 --- a/src/p_lx_sh.cpp +++ b/src/p_lx_sh.cpp @@ -62,15 +62,6 @@ PackLinuxI386sh::~PackLinuxI386sh() { } -static unsigned -umax(unsigned a, unsigned b) -{ - if (a <= b) { - return b; - } - return a; -} - void PackLinuxI386sh::buildLoader(Filter const *ft) { @@ -94,7 +85,7 @@ PackLinuxI386sh::buildLoader(Filter const *ft) sizeof(Elf32_Phdr) * get_te16(&((Elf32_Ehdr const *)(void *)buf)->e_phnum); if (0 == get_le32(buf + fold_hdrlen)) { // inconsistent SIZEOF_HEADERS in *.lds (ld, binutils) - fold_hdrlen = umax(0x80, fold_hdrlen); + fold_hdrlen = upx::umax(0x80u, fold_hdrlen); } bool success = fold_ft.filter(buf + fold_hdrlen, sz_fold - fold_hdrlen); UNUSED(success); diff --git a/src/p_mach.cpp b/src/p_mach.cpp index e53e1f4c..a26ac67a 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -1462,12 +1462,6 @@ void PackMachBase::pack1(OutputFile *const fo, Filter &/*ft*/) // generate e #define WANT_MACH_HEADER_ENUM 1 #include "p_mach_enum.h" -static unsigned -umin(unsigned a, unsigned b) -{ - return (a <= b) ? a : b; -} - #define MAX_N_CMDS 256 template @@ -1549,7 +1543,7 @@ void PackMachBase::unpack(OutputFile *fo) "bad packed Mach load_command @%#x", ptr_udiff_bytes(ptr, mhdr)); throwCantUnpack(msg); } - memcpy(&msegcmd[j], ptr, umin(sizeof(Mach_segment_command), cmdsize)); + memcpy(&msegcmd[j], ptr, upx::umin(usizeof(Mach_segment_command), cmdsize)); headway -= cmdsize; ptr += cmdsize; } @@ -1903,7 +1897,7 @@ tribool PackMachBase::canUnpack() if ( overlay_offset < sz_mach_headers || (off_t)overlay_offset >= file_size) { infoWarning("file corrupted: %s", fi->getName()); - MemBuffer buf2(umin(1<<14, file_size)); + MemBuffer buf2(upx::umin(1u<<14, file_size_u32)); fi->seek(sz_mach_headers, SEEK_SET); fi->readx(buf2, buf2.getSize()); unsigned const *p = (unsigned const *)&buf2[0]; @@ -1966,7 +1960,7 @@ tribool PackMachBase::canPack() throwCantPack("%d < Mach_header.ncmds", MAX_N_CMDS); } unsigned const sz_mhcmds = (unsigned)mhdri.sizeofcmds; - unsigned headway = umin(sz_mhcmds, file_size - sizeof(mhdri)); + unsigned headway = upx::umin(sz_mhcmds, file_size_u32 - usizeof(mhdri)); if (headway < sz_mhcmds) { char buf[32]; snprintf(buf, sizeof(buf), "bad sizeofcmds %d", sz_mhcmds); throwCantPack(buf); diff --git a/src/p_unix.cpp b/src/p_unix.cpp index 5114b7aa..13e28621 100644 --- a/src/p_unix.cpp +++ b/src/p_unix.cpp @@ -599,8 +599,6 @@ int PackUnix::find_overlay_offset(MemBuffer const &buf) // See notes there. **************************************************************************/ -static unsigned umax(unsigned a, unsigned b) {return (a < b) ? b : a;} - void PackUnix::unpack(OutputFile *fo) { b_info bhdr; @@ -671,7 +669,7 @@ void PackUnix::unpack(OutputFile *fo) // first flag bits of NRV_d32, the 5-byte info of LZMA, etc. // Fuzzers may try sz_cpr shorter than possible. // Use some OVERHEAD for safety. - i = blocksize + OVERHEAD - umax(12, sz_cpr); + i = blocksize + OVERHEAD - upx::umax(12u, sz_cpr); if (i < 0) throwCantUnpack("corrupt b_info"); fi->readx(buf+i, sz_cpr); diff --git a/src/p_unix.h b/src/p_unix.h index 146585c2..22a347b2 100644 --- a/src/p_unix.h +++ b/src/p_unix.h @@ -76,8 +76,8 @@ protected: protected: struct Extent { - off_t offset; - off_t size; + upx_off_t offset; + upx_off_t size; }; virtual void packExtent(const Extent &x, Filter *, OutputFile *, diff --git a/src/p_vmlinz.cpp b/src/p_vmlinz.cpp index d704dbd7..75742ccb 100644 --- a/src/p_vmlinz.cpp +++ b/src/p_vmlinz.cpp @@ -29,6 +29,7 @@ #define ALLOW_INT_PLUS_MEMBUFFER 1 #include "conf.h" +#if (WITH_ZLIB) #include "p_elf.h" #include "file.h" #include "filter.h" @@ -1071,4 +1072,6 @@ void PackVmlinuzARMEL::unpack(OutputFile *fo) } } +#endif // WITH_ZLIB + /* vim:set ts=4 sw=4 et: */ diff --git a/src/packer.cpp b/src/packer.cpp index 5c6cb502..1d37f0ea 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -36,9 +36,12 @@ // **************************************************************************/ -PackerBase::PackerBase(InputFile *f) : fi(f), file_size(f ? f->st_size() : 0) { +PackerBase::PackerBase(InputFile *f) + : fi(f), file_size(f != nullptr ? f->st_size() : 0), file_size_i32(file_size) { ph.reset(); - mem_size_assert(1, file_size); + mem_size_assert(1, file_size_u); + assert_noexcept(file_size_i32 == file_size); + assert_noexcept(file_size_u32 == file_size_u); } Packer::Packer(InputFile *f) : PackerBase(f) { uip = new UiPacker(this); } diff --git a/src/packer.h b/src/packer.h index b675038c..4995e47a 100644 --- a/src/packer.h +++ b/src/packer.h @@ -81,10 +81,17 @@ public: static constexpr unsigned MAX_FILTERS = 16; // for getFilters() protected: - InputFile *const fi; // reference - union { // unnamed union - const upx_int64_t file_size; // must get set by constructor - const upx_uint64_t file_size_u; // (explicitly unsigned to avoid -Wsign-compare casts) + InputFile *const fi; // reference + // multiple names for "file_size" to avoid casts + union { // unnamed union + const upx_int64_t file_size; // must get set by constructor + const upx_uint64_t file_size_u; + const upx_int64_t file_size_i64; + const upx_uint64_t file_size_u64; + }; + union { // unnamed union + const upx_int32_t file_size_i32; + const upx_uint32_t file_size_u32; }; PackHeader ph; // must be filled by canUnpack(); also used by UiPacker }; diff --git a/src/packmast.cpp b/src/packmast.cpp index 3b608558..e3a0367b 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -178,9 +178,11 @@ PackerBase *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const O VISIT(PackVmlinuxPPC64LE); VISIT(PackVmlinuxAMD64); VISIT(PackVmlinuxI386); +#if (WITH_ZLIB) VISIT(PackVmlinuzI386); VISIT(PackBvmlinuzI386); VISIT(PackVmlinuzARMEL); +#endif // // linux diff --git a/src/pefile.cpp b/src/pefile.cpp index d08d3f34..0dca1a79 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -2179,8 +2179,6 @@ unsigned PeFile::handleStripRelocs(upx_uint64_t ih_imagebase, upx_uint64_t defau return 0; } -static unsigned umax(unsigned a, unsigned b) { return (a >= b) ? a : b; } - unsigned PeFile::readSections(unsigned objs, unsigned usize, unsigned ih_filealign, unsigned ih_datasize) { const unsigned xtrasize = UPX_MAX(ih_datasize, 65536u) + IDSIZE(PEDIR_IMPORT) + @@ -2224,7 +2222,7 @@ unsigned PeFile::readSections(unsigned objs, unsigned usize, unsigned ih_fileali if (isection[ic].vaddr + jc > ibuf.getSize()) throwInternalError("buffer too small 1"); fi->readx(ibuf.subref("bad section %#x", isection[ic].vaddr, jc), jc); - ibufgood = umax(ibufgood, jc + isection[ic].vaddr); // FIXME: simplistic + ibufgood = upx::umax(ibufgood, jc + isection[ic].vaddr); // FIXME: simplistic jc += isection[ic].rawdataptr; } return overlaystart; diff --git a/src/util/cxxlib.h b/src/util/cxxlib.h index 42655388..f70058ce 100644 --- a/src/util/cxxlib.h +++ b/src/util/cxxlib.h @@ -142,7 +142,7 @@ private: #endif /************************************************************************* -// type_traits +// **************************************************************************/ // is_bounded_array: identical to C++20 std::is_bounded_array @@ -163,6 +163,63 @@ struct is_same_any : public std::disjunction...> {}; template inline constexpr bool is_same_any_v = is_same_any::value; +/************************************************************************* +// C++20 +**************************************************************************/ + +template +forceinline constexpr bool has_single_bit(T x) noexcept { + return x != 0 && (x & (x - 1)) == 0; +} + +/************************************************************************* +// +**************************************************************************/ + +template +inline T align_down(const T &x, const T &alignment) noexcept { + assert_noexcept(has_single_bit(alignment)); + T r; + r = (x / alignment) * alignment; + return r; +} +template +inline T align_up(const T &x, const T &alignment) noexcept { + assert_noexcept(has_single_bit(alignment)); + T r; + r = ((x + (alignment - 1)) / alignment) * alignment; + return r; +} +template +inline T align_gap(const T &x, const T &alignment) noexcept { + assert_noexcept(has_single_bit(alignment)); + T r; + r = align_up(x, alignment) - x; + return r; +} + +template +forceinline constexpr T min(const T &a, const T &b) noexcept { + return b < a ? b : a; +} +template +forceinline constexpr T max(const T &a, const T &b) noexcept { + return a < b ? b : a; +} + +template +inline constexpr bool is_uminmax_type = + is_same_any_v; + +template , T> > +forceinline constexpr T umin(const T &a, const T &b) noexcept { + return b < a ? b : a; +} +template , T> > +forceinline constexpr T umax(const T &a, const T &b) noexcept { + return a < b ? b : a; +} + /************************************************************************* // util **************************************************************************/ diff --git a/src/util/membuffer.cpp b/src/util/membuffer.cpp index ecfcfc47..64fb144c 100644 --- a/src/util/membuffer.cpp +++ b/src/util/membuffer.cpp @@ -97,8 +97,6 @@ void *MemBuffer::subref_impl(const char *errfmt, size_t skip, size_t take) { return ptr + skip; } -static forceinline constexpr size_t umax(size_t a, size_t b) { return (a >= b) ? a : b; } - /*static*/ unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned extra) { if (uncompressed_size == 0) @@ -106,9 +104,9 @@ unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned e const size_t z = uncompressed_size; // fewer keystrokes and display columns size_t bytes = mem_size(1, z); // check size // All literal: 1 bit overhead per literal byte; from UCL documentation - bytes = umax(bytes, z + z / 8 + 256); + bytes = upx::umax(bytes, z + z / 8 + 256); // zstd: ZSTD_COMPRESSBOUND - bytes = umax(bytes, z + (z >> 8) + ((z < (128 << 10)) ? (((128 << 10) - z) >> 11) : 0)); + bytes = upx::umax(bytes, z + (z >> 8) + ((z < (128 << 10)) ? (((128 << 10) - z) >> 11) : 0)); // add extra and 256 safety for various rounding/alignments bytes = mem_size(1, bytes, extra, 256); return ACC_ICONV(unsigned, bytes); diff --git a/src/util/system_defs.h b/src/util/system_defs.h index 17cc48f0..5a16a59d 100644 --- a/src/util/system_defs.h +++ b/src/util/system_defs.h @@ -47,6 +47,12 @@ #endif #endif +#if !defined(NOMINMAX) +#if defined(_WIN32) || defined(__CYGWIN__) +#define NOMINMAX 1 +#endif +#endif + #if defined(_WIN32) || defined(__CYGWIN__) // disable silly warnings about using "deprecated" POSIX functions like fopen() #if !defined(_CRT_NONSTDC_NO_DEPRECATE) diff --git a/src/util/system_features.h b/src/util/system_features.h index cb2fee2a..cd1b903e 100644 --- a/src/util/system_features.h +++ b/src/util/system_features.h @@ -44,18 +44,25 @@ // libc++ hardenining #if defined(__cplusplus) && 0 // TODO later + #if defined(__clang__) && defined(__clang_major__) && (__clang_major__ + 0 >= 18) +#if !defined(_LIBCPP_HARDENING_MODE) #if DEBUG #define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEBUG #else #define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_EXTENSIVE #endif #endif +#endif // clang >= 18 + #if defined(__clang__) && defined(__clang_major__) && (__clang_major__ + 0 < 18) +#if !defined(_LIBCPP_ENABLE_ASSERTIONS) #if DEBUG #define _LIBCPP_ENABLE_ASSERTIONS 1 #endif -#endif // clang >= 18 +#endif +#endif // clang < 18 + #endif // TODO later /* vim:set ts=4 sw=4 et: */