diff --git a/src/bele.h b/src/bele.h index 1b8ee586..ca2282cf 100644 --- a/src/bele.h +++ b/src/bele.h @@ -42,39 +42,103 @@ #define bswap64 upx_bswap64 #endif +/************************************************************************* +// XE - eXtended Endian compatibility +// try to detect XX16 vs XX32 vs XX64 size mismatches +**************************************************************************/ + +#if 0 // permissive version using "void *" + +#define REQUIRE_XE16 /*empty*/ +#define REQUIRE_XE24 /*empty*/ +#define REQUIRE_XE32 /*empty*/ +#define REQUIRE_XE64 /*empty*/ +typedef void XE16; +typedef void XE24; +typedef void XE32; +typedef void XE64; + +#else // permissive version + +// forward declarations +struct BE16; +struct BE32; +struct BE64; +struct LE16; +struct LE32; +struct LE64; + +// Note: +// void is explicitly allowed, but there is no automatic pointer conversion because of template +// char is explicitly allowed +// byte is explicitly allowed +template +static inline constexpr bool is_xe16_type = + upx::is_same_any_v; +template +static inline constexpr bool is_xe24_type = upx::is_same_any_v; +template +static inline constexpr bool is_xe32_type = + upx::is_same_any_v; +template +static inline constexpr bool is_xe64_type = + upx::is_same_any_v; + +template +using enable_if_xe16 = std::enable_if_t, T>; +template +using enable_if_xe24 = std::enable_if_t, T>; +template +using enable_if_xe32 = std::enable_if_t, T>; +template +using enable_if_xe64 = std::enable_if_t, T>; + +#define REQUIRE_XE16 template > +#define REQUIRE_XE24 template > +#define REQUIRE_XE32 template > +#define REQUIRE_XE64 template > + +#endif // permissive version + /************************************************************************* // core - NE **************************************************************************/ -static forceinline unsigned get_ne16(const void *p) noexcept { +REQUIRE_XE16 +static forceinline unsigned get_ne16(const XE16 *p) noexcept { upx_uint16_t v = 0; upx_memcpy_inline(&v, p, sizeof(v)); return v; } -static forceinline unsigned get_ne32(const void *p) noexcept { +REQUIRE_XE32 +static forceinline unsigned get_ne32(const XE32 *p) noexcept { upx_uint32_t v = 0; upx_memcpy_inline(&v, p, sizeof(v)); return v; } -static forceinline upx_uint64_t get_ne64(const void *p) noexcept { +REQUIRE_XE64 +static forceinline upx_uint64_t get_ne64(const XE64 *p) noexcept { upx_uint64_t v = 0; upx_memcpy_inline(&v, p, sizeof(v)); return v; } -static forceinline void set_ne16(void *p, unsigned vv) noexcept { +REQUIRE_XE16 +static forceinline void set_ne16(XE16 *p, unsigned vv) noexcept { upx_uint16_t v = (upx_uint16_t) (vv & 0xffff); upx_memcpy_inline(p, &v, sizeof(v)); } -static forceinline void set_ne32(void *p, unsigned vv) noexcept { +REQUIRE_XE32 +static forceinline void set_ne32(XE32 *p, unsigned vv) noexcept { upx_uint32_t v = vv; upx_memcpy_inline(p, &v, sizeof(v)); } -static forceinline void set_ne64(void *p, upx_uint64_t vv) noexcept { +REQUIRE_XE64 +static forceinline void set_ne64(XE64 *p, upx_uint64_t vv) noexcept { upx_uint64_t v = vv; upx_memcpy_inline(p, &v, sizeof(v)); } @@ -138,41 +202,58 @@ static forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) noexcept { // get/set 16/32/64 **************************************************************************/ -inline unsigned get_be16(const void *p) noexcept { return ne16_to_be16(get_ne16(p)); } -inline unsigned get_be32(const void *p) noexcept { return ne32_to_be32(get_ne32(p)); } -inline upx_uint64_t get_be64(const void *p) noexcept { return ne64_to_be64(get_ne64(p)); } -inline unsigned get_le16(const void *p) noexcept { return ne16_to_le16(get_ne16(p)); } -inline unsigned get_le32(const void *p) noexcept { return ne32_to_le32(get_ne32(p)); } -inline upx_uint64_t get_le64(const void *p) noexcept { return ne64_to_le64(get_ne64(p)); } -inline void set_be16(void *p, unsigned v) noexcept { set_ne16(p, ne16_to_be16(v)); } -inline void set_be32(void *p, unsigned v) noexcept { set_ne32(p, ne32_to_be32(v)); } -inline void set_be64(void *p, upx_uint64_t v) noexcept { set_ne64(p, ne64_to_be64(v)); } -inline void set_le16(void *p, unsigned v) noexcept { set_ne16(p, ne16_to_le16(v)); } -inline void set_le32(void *p, unsigned v) noexcept { set_ne32(p, ne32_to_le32(v)); } -inline void set_le64(void *p, upx_uint64_t v) noexcept { set_ne64(p, ne64_to_le64(v)); } +REQUIRE_XE16 +inline unsigned get_be16(const XE16 *p) noexcept { return ne16_to_be16(get_ne16(p)); } +REQUIRE_XE32 +inline unsigned get_be32(const XE32 *p) noexcept { return ne32_to_be32(get_ne32(p)); } +REQUIRE_XE64 +inline upx_uint64_t get_be64(const XE64 *p) noexcept { return ne64_to_be64(get_ne64(p)); } +REQUIRE_XE16 +inline unsigned get_le16(const XE16 *p) noexcept { return ne16_to_le16(get_ne16(p)); } +REQUIRE_XE32 +inline unsigned get_le32(const XE32 *p) noexcept { return ne32_to_le32(get_ne32(p)); } +REQUIRE_XE64 +inline upx_uint64_t get_le64(const XE64 *p) noexcept { return ne64_to_le64(get_ne64(p)); } + +REQUIRE_XE16 +inline void set_be16(XE16 *p, unsigned v) noexcept { set_ne16(p, ne16_to_be16(v)); } +REQUIRE_XE32 +inline void set_be32(XE32 *p, unsigned v) noexcept { set_ne32(p, ne32_to_be32(v)); } +REQUIRE_XE64 +inline void set_be64(XE64 *p, upx_uint64_t v) noexcept { set_ne64(p, ne64_to_be64(v)); } +REQUIRE_XE16 +inline void set_le16(XE16 *p, unsigned v) noexcept { set_ne16(p, ne16_to_le16(v)); } +REQUIRE_XE32 +inline void set_le32(XE32 *p, unsigned v) noexcept { set_ne32(p, ne32_to_le32(v)); } +REQUIRE_XE64 +inline void set_le64(XE64 *p, upx_uint64_t v) noexcept { set_ne64(p, ne64_to_le64(v)); } /************************************************************************* // get/set 24/26 **************************************************************************/ -inline unsigned get_be24(const void *p) noexcept { +REQUIRE_XE24 +inline unsigned get_be24(const XE24 *p) noexcept { const byte *b = ACC_CCAST(const byte *, p); return (b[0] << 16) | (b[1] << 8) | (b[2] << 0); } -inline unsigned get_le24(const void *p) noexcept { +REQUIRE_XE24 +inline unsigned get_le24(const XE24 *p) noexcept { const byte *b = ACC_CCAST(const byte *, p); return (b[0] << 0) | (b[1] << 8) | (b[2] << 16); } -inline void set_be24(void *p, unsigned v) noexcept { +REQUIRE_XE24 +inline void set_be24(XE24 *p, unsigned v) noexcept { byte *b = ACC_PCAST(byte *, p); b[0] = ACC_ICONV(byte, (v >> 16) & 0xff); b[1] = ACC_ICONV(byte, (v >> 8) & 0xff); b[2] = ACC_ICONV(byte, (v >> 0) & 0xff); } -inline void set_le24(void *p, unsigned v) noexcept { +REQUIRE_XE24 +inline void set_le24(XE24 *p, unsigned v) noexcept { byte *b = ACC_PCAST(byte *, p); b[0] = ACC_ICONV(byte, (v >> 0) & 0xff); b[1] = ACC_ICONV(byte, (v >> 8) & 0xff); @@ -201,56 +282,64 @@ inline void set_le14_5(void *p, unsigned v) noexcept { // get signed values **************************************************************************/ -static forceinline int sign_extend(unsigned v, unsigned bits) noexcept { +static forceinline constexpr int sign_extend(unsigned v, unsigned bits) noexcept { const unsigned sign_bit = 1u << (bits - 1); v &= sign_bit | (sign_bit - 1); v |= 0u - (v & sign_bit); return ACC_ICAST(int, v); } -static forceinline upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) noexcept { +static forceinline constexpr upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) noexcept { const upx_uint64_t sign_bit = 1ull << (bits - 1); v &= sign_bit | (sign_bit - 1); v |= 0ull - (v & sign_bit); return ACC_ICAST(upx_int64_t, v); } -inline int get_be16_signed(const void *p) noexcept { +REQUIRE_XE16 +inline int get_be16_signed(const XE16 *p) noexcept { unsigned v = get_be16(p); return sign_extend(v, 16); } -inline int get_be24_signed(const void *p) noexcept { +REQUIRE_XE24 +inline int get_be24_signed(const XE24 *p) noexcept { unsigned v = get_be24(p); return sign_extend(v, 24); } -inline int get_be32_signed(const void *p) noexcept { +REQUIRE_XE32 +inline int get_be32_signed(const XE32 *p) noexcept { unsigned v = get_be32(p); return sign_extend(v, 32); } -inline upx_int64_t get_be64_signed(const void *p) noexcept { +REQUIRE_XE64 +inline upx_int64_t get_be64_signed(const XE64 *p) noexcept { upx_uint64_t v = get_be64(p); return sign_extend(v, 64); } -inline int get_le16_signed(const void *p) noexcept { +REQUIRE_XE16 +inline int get_le16_signed(const XE16 *p) noexcept { unsigned v = get_le16(p); return sign_extend(v, 16); } -inline int get_le24_signed(const void *p) noexcept { +REQUIRE_XE24 +inline int get_le24_signed(const XE24 *p) noexcept { unsigned v = get_le24(p); return sign_extend(v, 24); } -inline int get_le32_signed(const void *p) noexcept { +REQUIRE_XE32 +inline int get_le32_signed(const XE32 *p) noexcept { unsigned v = get_le32(p); return sign_extend(v, 32); } -inline upx_int64_t get_le64_signed(const void *p) noexcept { +REQUIRE_XE64 +inline upx_int64_t get_le64_signed(const XE64 *p) noexcept { upx_uint64_t v = get_le64(p); return sign_extend(v, 64); } @@ -633,6 +722,7 @@ inline unsigned ALIGN_DOWN(const LE32 &a, unsigned b) { return ALIGN_DOWN(unsign 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); } +// TODO: 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)); } diff --git a/src/check/dt_check.cpp b/src/check/dt_check.cpp index c66b8f21..8f2251e3 100644 --- a/src/check/dt_check.cpp +++ b/src/check/dt_check.cpp @@ -113,6 +113,17 @@ ACC_COMPILE_TIME_ASSERT_HEADER(bswap64(bswap64(0xf8f7f6f5f4f3f2f1ull)) == no_bswap64(0xf8f7f6f5f4f3f2f1ull)) #endif +ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 0, 8) == 0) +ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 1, 8) == 1) +ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 127, 8) == 127) +ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 128, 8) == -128) +ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u - 1, 8) == -1) +ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 256, 8) == 0) +ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 257, 8) == 1) +ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 383, 8) == 127) +ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 384, 8) == -128) +ACC_COMPILE_TIME_ASSERT_HEADER(sign_extend(0u + 511, 8) == -1) + ACC_COMPILE_TIME_ASSERT_HEADER(CHAR_BIT == 8) #if 0 // does not work with MSVC #if '\0' - 1 < 0 diff --git a/src/conf.h b/src/conf.h index fc05d803..fd731f6e 100644 --- a/src/conf.h +++ b/src/conf.h @@ -109,8 +109,7 @@ inline constexpr bool upx_is_integral_v = upx_is_integral::value; // protect against integer overflows and malicious header fields // see C 11 standard, Annex K // -// this limits uncompressed_size to about 640 MiB which is perfectly fine: -// "640 MiB Ought to be Enough for Anyone" --Markus F.X.J. Oberhumer, 1981 ;-) +// this limits uncompressed_size to about 682 MiB (715_128_832 bytes) typedef size_t upx_rsize_t; #define UPX_RSIZE_MAX UPX_RSIZE_MAX_MEM #define UPX_RSIZE_MAX_MEM (768 * 1024 * 1024) // DO NOT CHANGE !!! diff --git a/src/util/membuffer.cpp b/src/util/membuffer.cpp index f5398082..061a9ac5 100644 --- a/src/util/membuffer.cpp +++ b/src/util/membuffer.cpp @@ -321,8 +321,11 @@ TEST_CASE("MemBuffer::getSizeForCompression") { CHECK(MemBuffer::getSizeForCompression(1024 * 1024) == 1180160); // 0x00100000 CHECK(MemBuffer::getSizeForCompression(64 * 1024 * 1024) == 75497984); // 0x04000000 CHECK(MemBuffer::getSizeForCompression(512 * 1024 * 1024) == 603980288); // 0x20000000 - // "640 MiB Ought to be Enough for Anyone" --Markus F.X.J. Oberhumer, 1981 ;-) CHECK(MemBuffer::getSizeForCompression(640 * 1024 * 1024) == 754975232); // 0x28000000 + // "682 MiB Ought to be Enough for Anyone" --Markus F.X.J. Oberhumer, 2023 ;-) + CHECK(MemBuffer::getSizeForCompression(682 * 1024 * 1024) == 804520448); // 0x2aa00000 + CHECK(MemBuffer::getSizeForCompression(715827428) == UPX_RSIZE_MAX); // 0x2aaaa8e4 + CHECK_THROWS(MemBuffer::getSizeForCompression(715827428 + 1)); // 0x2aaaa8e4 + 1 } /* vim:set ts=4 sw=4 et: */ diff --git a/src/util/util.cpp b/src/util/util.cpp index e241a41e..3c737bb8 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -43,8 +43,7 @@ // and malicious header fields // see C 11 standard, Annex K // -// this limits uncompressed_size to about 640 MiB which is perfectly fine: -// "640 MiB Ought to be Enough for Anyone" --Markus F.X.J. Oberhumer, 1981 ;-) +// this limits uncompressed_size to about 682 MiB (715_128_832 bytes) **************************************************************************/ ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_MEM == UPX_RSIZE_MAX)