all: assorted cleanups and updates

Changes include:
  - add a bunch of "noexcept", mostly to operators and forceinline
  - use "uchar"
  - use "charptr"
  - rename options_t to Options
  - add ptr_check_no_overlap()
  - rewrite p_exe.cpp, NFCI
  - clang-format help.cpp
  - spelling fixes
This commit is contained in:
Markus F.X.J. Oberhumer
2023-03-15 00:19:55 +01:00
parent 127fd095e7
commit a627648249
65 changed files with 1492 additions and 1138 deletions
+9 -6
View File
@@ -1,9 +1,10 @@
#
# UPX Makefile - needs GNU make
# UPX src Makefile - needs GNU make and CMake >= 3.13
#
# IMPORTANT NOTE: this Makefile is deprecated - please
# directly use the CMake build instead!
# NOTE: this Makefile is deprecated - please directly use the CMake build
# instead. And see the top-level Makefile for some pre-defined CMake
# build configurations.
MAKEFLAGS += -r
.SUFFIXES:
@@ -21,6 +22,7 @@ endif
# redirect to top-level CMake build
#
# note that top-level Makefile .DEFAULT_GOAL is build/release
.DEFAULT_GOAL = build/debug
build/debug: $(top_srcdir)/build/debug/upx
@@ -35,8 +37,10 @@ $(top_srcdir)/build/debug/upx: PHONY
$(top_srcdir)/build/release/upx: PHONY
$(MAKE) -C $(top_srcdir) build/release
.NOTPARALLEL: # because the actual builds use "cmake --parallel"
.PHONY: PHONY
.NOTPARALLEL:
.SECONDEXPANSION:
.SUFFIXES:
#
# "make run-testsuite"
@@ -79,9 +83,8 @@ endif
# automatically format some C++ source code files
ifeq ($(shell uname),Linux)
# Markus loves clang-format, but John hates it; find a compromise
CLANG_FORMAT_EXCLUDE_FILES += conf.h miniacc.h version.h help.cpp
CLANG_FORMAT_EXCLUDE_FILES += conf.h miniacc.h version.h packer_c.cpp
CLANG_FORMAT_EXCLUDE_FILES += p_elf.h p_elf_enum.h p_lx_% p_mach% p_unix% p_vmlin%
CLANG_FORMAT_EXCLUDE_FILES += packer_c.cpp
CLANG_FORMAT_EXCLUDE_FILES += compress/compress.h filter/filter_impl.cpp
CLANG_FORMAT_FILES := $(sort $(wildcard *.[ch]* ../maint/src/*.[ch]* [cu]*/*.[ch]*))
CLANG_FORMAT_FILES := $(filter-out $(CLANG_FORMAT_EXCLUDE_FILES),$(CLANG_FORMAT_FILES))
+139 -119
View File
@@ -38,35 +38,35 @@
// core - NE
**************************************************************************/
static forceinline unsigned get_ne16(const void *p) {
static forceinline unsigned get_ne16(const void *p) noexcept {
upx_uint16_t v = 0;
upx_memcpy_inline(&v, p, sizeof(v));
return v;
}
static forceinline unsigned get_ne32(const void *p) {
static forceinline unsigned get_ne32(const void *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) {
static forceinline upx_uint64_t get_ne64(const void *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) {
static forceinline void set_ne16(void *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) {
static forceinline void set_ne32(void *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) {
static forceinline void set_ne64(void *p, upx_uint64_t vv) noexcept {
upx_uint64_t v = vv;
upx_memcpy_inline(p, &v, sizeof(v));
}
@@ -79,31 +79,35 @@ static forceinline void set_ne64(void *p, upx_uint64_t vv) {
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)
// unfortunately *not* constexpr with MSVC
static forceinline unsigned bswap16(unsigned v) { return (unsigned) _byteswap_ulong(v << 16); }
static forceinline unsigned bswap32(unsigned v) { return (unsigned) _byteswap_ulong(v); }
static forceinline upx_uint64_t bswap64(upx_uint64_t v) { return _byteswap_uint64(v); }
// unfortunately *not* constexpr with current MSVC
static forceinline unsigned bswap16(unsigned v) noexcept {
return (unsigned) _byteswap_ulong(v << 16);
}
static forceinline unsigned bswap32(unsigned v) noexcept { return (unsigned) _byteswap_ulong(v); }
static forceinline upx_uint64_t bswap64(upx_uint64_t v) noexcept { return _byteswap_uint64(v); }
#else
static forceinline constexpr unsigned bswap16(unsigned v) {
static forceinline constexpr unsigned bswap16(unsigned v) noexcept {
// return __builtin_bswap16((upx_uint16_t) (v & 0xffff));
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48);
return __builtin_bswap32(v << 16);
}
static forceinline constexpr unsigned bswap32(unsigned v) {
static forceinline constexpr unsigned bswap32(unsigned v) noexcept {
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 32);
return __builtin_bswap32(v);
}
static forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) { return __builtin_bswap64(v); }
static forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) noexcept {
return __builtin_bswap64(v);
}
#endif
static forceinline constexpr unsigned no_bswap16(unsigned v) {
static forceinline constexpr unsigned no_bswap16(unsigned v) noexcept {
return v & 0xffff; // needed so that this is equivalent to bswap16() above
}
static forceinline constexpr unsigned no_bswap32(unsigned v) { return v; }
static forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) { return v; }
static forceinline constexpr unsigned no_bswap32(unsigned v) noexcept { return v; }
static forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) noexcept { return v; }
#if (ACC_ABI_BIG_ENDIAN)
#define ne16_to_be16(v) no_bswap16(v)
@@ -170,30 +174,27 @@ inline unsigned get_le26(const void *p) { return get_le32(p) & 0x03ffffff; }
inline void set_le26(void *p, unsigned v) {
// preserve the top 6 bits
#if 0
set_le32(p, (get_le32(p) & 0xfc000000) | (v & 0x03ffffff));
#else
// set_le32(p, (get_le32(p) & 0xfc000000) | (v & 0x03ffffff));
// optimized version, saving a runtime bswap32
set_ne32(p, (get_ne32(p) & ne32_to_le32(0xfc000000)) |
(ne32_to_le32(v) & ne32_to_le32(0x03ffffff)));
#endif
}
/*************************************************************************
// get signed values
**************************************************************************/
static forceinline int sign_extend(unsigned v, unsigned bits) {
static forceinline int sign_extend(unsigned v, unsigned bits) noexcept {
const unsigned sign_bit = 1u << (bits - 1);
v &= sign_bit | (sign_bit - 1);
v |= 0 - (v & sign_bit);
v |= 0u - (v & sign_bit);
return ACC_ICAST(int, v);
}
static forceinline upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) {
static forceinline 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 |= 0 - (v & sign_bit);
v |= 0ull - (v & sign_bit);
return ACC_ICAST(upx_int64_t, v);
}
@@ -252,359 +253,348 @@ struct alignas(1) BE16 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[2];
BE16 &operator=(unsigned v) {
BE16 &operator=(unsigned v) noexcept {
set_be16(d, v);
return *this;
}
BE16 &operator+=(unsigned v) {
BE16 &operator+=(unsigned v) noexcept {
set_be16(d, get_be16(d) + v);
return *this;
}
BE16 &operator-=(unsigned v) {
BE16 &operator-=(unsigned v) noexcept {
set_be16(d, get_be16(d) - v);
return *this;
}
BE16 &operator*=(unsigned v) {
BE16 &operator*=(unsigned v) noexcept {
set_be16(d, get_be16(d) * v);
return *this;
}
BE16 &operator/=(unsigned v) {
BE16 &operator/=(unsigned v) noexcept {
set_be16(d, get_be16(d) / v);
return *this;
}
BE16 &operator&=(unsigned v) {
BE16 &operator&=(unsigned v) noexcept {
set_be16(d, get_be16(d) & v);
return *this;
}
BE16 &operator|=(unsigned v) {
BE16 &operator|=(unsigned v) noexcept {
set_be16(d, get_be16(d) | v);
return *this;
}
BE16 &operator^=(unsigned v) {
BE16 &operator^=(unsigned v) noexcept {
set_be16(d, get_be16(d) ^ v);
return *this;
}
BE16 &operator<<=(unsigned v) {
BE16 &operator<<=(unsigned v) noexcept {
set_be16(d, get_be16(d) << v);
return *this;
}
BE16 &operator>>=(unsigned v) {
BE16 &operator>>=(unsigned v) noexcept {
set_be16(d, get_be16(d) >> v);
return *this;
}
operator unsigned() const { return get_be16(d); }
operator unsigned() const noexcept { return get_be16(d); }
bool operator<(const BE16 &v) const { return unsigned(*this) < unsigned(v); }
bool operator<(const BE16 &v) const noexcept { return unsigned(*this) < unsigned(v); }
};
struct alignas(1) BE32 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[4];
BE32 &operator=(unsigned v) {
BE32 &operator=(unsigned v) noexcept {
set_be32(d, v);
return *this;
}
BE32 &operator+=(unsigned v) {
BE32 &operator+=(unsigned v) noexcept {
set_be32(d, get_be32(d) + v);
return *this;
}
BE32 &operator-=(unsigned v) {
BE32 &operator-=(unsigned v) noexcept {
set_be32(d, get_be32(d) - v);
return *this;
}
BE32 &operator*=(unsigned v) {
BE32 &operator*=(unsigned v) noexcept {
set_be32(d, get_be32(d) * v);
return *this;
}
BE32 &operator/=(unsigned v) {
BE32 &operator/=(unsigned v) noexcept {
set_be32(d, get_be32(d) / v);
return *this;
}
BE32 &operator&=(unsigned v) {
BE32 &operator&=(unsigned v) noexcept {
set_be32(d, get_be32(d) & v);
return *this;
}
BE32 &operator|=(unsigned v) {
BE32 &operator|=(unsigned v) noexcept {
set_be32(d, get_be32(d) | v);
return *this;
}
BE32 &operator^=(unsigned v) {
BE32 &operator^=(unsigned v) noexcept {
set_be32(d, get_be32(d) ^ v);
return *this;
}
BE32 &operator<<=(unsigned v) {
BE32 &operator<<=(unsigned v) noexcept {
set_be32(d, get_be32(d) << v);
return *this;
}
BE32 &operator>>=(unsigned v) {
BE32 &operator>>=(unsigned v) noexcept {
set_be32(d, get_be32(d) >> v);
return *this;
}
operator unsigned() const { return get_be32(d); }
operator unsigned() const noexcept { return get_be32(d); }
bool operator<(const BE32 &v) const { return unsigned(*this) < unsigned(v); }
bool operator<(const BE32 &v) const noexcept { return unsigned(*this) < unsigned(v); }
};
struct alignas(1) BE64 {
typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t
byte d[8];
BE64 &operator=(upx_uint64_t v) {
BE64 &operator=(upx_uint64_t v) noexcept {
set_be64(d, v);
return *this;
}
BE64 &operator+=(upx_uint64_t v) {
BE64 &operator+=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) + v);
return *this;
}
BE64 &operator-=(upx_uint64_t v) {
BE64 &operator-=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) - v);
return *this;
}
BE64 &operator*=(upx_uint64_t v) {
BE64 &operator*=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) * v);
return *this;
}
BE64 &operator/=(upx_uint64_t v) {
BE64 &operator/=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) / v);
return *this;
}
BE64 &operator&=(upx_uint64_t v) {
BE64 &operator&=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) & v);
return *this;
}
BE64 &operator|=(upx_uint64_t v) {
BE64 &operator|=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) | v);
return *this;
}
BE64 &operator^=(upx_uint64_t v) {
BE64 &operator^=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) ^ v);
return *this;
}
BE64 &operator<<=(unsigned v) {
BE64 &operator<<=(unsigned v) noexcept {
set_be64(d, get_be64(d) << v);
return *this;
}
BE64 &operator>>=(unsigned v) {
BE64 &operator>>=(unsigned v) noexcept {
set_be64(d, get_be64(d) >> v);
return *this;
}
operator upx_uint64_t() const { return get_be64(d); }
operator upx_uint64_t() const noexcept { return get_be64(d); }
bool operator<(const BE64 &v) const { return upx_uint64_t(*this) < upx_uint64_t(v); }
bool operator<(const BE64 &v) const noexcept { return upx_uint64_t(*this) < upx_uint64_t(v); }
};
struct alignas(1) LE16 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[2];
LE16 &operator=(unsigned v) {
LE16 &operator=(unsigned v) noexcept {
set_le16(d, v);
return *this;
}
LE16 &operator+=(unsigned v) {
LE16 &operator+=(unsigned v) noexcept {
set_le16(d, get_le16(d) + v);
return *this;
}
LE16 &operator-=(unsigned v) {
LE16 &operator-=(unsigned v) noexcept {
set_le16(d, get_le16(d) - v);
return *this;
}
LE16 &operator*=(unsigned v) {
LE16 &operator*=(unsigned v) noexcept {
set_le16(d, get_le16(d) * v);
return *this;
}
LE16 &operator/=(unsigned v) {
LE16 &operator/=(unsigned v) noexcept {
set_le16(d, get_le16(d) / v);
return *this;
}
LE16 &operator&=(unsigned v) {
LE16 &operator&=(unsigned v) noexcept {
set_le16(d, get_le16(d) & v);
return *this;
}
LE16 &operator|=(unsigned v) {
LE16 &operator|=(unsigned v) noexcept {
set_le16(d, get_le16(d) | v);
return *this;
}
LE16 &operator^=(unsigned v) {
LE16 &operator^=(unsigned v) noexcept {
set_le16(d, get_le16(d) ^ v);
return *this;
}
LE16 &operator<<=(unsigned v) {
LE16 &operator<<=(unsigned v) noexcept {
set_le16(d, get_le16(d) << v);
return *this;
}
LE16 &operator>>=(unsigned v) {
LE16 &operator>>=(unsigned v) noexcept {
set_le16(d, get_le16(d) >> v);
return *this;
}
operator unsigned() const { return get_le16(d); }
operator unsigned() const noexcept { return get_le16(d); }
bool operator<(const LE16 &v) const { return unsigned(*this) < unsigned(v); }
bool operator<(const LE16 &v) const noexcept { return unsigned(*this) < unsigned(v); }
};
struct alignas(1) LE32 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[4];
LE32 &operator=(unsigned v) {
LE32 &operator=(unsigned v) noexcept {
set_le32(d, v);
return *this;
}
LE32 &operator+=(unsigned v) {
LE32 &operator+=(unsigned v) noexcept {
set_le32(d, get_le32(d) + v);
return *this;
}
LE32 &operator-=(unsigned v) {
LE32 &operator-=(unsigned v) noexcept {
set_le32(d, get_le32(d) - v);
return *this;
}
LE32 &operator*=(unsigned v) {
LE32 &operator*=(unsigned v) noexcept {
set_le32(d, get_le32(d) * v);
return *this;
}
LE32 &operator/=(unsigned v) {
LE32 &operator/=(unsigned v) noexcept {
set_le32(d, get_le32(d) / v);
return *this;
}
LE32 &operator&=(unsigned v) {
LE32 &operator&=(unsigned v) noexcept {
set_le32(d, get_le32(d) & v);
return *this;
}
LE32 &operator|=(unsigned v) {
LE32 &operator|=(unsigned v) noexcept {
set_le32(d, get_le32(d) | v);
return *this;
}
LE32 &operator^=(unsigned v) {
LE32 &operator^=(unsigned v) noexcept {
set_le32(d, get_le32(d) ^ v);
return *this;
}
LE32 &operator<<=(unsigned v) {
LE32 &operator<<=(unsigned v) noexcept {
set_le32(d, get_le32(d) << v);
return *this;
}
LE32 &operator>>=(unsigned v) {
LE32 &operator>>=(unsigned v) noexcept {
set_le32(d, get_le32(d) >> v);
return *this;
}
operator unsigned() const { return get_le32(d); }
operator unsigned() const noexcept { return get_le32(d); }
bool operator<(const LE32 &v) const { return unsigned(*this) < unsigned(v); }
bool operator<(const LE32 &v) const noexcept { return unsigned(*this) < unsigned(v); }
};
struct alignas(1) LE64 {
typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t
byte d[8];
LE64 &operator=(upx_uint64_t v) {
LE64 &operator=(upx_uint64_t v) noexcept {
set_le64(d, v);
return *this;
}
LE64 &operator+=(upx_uint64_t v) {
LE64 &operator+=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) + v);
return *this;
}
LE64 &operator-=(upx_uint64_t v) {
LE64 &operator-=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) - v);
return *this;
}
LE64 &operator*=(upx_uint64_t v) {
LE64 &operator*=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) * v);
return *this;
}
LE64 &operator/=(upx_uint64_t v) {
LE64 &operator/=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) / v);
return *this;
}
LE64 &operator&=(upx_uint64_t v) {
LE64 &operator&=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) & v);
return *this;
}
LE64 &operator|=(upx_uint64_t v) {
LE64 &operator|=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) | v);
return *this;
}
LE64 &operator^=(upx_uint64_t v) {
LE64 &operator^=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) ^ v);
return *this;
}
LE64 &operator<<=(unsigned v) {
LE64 &operator<<=(unsigned v) noexcept {
set_le64(d, get_le64(d) << v);
return *this;
}
LE64 &operator>>=(unsigned v) {
LE64 &operator>>=(unsigned v) noexcept {
set_le64(d, get_le64(d) >> v);
return *this;
}
operator upx_uint64_t() const { return get_le64(d); }
operator upx_uint64_t() const noexcept { return get_le64(d); }
bool operator<(const LE64 &v) const { return upx_uint64_t(*this) < upx_uint64_t(v); }
bool operator<(const LE64 &v) const noexcept { return upx_uint64_t(*this) < upx_uint64_t(v); }
};
// native types
#if (ACC_ABI_BIG_ENDIAN)
typedef BE16 NE16;
typedef BE32 NE32;
typedef BE64 NE64;
#else
typedef LE16 NE16;
typedef LE32 NE32;
typedef LE64 NE64;
#endif
/*************************************************************************
// global operators (pointer addition/subtraction)
**************************************************************************/
template <class T>
inline T *operator+(T *ptr, const BE16 &v) {
inline T *operator+(T *ptr, const BE16 &v) noexcept {
return ptr + unsigned(v);
}
template <class T>
inline T *operator-(T *ptr, const BE16 &v) {
inline T *operator-(T *ptr, const BE16 &v) noexcept {
return ptr - unsigned(v);
}
template <class T>
inline T *operator+(T *ptr, const BE32 &v) {
inline T *operator+(T *ptr, const BE32 &v) noexcept {
return ptr + unsigned(v);
}
template <class T>
inline T *operator-(T *ptr, const BE32 &v) {
inline T *operator-(T *ptr, const BE32 &v) noexcept {
return ptr - unsigned(v);
}
template <class T>
inline T *operator+(T *ptr, const LE16 &v) {
inline T *operator+(T *ptr, const LE16 &v) noexcept {
return ptr + unsigned(v);
}
template <class T>
inline T *operator-(T *ptr, const LE16 &v) {
inline T *operator-(T *ptr, const LE16 &v) noexcept {
return ptr - unsigned(v);
}
template <class T>
inline T *operator+(T *ptr, const LE32 &v) {
inline T *operator+(T *ptr, const LE32 &v) noexcept {
return ptr + unsigned(v);
}
template <class T>
inline T *operator-(T *ptr, const LE32 &v) {
inline T *operator-(T *ptr, const LE32 &v) noexcept {
return ptr - unsigned(v);
}
// these are not implemented on purpose and will cause errors
template <class T>
T *operator+(T *ptr, const BE64 &v) DELETED_FUNCTION;
T *operator+(T *ptr, const BE64 &v) noexcept DELETED_FUNCTION;
template <class T>
T *operator-(T *ptr, const BE64 &v) DELETED_FUNCTION;
T *operator-(T *ptr, const BE64 &v) noexcept DELETED_FUNCTION;
template <class T>
T *operator+(T *ptr, const LE64 &v) DELETED_FUNCTION;
T *operator+(T *ptr, const LE64 &v) noexcept DELETED_FUNCTION;
template <class T>
T *operator-(T *ptr, const LE64 &v) DELETED_FUNCTION;
T *operator-(T *ptr, const LE64 &v) noexcept DELETED_FUNCTION;
/*************************************************************************
// global overloads
@@ -644,6 +634,19 @@ inline unsigned UPX_MIN(const LE32 &a, unsigned b) { return UPX_MIN(unsigned(a),
// misc support
**************************************************************************/
template <>
struct upx_is_integral<BE16> : public std::true_type {};
template <>
struct upx_is_integral<BE32> : public std::true_type {};
template <>
struct upx_is_integral<BE64> : public std::true_type {};
template <>
struct upx_is_integral<LE16> : public std::true_type {};
template <>
struct upx_is_integral<LE32> : public std::true_type {};
template <>
struct upx_is_integral<LE64> : public std::true_type {};
// for use with qsort()
extern "C" {
int __acc_cdecl_qsort be16_compare(const void *, const void *);
@@ -664,6 +667,23 @@ int __acc_cdecl_qsort le32_compare_signed(const void *, const void *);
int __acc_cdecl_qsort le64_compare_signed(const void *, const void *);
} // extern "C"
// native types
#if (ACC_ABI_BIG_ENDIAN)
typedef BE16 NE16;
typedef BE32 NE32;
typedef BE64 NE64;
#define ne16_compare be16_compare
#define ne32_compare be32_compare
#define ne64_compare be64_compare
#else
typedef LE16 NE16;
typedef LE32 NE32;
typedef LE64 NE64;
#define ne16_compare le16_compare
#define ne32_compare le32_compare
#define ne64_compare le64_compare
#endif
/*************************************************************************
// Provide namespaces and classes to abstract endianness policies.
//
+7 -25
View File
@@ -37,20 +37,20 @@
// CTP - Compile-Time Polymorphism (templates)
#define V static inline
#define S static int __acc_cdecl_qsort
#define C /*empty*/
#define C noexcept
#elif defined(BELE_RTP)
// RTP - Run-Time Polymorphism (virtual functions)
#define V virtual
#define S virtual int
#define C const
#define C const noexcept
#else
#error
#endif
#if defined(BELE_RTP)
struct AbstractPolicy {
inline AbstractPolicy() {}
virtual inline ~AbstractPolicy() {}
inline AbstractPolicy() noexcept {}
virtual inline ~AbstractPolicy() noexcept {}
V bool isBE() C = 0;
V bool isLE() C = 0;
@@ -91,7 +91,7 @@ private:
#if defined(BELE_RTP)
#undef C
#define C const override
#define C const noexcept override
#endif
struct BEPolicy
@@ -99,7 +99,7 @@ struct BEPolicy
final : public AbstractPolicy
#endif
{
inline BEPolicy() {}
inline BEPolicy() noexcept {}
#if defined(BELE_CTP)
typedef N_BELE_RTP::BEPolicy RTP_Policy;
#elif defined(BELE_RTP)
@@ -160,7 +160,7 @@ struct LEPolicy
final : public AbstractPolicy
#endif
{
inline LEPolicy() {}
inline LEPolicy() noexcept {}
#if defined(BELE_CTP)
typedef N_BELE_RTP::LEPolicy RTP_Policy;
#elif defined(BELE_RTP)
@@ -225,24 +225,6 @@ typedef LEPolicy HostPolicy;
#error "ACC_ABI_ENDIAN"
#endif
#if 0 /* UNUSED */
struct HostAlignedPolicy {
#if defined(BELE_CTP)
enum { isBE = HostPolicy::isBE, isLE = HostPolicy::isLE };
#endif
typedef upx_uint16_t U16;
typedef upx_uint32_t U32;
typedef upx_uint64_t U64;
static void compileTimeAssertions() {
COMPILE_TIME_ASSERT(sizeof(U16) == 2)
COMPILE_TIME_ASSERT(sizeof(U32) == 4)
COMPILE_TIME_ASSERT(sizeof(U64) == 8)
}
};
#endif
#undef V
#undef S
#undef C
+22 -14
View File
@@ -39,7 +39,7 @@ int upx_doctest_check(int argc, char **argv) {
const char *e = getenv("UPX_DEBUG_DOCTEST_DISABLE");
if (e && e[0] && strcmp(e, "0") != 0)
return 0;
bool minimal = true; // only show failing tests
bool minimal = true; // don't show summary
bool duration = false; // show timings
bool success = false; // show all tests
#if DEBUG
@@ -47,12 +47,13 @@ int upx_doctest_check(int argc, char **argv) {
#endif
e = getenv("UPX_DEBUG_DOCTEST_VERBOSE");
if (e && e[0]) {
minimal = false;
if (strcmp(e, "0") == 0) {
minimal = true;
} else if (strcmp(e, "2") == 0) {
minimal = false;
duration = true;
} else if (strcmp(e, "3") == 0) {
minimal = false;
duration = true;
success = true;
}
@@ -100,6 +101,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER(bswap64(0x0807060504030201ull) == 0x0102030405060
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("") == 0)
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("a") == 1)
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("ab") == 2)
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_eq("", ""))
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("a", ""))
@@ -145,15 +147,18 @@ namespace {
template <class T>
struct TestBELE {
__acc_static_noinline bool test(void) {
static noinline bool test(void) {
// POD checks
{
COMPILE_TIME_ASSERT(std::is_standard_layout<T>::value)
COMPILE_TIME_ASSERT(std::is_trivial<T>::value)
// extra checks, these are probably implied by std::is_trivial:
// extra checks, these are probably implied by std::is_trivial
COMPILE_TIME_ASSERT(std::is_nothrow_default_constructible<T>::value)
COMPILE_TIME_ASSERT(std::is_trivially_copyable<T>::value)
COMPILE_TIME_ASSERT(std::is_trivially_default_constructible<T>::value)
// UPX
COMPILE_TIME_ASSERT(upx_is_integral<T>::value)
COMPILE_TIME_ASSERT(upx_is_integral_v<T>)
}
// alignment checks
{
@@ -177,8 +182,7 @@ struct TestBELE {
UNUSED(t1);
UNUSED(t2);
}
#if 1
// arithmetic checks
// arithmetic checks (modern compilers will optimize this away)
{
T allbits;
allbits = 0;
@@ -187,6 +191,7 @@ struct TestBELE {
T v1;
v1 = 1;
v1 *= 2;
v1 /= 1;
v1 -= 1;
T v2;
v2 = 1;
@@ -217,14 +222,13 @@ struct TestBELE {
if ((v1 ^ v2) != 1)
return false;
}
#endif
return true;
}
};
template <class A, class B>
struct TestNoAliasingStruct {
__acc_static_noinline bool test(A *a, B *b) {
static noinline bool test(A *a, B *b) {
*a = 0;
*b = 0;
*b -= 3;
@@ -232,7 +236,7 @@ struct TestNoAliasingStruct {
}
};
template <class A, class B>
__acc_static_forceinline bool testNoAliasing(A *a, B *b) {
static forceinline bool testNoAliasing(A *a, B *b) {
return TestNoAliasingStruct<A, B>::test(a, b);
}
template <class T>
@@ -274,6 +278,10 @@ void upx_compiler_sanity_check(void) {
COMPILE_TIME_ASSERT_ALIGNED1(LE32)
COMPILE_TIME_ASSERT_ALIGNED1(LE64)
COMPILE_TIME_ASSERT(sizeof(upx_charptr_unit_type) == 1)
COMPILE_TIME_ASSERT_ALIGNED1(upx_charptr_unit_type)
COMPILE_TIME_ASSERT(sizeof(*((charptr) nullptr)) == 1)
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_STRING4) == 4 + 1)
assert(strlen(UPX_VERSION_STRING4) == 4);
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_YEAR) == 4 + 1)
@@ -293,7 +301,7 @@ void upx_compiler_sanity_check(void) {
}
assert(UPX_RSIZE_MAX_MEM == 805306368);
#if 1
#if DEBUG || 1
assert(TestBELE<LE16>::test());
assert(TestBELE<LE32>::test());
assert(TestBELE<LE64>::test());
@@ -354,9 +362,9 @@ void upx_compiler_sanity_check(void) {
assert(dd == ne32_to_le32(0xf7020304));
}
{
upx_uint16_t a;
upx_uint32_t b;
upx_uint64_t c;
upx_uint16_t a = 0;
upx_uint32_t b = 0;
upx_uint64_t c = 0;
set_ne16(&a, 0x04030201); // ignore upper bits
set_ne32(&b, 0x04030201);
set_ne64(&c, 0x0807060504030201ull);
@@ -454,7 +462,7 @@ TEST_CASE("working -fno-strict-overflow") {
}
TEST_CASE("libc snprintf") {
// runtime check that Win32/MinGW <stdio.h> works as expected
// runtime check that Windows/MinGW <stdio.h> works as expected
char buf[64];
long long ll = acc_vget_int(-1, 0);
unsigned long long llu = (unsigned long long) ll;
+13 -6
View File
@@ -29,23 +29,30 @@
**************************************************************************/
#define DOCTEST_CONFIG_IMPLEMENT
#if !defined(UPX_DOCTEST_CONFIG_MULTITHREADING)
#define DOCTEST_CONFIG_NO_MULTITHREADING
#endif
#define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
#if !defined(DOCTEST_CONFIG_DISABLE)
#if defined(__i386__) && defined(__MSDOS__) && defined(__DJGPP__) && defined(__GNUC__)
#define DOCTEST_CONFIG_NO_MULTITHREADING
#define DOCTEST_CONFIG_NO_POSIX_SIGNALS
#elif defined(__m68k__) && defined(__atarist__) && defined(__GNUC__)
#define DOCTEST_CONFIG_COLORS_NONE
#define DOCTEST_CONFIG_NO_MULTITHREADING
#define DOCTEST_CONFIG_NO_POSIX_SIGNALS
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
#if !defined(DOCTEST_CONFIG_DISABLE)
#if !defined(UPX_DOCTEST_CONFIG_MULTITHREADING)
#define DOCTEST_CONFIG_NO_MULTITHREADING
#endif
#if defined(__clang__) && defined(__FAST_MATH__) && defined(__INTEL_LLVM_COMPILER)
// warning: comparison with NaN always evaluates to false in fast floating point modes
#pragma clang diagnostic ignored "-Wtautological-constant-compare"
#endif
#include <doctest/doctest/parts/doctest.cpp>
#endif
#endif // DOCTEST_CONFIG_DISABLE
/* vim:set ts=4 sw=4 et: */
+22
View File
@@ -91,6 +91,17 @@ TEST_CASE("basic xspan usage") {
CHECK_NOTHROW(raw_bytes(a0, 0));
CHECK_THROWS(raw_bytes(a0, 1));
CHECK_THROWS(raw_index_bytes(a0, 0, 0));
CHECK(raw_bytes(b0, 0) == buf);
CHECK(raw_bytes(bp, 0) == buf);
// info: these will fail if we ever add an overload for bounded-arrays
#if WITH_XSPAN >= 2
CHECK(b0.raw_size_in_bytes() == 0u);
CHECK(bp.raw_size_in_bytes() == 0u);
#endif
CHECK(raw_bytes(b0, 999999) == buf);
CHECK(raw_bytes(bp, 999999) == buf);
CHECK(raw_bytes(c0, 4) == buf);
CHECK(raw_index_bytes(c0, 1, 3) == buf + 1);
CHECK(raw_bytes(cp, 4) == buf);
@@ -136,6 +147,17 @@ TEST_CASE("basic xspan usage") {
CHECK_NOTHROW(raw_bytes(a0, 0));
CHECK_THROWS(raw_bytes(a0, 1));
CHECK_THROWS(raw_index_bytes(a0, 0, 0));
CHECK(raw_bytes(b0, 0) == buf);
CHECK(raw_bytes(bp, 0) == buf);
// info: these will fail if we ever add an overload for bounded-arrays
#if WITH_XSPAN >= 2
CHECK(b0.raw_size_in_bytes() == 0u);
CHECK(bp.raw_size_in_bytes() == 0u);
#endif
CHECK(raw_bytes(b0, 999999) == buf);
CHECK(raw_bytes(bp, 999999) == buf);
CHECK(raw_bytes(c0, 4) == buf);
CHECK(raw_index_bytes(c0, 1, 3) == buf + 1);
CHECK(raw_bytes(cp, 4) == buf);
+1 -1
View File
@@ -78,7 +78,7 @@ int upx_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned
// force users to provide *dst_len
assert(*dst_len != 0);
#endif
// for UPX, we always require a reasonably sized outbut buffer
// for UPX, we always require a reasonably sized output buffer
assert(*dst_len >= MemBuffer::getSizeForCompression(src_len));
if (!cresult)
+4 -5
View File
@@ -116,7 +116,7 @@ static bool prepare_result(lzma_compress_result_t *res, unsigned src_len, int me
res->lit_context_bits = (method >> 8) & 15;
}
#if 0
// DEBUG - set sizes so that we use a maxmimum amount of stack.
// DEBUG - set sizes so that we use a maximum amount of stack.
// These settings cause res->num_probs == 3147574, i.e. we will
// need about 6 MiB of stack during runtime decompression.
res->lit_pos_bits = 4;
@@ -524,13 +524,12 @@ const char *upx_lzma_version_string(void) { return "4.43"; }
**************************************************************************/
TEST_CASE("upx_lzma_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[16];
const byte *c_data;
byte d_buf[16];
unsigned d_len;
int r;
c_data = (C *) "\x1a\x03\x00\x7f\xed\x3c\x00\x00\x00";
c_data = (const byte *) "\x1a\x03\x00\x7f\xed\x3c\x00\x00\x00";
d_len = 16;
r = upx_lzma_decompress(c_data, 9, d_buf, &d_len, M_LZMA, nullptr);
CHECK((r == 0 && d_len == 16));
+9 -10
View File
@@ -113,14 +113,14 @@ int upx_ucl_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsig
cconf.bb_endian = 0;
cconf.bb_size = 0;
if (method >= M_NRV2B_LE32 && method <= M_NRV2E_LE16) {
static const unsigned char sizes[3] = {32, 8, 16};
static const upx_uint8_t sizes[3] = {32, 8, 16};
cconf.bb_size = sizes[(method - M_NRV2B_LE32) % 3];
} else {
throwInternalError("unknown compression method");
return UPX_E_ERROR;
}
// optimize compression parms
// optimize compression params
if (level <= 3 && cconf.max_offset == UCL_UINT_MAX)
cconf.max_offset = 8 * 1024 - 1;
else if (level == 4 && cconf.max_offset == UCL_UINT_MAX)
@@ -241,9 +241,9 @@ int upx_ucl_test_overlap(const upx_bytep buf, const upx_bytep tbuf, unsigned src
**************************************************************************/
extern "C" {
static ucl_voidp __UCL_CDECL my_malloc(ucl_uint n) { return calloc(1, n); }
static ucl_voidp __UCL_CDECL my_malloc(ucl_uint n) { return upx_calloc(n, 1); }
static void __UCL_CDECL my_free(ucl_voidp p) { free(p); }
}
} // extern "C"
int upx_ucl_init(void) {
if (ucl_init() != UCL_E_OK)
@@ -327,13 +327,12 @@ TEST_CASE("compress_ucl") {
#endif // DEBUG
TEST_CASE("upx_ucl_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[16];
const byte *c_data;
byte d_buf[16];
unsigned d_len;
int r;
c_data = (C *) "\x92\xff\x10\x00\x00\x00\x00\x00\x48\xff";
c_data = (const byte *) "\x92\xff\x10\x00\x00\x00\x00\x00\x48\xff";
d_len = 16;
r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr);
CHECK((r == 0 && d_len == 16));
@@ -343,7 +342,7 @@ TEST_CASE("upx_ucl_decompress") {
r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr);
CHECK(r == UPX_E_OUTPUT_OVERRUN);
c_data = (C *) "\x92\xff\x10\x92\x49\x24\x92\xa0\xff";
c_data = (const byte *) "\x92\xff\x10\x92\x49\x24\x92\xa0\xff";
d_len = 16;
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr);
CHECK((r == 0 && d_len == 16));
@@ -353,7 +352,7 @@ TEST_CASE("upx_ucl_decompress") {
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr);
CHECK(r == UPX_E_OUTPUT_OVERRUN);
c_data = (C *) "\x90\xff\xb0\x92\x49\x24\x92\xa0\xff";
c_data = (const byte *) "\x90\xff\xb0\x92\x49\x24\x92\xa0\xff";
d_len = 16;
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2E_8, nullptr);
CHECK((r == 0 && d_len == 16));
+3 -4
View File
@@ -287,13 +287,12 @@ TEST_CASE("compress_zlib") {
#endif // DEBUG
TEST_CASE("upx_zlib_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[16];
const byte *c_data;
byte d_buf[16];
unsigned d_len;
int r;
c_data = (C *) "\xfb\xff\x1f\x15\x00\x00";
c_data = (const byte *) "\xfb\xff\x1f\x15\x00\x00";
d_len = 16;
r = upx_zlib_decompress(c_data, 6, d_buf, &d_len, M_DEFLATE, nullptr);
CHECK((r == 0 && d_len == 16));
+3 -4
View File
@@ -207,13 +207,12 @@ TEST_CASE("compress_zstd") {
#endif // DEBUG
TEST_CASE("upx_zstd_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[32];
const byte *c_data;
byte d_buf[32];
unsigned d_len;
int r;
c_data = (C *) "\x28\xb5\x2f\xfd\x20\x20\x3d\x00\x00\x08\xff\x01\x00\x34\x4e\x08";
c_data = (const byte *) "\x28\xb5\x2f\xfd\x20\x20\x3d\x00\x00\x08\xff\x01\x00\x34\x4e\x08";
d_len = 32;
r = upx_zstd_decompress(c_data, 16, d_buf, &d_len, M_ZSTD, nullptr);
CHECK((r == 0 && d_len == 32));
+84 -60
View File
@@ -100,6 +100,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
# pragma warning(error: 4805)
#endif
#endif // !UPX_CONFIG_DISABLE_WSTRICT && !UPX_CONFIG_DISABLE_WERROR
// disable some warnings
#if (ACC_CC_MSC)
# pragma warning(disable: 4244) // -Wconversion
@@ -124,22 +125,30 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
#include <new>
#include <type_traits>
#include <typeinfo>
#if __STDC_NO_ATOMICS__ || 1
// UPX currently does not use multithreading
#define upx_std_atomic(Type) Type
//#define upx_std_atomic(Type) typename std::add_volatile<Type>::type
#define upx_std_once_flag upx_std_atomic(size_t)
template <class NoexceptCallable>
inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
if (__acc_unlikely(!flag)) { flag = 1; f(); }
}
#else
// multithreading (UPX currently does not use multithreading)
#ifndef WITH_THREADS
# define WITH_THREADS 0
#endif
#if __STDC_NO_ATOMICS__
# undef WITH_THREADS
#endif
#if (WITH_THREADS)
#define upx_thread_local thread_local
#include <atomic>
#define upx_std_atomic(Type) std::atomic<Type>
#include <mutex>
#define upx_std_once_flag std::once_flag
#define upx_std_call_once std::call_once
#endif
#else
#define upx_thread_local /*empty*/
#define upx_std_atomic(Type) Type
#define upx_std_once_flag upx_std_atomic(size_t)
template <class NoexceptCallable>
inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
if (__acc_unlikely(!flag)) { flag = 1; f(); }
}
#endif // WITH_THREADS
// C++ submodule headers
#include <doctest/doctest/parts/doctest_fwd.h>
@@ -166,16 +175,39 @@ inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
// <type_traits> C++20 std::is_bounded_array
template <class T>
struct std_is_bounded_array : public std::false_type {};
struct upx_std_is_bounded_array : public std::false_type {};
template <class T, size_t N>
struct std_is_bounded_array<T[N]> : public std::true_type {};
struct upx_std_is_bounded_array<T[N]> : public std::true_type {};
template <class T>
inline constexpr bool upx_std_is_bounded_array_v = upx_std_is_bounded_array<T>::value;
// see bele.h
template <class T>
struct upx_is_integral : public std::is_integral<T> {};
template <class T>
inline constexpr bool upx_is_integral_v = upx_is_integral<T>::value;
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
// horrible hack for broken compiler
#define upx_fake_alignas_1 __attribute__((__aligned__(1),__packed__))
#define upx_fake_alignas_16 __attribute__((__aligned__(2))) // object file maximum 2 ???
#define upx_fake_alignas__(a) upx_fake_alignas_ ## a
#define alignas(x) upx_fake_alignas__(x)
#endif
/*************************************************************************
// core
**************************************************************************/
// intergral types
// protect against integer overflows and malicious header fields
// see C 11 standard, Annex K
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 !!!
#define UPX_RSIZE_MAX_STR (256 * 1024)
// integral types
typedef acc_int8_t upx_int8_t;
typedef acc_uint8_t upx_uint8_t;
typedef acc_int16_t upx_int16_t;
@@ -186,16 +218,17 @@ typedef acc_int64_t upx_int64_t;
typedef acc_uint64_t upx_uint64_t;
typedef acc_uintptr_t upx_uintptr_t;
// convention: use "byte" when dealing with data; use "char/uchar" when dealing
// with strings; use "upx_uint8_t" when dealing with small integers
typedef unsigned char byte;
#define upx_byte byte
#define upx_bytep byte *
// protect against integer overflows and malicious header fields
// see C 11 standard, Annex K
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 !!!
#define UPX_RSIZE_MAX_STR (1024 * 1024)
typedef unsigned char uchar;
// use "charptr" when dealing with pointer arithmetics
#define charptr upx_charptr_unit_type *
// upx_charptr_unit_type is some opaque type with sizeof(type) == 1
struct alignas(1) upx_charptr_unit_type { char dummy; };
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(upx_charptr_unit_type) == 1)
// using the system off_t was a bad idea even back in 199x...
typedef upx_int64_t upx_off_t;
@@ -244,8 +277,8 @@ typedef upx_int64_t upx_off_t;
#endif
#if (ACC_OS_DOS32) && defined(__DJGPP__)
# undef sopen
# undef __unix__
# undef __unix
# undef __unix__
#endif
#ifndef STDIN_FILENO
@@ -304,7 +337,7 @@ typedef upx_int64_t upx_off_t;
# endif
#endif
// avoid warnings about shadowing global functions
// avoid warnings about shadowing global symbols
#undef _base
#undef basename
#undef index
@@ -391,14 +424,6 @@ inline void NO_fprintf(FILE *, const char *, ...) {}
#define __packed_struct(s) struct alignas(1) s {
#define __packed_struct_end() };
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
// horrible hack for broken compiler
#define upx_fake_alignas_1 __attribute__((__aligned__(1),__packed__))
#define upx_fake_alignas_16 __attribute__((__aligned__(2))) // object file maximum 2 ???
#define upx_fake_alignas__(a) upx_fake_alignas_ ## a
#define alignas(x) upx_fake_alignas__(x)
#endif
#define COMPILE_TIME_ASSERT_ALIGNOF_USING_SIZEOF__(a,b) { \
typedef a acc_tmp_a_t; typedef b acc_tmp_b_t; \
struct alignas(1) acc_tmp_t { acc_tmp_b_t x; acc_tmp_a_t y; acc_tmp_b_t z; }; \
@@ -426,15 +451,13 @@ inline const T& UPX_MAX(const T& a, const T& b) { if (a < b) return b; return a;
template <class T>
inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; }
template <size_t TypeSize>
struct USizeOfTypeImpl {
static forceinline constexpr unsigned value() {
COMPILE_TIME_ASSERT(TypeSize >= 1 && TypeSize <= 64 * 1024) // arbitrary limit
return ACC_ICONV(unsigned, TypeSize);
}
template <size_t Size>
struct UnsignedSizeOf {
static_assert(Size >= 1 && Size <= UPX_RSIZE_MAX_MEM);
static constexpr unsigned value = unsigned(Size);
};
#define usizeof(type) (USizeOfTypeImpl<sizeof(type)>::value())
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == 4)
#define usizeof(expr) (UnsignedSizeOf<sizeof(expr)>::value)
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == sizeof(int))
// An Array allocates memory on the heap, and automatically
// gets destructed when leaving scope or on exceptions.
@@ -442,16 +465,16 @@ ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == 4)
MemBuffer var ## _membuf(mem_size(sizeof(type), size)); \
type * const var = ACC_STATIC_CAST(type *, var ## _membuf.getVoidPtr())
#define ByteArray(var, size) Array(unsigned char, var, size)
#define ByteArray(var, size) Array(byte, var, size)
class noncopyable
{
protected:
inline noncopyable() {}
inline ~noncopyable() {}
inline noncopyable() noexcept {}
inline ~noncopyable() noexcept {}
private:
noncopyable(const noncopyable &) DELETED_FUNCTION; // copy constuctor
noncopyable(const noncopyable &) DELETED_FUNCTION; // copy constructor
noncopyable& operator=(const noncopyable &) DELETED_FUNCTION; // copy assignment
noncopyable(noncopyable &&) DELETED_FUNCTION; // move constructor
noncopyable& operator=(noncopyable &&) DELETED_FUNCTION; // move assignment
@@ -466,7 +489,7 @@ constexpr bool string_eq(const char *a, const char *b) {
return *a == *b && (*a == '\0' || string_eq(a + 1, b + 1));
}
constexpr bool string_lt(const char *a, const char *b) {
return (unsigned char)*a < (unsigned char)*b || (*a != '\0' && *a == *b && string_lt(a + 1, b + 1));
return (uchar)*a < (uchar)*b || (*a != '\0' && *a == *b && string_lt(a + 1, b + 1));
}
constexpr bool string_ne(const char *a, const char *b) {
return !string_eq(a, b);
@@ -644,7 +667,7 @@ struct upx_callback_t
upx_progress_func_t nprogress;
void *user;
void reset() { memset(this, 0, sizeof(*this)); }
void reset() noexcept { memset(this, 0, sizeof(*this)); }
};
@@ -670,7 +693,7 @@ struct OptVar
assertValue(v);
}
OptVar() : v(default_value), is_set(false) { }
OptVar() noexcept : v(default_value), is_set(false) { }
OptVar& operator= (const T &other) {
assertValue(other);
v = other;
@@ -678,8 +701,8 @@ struct OptVar
return *this;
}
void reset() { v = default_value; is_set = false; }
operator T () const { return v; }
void reset() noexcept { v = default_value; is_set = false; }
operator T () const noexcept { return v; }
T v;
bool is_set;
@@ -818,26 +841,16 @@ struct upx_compress_result_t
// globals
**************************************************************************/
#include "util/snprintf.h" // must get included first!
#include "options.h"
#include "except.h"
#include "bele.h"
#include "console/console.h"
#include "util/util.h"
// classes
class ElfLinker;
typedef ElfLinker Linker;
class Throwable;
// util/membuffer.h
class MemBuffer;
void *membuffer_get_void_ptr(MemBuffer &mb);
unsigned membuffer_get_size(MemBuffer &mb);
// xspan
#include "util/raw_bytes.h"
#include "util/xspan.h"
// util/dt_check.cpp
void upx_compiler_sanity_check();
int upx_doctest_check();
@@ -870,7 +883,7 @@ int do_files(int i, int argc, char *argv[]);
// help.cpp
extern const char gitrev[];
void show_head();
void show_header();
void show_help(int verbose=0);
void show_license();
void show_usage();
@@ -898,6 +911,17 @@ int upx_test_overlap ( const upx_bytep buf,
const upx_compress_result_t *cresult );
#include "util/snprintf.h" // must get included first!
#include "options.h"
#include "except.h"
#include "bele.h"
#include "console/console.h"
#include "util/util.h"
// xspan
#include "util/raw_bytes.h"
#include "util/xspan.h"
#if (ACC_OS_CYGWIN || ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_EMX || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64)
# if defined(INVALID_HANDLE_VALUE) || defined(MAKEWORD) || defined(RT_CURSOR)
# error "something pulled in <windows.h>"
+11
View File
@@ -269,6 +269,17 @@ void OutputFile::write(SPAN_0(const void) buf, int len) {
if (l != len)
throwIOException("write error", errno);
bytes_written += len;
#if TESTING && 0
static upx_std_atomic(bool) dumping;
if (!dumping) {
dumping = true;
char fn[64];
static int part = 0;
snprintf(fn, sizeof(fn), "upx-dump-%04d.data", part++);
OutputFile::dump(fn, buf, len);
dumping = false;
}
#endif
}
upx_off_t OutputFile::st_size() const {
+103 -119
View File
@@ -25,36 +25,33 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#include "conf.h"
#include "packmast.h"
#include "packer.h"
#include "compress/compress.h" // upx_ucl_version_string()
/*************************************************************************
//
// header
**************************************************************************/
static bool head_done = 0;
// also see UPX_CONFIG_DISABLE_GITREV in CMakeLists.txt
#if defined(UPX_VERSION_GITREV)
const char gitrev[] = UPX_VERSION_GITREV;
#else
const char gitrev[1] = { 0 };
const char gitrev[1] = {0};
#endif
void show_head(void)
{
void show_header(void) {
FILE *f = con_term;
int fg;
if (head_done)
static bool header_done;
if (header_done)
return;
head_done = 1;
header_done = true;
fg = con_fg(f,FG_GREEN);
fg = con_fg(f, FG_GREEN);
// clang-format off
con_fprintf(f,
" Ultimate Packer for eXecutables\n"
" Copyright (C) 1996 - " UPX_VERSION_YEAR "\n"
@@ -71,22 +68,19 @@ void show_head(void)
UPX_VERSION_STRING,
#endif
UPX_VERSION_DATE);
fg = con_fg(f,fg);
#undef V
// clang-format on
fg = con_fg(f, fg);
UNUSED(fg);
}
/*************************************************************************
//
// usage
**************************************************************************/
void show_usage(void)
{
void show_usage(void) {
FILE *f = con_term;
con_fprintf(f,"Usage: %s [-123456789dlthVL] [-qvfk] [-o file] %sfile..\n", progname,
con_fprintf(f, "Usage: %s [-123456789dlthVL] [-qvfk] [-o file] %sfile..\n", progname,
#if (ACC_OS_DOS32) && defined(__DJGPP__)
"[@]");
#else
@@ -94,34 +88,30 @@ void show_usage(void)
#endif
}
/*************************************************************************
//
// util
**************************************************************************/
struct PackerNames
{
namespace {
struct PackerNames {
struct Entry {
const char* fname;
const char* sname;
const char *fname;
const char *sname;
};
Entry names[64];
size_t names_count;
const options_t *o;
PackerNames() : names_count(0), o(nullptr) { }
void add(const Packer *p)
{
p->assertPacker();
const Options *o;
PackerNames() : names_count(0), o(nullptr) {}
void add(const Packer *p) {
assert(names_count < 64);
names[names_count].fname = p->getFullName(o);
names[names_count].sname = p->getName();
names_count++;
}
static Packer* visit(Packer *p, void *user)
{
static Packer *visit(Packer *p, void *user) {
PackerNames *self = (PackerNames *) user;
self->add(p);
delete p; p = nullptr;
delete p;
return nullptr;
}
static int __acc_cdecl_qsort cmp_fname(const void *a, const void *b) {
@@ -132,23 +122,20 @@ struct PackerNames
}
};
static void show_all_packers(FILE *f, int verbose)
{
options_t o; o.reset();
PackerNames pn; pn.o = &o;
static void show_all_packers(FILE *f, int verbose) {
Options o;
o.reset();
PackerNames pn;
pn.o = &o;
PackMaster::visitAllPackers(PackerNames::visit, nullptr, &o, &pn);
qsort(pn.names, pn.names_count, sizeof(PackerNames::Entry), PackerNames::cmp_fname);
size_t pos = 0;
for (size_t i = 0; i < pn.names_count; ++i)
{
for (size_t i = 0; i < pn.names_count; ++i) {
const char *fn = pn.names[i].fname;
const char *sn = pn.names[i].sname;
if (verbose > 0)
{
if (verbose > 0) {
con_fprintf(f, " %-36s %s\n", fn, sn);
}
else
{
} else {
size_t fl = strlen(fn);
if (pos == 0) {
con_fprintf(f, " %s", fn);
@@ -165,23 +152,23 @@ static void show_all_packers(FILE *f, int verbose)
if (verbose <= 0 && pn.names_count)
con_fprintf(f, "\n");
}
} // namespace
/*************************************************************************
//
// help
**************************************************************************/
void show_help(int verbose)
{
void show_help(int verbose) {
FILE *f = con_term;
int fg;
show_head();
show_header();
show_usage();
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"\nCommands:\n");
fg = con_fg(f,fg);
// clang-format off
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "\nCommands:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" -1 compress faster -9 compress better\n"
"%s"
@@ -191,9 +178,9 @@ void show_help(int verbose)
verbose == 0 ? "" : " --best compress best (can be slow for big files)\n",
verbose == 0 ? "more" : "this", verbose == 0 ? "" : "\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Options:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" -q be quiet -v be verbose\n"
@@ -211,72 +198,72 @@ void show_help(int verbose)
if (verbose > 0)
{
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"\nCompression tuning options:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "\nCompression tuning options:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" --lzma try LZMA [slower but tighter than NRV]\n"
" --brute try all available compression methods & filters [slow]\n"
" --ultra-brute try even more compression variants [very slow]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Backup options:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Backup options:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" -k, --backup keep backup files\n"
" --no-backup no backup files [default]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Overlay options:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Overlay options:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" --overlay=copy copy any extra data attached to the file [default]\n"
" --overlay=strip strip any extra data attached to the file [DANGEROUS]\n"
" --overlay=skip don't compress a file with an overlay\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for djgpp2/coff:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Options for djgpp2/coff:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" --coff produce COFF output [default: EXE]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for dos/com:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Options for dos/com:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" --8086 make compressed com work on any 8086\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for dos/exe:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Options for dos/exe:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" --8086 make compressed exe work on any 8086\n"
" --no-reloc put no relocations in to the exe header\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for dos/sys:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Options for dos/sys:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" --8086 make compressed sys work on any 8086\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for ps1/exe:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Options for ps1/exe:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" --8-bit uses 8 bit size compression [default: 32 bit]\n"
" --8mib-ram 8 megabyte memory limit [default: 2 MiB]\n"
" --boot-only disables client/host transfer compatibility\n"
" --no-align don't align to 2048 bytes [enables: --console-run]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for watcom/le:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Options for watcom/le:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" --le produce LE output [default: EXE]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for win32/pe, win64/pe & rtm32/pe:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Options for win32/pe, win64/pe & rtm32/pe:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" --compress-exports=0 do not compress the export section\n"
" --compress-exports=1 compress the export section [default]\n"
@@ -289,59 +276,55 @@ void show_help(int verbose)
" --strip-relocs=0 do not strip relocations\n"
" --strip-relocs=1 strip relocations [default]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for linux/elf:\n");
fg = con_fg(f,fg);
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "Options for linux/elf:\n");
fg = con_fg(f, fg);
con_fprintf(f,
" --preserve-build-id copy .gnu.note.build-id to compressed output\n"
"\n");
}
// clang-format on
con_fprintf(f, "file.. executables to (de)compress\n");
if (verbose > 0)
{
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"\nThis version supports:\n");
fg = con_fg(f,fg);
if (verbose > 0) {
fg = con_fg(f, FG_YELLOW);
con_fprintf(f, "\nThis version supports:\n");
fg = con_fg(f, fg);
show_all_packers(f, verbose);
}
else
{
con_fprintf(f,"\nType '%s --help' for more detailed help.\n", progname);
} else {
con_fprintf(f, "\nType '%s --help' for more detailed help.\n", progname);
}
con_fprintf(f,"\nUPX comes with ABSOLUTELY NO WARRANTY; for details visit https://upx.github.io\n"
// "\nUPX comes with ABSOLUTELY NO WARRANTY; for details type 'upx -L'.\n"
"");
con_fprintf(f, "\nUPX comes with ABSOLUTELY NO WARRANTY; "
"for details visit https://upx.github.io\n");
#if DEBUG || TESTING
fg = con_fg(f,FG_RED);
con_fprintf(f,"\nWARNING: this version is compiled with"
fg = con_fg(f, FG_RED);
con_fprintf(f, "\nWARNING: this version is compiled with"
#if DEBUG
" -DDEBUG"
" -DDEBUG"
#endif
#if TESTING
" -DTESTING"
" -DTESTING"
#endif
"\n");
fg = con_fg(f,fg);
"\n");
fg = con_fg(f, fg);
#endif
UNUSED(fg);
}
/*************************************************************************
//
// license
**************************************************************************/
void show_license(void)
{
void show_license(void) {
FILE *f = con_term;
show_head();
show_header();
// clang-format off
con_fprintf(f,
" This program may be used freely, and you are welcome to\n"
" redistribute it under certain conditions.\n"
@@ -356,29 +339,27 @@ void show_license(void)
" If not, visit one of the following pages:\n"
"\n"
);
int fg = con_fg(f,FG_CYAN);
int fg = con_fg(f, FG_CYAN);
con_fprintf(f,
" https://upx.github.io\n"
" https://www.oberhumer.com/opensource/upx/\n"
);
(void)con_fg(f,FG_ORANGE);
(void) con_fg(f, FG_ORANGE);
con_fprintf(f,
"\n"
" Markus F.X.J. Oberhumer Laszlo Molnar\n"
" <markus@oberhumer.com> <ezerotven+github@gmail.com>\n"
);
fg = con_fg(f,fg);
// clang-format on
fg = con_fg(f, fg);
UNUSED(fg);
}
/*************************************************************************
//
// version
**************************************************************************/
void show_version(bool one_line)
{
void show_version(bool one_line) {
FILE *fp = stdout;
const char *v;
@@ -391,6 +372,7 @@ void show_version(bool one_line)
#endif
if (one_line)
return;
#if (WITH_NRV)
v = upx_nrv_version_string();
if (v != nullptr && v[0])
@@ -419,6 +401,7 @@ void show_version(bool one_line)
#if !defined(DOCTEST_CONFIG_DISABLE)
fprintf(fp, "doctest C++ testing framework version %s\n", DOCTEST_VERSION_STR);
#endif
// clang-format off
fprintf(fp, "Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer\n");
fprintf(fp, "Copyright (C) 1996-2023 Laszlo Molnar\n");
fprintf(fp, "Copyright (C) 2000-2023 John F. Reiser\n");
@@ -437,6 +420,7 @@ void show_version(bool one_line)
fprintf(fp, "Copyright (C) 2016" "-2021 Viktor Kirilov\n");
#endif
fprintf(fp, "UPX comes with ABSOLUTELY NO WARRANTY; for details type '%s -L'.\n", progname);
// clang-format on
}
/* vim:set ts=4 sw=4 et: */
+8 -8
View File
@@ -28,7 +28,7 @@
#include "conf.h"
#include "linker.h"
static unsigned hex(unsigned char c) { return (c & 0xf) + (c > '9' ? 9 : 0); }
static unsigned hex(uchar c) { return (c & 0xf) + (c > '9' ? 9 : 0); }
static bool update_capacity(unsigned size, unsigned *capacity) {
if (size < *capacity)
@@ -67,7 +67,7 @@ ElfLinker::Section::Section(const char *n, const void *i, unsigned s, unsigned a
((char *) input)[s] = 0;
}
ElfLinker::Section::~Section() {
ElfLinker::Section::~Section() noexcept {
free(name);
free(input);
}
@@ -83,7 +83,7 @@ ElfLinker::Symbol::Symbol(const char *n, Section *s, upx_uint64_t o)
assert(section != nullptr);
}
ElfLinker::Symbol::~Symbol() { free(name); }
ElfLinker::Symbol::~Symbol() noexcept { free(name); }
/*************************************************************************
// Relocation
@@ -105,7 +105,7 @@ ElfLinker::ElfLinker()
nsections_capacity(0), nsymbols(0), nsymbols_capacity(0), nrelocations(0),
nrelocations_capacity(0), reloc_done(false) {}
ElfLinker::~ElfLinker() {
ElfLinker::~ElfLinker() noexcept {
delete[] input;
delete[] output;
@@ -548,7 +548,7 @@ upx_uint64_t ElfLinker::getSymbolOffset(const char *name) const {
return symbol->section->offset + symbol->offset;
}
void ElfLinker::alignWithByte(unsigned len, unsigned char b) {
void ElfLinker::alignWithByte(unsigned len, byte b) {
memset(output + outputlen, b, len);
outputlen += len;
}
@@ -559,7 +559,7 @@ void ElfLinker::relocate1(const Relocation *rel, byte *, upx_uint64_t, const cha
/*************************************************************************
// ElfLinker arch subclasses
// FIXME: add more displacment overflow checks
// FIXME: add more displacement overflow checks
// FIXME: add support for our special "ignore_reloc_overflow" section
**************************************************************************/
@@ -802,12 +802,12 @@ void ElfLinkerPpc32::relocate1(const Relocation *rel, byte *location, upx_uint64
if (strcmp(type, "24") == 0) {
if (3 & value)
internal_error("unaligned word diplacement");
// FIXME: displacment overflow?
// FIXME: displacement overflow?
set_be32(location, (0xfc000003 & get_be32(location)) + (0x03fffffc & value));
} else if (strcmp(type, "14") == 0) {
if (3 & value)
internal_error("unaligned word diplacement");
// FIXME: displacment overflow?
// FIXME: displacement overflow?
set_be32(location, (0xffff0003 & get_be32(location)) + (0x0000fffc & value));
} else
super::relocate1(rel, location, value, type);
+5 -4
View File
@@ -77,7 +77,7 @@ protected:
public:
ElfLinker();
virtual ~ElfLinker();
virtual ~ElfLinker() noexcept;
void init(const void *pdata, int plen, unsigned pxtra = 0);
// virtual void setLoaderAlignOffset(int phase);
@@ -98,7 +98,7 @@ public:
void dumpSymbol(const Symbol *, unsigned flags, FILE *fp) const;
void dumpSymbols(unsigned flags = 0, FILE *fp = nullptr) const;
void alignWithByte(unsigned len, unsigned char b);
void alignWithByte(unsigned len, byte b);
virtual void alignCode(unsigned len) { alignWithByte(len, 0); }
virtual void alignData(unsigned len) { alignWithByte(len, 0); }
@@ -133,7 +133,7 @@ struct ElfLinker::Section : private noncopyable {
Section *next = nullptr;
Section(const char *n, const void *i, unsigned s, unsigned a = 0);
~Section();
~Section() noexcept;
};
struct ElfLinker::Symbol : private noncopyable {
@@ -142,7 +142,7 @@ struct ElfLinker::Symbol : private noncopyable {
upx_uint64_t offset = 0;
Symbol(const char *n, Section *s, upx_uint64_t o);
~Symbol();
~Symbol() noexcept;
};
struct ElfLinker::Relocation : private noncopyable {
@@ -153,6 +153,7 @@ struct ElfLinker::Relocation : private noncopyable {
upx_uint64_t add; // used in .rela relocations
Relocation(const Section *s, unsigned o, const char *t, const Symbol *v, upx_uint64_t a);
~Relocation() noexcept {}
};
/*************************************************************************
+5 -6
View File
@@ -626,7 +626,7 @@ static int do_option(int optc, const char *arg) {
opt->backup = 1;
break;
case 541:
if (opt->backup != 1) // do not overide '--backup'
if (opt->backup != 1) // do not override '--backup'
opt->backup = 0;
break;
// overlay
@@ -974,11 +974,10 @@ int main_get_options(int argc, char **argv) {
int optc, longind;
char shortopts[256];
prepare_shortopts(shortopts, "123456789hH?V", longopts),
acc_getopt_init(&mfx_getopt, 1, argc, argv);
prepare_shortopts(shortopts, "123456789hH?V", longopts);
acc_getopt_init(&mfx_getopt, 1, argc, argv);
mfx_getopt.progname = progname;
mfx_getopt.opterr = handle_opterr;
opt->o_unix.osabi0 = Elf32_Ehdr::ELFOSABI_LINUX;
while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, &longind)) >= 0) {
if (do_option(optc, argv[mfx_optind - 1]) != 0)
e_usage();
@@ -1088,7 +1087,7 @@ void main_get_envoptions() {
/* alloc temp argv */
if (targc > 1)
targv = (const char **) calloc(targc + 1, sizeof(char *));
targv = (const char **) upx_calloc(targc + 1, sizeof(char *));
if (targv == nullptr) {
free(env);
return;
@@ -1188,7 +1187,7 @@ int upx_main(int argc, char *argv[]) {
char *p;
bool allupper = true;
for (p = prog; *p; p++)
if (islower((unsigned char) *p))
if (islower((uchar) *p))
allupper = false;
if (allupper)
fn_strlwr(prog);
+21 -10
View File
@@ -27,15 +27,19 @@
#include "conf.h"
static options_t global_options;
options_t *opt = &global_options; // also see class PackMaster
static Options global_options;
Options *opt = &global_options; // also see class PackMaster
#if WITH_THREADS
std::mutex opt_lock_mutex;
#endif
/*************************************************************************
// reset
**************************************************************************/
void options_t::reset() {
options_t *o = this;
void Options::reset() {
Options *const o = this;
mem_clear(o, sizeof(*o));
o->crp.reset();
@@ -65,7 +69,7 @@ void options_t::reset() {
o->win32_pe.compress_exports = 1;
o->win32_pe.compress_icons = 2;
o->win32_pe.compress_resources = -1;
for (unsigned i = 0; i < TABLESIZE(o->win32_pe.compress_rt); i++)
for (size_t i = 0; i < TABLESIZE(o->win32_pe.compress_rt); i++)
o->win32_pe.compress_rt[i] = -1;
o->win32_pe.compress_rt[24] = false; // 24 == RT_MANIFEST
o->win32_pe.strip_relocs = -1;
@@ -76,9 +80,13 @@ void options_t::reset() {
// doctest checks
**************************************************************************/
TEST_CASE("options_t::reset") {
options_t local_options;
options_t *o = &local_options;
TEST_CASE("Options::reset") {
COMPILE_TIME_ASSERT(std::is_standard_layout<Options>::value)
COMPILE_TIME_ASSERT(std::is_nothrow_default_constructible<Options>::value)
COMPILE_TIME_ASSERT(std::is_trivially_copyable<Options>::value)
Options local_options;
Options *o = &local_options;
o->reset();
CHECK(o->o_unix.osabi0 == 3);
}
@@ -89,8 +97,11 @@ static inline void test_options(const char *(&a)[N]) {
}
TEST_CASE("getopt") {
options_t *const saved_opt = opt;
options_t local_options;
#if WITH_THREADS
std::lock_guard<std::mutex> lock(opt_lock_mutex);
#endif
Options *const saved_opt = opt;
Options local_options;
opt = &local_options;
opt->reset();
opt->debug.getopt_throw_instead_of_exit = true;
+9 -3
View File
@@ -29,6 +29,14 @@
#ifndef UPX_OPTIONS_H__
#define UPX_OPTIONS_H__ 1
struct Options;
extern Options *opt;
#define options_t Options // old name
#if WITH_THREADS
extern std::mutex opt_lock_mutex;
#endif
/*************************************************************************
// globals
**************************************************************************/
@@ -46,7 +54,7 @@ enum {
CMD_VERSION,
};
struct options_t final {
struct Options final {
int cmd;
// compression options
@@ -164,8 +172,6 @@ struct options_t final {
void reset();
};
extern struct options_t *opt;
#endif /* already included */
/* vim:set ts=4 sw=4 et: */
+1 -1
View File
@@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_DOS_COM; }
virtual const char *getName() const override { return "dos/com"; }
virtual const char *getFullName(const options_t *) const override { return "i086-dos16.com"; }
virtual const char *getFullName(const Options *) const override { return "i086-dos16.com"; }
virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override;
+1 -1
View File
@@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 14; }
virtual int getFormat() const override { return UPX_F_DJGPP2_COFF; }
virtual const char *getName() const override { return "djgpp2/coff"; }
virtual const char *getFullName(const options_t *) const override {
virtual const char *getFullName(const Options *) const override {
return "i386-dos32.djgpp2.coff";
}
virtual const int *getCompressionMethods(int method, int level) const override;
+109 -106
View File
@@ -35,9 +35,8 @@
static const CLANG_FORMAT_DUMMY_STATEMENT
#include "stub/i086-dos16.exe.h"
#define RSFCRI 4096 // Reserved Space For Compressed Relocation Info
#define MAXMATCH 0x2000
#define MAXRELOCS (0x8000 - MAXMATCH)
#define MAXRELOCSIZE (0x8000 - MAXMATCH)
#define DI_LIMIT 0xff00 // see the assembly why
@@ -49,9 +48,6 @@ PackExe::PackExe(InputFile *f) : super(f) {
bele = &N_BELE_RTP::le_policy;
COMPILE_TIME_ASSERT(sizeof(exe_header_t) == 32)
COMPILE_TIME_ASSERT_ALIGNED1(exe_header_t)
ih_exesize = ih_imagesize = ih_overlay = 0;
stack_for_lzma = 0;
use_clear_dirty_stack = false;
}
Linker *PackExe::newLinker() const { return new ElfLinkerX86(); }
@@ -59,8 +55,7 @@ Linker *PackExe::newLinker() const { return new ElfLinkerX86(); }
const int *PackExe::getCompressionMethods(int method, int level) const {
bool small = ih_imagesize <= 256 * 1024;
// disable lzma for "--brute" unless explicitly given "--lzma"
// WARNING: this side effect may persists for later files;
// but note that class PackMaster creates per-file local options
// (note that class PackMaster creates per-file local options)
if (opt->all_methods_use_lzma == 1 && !opt->method_lzma_seen)
opt->all_methods_use_lzma = 0;
return Packer::getDefaultCompressionMethods_8(method, level, small);
@@ -125,7 +120,7 @@ void PackExe::addLoaderEpilogue(int flag) {
linker->defineSymbol("original_ss", ih.ss);
linker->defineSymbol(
"reloc_size",
(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? 0 : MAXRELOCS) - relocsize);
(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? 0 : MAXRELOCSIZE) - relocsize);
}
void PackExe::buildLoader(const Filter *) {
@@ -229,18 +224,18 @@ int PackExe::readFileHeader() {
ih_overlay = file_size - ih_exesize;
if (file_size_u < sizeof(ih) || ((ih.m512 | ih.p512) && ih.m512 + ih.p512 * 512u < sizeof(ih)))
throwCantPack("illegal exe header");
if (file_size_u < ih_exesize || ih_imagesize <= 0 || ih_imagesize > ih_exesize)
if (ih_exesize > file_size_u || ih_imagesize <= 0 || ih_imagesize > ih_exesize)
throwCantPack("exe header corrupted");
NO_printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay);
return UPX_F_DOS_EXE;
}
bool PackExe::canPack() {
if (fn_has_ext(fi->getName(), "sys"))
if (fn_has_ext(fi->getName(), "sys")) // dos/sys
return false;
if (!readFileHeader())
return false;
if (file_size < 1024)
if (file_size < 1024 || ih_imagesize < 512)
throwCantPack("file is too small for dos/exe");
fi->seek(0x3c, SEEK_SET);
LE32 offs;
@@ -258,13 +253,17 @@ bool PackExe::canPack() {
//
**************************************************************************/
static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs,
const unsigned nrelocs, byte *crel, bool *has_9a) {
static unsigned optimize_relocs(SPAN_S(byte) image, const unsigned image_size,
SPAN_S(const byte) relocs, const unsigned relocnum,
SPAN_S(byte) crel, bool *has_9a) {
#if WITH_XSPAN >= 2
ptr_check_no_overlap(image.data(image_size), image_size, relocs.data(), relocs.size_bytes(),
crel.data(), crel.size_bytes());
#endif
if (opt->exact)
throwCantPackExact();
byte *const crel_save = crel;
unsigned i;
SPAN_S_VAR(byte, const crel_start, crel);
unsigned seg_high = 0;
#if 0
unsigned seg_low = 0xffffffff;
@@ -274,19 +273,19 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
unsigned linear_high = 0;
#endif
// pass 1 - find 0x9a bounds
for (i = 0; i < nrelocs; i++) {
// pass 1 - find 0x9a bounds in image
for (unsigned i = 0; i < relocnum; i++) {
unsigned addr = get_le32(relocs + 4 * i);
if (addr >= size - 1)
if (addr >= image_size - 1)
throwCantPack("unexpected relocation 1");
if (addr >= 3 && b[addr - 3] == 0x9a) {
unsigned seg = get_le16(b + addr);
if (addr >= 3 && image[addr - 3] == 0x9a) {
unsigned seg = get_le16(image + addr);
if (seg > seg_high)
seg_high = seg;
#if 0
if (seg < seg_low)
seg_low = seg;
unsigned off = get_le16(b+addr-2);
unsigned off = get_le16(image + addr - 2);
if (off < off_low)
off_low = off;
if (off > off_high)
@@ -308,19 +307,20 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
crel += 4; // to be filled in later
unsigned ones = 0;
unsigned es = 0, di, t;
i = 0;
do {
unsigned es = 0;
for (unsigned i = 0; i < relocnum;) {
unsigned addr = get_le32(relocs + 4 * i);
set_le16(crel, di = addr & 0x0f);
unsigned di = addr & 0x0f;
set_le16(crel + 0, di);
set_le16(crel + 2, (addr >> 4) - es);
es = addr >> 4;
crel += 4;
es = addr >> 4;
for (++i; i < nrelocs; i++) {
for (++i; i < relocnum; i++) {
unsigned t;
addr = get_le32(relocs + 4 * i);
// printf ("%x\n",es*16+di);
if ((addr - es * 16 > 0xfffe) || (i == nrelocs - 1 && addr - es * 16 > 0xff00)) {
NO_printf("%x\n", es * 16 + di);
if ((addr - es * 16 > 0xfffe) || (i == relocnum - 1 && addr - es * 16 > 0xff00)) {
// segment change
t = 1 + (0xffff - di) / 254;
memset(crel, 1, t);
@@ -329,9 +329,9 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
break;
}
unsigned offs = addr - es * 16;
if (offs >= 3 && b[es * 16 + offs - 3] == 0x9a && offs > di + 3) {
if (offs >= 3 && image[es * 16 + offs - 3] == 0x9a && offs > di + 3) {
for (t = di; t < offs - 3; t++)
if (b[es * 16 + t] == 0x9a && get_le16(b + es * 16 + t + 3) <= seg_high)
if (image[es * 16 + t] == 0x9a && get_le16(image + es * 16 + t + 3) <= seg_high)
break;
if (t == offs - 3) {
// code 0: search for 0x9a
@@ -342,9 +342,8 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
}
}
t = offs - di;
if (t < 2)
if ((int) t < 2)
throwCantPack("unexpected relocation 2");
while (t >= 256) {
// code 1: add 254, don't reloc
*crel++ = 1;
@@ -354,14 +353,14 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
*crel++ = (byte) t;
di = offs;
}
} while (i < nrelocs);
}
*crel++ = 1;
ones++;
set_le16(crel_save, ones);
set_le16(crel_save + 2, seg_high);
set_le16(crel_start, ones);
set_le16(crel_start + 2, seg_high);
// OutputFile::dump("x.rel", crel_save, crel - crel_save);
return (unsigned) (crel - crel_save);
// OutputFile::dump("x.rel", crel_start, ptr_udiff_bytes(crel, crel_start));
return ptr_udiff_bytes(crel, crel_start);
}
/*************************************************************************
@@ -371,16 +370,14 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
void PackExe::pack(OutputFile *fo) {
unsigned ic;
if (ih.relocs > MAXRELOCS)
const unsigned relocnum = ih.relocs;
if (relocnum > MAXRELOCSIZE) // early check
throwCantPack("too many relocations");
checkOverlay(ih_overlay);
// alloc buffers
relocsize = RSFCRI + 4 * ih.relocs;
ibuf.alloc(ih_imagesize + 16 + relocsize + 2);
obuf.allocForCompression(ih_imagesize + 16 + relocsize + 2);
// read image
// image + space for optimized relocs + safety/alignments
ibuf.alloc(ih_imagesize + 4 * relocnum + 1024);
fi->seek(ih.headsize16 * 16, SEEK_SET);
fi->readx(ibuf, ih_imagesize);
@@ -389,37 +386,41 @@ void PackExe::pack(OutputFile *fo) {
device_driver = get_le32(ibuf) == 0xffffffffu;
// relocations
relocsize = 0;
has_9a = false;
byte *w = ibuf + ih_imagesize;
if (ih.relocs) {
byte *wr = w + RSFCRI;
if (relocnum) {
MemBuffer mb_relocs(4 * relocnum);
SPAN_S_VAR(byte, relocs, mb_relocs);
fi->seek(ih.relocoffs, SEEK_SET);
fi->readx(wr, 4 * ih.relocs);
fi->readx(relocs, 4 * relocnum);
for (ic = 0; ic < ih.relocs; ic++) {
unsigned jc = get_le32(wr + 4 * ic);
set_le32(wr + 4 * ic, ((jc >> 16) * 16 + (jc & 0xffff)) & 0xfffff);
// dos/exe runs in real-mode, so convert to linear addresses
for (ic = 0; ic < relocnum; ic++) {
unsigned jc = get_le32(relocs + 4 * ic);
set_le32(relocs + 4 * ic, ((jc >> 16) * 16 + (jc & 0xffff)) & 0xfffff);
}
qsort(wr, ih.relocs, 4, le32_compare);
relocsize = optimize_relocs(ibuf, ih_imagesize, wr, ih.relocs, w, &has_9a);
set_le16(w + relocsize, relocsize + 2);
qsort(raw_bytes(relocs, 4 * relocnum), relocnum, 4, le32_compare);
SPAN_S_VAR(byte, image, ibuf + 0, ih_imagesize);
SPAN_S_VAR(byte, crel, ibuf + ih_imagesize, ibuf);
relocsize = optimize_relocs(image, ih_imagesize, relocs, relocnum, crel, &has_9a);
set_le16(crel + relocsize, relocsize + 2);
relocsize += 2;
if (relocsize > MAXRELOCS)
assert(relocsize >= 11);
if (relocsize > MAXRELOCSIZE) // optimize_relocs did not help
throwCantPack("too many relocations");
#if 0
byte out[9*relocsize/8+1024];
unsigned in_len = relocsize;
unsigned out_len = 0;
ucl_nrv2b_99_compress(w, in_len, out, &out_len, nullptr, 9, nullptr, nullptr);
printf("reloc compress: %d -> %d\n", in_len, out_len);
#if TESTING && 0
unsigned rout_len = MemBuffer::getSizeForCompression(relocsize);
MemBuffer rout(rout_len);
ucl_nrv2b_99_compress(raw_bytes(crel, relocsize), relocsize, rout, &rout_len, nullptr, 9,
nullptr, nullptr);
printf("dos/exe reloc compress: %d -> %d\n", relocsize, rout_len);
#endif
} else {
relocsize = 0;
}
// prepare packheader
ph.u_len = ih_imagesize + relocsize;
obuf.allocForCompression(ph.u_len);
// prepare filter
Filter ft(ph.level);
// compress (max_match = 8192)
@@ -511,9 +512,7 @@ void PackExe::pack(OutputFile *fo) {
oh.firstreloc = ih.cs * 0x10000 + ih.ip;
}
// g++ 3.1 does not like the following line...
oh.relocoffs = offsetof(exe_header_t, firstreloc);
// oh.relocoffs = ptr_udiff_bytes(&oh.firstreloc, &oh);
linker->defineSymbol("destination_segment", oh.ss - ph.c_len / 16 - e_len / 16);
linker->defineSymbol("source_segment", e_len / 16 + (copysize - firstcopy) / 16);
@@ -526,7 +525,7 @@ void PackExe::pack(OutputFile *fo) {
linker->defineSymbol("attribute", get_le16(ibuf + 4));
linker->defineSymbol("orig_strategy", get_le16(ibuf + 6));
const unsigned outputlen = sizeof(oh) + lsize + packedsize + eisize;
const unsigned outputlen = sizeof(oh) + e_len + packedsize + d_len + eisize;
oh.m512 = outputlen & 511;
oh.p512 = (outputlen + 511) >> 9;
@@ -538,20 +537,19 @@ void PackExe::pack(OutputFile *fo) {
memcpy(loader, getLoader(), lsize);
patchPackHeader(loader, e_len);
NO_fprintf(stderr, "\ne_len=%x d_len=%x c_len=%x oo=%x ulen=%x destp=%x copys=%x images=%x",
e_len, d_len, packedsize, ph.overlap_overhead, ph.u_len, /*destpara*/ 0, copysize,
ih_imagesize);
NO_fprintf(stderr, "\ne_len=%x d_len=%x c_len=%x oo=%x ulen=%x copysize=%x imagesize=%x", e_len,
d_len, packedsize, ph.overlap_overhead, ph.u_len, copysize, ih_imagesize);
// write header + write loader + compressed file
#if TESTING
if (opt->debug.debug_level)
printf("\n%d %d %d %d\n", (int) sizeof(oh), e_len, packedsize, d_len);
#endif
fo->write(&oh, sizeof(oh));
fo->write(loader, e_len); // entry
fo->write(obuf, packedsize);
fo->write(loader + e_len, d_len); // decompressor
fo->write(extra_info, eisize);
fo->write(&oh, sizeof(oh)); // program header
fo->write(loader, e_len); // entry code
fo->write(obuf, packedsize); // compressed data
fo->write(loader + e_len, d_len); // decompressor code
fo->write(extra_info, eisize); // extra info for unpacking
assert(eisize <= 9);
NO_printf("%-13s: program hdr : %8u bytes\n", getName(), usizeof(oh));
NO_printf("%-13s: entry : %8u bytes\n", getName(), e_len);
@@ -564,7 +562,7 @@ void PackExe::pack(OutputFile *fo) {
// copy the overlay
copyOverlay(fo, ih_overlay, obuf);
// fprintf (stderr,"%x %x\n",relocsize,ph.u_len);
NO_fprintf(stderr, "dos/exe %x %x\n", relocsize, ph.u_len);
// finally check the compression ratio
if (!checkFinalCompressionRatio(fo))
@@ -607,41 +605,46 @@ void PackExe::unpack(OutputFile *fo) {
decompress(ibuf + e_len, obuf);
unsigned imagesize = ih_imagesize;
imagesize--;
imagesize -= 1;
const byte flag = ibuf[imagesize];
unsigned relocn = 0;
SPAN_S_VAR(byte, relocs, obuf + ph.u_len, obuf);
MemBuffer mb_wrkmem;
SPAN_0_VAR(byte, wrkmem, nullptr);
// relocations
unsigned relocnum = 0;
SPAN_S_VAR(const byte, relocstart, obuf + ph.u_len, obuf);
MemBuffer mb_relocs;
SPAN_0_VAR(byte, relocs, nullptr);
if (!(flag & NORELOC)) {
relocs -= get_le16(obuf + (ph.u_len - 2));
mb_relocs.alloc(4 * MAXRELOCSIZE);
relocs = mb_relocs; // => now a SPAN_S
relocsize = get_le16(obuf + ph.u_len - 2);
ph.u_len -= 2;
if (relocsize < 11 || relocsize > MAXRELOCSIZE || relocsize >= imagesize)
throwCantUnpack("bad relocations");
relocstart -= relocsize;
mb_wrkmem.alloc(4 * MAXRELOCS);
wrkmem = mb_wrkmem; // => now a SPAN_S
unsigned es = 0, ones = get_le16(relocs);
const unsigned seghi = get_le16(relocs + 2);
SPAN_S_VAR(const byte, p, relocs + 4);
// unoptimize_relocs
unsigned ones = get_le16(relocstart);
const unsigned seg_high = get_le16(relocstart + 2);
SPAN_S_VAR(const byte, p, relocstart + 4);
unsigned es = 0;
while (ones) {
unsigned di = get_le16(p);
es += get_le16(p + 2);
bool dorel = true;
for (p += 4; ones && di < 0x10000; p++) {
if (dorel) {
set_le16(wrkmem + (4 * relocn), di);
set_le16(wrkmem + (2 + 4 * relocn++), es);
NO_printf("%x\n", es * 16 + di);
set_le16(relocs + (4 * relocnum + 0), di);
set_le16(relocs + (4 * relocnum + 2), es);
NO_printf("dos/exe unreloc %4d %6x\n", relocnum, es * 16 + di);
relocnum++;
}
dorel = true;
if (*p == 0) {
SPAN_S_VAR(const byte, q, obuf);
for (q = obuf + (es * 16 + di); !(*q == 0x9a && get_le16(q + 3) <= seghi);
q++) {
}
di = ptr_diff_bytes(q, obuf + (es * 16)) + 3;
SPAN_S_VAR(const byte, q, obuf + (es * 16 + di), obuf);
while (!(*q == 0x9a && get_le16(q + 3) <= seg_high))
q++;
di = ptr_udiff_bytes(q, obuf + (es * 16)) + 3;
} else if (*p == 1) {
di += 254;
if (di < 0x10000)
@@ -657,16 +660,16 @@ void PackExe::unpack(OutputFile *fo) {
memset(&oh, 0, sizeof(oh));
oh.ident = 'M' + 'Z' * 256;
if (relocn) {
oh.relocs = relocn;
while (relocn & 3)
set_le32(wrkmem + (4 * relocn++), 0);
if (relocnum) {
oh.relocs = relocnum;
while (relocnum & 3) // paragraph align
set_le32(relocs + (4 * relocnum++), 0);
}
unsigned outputlen = ptr_udiff_bytes(relocs, obuf) + sizeof(oh) + relocn * 4;
unsigned outputlen = sizeof(oh) + 4 * relocnum + ptr_udiff_bytes(relocstart, obuf);
oh.m512 = outputlen & 511;
oh.p512 = (outputlen + 511) >> 9;
oh.headsize16 = 2 + relocn / 4;
oh.headsize16 = 2 + relocnum / 4;
oh.max = ih.max;
oh.min = ih.min;
@@ -701,9 +704,9 @@ void PackExe::unpack(OutputFile *fo) {
// write header + relocations + uncompressed file
fo->write(&oh, sizeof(oh));
if (relocn)
fo->write(wrkmem, relocn * 4);
fo->write(obuf, ptr_udiff_bytes(relocs, obuf));
if (relocnum)
fo->write(relocs, 4 * relocnum);
fo->write(obuf, ptr_udiff_bytes(relocstart, obuf));
// copy the overlay
copyOverlay(fo, ih_overlay, obuf);
+9 -9
View File
@@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_DOS_EXE; }
virtual const char *getName() const override { return "dos/exe"; }
virtual const char *getFullName(const options_t *) const override { return "i086-dos16.exe"; }
virtual const char *getFullName(const Options *) const override { return "i086-dos16.exe"; }
virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override;
@@ -90,18 +90,18 @@ protected:
exe_header_t ih, oh;
unsigned ih_exesize;
unsigned ih_imagesize;
unsigned ih_overlay;
unsigned relocsize;
unsigned ih_exesize = 0;
unsigned ih_imagesize = 0;
unsigned ih_overlay = 0;
unsigned relocsize = 0;
bool has_9a;
bool device_driver;
bool has_9a = false;
bool device_driver = false;
enum { NORELOC = 1, USEJUMP = 2, SS = 4, SP = 8, MINMEM = 16, MAXMEM = 32 };
unsigned stack_for_lzma; // stack size required for lzma
bool use_clear_dirty_stack;
unsigned stack_for_lzma = 0; // stack size required for lzma
bool use_clear_dirty_stack = false;
};
#endif /* already included */
+1 -1
View File
@@ -45,7 +45,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_PS1_EXE; }
virtual const char *getName() const override { return "ps1/exe"; }
virtual const char *getFullName(const options_t *) const override { return "mipsel.r3000-ps1"; }
virtual const char *getFullName(const Options *) const override { return "mipsel.r3000-ps1"; }
virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override;
+1 -1
View File
@@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_DOS_SYS; }
virtual const char *getName() const override { return "dos/sys"; }
virtual const char *getFullName(const options_t *) const override { return "i086-dos16.sys"; }
virtual const char *getFullName(const Options *) const override { return "i086-dos16.sys"; }
virtual bool canPack() override;
+6 -3
View File
@@ -188,15 +188,18 @@ void PackTmt::pack(OutputFile *fo) {
checkOverlay(overlay);
for (unsigned ic = 0; ic < relocnum; ic++)
set_le32(relocs + ic * 4, get_le32(relocs + ic * 4) - 4);
set_le32(relocs + 4 * ic, get_le32(relocs + 4 * ic) - 4);
MemBuffer mb_orelocs(4 * relocnum + 8192); // relocations + extra_info
SPAN_S_VAR(byte, orelocs, mb_orelocs);
unsigned orelocsize =
optimizeReloc(relocnum, relocs, orelocs, ibuf, usize, 32, true, &big_relocs);
mb_relocs.dealloc(); // done
#if 1
// write duplicate end marker; why is this here - historical oversight ???
orelocs[orelocsize++] = 0;
#endif
// extra_info
orelocs[orelocsize++] = 0; // why is this needed - historical oversight ???
set_le32(orelocs + orelocsize, ih.entry); // save original entry point
orelocsize += 4;
set_le32(orelocs + orelocsize, orelocsize + 4); // save orelocsize
@@ -303,7 +306,7 @@ void PackTmt::unpack(OutputFile *fo) {
const unsigned relocnum = unoptimizeReloc(orelocs, mb_relocs, reloc_image, osize, 32, true);
SPAN_S_VAR(byte, relocs, mb_relocs);
for (unsigned ic = 0; ic < relocnum; ic++)
set_le32(relocs + ic * 4, get_le32(relocs + ic * 4) + 4);
set_le32(relocs + 4 * ic, get_le32(relocs + 4 * ic) + 4);
memcpy(&oh, &ih, sizeof(oh));
oh.imagesize = osize;
+1 -1
View File
@@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_TMT_ADAM; }
virtual const char *getName() const override { return "tmt/adam"; }
virtual const char *getFullName(const options_t *) const override {
virtual const char *getFullName(const Options *) const override {
return "i386-dos32.tmt.adam";
}
virtual const int *getCompressionMethods(int method, int level) const override;
+17 -19
View File
@@ -223,11 +223,9 @@ void PackTos::buildLoader(const Filter *ft) {
#define F_FASTLOAD 0x01 // don't zero heap
#define F_ALTLOAD 0x02 // OK to load in alternate ram
#define F_ALTALLOC 0x04 // OK to malloc from alt. ram
#define F_SMALLTPA \
0x08 // used in MagiC: TPA can be allocated
// as specified in the program header
// rather than the biggest free memory
// block
#define F_SMALLTPA 0x08
// used in MagiC: TPA can be allocated as specified in the program header
// rather than the biggest free memory block
#define F_MEMFLAGS 0xf0 // reserved for future use
#define F_SHTEXT 0x800 // program's text may be shared
@@ -297,26 +295,26 @@ bool PackTos::checkFileHeader() {
// relocs
**************************************************************************/
// Check relocation for errors to make sure our loader can handle it.
static int check_relocs(const byte *relocs, unsigned rsize, unsigned isize, unsigned *nrelocs,
// Check relocation for errors to make sure our loader can handle them
static int check_relocs(const byte *relocs, unsigned rsize, unsigned image_size, unsigned *relocnum,
unsigned *relocsize, unsigned *overlay) {
assert(rsize >= 4);
assert(image_size >= 4);
unsigned fixup = get_be32(relocs);
assert(fixup > 0);
unsigned last_fixup = fixup;
unsigned i = 4;
assert(isize >= 4);
assert(fixup > 0);
*nrelocs = 1;
*relocnum = 1;
for (;;) {
if (fixup & 1) // must be word-aligned
return -1;
if (fixup + 4 > isize) // too far
if (fixup + 4 > image_size) // out of bounds
return -1;
if (i >= rsize) // premature EOF in relocs
return -1;
unsigned c = relocs[i++];
if (c == 0) // end marker
if (c == 0) // EOF end marker
break;
else if (c == 1) // increase fixup, no reloc
fixup += 254;
@@ -328,7 +326,7 @@ static int check_relocs(const byte *relocs, unsigned rsize, unsigned isize, unsi
if (fixup - last_fixup < 4) // overlapping relocation
return -1;
last_fixup = fixup;
*nrelocs += 1;
*relocnum += 1;
}
}
@@ -352,7 +350,7 @@ bool PackTos::canPack() {
if (!checkFileHeader())
throwCantPack("unsupported header flags");
if (file_size < 1024)
throwCantPack("program is too small");
throwCantPack("program is too small for atari/tos");
return true;
}
@@ -370,7 +368,7 @@ void PackTos::fileInfo() {
void PackTos::pack(OutputFile *fo) {
unsigned t;
unsigned nrelocs = 0;
unsigned relocnum = 0;
unsigned relocsize = 0;
unsigned overlay = 0;
@@ -426,14 +424,14 @@ void PackTos::pack(OutputFile *fo) {
} else if (ih.fh_reloc != 0)
relocsize = 0;
else {
int r = check_relocs(ibuf + t, overlay, t, &nrelocs, &relocsize, &overlay);
int r = check_relocs(ibuf + t, overlay, t, &relocnum, &relocsize, &overlay);
if (r != 0)
throwCantPack("bad relocation table");
symbols.need_reloc = true;
}
#if TESTING
printf("xx2: %d relocs: %d, overlay: %d, t: %d\n", nrelocs, relocsize, overlay, t);
printf("xx2: %d relocs: %d, overlay: %d, t: %d\n", relocnum, relocsize, overlay, t);
#endif
checkOverlay(overlay);
@@ -451,7 +449,7 @@ void PackTos::pack(OutputFile *fo) {
// Now the data in ibuf[0..t] looks like this:
// text + data + relocs + original file header
// After compression this will become the first part of the
// data segement. The second part will be the decompressor.
// data segment. The second part will be the decompressor.
// alloc buffer (4096 is for decompressor and the various alignments)
obuf.allocForCompression(t, 4096);
+1 -1
View File
@@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_ATARI_TOS; }
virtual const char *getName() const override { return "atari/tos"; }
virtual const char *getFullName(const options_t *) const override { return "m68k-atari.tos"; }
virtual const char *getFullName(const Options *) const override { return "m68k-atari.tos"; }
virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override;
+2 -2
View File
@@ -62,8 +62,8 @@ Linker *PackW32PeI386::newLinker() const { return new ElfLinkerX86; }
**************************************************************************/
int PackW32PeI386::readFileHeader() {
if (fi->st_size() >= 0x206) {
char buf[6];
if (file_size >= 0x206) {
byte buf[6];
fi->seek(0x200, SEEK_SET);
fi->readx(buf, 6);
isrtm = memcmp(buf, "32STUB", 6) == 0;
+1 -1
View File
@@ -39,7 +39,7 @@ public:
virtual ~PackW32PeI386();
virtual int getFormat() const override { return UPX_F_W32PE_I386; }
virtual const char *getName() const override { return isrtm ? "rtm32/pe" : "win32/pe"; }
virtual const char *getFullName(const options_t *) const override { return "i386-win32.pe"; }
virtual const char *getFullName(const Options *) const override { return "i386-win32.pe"; }
virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override;
+1 -1
View File
@@ -39,7 +39,7 @@ public:
virtual ~PackW64PeAmd64();
virtual int getFormat() const override { return UPX_F_W64PE_AMD64; }
virtual const char *getName() const override { return "win64/pe"; }
virtual const char *getFullName(const options_t *) const override { return "amd64-win64.pe"; }
virtual const char *getFullName(const Options *) const override { return "amd64-win64.pe"; }
virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override;
+2 -2
View File
@@ -39,7 +39,7 @@ public:
virtual ~PackW64PeArm64() {}
virtual int getFormat() const override { return UPX_F_W64PE_ARM64; }
virtual const char *getName() const override { return "win64/arm64"; }
virtual const char *getFullName(const options_t *) const override { return "arm64-win64.pe"; }
virtual const char *getFullName(const Options *) const override { return "arm64-win64.pe"; }
virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override;
@@ -70,7 +70,7 @@ public:
PackW64PeArm64EC(InputFile *f) : super(f) {}
virtual int getFormat() const override { return UPX_F_W64PE_ARM64EC; }
virtual const char *getName() const override { return "win64/arm64ec"; }
virtual const char *getFullName(const options_t *) const override { return "arm64ec-win64.pe"; }
virtual const char *getFullName(const Options *) const override { return "arm64ec-win64.pe"; }
virtual bool canPack() override;
};
+1 -1
View File
@@ -39,7 +39,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_WATCOM_LE; }
virtual const char *getName() const override { return "watcom/le"; }
virtual const char *getFullName(const options_t *) const override {
virtual const char *getFullName(const Options *) const override {
return "i386-dos32.watcom.le";
}
virtual const int *getCompressionMethods(int method, int level) const override;
+1 -1
View File
@@ -39,7 +39,7 @@ public:
virtual ~PackWinCeArm();
virtual int getFormat() const override { return UPX_F_WINCE_ARM; }
virtual const char *getName() const override { return "wince/arm"; }
virtual const char *getFullName(const options_t *) const override { return "arm-wince.pe"; }
virtual const char *getFullName(const Options *) const override { return "arm-wince.pe"; }
virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override;
virtual void defineFilterSymbols(const Filter *) override {}
+20 -21
View File
@@ -46,7 +46,7 @@ Packer::Packer(InputFile *f)
mem_clear(&ph, sizeof(ph));
}
Packer::~Packer() {
Packer::~Packer() noexcept {
delete uip;
uip = nullptr;
delete linker;
@@ -834,27 +834,26 @@ static const char *getIdentstr(unsigned *size, int small) {
"\n";
static char identtiny[] = UPX_VERSION_STRING4;
static int done;
if (!done && (opt->debug.fake_stub_version[0] || opt->debug.fake_stub_year[0])) {
struct strinfo_t {
char *s;
int size;
};
static const strinfo_t strlist[] = {{identbig, (int) sizeof(identbig)},
{identsmall, (int) sizeof(identsmall)},
{identtiny, (int) sizeof(identtiny)},
{nullptr, 0}};
const strinfo_t *iter;
for (iter = strlist; iter->s; ++iter) {
if (opt->debug.fake_stub_version[0])
mem_replace(iter->s, iter->size, UPX_VERSION_STRING4, 4,
opt->debug.fake_stub_version);
if (opt->debug.fake_stub_year[0])
mem_replace(iter->s, iter->size, UPX_VERSION_YEAR, 4, opt->debug.fake_stub_year);
static upx_std_once_flag init_done;
upx_std_call_once(init_done, []() noexcept {
if (opt->debug.fake_stub_version[0] || opt->debug.fake_stub_year[0]) {
struct Ident {
char *s;
int len;
};
static const Ident idents[] = {{identbig, (int) sizeof(identbig) - 1},
{identsmall, (int) sizeof(identsmall) - 1},
{identtiny, (int) sizeof(identtiny) - 1},
{nullptr, 0}};
for (const Ident *iter = idents; iter->s; ++iter) {
if (opt->debug.fake_stub_version[0])
mem_replace(iter->s, iter->len, UPX_VERSION_STRING4, 4,
opt->debug.fake_stub_version);
if (opt->debug.fake_stub_year[0])
mem_replace(iter->s, iter->len, UPX_VERSION_YEAR, 4, opt->debug.fake_stub_year);
}
}
done = 1;
}
});
if (small < 0)
small = opt->small;
+6 -6
View File
@@ -112,7 +112,7 @@ protected:
Packer(InputFile *f);
public:
virtual ~Packer();
virtual ~Packer() noexcept;
virtual void assertPacker() const;
// getVersion() enables detecting forward incompatibility of unpack()
@@ -121,7 +121,7 @@ public:
// A unique integer ID for this executable format. See conf.h.
virtual int getFormat() const = 0;
virtual const char *getName() const = 0;
virtual const char *getFullName(const options_t *) const = 0;
virtual const char *getFullName(const Options *) const = 0;
virtual const int *getCompressionMethods(int method, int level) const = 0;
virtual const int *getFilters() const = 0;
@@ -187,7 +187,7 @@ protected:
unsigned overlap_range, upx_compress_config_t const *cconf,
int filter_strategy, bool inhibit_compression_check = false);
// util for verifying overlapping decompresion
// util for verifying overlapping decompression
// non-destructive test
virtual bool testOverlappingDecompression(const byte *buf, const byte *tbuf,
unsigned overlap_overhead) const;
@@ -299,9 +299,9 @@ protected:
int ph_version;
// compression buffers
MemBuffer ibuf; // input
MemBuffer obuf; // output
unsigned ibufgood; // high-water mark in ibuf (pefile.cpp)
MemBuffer ibuf; // input
MemBuffer obuf; // output
unsigned ibufgood = 0; // high-water mark in ibuf (pefile.cpp)
// UI handler
UiPacker *uip = nullptr;
+12 -5
View File
@@ -30,7 +30,7 @@
/*************************************************************************
// sort and delta-compress relocations with optional bswap within image
// returns number of bytes written to |out|
// returns number of bytes written to 'out'
**************************************************************************/
unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(byte) out,
@@ -38,6 +38,10 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
int *big) {
assert(bits == 32 || bits == 64);
mem_size_assert(1, image_size);
#if WITH_XSPAN >= 2
ptr_check_no_overlap(relocs.data(), relocs.size_bytes(), image.data(image_size), image_size,
out.data(), out.size_bytes());
#endif
SPAN_P_VAR(byte, fix, out);
*big = 0;
@@ -69,7 +73,7 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
fix += 4;
}
pc += delta;
if (pc + 4 >= image_size)
if (pc + 4 > image_size)
throwCantPack("bad reloc[%#x] = %#x", i, pc);
if (bswap) {
if (bits == 32)
@@ -84,14 +88,17 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
/*************************************************************************
// delta-decompress relocations
// advances |in|
// allocates |out| and returns number of relocs written to |out|
// advances 'in'
// allocates 'out' and returns number of relocs written to 'out'
**************************************************************************/
unsigned Packer::unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P(byte) image,
unsigned image_size, int bits, bool bswap) {
assert(bits == 32 || bits == 64);
mem_size_assert(1, image_size);
#if WITH_XSPAN >= 2
ptr_check_no_overlap(in.data(), in.size_bytes(), image.data(image_size), image_size);
#endif
SPAN_S_VAR(const byte, fix, in);
// count
@@ -125,7 +132,7 @@ unsigned Packer::unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P
if ((int) delta < 4)
throwCantUnpack("overlapping fixups");
pc += delta;
if (pc + 4 >= image_size)
if (pc + 4 > image_size)
throwCantUnpack("bad reloc[%#x] = %#x", i, pc);
*relocs++ = pc;
if (bswap && image != nullptr) {
+65 -72
View File
@@ -59,34 +59,37 @@
//
**************************************************************************/
PackMaster::PackMaster(InputFile *f, options_t *o) : fi(f), p(nullptr) {
PackMaster::PackMaster(InputFile *f, Options *o) noexcept : fi(f) {
// replace global options with local options
saved_opt = o;
if (o) {
if (o != nullptr) {
#if WITH_THREADS
std::lock_guard<std::mutex> lock(opt_lock_mutex);
#endif
saved_opt = o;
memcpy(&this->local_options, o, sizeof(*o)); // struct copy
opt = &this->local_options;
}
}
PackMaster::~PackMaster() {
fi = nullptr;
delete p;
p = nullptr;
PackMaster::~PackMaster() noexcept {
delete packer;
packer = nullptr;
// restore global options
if (saved_opt)
if (saved_opt != nullptr) {
#if WITH_THREADS
std::lock_guard<std::mutex> lock(opt_lock_mutex);
#endif
opt = saved_opt;
saved_opt = nullptr;
saved_opt = nullptr;
}
}
/*************************************************************************
//
**************************************************************************/
static Packer *try_pack(Packer *p, void *user) {
if (p == nullptr)
return nullptr;
static Packer *try_can_pack(Packer *p, void *user) {
InputFile *f = (InputFile *) user;
p->assertPacker();
try {
p->initPackHeader();
f->seek(0, SEEK_SET);
@@ -105,11 +108,8 @@ static Packer *try_pack(Packer *p, void *user) {
return nullptr;
}
static Packer *try_unpack(Packer *p, void *user) {
if (p == nullptr)
return nullptr;
static Packer *try_can_unpack(Packer *p, void *user) {
InputFile *f = (InputFile *) user;
p->assertPacker();
try {
p->initPackHeader();
f->seek(0, SEEK_SET);
@@ -123,6 +123,7 @@ static Packer *try_unpack(Packer *p, void *user) {
// see canUnpack() in packer.h
}
} catch (const IOException &) {
// ignored
} catch (...) {
delete p;
throw;
@@ -135,41 +136,40 @@ static Packer *try_unpack(Packer *p, void *user) {
//
**************************************************************************/
Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const options_t *o,
void *user) {
Packer *p = nullptr;
/*static*/
Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const Options *o, void *user) {
#define D(Klass) \
ACC_BLOCK_BEGIN \
Klass *const kp = new Klass(f); \
COMPILE_TIME_ASSERT(std::is_nothrow_destructible_v<Klass>) \
Klass *kp = new Klass(f); \
kp->assertPacker(); \
if (o->debug.debug_level) \
fprintf(stderr, "visitAllPackers: (ver=%d, fmt=%3d) %s\n", kp->getVersion(), \
kp->getFormat(), #Klass); \
if ((p = func(kp, user)) != nullptr) \
Packer *p = func(kp, user); \
if (p != nullptr) \
return p; \
ACC_BLOCK_END
// note: order of tries is important !
// NOTE: order of tries is important !!!
//
// .exe
//
if (!o->dos_exe.force_stub) {
// dos32
D(PackDjgpp2);
D(PackTmt);
D(PackWcle);
// Windows
// D(PackW64PeArm64EC); // NOT YET IMPLEMENTED
// D(PackW64PeArm64); // NOT YET IMPLEMENTED
D(PackW64PeAmd64);
D(PackW32PeI386);
D(PackWinCeArm);
}
D(PackWinCeArm);
D(PackExe);
//
// atari
//
D(PackTos);
D(PackExe); // dos/exe
//
// linux kernel
@@ -210,18 +210,7 @@ Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio
D(PackMachFat); // cafebabe conflict
D(PackLinuxI386); // cafebabe conflict
//
// psone
//
D(PackPs1);
//
// .sys and .com
//
D(PackSys);
D(PackCom);
// Mach (macOS)
// Mach (Darwin / macOS)
D(PackDylibAMD64);
D(PackMachPPC32); // TODO: this works with upx 3.91..3.94 but got broken in 3.95; FIXME
D(PackMachI386);
@@ -235,24 +224,30 @@ Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio
// D(PackDylibI386);
// D(PackDylibPPC32);
//
// misc
//
D(PackTos); // atari/tos
D(PackPs1); // ps1/exe
D(PackSys); // dos/sys
D(PackCom); // dos/com
return nullptr;
#undef D
}
Packer *PackMaster::getPacker(InputFile *f) {
Packer *pp = visitAllPackers(try_pack, f, opt, f);
if (!pp)
/*static*/ Packer *PackMaster::getPacker(InputFile *f) {
Packer *p = visitAllPackers(try_can_pack, f, opt, f);
if (!p)
throwUnknownExecutableFormat();
pp->assertPacker();
return pp;
return p;
}
Packer *PackMaster::getUnpacker(InputFile *f) {
Packer *pp = visitAllPackers(try_unpack, f, opt, f);
if (!pp)
/*static*/ Packer *PackMaster::getUnpacker(InputFile *f) {
Packer *p = visitAllPackers(try_can_unpack, f, opt, f);
if (!p)
throwNotPacked();
pp->assertPacker();
return pp;
return p;
}
/*************************************************************************
@@ -260,39 +255,37 @@ Packer *PackMaster::getUnpacker(InputFile *f) {
**************************************************************************/
void PackMaster::pack(OutputFile *fo) {
p = getPacker(fi);
fi = nullptr;
p->doPack(fo);
assert(packer == nullptr);
packer = getPacker(fi);
packer->doPack(fo);
}
void PackMaster::unpack(OutputFile *fo) {
p = getUnpacker(fi);
p->assertPacker();
fi = nullptr;
p->doUnpack(fo);
assert(packer == nullptr);
packer = getUnpacker(fi);
packer->doUnpack(fo);
}
void PackMaster::test() {
p = getUnpacker(fi);
fi = nullptr;
p->doTest();
assert(packer == nullptr);
packer = getUnpacker(fi);
packer->doTest();
}
void PackMaster::list() {
p = getUnpacker(fi);
fi = nullptr;
p->doList();
assert(packer == nullptr);
packer = getUnpacker(fi);
packer->doList();
}
void PackMaster::fileInfo() {
p = visitAllPackers(try_unpack, fi, opt, fi);
if (!p)
p = visitAllPackers(try_pack, fi, opt, fi);
if (!p)
assert(packer == nullptr);
packer = visitAllPackers(try_can_unpack, fi, opt, fi);
if (!packer)
packer = visitAllPackers(try_can_pack, fi, opt, fi);
if (!packer)
throwUnknownExecutableFormat(nullptr, 1); // make a warning here
p->assertPacker();
fi = nullptr;
p->doFileInfo();
packer->doFileInfo();
}
/* vim:set ts=4 sw=4 et: */
+8 -8
View File
@@ -32,13 +32,13 @@ class InputFile;
class OutputFile;
/*************************************************************************
// interface for work.cpp
// dispatch to a concrete subclass of class Packer; see work.cpp
**************************************************************************/
class PackMaster final {
public:
PackMaster(InputFile *f, options_t *o = nullptr);
~PackMaster();
PackMaster(InputFile *f, Options *o = nullptr) noexcept;
~PackMaster() noexcept;
void pack(OutputFile *fo);
void unpack(OutputFile *fo);
@@ -47,18 +47,18 @@ public:
void fileInfo();
typedef Packer *(*visit_func_t)(Packer *p, void *user);
static Packer *visitAllPackers(visit_func_t, InputFile *f, const options_t *, void *user);
static Packer *visitAllPackers(visit_func_t, InputFile *f, const Options *, void *user);
private:
InputFile *fi = nullptr;
Packer *p = nullptr;
Packer *packer = nullptr; // owner
InputFile *fi = nullptr; // reference
static Packer *getPacker(InputFile *f);
static Packer *getUnpacker(InputFile *f);
// setup local options for each file
options_t local_options;
options_t *saved_opt = nullptr;
Options local_options;
Options *saved_opt = nullptr;
};
/* vim:set ts=4 sw=4 et: */
+70 -47
View File
@@ -140,7 +140,7 @@ bool PeFile::testUnpackVersion(int version) const {
if (cpu >= IMAGE_FILE_MACHINE_I386 && cpu <= 0x150) // what is this 0x150 ???
return UPX_F_W32PE_I386;
// other or unkown (alpha, mips, etc.)
// other or unknown (alpha, mips, etc.)
throwCantPack("pefile: unsupported machine %#x", cpu);
return 0; // pacify msvc
}
@@ -274,6 +274,19 @@ void PeFile::Interval::dump() const {
// relocation handling
**************************************************************************/
namespace {
struct FixDeleter { // don't leak memory on exceptions
LE32 **fix;
size_t n;
~FixDeleter() noexcept {
for (size_t i = 0; i < n; i++) {
delete[] fix[i];
fix[i] = nullptr;
}
}
};
} // namespace
struct alignas(1) PeFile::Reloc::reloc {
LE32 pagestart;
LE32 size;
@@ -371,17 +384,21 @@ void PeFile32::processRelocs() // pass1
}
mb_orelocs.alloc(1);
orelocs = mb_orelocs; // => orelocs now is a SPAN_S
orelocs[0] = 0; // clear
sorelocs = 0;
return;
}
for (ic = 15; ic > 3; ic--)
for (ic = 4; ic < 16; ic++)
if (counts[ic])
infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]);
LE32 *fix[4];
for (; ic; ic--)
FixDeleter fixdel{fix, 0}; // don't leak memory
for (ic = 0; ic < 4; ic++) {
fix[ic] = New(LE32, counts[ic]);
fixdel.n += 1;
}
unsigned xcounts[4];
memset(xcounts, 0, sizeof(xcounts));
@@ -420,7 +437,6 @@ void PeFile32::processRelocs() // pass1
orelocs = mb_orelocs; // => orelocs now is a SPAN_S
sorelocs = optimizeReloc(xcounts[3], (byte *) fix[3], orelocs, ibuf + rvamin, ibufgood - rvamin,
32, true, &big_relocs);
delete[] fix[3];
// Malware that hides behind UPX often has PE header info that is
// deliberately corrupt. Sometimes it is even tuned to cause us trouble!
@@ -433,7 +449,6 @@ void PeFile32::processRelocs() // pass1
for (ic = 2; ic; ic--) {
memcpy(orelocs + sorelocs, fix[ic], 4 * xcounts[ic]);
sorelocs += 4 * xcounts[ic];
delete[] fix[ic];
set_le32(orelocs + sorelocs, 0);
if (xcounts[ic]) {
@@ -471,13 +486,16 @@ void PeFile64::processRelocs() // pass1
return;
}
for (ic = 15; ic; ic--)
for (ic = 0; ic < 16; ic++)
if (ic != 10 && counts[ic])
infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]);
LE32 *fix[16];
for (ic = 15; ic; ic--)
FixDeleter fixdel{fix, 0}; // don't leak memory
for (ic = 0; ic < 16; ic++) {
fix[ic] = New(LE32, counts[ic]);
fixdel.n += 1;
}
unsigned xcounts[16];
memset(xcounts, 0, sizeof(xcounts));
@@ -495,7 +513,7 @@ void PeFile64::processRelocs() // pass1
}
// remove duplicated records
for (ic = 1; ic <= 15; ic++) {
for (ic = 1; ic < 16; ic++) {
qsort(fix[ic], xcounts[ic], 4, le32_compare);
unsigned prev = ~0u;
unsigned jc = 0;
@@ -520,9 +538,6 @@ void PeFile64::processRelocs() // pass1
sorelocs = optimizeReloc(xcounts[10], (byte *) fix[10], orelocs, ibuf + rvamin,
ibufgood - rvamin, 64, true, &big_relocs);
for (ic = 15; ic; ic--)
delete[] fix[ic];
#if 0
// Malware that hides behind UPX often has PE header info that is
// deliberately corrupt. Sometimes it is even tuned to cause us trouble!
@@ -536,7 +551,6 @@ void PeFile64::processRelocs() // pass1
{
memcpy(orelocs + sorelocs,fix[ic],4 * xcounts[ic]);
sorelocs += 4 * xcounts[ic];
delete [] fix[ic];
set_le32(orelocs + sorelocs,0);
if (xcounts[ic])
@@ -574,7 +588,7 @@ const LE32 &PeFile::IDADDR(unsigned x) const { return iddirs[x].vaddr; }
in the sorted order.
*/
class PeFile::ImportLinker : public ElfLinkerAMD64 {
class PeFile::ImportLinker final : public ElfLinkerAMD64 {
struct tstr : private ::noncopyable {
char *s = nullptr;
explicit tstr(char *str) : s(str) {}
@@ -833,7 +847,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
import_desc *const im_save = im;
if (IDADDR(PEDIR_IMPORT)) {
for (;; ++dllnum, ++im) {
unsigned const skip2 = ptr_diff_bytes(im, ibuf);
unsigned const skip2 = ptr_udiff_bytes(im, ibuf);
(void) ibuf.subref("bad import %#x", skip2, sizeof(*im));
if (!im->dllname)
break;
@@ -853,25 +867,17 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
static int __acc_cdecl_qsort compare(const void *p1, const void *p2) {
const udll *u1 = *(const udll *const *) p1;
const udll *u2 = *(const udll *const *) p2;
if (u1->isk32)
return -1;
if (u2->isk32)
return 1;
if (!*u1->lookupt)
return 1;
if (!*u2->lookupt)
return -1;
if (u1->isk32 != u2->isk32)
return u1->isk32 ? -1 : 1;
if ((*u1->lookupt != 0) != (*u2->lookupt != 0))
return (*u1->lookupt != 0) ? -1 : 1;
int rc = strcasecmp(u1->name, u2->name);
if (rc)
return rc;
if (u1->ordinal)
return -1;
if (u2->ordinal)
return 1;
if (!u1->shname)
return 1;
if (!u2->shname)
return -1;
if ((u1->ordinal != 0) != (u2->ordinal != 0))
return (u1->ordinal != 0) ? -1 : 1;
if ((u1->shname != nullptr) != (u2->shname != nullptr))
return (u1->shname != nullptr) ? -1 : 1;
rc = (int) (upx_safe_strlen(u1->shname) - upx_safe_strlen(u2->shname));
if (rc)
return rc;
@@ -904,8 +910,8 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
importbyordinal = true;
soimport += 2; // ordinal num: 2 bytes
dlls[ic].ordinal = *tarr & 0xffff;
} else // it's an import by name
{
} else {
// it's an import by name
IPTR_VAR(const byte, const name, ibuf + *tarr + 2);
unsigned len = strlen(name);
soimport += len + 1;
@@ -919,9 +925,12 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
mb_oimport.clear();
oimport = mb_oimport;
qsort(idlls, dllnum, sizeof(udll *), udll::compare);
qsort(idlls, dllnum, sizeof(*idlls), udll::compare);
info("Processing imports: %d DLLs", dllnum);
for (ic = 0; ic < dllnum; ic++) {
info(" DLL %3d %s %s", ic, idlls[ic]->name, idlls[ic]->shname);
}
ilinker = new ImportLinker(sizeof(LEXX));
// create the new import table
@@ -981,7 +990,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
}
ppi++;
unsigned esize = ptr_diff_bytes(tarr, idlls[ic]->lookupt);
unsigned esize = ptr_udiff_bytes(tarr, idlls[ic]->lookupt);
lookups.add(idlls[ic]->lookupt, esize);
if (ptr_diff_bytes(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1),
(char *) idlls[ic]->lookupt) != 0) {
@@ -1299,7 +1308,7 @@ void PeFile::processTls1(Interval *iv, typename tls_traits<LEXX>::cb_value_t ima
unsigned const take1 = sizeof(tls);
unsigned const skip1 = IDADDR(PEDIR_TLS);
memcpy(otls, ibuf.subref("bad tls %#x", skip1, take1), take1);
// WARNING: this can acces data in BSS
// WARNING: this can access data in BSS
unsigned const take3 = sotls - sizeof(tls);
memcpy(otls + sizeof(tls), ibuf.subref("bad tls %#x", tlsdatastart, take3), take3);
tlsindex = tlsp->tlsindex - imagebase;
@@ -1887,6 +1896,7 @@ void PeFile::processResources(Resource *res) {
soresources = ptr_diff_bytes(ores, oresources);
delete[] keep_icons;
keep_icons = nullptr;
if (!res->clear()) {
// The area occupied by the resource directory is not continuous
// so to still support uncompression, I can't zero this area.
@@ -2637,6 +2647,16 @@ void PeFile::rebuildTls() {
// this is an easy one : just do nothing ;-)
}
namespace {
template <class T>
struct VPtr {
static_assert(sizeof(T) == 1);
SPAN_S(T) ptr;
size_t vaddr;
auto operator+(size_t n) const { return ptr + mem_size(sizeof(T), n - vaddr); }
};
} // namespace
void PeFile::rebuildResources(SPAN_S(byte) & extra_info, unsigned lastvaddr) {
if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0)
return;
@@ -2646,12 +2666,13 @@ void PeFile::rebuildResources(SPAN_S(byte) & extra_info, unsigned lastvaddr) {
const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
if (lastvaddr > vaddr || (vaddr - lastvaddr) > ibuf.getSize())
if (vaddr < lastvaddr || (vaddr - lastvaddr) > ibuf.getSize())
throwCantUnpack("corrupted PE header");
// TODO: introduce WildPtr for "virtual pointer" pointing before a buffer
const byte *r = ibuf.raw_bytes(0) - lastvaddr;
Resource res(r + vaddr, ibuf, ibuf + ibuf.getSize());
// INFO: use VPtr for "virtual pointer" pointing before a buffer
//// const byte *const r = ibuf.raw_bytes(0) - lastvaddr;
VPtr<const byte> const r{ibuf, lastvaddr};
Resource res(raw_bytes(r + vaddr, 0), ibuf, ibuf + ibuf.getSize());
while (res.next())
if (res.offs() > vaddr) {
ICHECK(r + (res.offs() - 4), 4);
@@ -2702,8 +2723,9 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
}
sdllnames = ALIGN_UP(sdllnames, 2u);
// TODO: introduce WildPtr for "virtual pointer" pointing before a buffer
byte *const Obuf = obuf.raw_bytes(0) - rvamin;
// INFO: use VPtr for "virtual pointer" pointing before a buffer
//// byte *const Obuf = obuf.raw_bytes(0) - rvamin;
VPtr<byte> const Obuf{obuf, rvamin};
#if 0
import_desc * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT));
import_desc *im = im0;
@@ -2711,9 +2733,10 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
byte *importednames = dllnames + sdllnames;
byte * const importednames_start = importednames;
#else
SPAN_S_VAR(import_desc, const im0, (import_desc *) (Obuf + ODADDR(PEDIR_IMPORT)), obuf);
SPAN_S_VAR(import_desc, const im0, (import_desc *) raw_bytes(Obuf + ODADDR(PEDIR_IMPORT), 0),
obuf);
SPAN_S_VAR(import_desc, im, im0);
SPAN_0_VAR(byte, dllnames, inamespos ? Obuf + inamespos : nullptr, obuf);
SPAN_0_VAR(byte, dllnames, inamespos ? raw_bytes(Obuf + inamespos, 0) : nullptr, obuf);
SPAN_0_VAR(byte, importednames, inamespos ? dllnames + sdllnames : nullptr);
SPAN_0_VAR(byte, const importednames_start, importednames);
#endif
@@ -2728,7 +2751,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
if (inamespos) {
// now I rebuild the dll names
omemcpy(dllnames, dname, dlen + 1);
im->dllname = ptr_udiff_bytes(dllnames, Obuf);
im->dllname = ptr_udiff_bytes(dllnames, obuf) + rvamin;
//;;;printf("\ndll: %s:",dllnames);
dllnames += dlen + 1;
} else {
@@ -2738,7 +2761,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
if (set_oft)
im->oft = iatoffs;
OPTR_VAR(LEXX, newiat, (LEXX *) (Obuf + iatoffs));
OPTR_VAR(LEXX, newiat, (LEXX *) raw_bytes(Obuf + iatoffs, 0));
// restore the imported names+ordinals
for (p += 8; *p; ++newiat)
@@ -2749,7 +2772,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
importednames -= 1;
omemcpy(importednames + 2, p, ilen);
//;;;printf(" %s",importednames+2);
*newiat = ptr_udiff_bytes(importednames, Obuf);
*newiat = ptr_udiff_bytes(importednames, obuf) + rvamin;
importednames += 2 + ilen;
} else {
// Beware overlap!
@@ -2986,7 +3009,7 @@ void PeFile32::readPeHeader() {
void PeFile32::pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase,
bool last_section_rsrc_only) {
super::pack0<LE32>(fo, ih, oh, subsystem_mask, default_imagebase, last_section_rsrc_only);
infoWarning("End of PeFile32::pack0");
// infoWarning("End of PeFile32::pack0");
}
void PeFile32::unpack(OutputFile *fo) {
+2 -2
View File
@@ -147,7 +147,7 @@ protected:
unsigned sotls;
unsigned tlsindex;
unsigned tlscb_ptr;
unsigned tls_handler_offset;
unsigned tls_handler_offset = 0;
bool use_tls_callbacks = false;
void processLoadConf(Reloc *, const Interval *, unsigned);
@@ -288,7 +288,7 @@ protected:
enum {
IMAGE_SUBSYSTEM_UNKNOWN = 0,
IMAGE_SUBSYSTEM_NATIVE = 1,
IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, // Grapical
IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, // Graphical
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, // Character-mode
IMAGE_SUBSYSTEM_WINDOWS_OS2_CUI = 5,
IMAGE_SUBSYSTEM_WINDOWS_POSIX_CUI = 7,
+1 -1
View File
@@ -182,7 +182,7 @@ UiPacker::UiPacker(const Packer *p_) : ui_pass(0), ui_total_passes(0), p(p_), s(
s->mode = M_CB_SCREEN;
}
UiPacker::~UiPacker() {
UiPacker::~UiPacker() noexcept {
cb.reset();
delete s;
s = nullptr;
+1 -1
View File
@@ -39,7 +39,7 @@ public:
UiPacker(const Packer *p_);
public:
virtual ~UiPacker();
virtual ~UiPacker() noexcept;
static void uiConfirmUpdate();
static void uiPackTotal();
+5 -5
View File
@@ -74,7 +74,7 @@ MemBuffer::MemBuffer(upx_uint64_t bytes) {
debug_set(debug.last_return_address_alloc, upx_return_address());
}
MemBuffer::~MemBuffer() { this->dealloc(); }
MemBuffer::~MemBuffer() noexcept { this->dealloc(); }
// similar to BoundedPtr, except checks only at creation
// skip == offset, take == size_in_bytes
@@ -215,19 +215,19 @@ void MemBuffer::alloc(upx_uint64_t bytes) {
set_ne32(p + size_in_bytes + 4, stats.global_alloc_counter);
}
ptr = (pointer) (void *) p;
#if !defined(__SANITIZE_ADDRESS__) && 0
fill(0, size_in_bytes, (rand() & 0xff) | 1); // debug
#if DEBUG
memset(ptr, 0xff, size_in_bytes);
(void) VALGRIND_MAKE_MEM_UNDEFINED(ptr, size_in_bytes);
#endif
stats.global_alloc_counter += 1;
stats.global_total_bytes += size_in_bytes;
stats.global_total_active_bytes += size_in_bytes;
#if DEBUG
#if DEBUG || 1
checkState();
#endif
}
void MemBuffer::dealloc() {
void MemBuffer::dealloc() noexcept {
if (ptr != nullptr) {
debug_set(debug.last_return_address_dealloc, upx_return_address());
checkState();
+7 -6
View File
@@ -46,11 +46,12 @@ protected:
size_type size_in_bytes;
public:
MemBufferBase() : ptr(nullptr), size_in_bytes(0) {}
MemBufferBase() noexcept : ptr(nullptr), size_in_bytes(0) {}
inline ~MemBufferBase() noexcept {}
// NOTE: implicit conversion to underlying pointer
// HINT: for fully bound-checked pointer use XSPAN_S from xspan.h
operator pointer() const { return ptr; }
operator pointer() const noexcept { return ptr; }
// membuffer + n -> pointer
template <class U>
@@ -66,8 +67,8 @@ private:
DELETED_FUNCTION;
public: // raw access
pointer raw_ptr() const { return ptr; }
size_type raw_size_in_bytes() const { return size_in_bytes; }
pointer raw_ptr() const noexcept { return ptr; }
size_type raw_size_in_bytes() const noexcept { return size_in_bytes; }
pointer raw_bytes(size_t bytes) const {
if (bytes > 0) {
@@ -84,7 +85,7 @@ class MemBuffer final : public MemBufferBase<byte> {
public:
MemBuffer() : MemBufferBase<byte>() {}
explicit MemBuffer(upx_uint64_t bytes);
~MemBuffer();
~MemBuffer() noexcept;
static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra = 0);
static unsigned getSizeForDecompression(unsigned uncompressed_size, unsigned extra = 0);
@@ -93,7 +94,7 @@ public:
void allocForCompression(unsigned uncompressed_size, unsigned extra = 0);
void allocForDecompression(unsigned uncompressed_size, unsigned extra = 0);
void dealloc();
void dealloc() noexcept;
void checkState() const;
unsigned getSize() const { return size_in_bytes; }
+9 -6
View File
@@ -35,9 +35,11 @@
// default: for any regular pointer, raw_bytes() is just the pointer itself
template <class T>
inline
typename std::enable_if<std::is_pointer<T>::value && !std_is_bounded_array<T>::value, T>::type
raw_bytes(T ptr, size_t size_in_bytes) {
inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_is_bounded_array<T>::value &&
(upx_is_integral<typename std::remove_pointer<T>::type>::value ||
std::is_void<typename std::remove_pointer<T>::type>::value),
T>::type
raw_bytes(T ptr, size_t size_in_bytes) {
if (size_in_bytes > 0) {
if very_unlikely (ptr == nullptr)
throwCantPack("raw_bytes unexpected NULL ptr");
@@ -50,9 +52,10 @@ inline
// default: for any regular pointer, raw_index_bytes() is just "pointer + index"
// NOTE: index == number of elements, *NOT* size in bytes!
template <class T>
inline
typename std::enable_if<std::is_pointer<T>::value && !std_is_bounded_array<T>::value, T>::type
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_is_bounded_array<T>::value &&
upx_is_integral<typename std::remove_pointer<T>::type>::value,
T>::type
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
typedef typename std::remove_pointer<T>::type element_type;
if very_unlikely (ptr == nullptr)
throwCantPack("raw_index_bytes unexpected NULL ptr");
+10 -10
View File
@@ -60,30 +60,30 @@ upx_rsize_t upx_safe_strlen(const char *);
#define vsnprintf upx_safe_vsnprintf
/*************************************************************************
// some unsigned char string support functions to avoid casts
// some uchar string support functions to avoid casts
**************************************************************************/
inline unsigned char *strcpy(unsigned char *s1, const unsigned char *s2) {
return (unsigned char *) strcpy((char *) s1, (const char *) s2);
forceinline uchar *strcpy(uchar *s1, const uchar *s2) {
return (uchar *) strcpy((char *) s1, (const char *) s2);
}
inline int strcmp(const unsigned char *s1, const char *s2) { return strcmp((const char *) s1, s2); }
inline int strcmp(const char *s1, const unsigned char *s2) { return strcmp(s1, (const char *) s2); }
inline int strcmp(const unsigned char *s1, const unsigned char *s2) {
forceinline int strcmp(const uchar *s1, const char *s2) { return strcmp((const char *) s1, s2); }
forceinline int strcmp(const char *s1, const uchar *s2) { return strcmp(s1, (const char *) s2); }
forceinline int strcmp(const uchar *s1, const uchar *s2) {
return strcmp((const char *) s1, (const char *) s2);
}
inline int strcasecmp(const unsigned char *s1, const char *s2) {
forceinline int strcasecmp(const uchar *s1, const char *s2) {
return strcasecmp((const char *) s1, s2);
}
inline int strcasecmp(const char *s1, const unsigned char *s2) {
forceinline int strcasecmp(const char *s1, const uchar *s2) {
return strcasecmp(s1, (const char *) s2);
}
inline int strcasecmp(const unsigned char *s1, const unsigned char *s2) {
forceinline int strcasecmp(const uchar *s1, const uchar *s2) {
return strcasecmp((const char *) s1, (const char *) s2);
}
inline upx_rsize_t upx_safe_strlen(const unsigned char *s) {
forceinline upx_rsize_t upx_safe_strlen(const uchar *s) {
return upx_safe_strlen((const char *) s);
}
+166 -6
View File
@@ -101,6 +101,10 @@ TEST_CASE("mem_size") {
CHECK_THROWS(mem_size(1, 0x30000000, 0x30000000, 0x30000000));
}
/*************************************************************************
// ptr util
**************************************************************************/
int ptr_diff_bytes(const void *a, const void *b) {
if very_unlikely (a == nullptr) {
throwCantPack("ptr_diff_bytes null 1; take care");
@@ -108,13 +112,13 @@ int ptr_diff_bytes(const void *a, const void *b) {
if very_unlikely (b == nullptr) {
throwCantPack("ptr_diff_bytes null 2; take care");
}
ptrdiff_t d = (const char *) a - (const char *) b;
ptrdiff_t d = (const charptr) a - (const charptr) b;
if (a >= b) {
if very_unlikely (!mem_size_valid_bytes(d))
throwCantPack("ptr_diff_bytes 1; take care");
throwCantPack("ptr_diff_bytes-1; take care");
} else {
if very_unlikely (!mem_size_valid_bytes(-d))
throwCantPack("ptr_diff_bytes 2; take care");
throwCantPack("ptr_diff_bytes-2; take care");
}
return ACC_ICONV(int, d);
}
@@ -127,7 +131,7 @@ unsigned ptr_udiff_bytes(const void *a, const void *b) {
}
TEST_CASE("ptr_diff") {
char buf[4] = {0, 1, 2, 3};
byte buf[4] = {0, 1, 2, 3};
CHECK_THROWS(ptr_diff_bytes(nullptr, buf));
CHECK_THROWS(ptr_diff_bytes(buf, nullptr));
CHECK(ptr_diff(buf, buf) == 0);
@@ -138,6 +142,108 @@ TEST_CASE("ptr_diff") {
CHECK_THROWS(ptr_udiff(buf, buf + 1));
}
// check that 2 buffers do not overlap; will throw on error
void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b, size_t b_size) {
if very_unlikely (a == 0 || b == 0)
throwCantPack("ptr_check_no_overlap-nullptr");
upx_uintptr_t a_end = a + mem_size(1, a_size);
upx_uintptr_t b_end = b + mem_size(1, b_size);
if very_unlikely (a_end < a || b_end < b) // wrap-around
throwCantPack("ptr_check_no_overlap-overflow");
// same as (!(a >= b_end || b >= a_end))
if (a < b_end && b < a_end)
throwCantPack("ptr_check_no_overlap-ab");
}
// check that 3 buffers do not overlap; will throw on error
void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b, size_t b_size,
upx_uintptr_t c, size_t c_size) {
if very_unlikely (a == 0 || b == 0 || c == 0)
throwCantPack("ptr_check_no_overlap-nullptr");
upx_uintptr_t a_end = a + mem_size(1, a_size);
upx_uintptr_t b_end = b + mem_size(1, b_size);
upx_uintptr_t c_end = c + mem_size(1, c_size);
if very_unlikely (a_end < a || b_end < b || c_end < c) // wrap-around
throwCantPack("ptr_check_no_overlap-overflow");
if (a < b_end && b < a_end)
throwCantPack("ptr_check_no_overlap-ab");
if (a < c_end && c < a_end)
throwCantPack("ptr_check_no_overlap-ac");
if (b < c_end && c < b_end)
throwCantPack("ptr_check_no_overlap-bc");
}
TEST_CASE("ptr_check_no_overlap 2") {
byte p[4] = {};
auto check_nothrow = [&p](int a, int as, int b, int bs) {
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + b, bs)); // ab
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + a, as)); // ba
};
auto check_throws_ = [&p](int a, int as, int b, int bs) {
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + b, bs)); // ab
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + a, as)); // ba
};
check_throws_(0, 1, 0, 1);
check_nothrow(0, 1, 1, 1);
check_throws_(0, 2, 1, 1);
check_nothrow(0, 2, 2, 1);
// empty buffers at edge
check_nothrow(0, 0, 0, 0);
check_nothrow(0, 0, 0, 1);
check_nothrow(0, 0, 1, 0);
// empty buffer
check_nothrow(0, 4, 0, 0);
check_throws_(0, 4, 1, 0);
check_throws_(0, 4, 2, 0);
check_throws_(0, 4, 3, 0);
check_nothrow(0, 4, 4, 0);
}
TEST_CASE("ptr_check_no_overlap 3") {
byte p[4] = {};
auto check_nothrow = [&p](int a, int as, int b, int bs, int c, int cs) {
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + b, bs, p + c, cs)); // abc
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + c, cs, p + b, bs)); // acb
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + a, as, p + c, cs)); // bac
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + c, cs, p + a, as)); // bca
CHECK_NOTHROW(ptr_check_no_overlap(p + c, cs, p + a, as, p + b, bs)); // cab
CHECK_NOTHROW(ptr_check_no_overlap(p + c, cs, p + b, bs, p + a, as)); // cba
};
auto check_throws_ = [&p](int a, int as, int b, int bs, int c, int cs) {
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + b, bs, p + c, cs)); // abc
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + c, cs, p + b, bs)); // acb
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + a, as, p + c, cs)); // bac
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + c, cs, p + a, as)); // bca
CHECK_THROWS(ptr_check_no_overlap(p + c, cs, p + a, as, p + b, bs)); // cab
CHECK_THROWS(ptr_check_no_overlap(p + c, cs, p + b, bs, p + a, as)); // cba
};
check_throws_(0, 1, 0, 1, 1, 1);
check_nothrow(0, 1, 1, 1, 2, 1);
check_throws_(0, 2, 1, 1, 2, 1);
check_nothrow(0, 2, 2, 1, 3, 1);
// empty buffers at edge
check_nothrow(0, 0, 0, 0, 0, 0);
check_nothrow(0, 0, 0, 0, 0, 1);
check_nothrow(0, 0, 0, 1, 1, 1);
check_nothrow(0, 0, 1, 0, 1, 1);
// empty buffer
check_nothrow(0, 4, 0, 0, 0, 0);
check_throws_(0, 4, 1, 0, 0, 0);
check_throws_(0, 4, 2, 0, 0, 0);
check_throws_(0, 4, 3, 0, 0, 0);
check_nothrow(0, 4, 4, 0, 0, 0);
// empty buffer
check_throws_(0, 4, 0, 0, 1, 0);
check_throws_(0, 4, 1, 0, 1, 0);
check_throws_(0, 4, 2, 0, 1, 0);
check_throws_(0, 4, 3, 0, 1, 0);
check_throws_(0, 4, 4, 0, 1, 0);
}
/*************************************************************************
// bele.h
**************************************************************************/
@@ -152,6 +258,60 @@ const BEPolicy be_policy;
const LEPolicy le_policy;
} // namespace N_BELE_RTP
/*************************************************************************
// stdlib
**************************************************************************/
void *upx_calloc(size_t n, size_t element_size) {
size_t bytes = mem_size(element_size, n); // assert size
void *p = malloc(bytes);
if (p != nullptr)
memset(p, 0, bytes);
return p;
}
// extremely simple stable sort: Gnomesort
// WARNING: O(n**2) !!!!!
void upx_stable_sort(void *base, size_t n, size_t element_size,
int(__acc_cdecl_qsort *compare)(const void *, const void *)) {
(void) mem_size(element_size, n); // assert size
for (size_t i = 1; i < n;) {
char *a = (char *) base + element_size * i; // a = &array[i]
if (i == 0 || (compare(a - element_size, a) <= 0)) {
i += 1;
} else {
i -= 1;
// swap elements a[-1] <=> a[0]
// upx_memswap(a - element_size, a, element_size);
size_t j = element_size;
do {
char tmp = *(a - element_size);
*(a - element_size) = *a;
*a++ = tmp;
} while (--j != 0);
}
}
}
TEST_CASE("upx_stable_sort") {
// TODO C++20: use std::next_permutation() to test all permutations
{
unsigned a[] = {0, 1};
upx_stable_sort(a, 2, sizeof(*a), ne32_compare);
CHECK((a[0] == 0 && a[1] == 1));
}
{
unsigned a[] = {1, 0};
upx_stable_sort(a, 2, sizeof(*a), ne32_compare);
CHECK((a[0] == 0 && a[1] == 1));
}
{
unsigned a[] = {2, 1, 0};
upx_stable_sort(a, 3, sizeof(*a), ne32_compare);
CHECK((a[0] == 0 && a[1] == 1 && a[2] == 2));
}
}
/*************************************************************************
// qsort() util
**************************************************************************/
@@ -258,7 +418,7 @@ int __acc_cdecl_qsort le64_compare_signed(const void *e1, const void *e2) {
int find(const void *buf, int blen, const void *what, int wlen) {
// nullptr is explicitly allowed here
if (buf == nullptr || blen <= 0 || what == nullptr || wlen <= 0)
if (buf == nullptr || blen < wlen || what == nullptr || wlen <= 0)
return -1;
const byte *b = (const byte *) buf;
@@ -367,7 +527,7 @@ static const char dir_sep[] = "/\\";
#define fn_is_drive(s) (s[0] && s[1] == ':')
#define fn_is_sep(c) (strchr(dir_sep, c) != nullptr)
#define fn_skip_drive(s) (fn_is_drive(s) ? (s) + 2 : (s))
#define fn_tolower(c) (tolower(((unsigned char) (c))))
#define fn_tolower(c) (tolower(((uchar) (c))))
#else
+45 -3
View File
@@ -40,9 +40,6 @@ inline bool mem_size_valid_bytes(upx_uint64_t bytes) noexcept { return bytes <=
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0,
upx_uint64_t extra2 = 0) noexcept;
// "new" with asserted size; will throw on invalid size
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
// will throw on invalid size
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
upx_uint64_t extra2 = 0);
@@ -77,6 +74,27 @@ inline void mem_clear(void *p, size_t n) {
memset(p, 0, n);
}
// "new" with asserted size; will throw on invalid size
#if DEBUG
template <class T>
T *NewArray(upx_uint64_t n) {
size_t bytes = mem_size(sizeof(T), n); // assert size
T *array = new T[size_t(n)];
if (array) {
memset(array, 0xff, bytes);
(void) VALGRIND_MAKE_MEM_UNDEFINED(array, bytes);
}
return array;
}
#define New(type, n) (NewArray<type>(n))
#else
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
#endif
/*************************************************************************
// ptr util
**************************************************************************/
// ptrdiff_t with nullptr checks and asserted size; will throw on failure
// NOTE: returns size_in_bytes, not number of elements!
int ptr_diff_bytes(const void *a, const void *b);
@@ -94,6 +112,30 @@ ptr_udiff(const T *a, const U *b) {
return ptr_udiff_bytes(a, b);
}
// check that buffers do not overlap; will throw on error
noinline void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b,
size_t b_size);
noinline void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b,
size_t b_size, upx_uintptr_t c, size_t c_size);
forceinline void ptr_check_no_overlap(const void *a, size_t a_size, const void *b, size_t b_size) {
uintptr_check_no_overlap((upx_uintptr_t) a, a_size, (upx_uintptr_t) b, b_size);
}
forceinline void ptr_check_no_overlap(const void *a, size_t a_size, const void *b, size_t b_size,
const void *c, size_t c_size) {
uintptr_check_no_overlap((upx_uintptr_t) a, a_size, (upx_uintptr_t) b, b_size,
(upx_uintptr_t) c, c_size);
}
/*************************************************************************
// stdlib
**************************************************************************/
void *upx_calloc(size_t n, size_t element_size);
void upx_stable_sort(void *base, size_t n, size_t element_size,
int(__acc_cdecl_qsort *compare)(const void *, const void *));
/*************************************************************************
// misc. support functions
**************************************************************************/
+7 -7
View File
@@ -44,28 +44,28 @@ struct XSpanStats {
static XSpanStats xspan_stats;
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
noinline void xspan_fail_nullptr() {
void xspan_fail_nullptr() {
xspan_stats.fail_nullptr += 1;
throwCantPack("xspan unexpected NULL pointer; take care!");
}
noinline void xspan_fail_nullbase() {
void xspan_fail_nullbase() {
xspan_stats.fail_nullbase += 1;
throwCantPack("xspan unexpected NULL base; take care!");
}
noinline void xspan_fail_not_same_base() {
void xspan_fail_not_same_base() {
xspan_stats.fail_not_same_base += 1;
throwCantPack("xspan unexpected base pointer; take care!");
}
noinline void xspan_fail_range_nullptr() {
void xspan_fail_range_nullptr() {
xspan_stats.fail_range_nullptr += 1;
throwCantPack("xspan_check_range: unexpected NULL pointer; take care!");
}
noinline void xspan_fail_range_nullbase() {
void xspan_fail_range_nullbase() {
xspan_stats.fail_range_nullbase += 1;
throwCantPack("xspan_check_range: unexpected NULL base; take care!");
}
noinline void xspan_fail_range_range() {
void xspan_fail_range_range() {
xspan_stats.fail_range_range += 1;
throwCantPack("xspan_check_range: pointer out of range; take care!");
}
@@ -75,7 +75,7 @@ void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes)
xspan_fail_range_nullptr();
if very_unlikely (base == nullptr)
xspan_fail_range_nullbase();
ptrdiff_t off = (const char *) p - (const char *) base;
ptrdiff_t off = (const charptr) p - (const charptr) base;
if very_unlikely (off < 0 || off > size_in_bytes)
xspan_fail_range_range();
xspan_stats.check_range_counter += 1;
+4 -1
View File
@@ -146,8 +146,11 @@ inline R *xspan_make_helper__(R * /*dummy*/, MemBuffer &first) {
#endif // WITH_XSPAN
#if 1
/*************************************************************************
// nicer names
**************************************************************************/
#if 1
#define SPAN_0 XSPAN_0
#define SPAN_P XSPAN_P
#define SPAN_S XSPAN_S
+2 -2
View File
@@ -52,11 +52,11 @@ void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes)
// help constructor to distinguish between number of elements and bytes
struct XSpanCount {
explicit XSpanCount(size_t n) : count(n) {}
explicit XSpanCount(size_t n) noexcept : count(n) {}
size_t count; // public
};
struct XSpanSizeInBytes {
explicit XSpanSizeInBytes(size_t bytes) : size_in_bytes(bytes) {}
explicit XSpanSizeInBytes(size_t bytes) noexcept : size_in_bytes(bytes) {}
size_t size_in_bytes; // public
};
+365 -334
View File
@@ -28,165 +28,176 @@
//
**************************************************************************/
public:
typedef T element_type;
typedef typename std::add_lvalue_reference<T>::type reference;
typedef typename std::add_pointer<T>::type pointer;
typedef size_t size_type;
#if CLANG_FORMAT_DUMMY_CLASS
class CSelf {
#endif
// befriend all
template <class>
friend struct PtrOrSpan;
template <class>
friend struct PtrOrSpanOrNull;
template <class>
friend struct Span;
public:
typedef T element_type;
typedef typename std::add_lvalue_reference<T>::type reference;
typedef typename std::add_pointer<T>::type pointer;
typedef size_t size_type;
// befriend all
template <class>
friend struct PtrOrSpan;
template <class>
friend struct PtrOrSpanOrNull;
template <class>
friend struct Span;
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION
operator pointer() const { return ptr; }
public:
operator pointer() const noexcept { return ptr; }
#endif
private:
pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr
pointer base;
size_type size_in_bytes;
pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr
pointer base;
size_type size_in_bytes;
// debug - internal sanity check; also serves as pseudo-documentation
#if DEBUG
noinline void assertInvariants() const {
if __acc_cte (configRequirePtr)
assert(ptr != nullptr);
if __acc_cte (configRequireBase)
assert(base != nullptr);
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
}
noinline void assertInvariants() const {
if __acc_cte (configRequirePtr)
assert(ptr != nullptr);
if __acc_cte (configRequireBase)
assert(base != nullptr);
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
}
#else
forceinline void assertInvariants() const {}
inline void assertInvariants() const noexcept {}
#endif
static forceinline pointer makeNotNull(pointer p) {
if very_unlikely (p == nullptr)
xspan_fail_nullptr();
return p;
}
// enforce config invariants at constructor time - static functions
static forceinline pointer makePtr(pointer p) {
if __acc_cte (configRequirePtr && p == nullptr)
xspan_fail_nullptr();
return p;
}
static forceinline pointer makeBase(pointer b) {
if __acc_cte (configRequireBase && b == nullptr)
xspan_fail_nullbase();
return b;
}
// inverse logic for ensuring valid pointers from existing objets
forceinline pointer ensurePtr() const {
if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr();
return ptr;
}
forceinline pointer ensureBase() const {
if __acc_cte (!configRequireBase && base == nullptr)
xspan_fail_nullbase();
return base;
}
static inline pointer makeNotNull(pointer p) {
if very_unlikely (p == nullptr)
xspan_fail_nullptr();
return p;
}
// enforce config invariants at constructor time - static functions
static inline pointer makePtr(pointer p) {
if __acc_cte (configRequirePtr && p == nullptr)
xspan_fail_nullptr();
return p;
}
static inline pointer makeBase(pointer b) {
if __acc_cte (configRequireBase && b == nullptr)
xspan_fail_nullbase();
return b;
}
// inverse logic for ensuring valid pointers from existing objects
inline pointer ensurePtr() const {
if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr();
return ptr;
}
inline pointer ensureBase() const {
if __acc_cte (!configRequireBase && base == nullptr)
xspan_fail_nullbase();
return base;
}
public:
inline ~CSelf() {
#if DEBUG
invalidate();
inline ~CSelf() { invalidate(); }
#else
inline ~CSelf() noexcept {}
#endif
}
noinline void invalidate() {
assertInvariants();
ptr = (pointer) (acc_uintptr_t) 16; // point to non-null invalid address
// ptr = (pointer) (void *) &ptr; // point to self
base = ptr;
size_in_bytes = 0;
assertInvariants();
}
// constructors from pointers
CSelf(pointer first, XSpanCount count)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count.count)) {
assertInvariants();
}
CSelf(pointer first, XSpanSizeInBytes bytes)
: ptr(makePtr(first)), base(makeBase(first)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(U *first, size_type count, XSPAN_REQUIRES_SIZE_1_A)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count)) {
assertInvariants();
}
CSelf(pointer first, XSpanCount count, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count.count)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
CSelf(pointer first, XSpanSizeInBytes bytes, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(pointer first, size_type count, U *base_, XSPAN_REQUIRES_SIZE_1_A)
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
noinline void invalidate() {
assertInvariants();
ptr = (pointer) (upx_uintptr_t) 16; // point to non-null invalid address
// ptr = (pointer) (void *) &ptr; // point to self
base = ptr;
size_in_bytes = 0;
assertInvariants();
}
// constructors from pointers
CSelf(pointer first, XSpanCount count)
: ptr(makePtr(first)), base(makeBase(first)),
size_in_bytes(xspan_mem_size<T>(count.count)) {
assertInvariants();
}
CSelf(pointer first, XSpanSizeInBytes bytes)
: ptr(makePtr(first)), base(makeBase(first)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(U *first, size_type count, XSPAN_REQUIRES_SIZE_1_A)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count)) {
assertInvariants();
}
CSelf(pointer first, XSpanCount count, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)),
size_in_bytes(xspan_mem_size<T>(count.count)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
CSelf(pointer first, XSpanSizeInBytes bytes, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(pointer first, size_type count, U *base_, XSPAN_REQUIRES_SIZE_1_A)
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
#ifdef UPX_VERSION_HEX
// constructors from MemBuffer
CSelf(MemBuffer &mb)
: CSelf(makeNotNull((pointer) membuffer_get_void_ptr(mb)),
XSpanSizeInBytes(membuffer_get_size(mb))) {}
CSelf(pointer first, MemBuffer &mb)
: CSelf(first, XSpanSizeInBytes(membuffer_get_size(mb)),
makeNotNull((pointer) membuffer_get_void_ptr(mb))) {}
CSelf(std::nullptr_t, MemBuffer &) XSPAN_DELETED_FUNCTION;
// constructors from MemBuffer
CSelf(MemBuffer &mb)
: CSelf(makeNotNull((pointer) membuffer_get_void_ptr(mb)),
XSpanSizeInBytes(membuffer_get_size(mb))) {}
CSelf(pointer first, MemBuffer &mb)
: CSelf(first, XSpanSizeInBytes(membuffer_get_size(mb)),
makeNotNull((pointer) membuffer_get_void_ptr(mb))) {}
CSelf(std::nullptr_t, MemBuffer &) XSPAN_DELETED_FUNCTION;
#endif
// disable constructors from nullptr to catch compile-time misuse
// disable constructors from nullptr to catch compile-time misuse
private:
CSelf(std::nullptr_t, XSpanCount) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanSizeInBytes) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, size_type) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanCount) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanSizeInBytes) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, size_type) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
// unchecked constructor
// unchecked constructor
protected:
enum ModeUnchecked { Unchecked };
CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b)
: ptr(p), base(b), size_in_bytes(bytes) {
assertInvariants();
}
// unchecked assignment
Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) {
ptr = p;
base = b;
size_in_bytes = bytes;
assertInvariants();
return *this;
}
enum ModeUnchecked { Unchecked };
CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b)
: ptr(p), base(b), size_in_bytes(bytes) {
assertInvariants();
}
// unchecked assignment
Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) {
ptr = p;
base = b;
size_in_bytes = bytes;
assertInvariants();
return *this;
}
#if 0
Self &assign(ModeUnchecked, const Self &other) {
ptr = other.ptr;
@@ -198,230 +209,250 @@ Self &assign(ModeUnchecked, const Self &other) {
#endif
public:
// assignment - here we can rely on invariants enforced at construction time by makePtr/makeBase
// NOTE: *this remains unmodified in case of failure
Self &assign(pointer other) {
assertInvariants();
other = makePtr(other);
if __acc_cte ((configRequirePtr || other != nullptr) && (configRequireBase || base != nullptr))
xspan_check_range(other, base, size_in_bytes);
// ok
ptr = other;
assertInvariants();
return *this;
}
Self &assign(const Self &other) {
assertInvariants();
other.assertInvariants();
if __acc_cte (!configRequireBase && base == nullptr) {
// magic 1: if base is unset, automatically set base/size_in_bytes from other
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
(configRequireBase || other.base != nullptr))
xspan_check_range(other.ptr, other.base, other.size_in_bytes);
// ok
ptr = other.ptr;
base = other.base;
size_in_bytes = other.size_in_bytes;
} else {
// magic 2: assert same base (but ignore size_in_bytes !)
if __acc_cte (configRequireBase || other.base != nullptr)
if very_unlikely (base != other.base)
xspan_fail_not_same_base();
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
// assignment - here we can rely on invariants enforced at construction time by makePtr/makeBase
// NOTE: *this remains unmodified in case of failure
Self &assign(pointer other) {
assertInvariants();
other = makePtr(other);
if __acc_cte ((configRequirePtr || other != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(other.ptr, base, size_in_bytes);
xspan_check_range(other, base, size_in_bytes);
// ok
ptr = other.ptr;
ptr = other;
assertInvariants();
return *this;
}
Self &assign(const Self &other) {
assertInvariants();
other.assertInvariants();
if __acc_cte (!configRequireBase && base == nullptr) {
// magic 1: if base is unset, automatically set base/size_in_bytes from other
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
(configRequireBase || other.base != nullptr))
xspan_check_range(other.ptr, other.base, other.size_in_bytes);
// ok
ptr = other.ptr;
base = other.base;
size_in_bytes = other.size_in_bytes;
} else {
// magic 2: assert same base (but ignore size_in_bytes !)
if __acc_cte (configRequireBase || other.base != nullptr)
if very_unlikely (base != other.base)
xspan_fail_not_same_base();
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(other.ptr, base, size_in_bytes);
// ok
ptr = other.ptr;
}
assertInvariants();
return *this;
}
assertInvariants();
return *this;
}
Self &operator=(pointer other) { return assign(other); }
Self &operator=(pointer other) { return assign(other); }
Self &operator=(const Self &other) { return assign(other); }
Self &operator=(const Self &other) { return assign(other); }
// FIXME: this is not called??
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const CSelf<U> &other) {
// assert(0);
return assign(Self(other));
}
// FIXME: this is not called??
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const CSelf<U> &other) {
// assert(0);
return assign(Self(other));
}
#ifdef UPX_VERSION_HEX
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
#endif
Self subspan(ptrdiff_t offset, ptrdiff_t count) {
pointer begin = check_add(ptr, offset);
pointer end = check_add(begin, count);
if (begin <= end)
return Self(Unchecked, begin, (end - begin) * sizeof(T), begin);
else
return Self(Unchecked, end, (begin - end) * sizeof(T), end);
}
Self subspan(ptrdiff_t offset, ptrdiff_t count) {
pointer begin = check_add(ptr, offset);
pointer end = check_add(begin, count);
if (begin <= end)
return Self(Unchecked, begin, (end - begin) * sizeof(T), begin);
else
return Self(Unchecked, end, (begin - end) * sizeof(T), end);
}
bool operator==(pointer other) const { return ptr == other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(U *other) const {
return ptr == other;
}
bool operator!=(pointer other) const { return ptr != other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(U *other) const {
return ptr != other;
}
bool operator==(pointer other) const { return ptr == other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(U *other) const {
return ptr == other;
}
bool operator!=(pointer other) const { return ptr != other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(U *other) const {
return ptr != other;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpan<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpanOrNull<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const Span<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpan<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpanOrNull<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const Span<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpan<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpanOrNull<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const Span<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpan<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpanOrNull<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const Span<U> &other) const {
return !(*this == other);
}
// check for notNull here
bool operator<(std::nullptr_t) const XSPAN_DELETED_FUNCTION;
bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); }
// check for notNull here
bool operator<(std::nullptr_t) const XSPAN_DELETED_FUNCTION;
bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpan<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpanOrNull<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const Span<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpan<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpanOrNull<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const Span<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
// dereference
reference operator*() const { return *check_deref(ptr); }
// dereference
reference operator*() const { return *check_deref(ptr); }
// array access
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
// array access
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
// arrow operator
pointer operator->() const { return check_deref(ptr); }
// arrow operator
pointer operator->() const { return check_deref(ptr); }
Self &operator++() {
ptr = check_add(ptr, 1);
return *this;
}
Self operator++(int) {
Self tmp = *this;
++*this;
return tmp;
}
Self &operator--() {
ptr = check_add(ptr, -1);
return *this;
}
Self operator--(int) {
Self tmp = *this;
--*this;
return tmp;
}
Self &operator++() {
ptr = check_add(ptr, 1);
return *this;
}
Self operator++(int) {
Self tmp = *this;
++*this;
return tmp;
}
Self &operator--() {
ptr = check_add(ptr, -1);
return *this;
}
Self operator--(int) {
Self tmp = *this;
--*this;
return tmp;
}
Self &operator+=(ptrdiff_t n) {
ptr = check_add(ptr, n);
return *this;
}
Self &operator-=(ptrdiff_t n) {
ptr = check_add(ptr, -n);
return *this;
}
Self &operator+=(ptrdiff_t n) {
ptr = check_add(ptr, n);
return *this;
}
Self &operator-=(ptrdiff_t n) {
ptr = check_add(ptr, -n);
return *this;
}
Self operator+(ptrdiff_t n) const {
pointer first = check_add(ptr, n);
return Self(Unchecked, first, size_in_bytes, base);
}
Self operator-(ptrdiff_t n) const {
pointer first = check_add(ptr, -n);
return Self(Unchecked, first, size_in_bytes, base);
}
Self operator+(ptrdiff_t n) const {
pointer first = check_add(ptr, n);
return Self(Unchecked, first, size_in_bytes, base);
}
Self operator-(ptrdiff_t n) const {
pointer first = check_add(ptr, -n);
return Self(Unchecked, first, size_in_bytes, base);
}
private:
pointer check_deref(pointer p) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants();
return p;
}
pointer check_deref(pointer p, ptrdiff_t n) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n);
p += n;
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants();
return p;
}
pointer check_add(pointer p, ptrdiff_t n) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n);
p += n;
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes);
assertInvariants();
return p;
}
pointer check_deref(pointer p) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants();
return p;
}
pointer check_deref(pointer p, ptrdiff_t n) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n);
p += n;
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants();
return p;
}
pointer check_add(pointer p, ptrdiff_t n) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n);
p += n;
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes);
assertInvariants();
return p;
}
// disable taking the address => force passing by reference
// [I'm not too sure about this design decision, but we can always allow it if needed]
Self *operator&() const XSPAN_DELETED_FUNCTION;
// disable taking the address => force passing by reference
// [I'm not too sure about this design decision, but we can always allow it if needed]
Self *operator&() const XSPAN_DELETED_FUNCTION;
public: // raw access
pointer raw_ptr() const { return ptr; }
pointer raw_base() const { return base; }
size_type raw_size_in_bytes() const { return size_in_bytes; }
pointer raw_ptr() const noexcept { return ptr; }
pointer raw_base() const noexcept { return base; }
size_type raw_size_in_bytes() const noexcept { return size_in_bytes; }
pointer raw_bytes(size_t bytes) const {
assertInvariants();
if (bytes > 0) {
if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr) {
xspan_check_range(ptr, base, size_in_bytes - bytes);
pointer raw_bytes(size_t bytes) const {
assertInvariants();
if (bytes > 0) {
if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr) {
xspan_check_range(ptr, base, size_in_bytes - bytes);
}
}
return ptr;
}
return ptr;
}
// like C++ std::span
pointer data() const noexcept { return ptr; }
pointer data(size_t bytes) const { return raw_bytes(bytes); } // UPX extra
// size_type size() const { return size_bytes() / sizeof(element_type); } // NOT USED
size_type size_bytes() const {
assertInvariants();
if __acc_cte (!configRequirePtr && ptr == nullptr)
return 0;
if __acc_cte (!configRequireBase && base == nullptr)
return 0;
const charptr begin = (const charptr) ptr;
const charptr end = (const charptr) base + size_in_bytes;
return end - begin;
}
#if CLANG_FORMAT_DUMMY_CLASS
}; // class
#endif
/* vim:set ts=4 sw=4 et: */
+11 -11
View File
@@ -51,25 +51,25 @@ private:
pointer ptr;
// enforce config invariants at constructor time - static functions
static forceinline pointer makePtr(pointer p) { return p; }
// inverse logic for ensuring valid pointers from existing objets
forceinline pointer ensurePtr() const { return ptr; }
static inline pointer makePtr(pointer p) { return p; }
// inverse logic for ensuring valid pointers from existing objects
inline pointer ensurePtr() const { return ptr; }
// debug
forceinline void assertInvariants() const {}
inline void assertInvariants() const noexcept {}
public:
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
operator pointer() const { return ptr; }
operator pointer() const noexcept { return ptr; }
#endif
inline ~CSelf() {
#if DEBUG
invalidate();
inline ~CSelf() { invalidate(); }
#else
inline ~CSelf() noexcept {}
#endif
}
noinline void invalidate() {
assertInvariants();
ptr = (pointer) (acc_uintptr_t) 16; // point to non-null invalid address
ptr = (pointer) (upx_uintptr_t) 16; // point to non-null invalid address
// ptr = (pointer) (void *) &ptr; // point to self
assertInvariants();
}
@@ -116,7 +116,7 @@ public:
return assign(Self(other));
}
// comparision
// comparison
bool operator==(pointer other) const { return ptr == other; }
template <class U>
@@ -187,7 +187,7 @@ private:
forceinline pointer check_add(pointer p, ptrdiff_t n) const { return p + n; }
public: // raw access
pointer raw_ptr() const { return ptr; }
pointer raw_ptr() const noexcept { return ptr; }
pointer raw_bytes(size_t bytes) const {
assertInvariants();
+3 -3
View File
@@ -26,7 +26,7 @@
*/
// This file implements the central loop, and it uses class PackMaster to
// dispatch. PackMaster by itself will instatiate a concrete subclass
// dispatch. PackMaster by itself will instantiate a concrete subclass
// of class Packer which then does the actual work.
// And see p_com.cpp for a simple executable format.
@@ -141,7 +141,7 @@ void do_one_file(const char *iname, char *oname) {
else
flags |= O_EXCL;
int shmode = SH_DENYWR;
#if defined(__MINT__)
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
flags |= O_TRUNC;
shmode = O_DENYRW;
#endif
@@ -266,7 +266,7 @@ static void unlink_ofile(char *oname) {
int do_files(int i, int argc, char *argv[]) {
upx_compiler_sanity_check();
if (opt->verbose >= 1) {
show_head();
show_header();
UiPacker::uiHeader();
}