From b8b94ee89ed1e0e23cfe2f3dafdc3780b91913b4 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Thu, 15 Sep 2022 01:14:38 +0200 Subject: [PATCH] src: more cleanups; NFCI --- doc/{loader.txt => linker.txt} | 0 src/conf.h | 64 +++++++++++++--------------- src/except.h | 2 +- src/options.cpp | 41 ++++++++++++------ src/ui.cpp | 4 +- src/util/dt_check.cpp | 4 -- src/util/membuffer.cpp | 70 +++++++++++++++++++++---------- src/util/membuffer.h | 20 +++++---- src/util/snprintf.cpp | 6 ++- src/util/util.cpp | 25 ++++++----- src/util/util.h | 26 ++++++------ src/util/xspan.cpp | 2 +- src/util/xspan_impl_common.h | 35 ++++++++-------- src/util/xspan_impl_ptr.h | 20 +++++---- src/util/xspan_impl_ptr_or_null.h | 19 ++++++--- src/util/xspan_impl_ptr_or_span.h | 21 +++++++--- src/util/xspan_impl_span.h | 17 ++++++-- 17 files changed, 226 insertions(+), 150 deletions(-) rename doc/{loader.txt => linker.txt} (100%) diff --git a/doc/loader.txt b/doc/linker.txt similarity index 100% rename from doc/loader.txt rename to doc/linker.txt diff --git a/src/conf.h b/src/conf.h index 13834224..a3a1952e 100644 --- a/src/conf.h +++ b/src/conf.h @@ -63,7 +63,7 @@ #include "miniacc.h" #if !(ACC_CC_CLANG || ACC_CC_GNUC || ACC_CC_MSC) // other compilers may work, but we're NOT interested into supporting them -# error "only clang and gcc are officially supported" +# error "only clang, gcc and msvc are officially supported" #endif // UPX sanity checks for a sane compiler #if !defined(UINT_MAX) || (UINT_MAX != 0xffffffffL) @@ -317,28 +317,24 @@ inline void NO_fprintf(FILE *, const char *, ...) {} # define upx_memcpy_inline memcpy #endif - -#define __packed_struct(s) struct alignas(1) s { -#define __packed_struct_end() }; - #define UNUSED(var) ACC_UNUSED(var) #define COMPILE_TIME_ASSERT(e) ACC_COMPILE_TIME_ASSERT(e) -#define __COMPILE_TIME_ASSERT_ALIGNOF_SIZEOF(a,b) { \ +// TODO cleanup: we now require C++14, so remove all __packed_struct usage +#define __packed_struct(s) struct alignas(1) s { +#define __packed_struct_end() }; + +#define COMPILE_TIME_ASSERT_ALIGNOF_USING_SIZEOF__(a,b) { \ typedef a acc_tmp_a_t; typedef b acc_tmp_b_t; \ - __packed_struct(acc_tmp_t) acc_tmp_b_t x; acc_tmp_a_t y; acc_tmp_b_t z; __packed_struct_end() \ + struct alignas(1) acc_tmp_t { acc_tmp_b_t x; acc_tmp_a_t y; acc_tmp_b_t z; }; \ COMPILE_TIME_ASSERT(sizeof(struct acc_tmp_t) == 2*sizeof(b)+sizeof(a)) \ COMPILE_TIME_ASSERT(sizeof(((acc_tmp_t*)nullptr)->x)+sizeof(((acc_tmp_t*)nullptr)->y)+sizeof(((acc_tmp_t*)nullptr)->z) == 2*sizeof(b)+sizeof(a)) \ } -#if defined(__acc_alignof) -# define __COMPILE_TIME_ASSERT_ALIGNOF(a,b) \ - __COMPILE_TIME_ASSERT_ALIGNOF_SIZEOF(a,b) \ - COMPILE_TIME_ASSERT(__acc_alignof(a) == sizeof(b)) -#else -# define __COMPILE_TIME_ASSERT_ALIGNOF(a,b) \ - __COMPILE_TIME_ASSERT_ALIGNOF_SIZEOF(a,b) -#endif -#define COMPILE_TIME_ASSERT_ALIGNED1(a) __COMPILE_TIME_ASSERT_ALIGNOF(a,char) +#define COMPILE_TIME_ASSERT_ALIGNOF__(a,b) \ + COMPILE_TIME_ASSERT_ALIGNOF_USING_SIZEOF__(a,b) \ + COMPILE_TIME_ASSERT(__acc_alignof(a) == sizeof(b)) \ + COMPILE_TIME_ASSERT(alignof(a) == sizeof(b)) +#define COMPILE_TIME_ASSERT_ALIGNED1(a) COMPILE_TIME_ASSERT_ALIGNOF__(a,char) #define TABLESIZE(table) ((sizeof(table)/sizeof((table)[0]))) @@ -397,23 +393,6 @@ constexpr bool string_ge(const char *a, const char *b) { } } -/************************************************************************* -// raw_bytes() - get underlying memory from checked buffers/pointers. -// This is overloaded by various utility classes like BoundedPtr, -// MemBuffer and Span. -// -// Note that the pointer type is retained, the "_bytes" hints size_in_bytes -**************************************************************************/ - -// default: for any regular pointer, raw_bytes() is just the pointer itself -template -inline T *raw_bytes(T *ptr, size_t size_in_bytes) { - if (size_in_bytes > 0) { - assert(ptr != nullptr); - } - return ptr; -} - /************************************************************************* // constants **************************************************************************/ @@ -815,6 +794,24 @@ int upx_test_overlap ( const upx_bytep buf, int method, const upx_compress_result_t *cresult ); +/************************************************************************* +// raw_bytes() - get underlying memory from checked buffers/pointers. +// This is overloaded by various utility classes like BoundedPtr, +// MemBuffer and Span. +// +// Note that the pointer type is retained, the "_bytes" hints size_in_bytes +**************************************************************************/ + +// default: for any regular pointer, raw_bytes() is just the pointer itself +template +inline T *raw_bytes(T *ptr, size_t size_in_bytes) { + if (size_in_bytes > 0) { + if __acc_very_unlikely (ptr == nullptr) + throwInternalError("raw_bytes unexpected NULL ptr"); + } + return ptr; +} + #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) @@ -822,7 +819,6 @@ int upx_test_overlap ( const upx_bytep buf, # endif #endif - #endif /* already included */ /* vim:set ts=4 sw=4 et: */ diff --git a/src/except.h b/src/except.h index c20f8671..adab6952 100644 --- a/src/except.h +++ b/src/except.h @@ -193,7 +193,7 @@ public: #undef NORET #if 1 && defined(__GNUC__) -#define NORET __attribute__((__noreturn__)) __acc_noinline +#define NORET __acc_noinline __attribute__((__noreturn__)) #else #define NORET __acc_noinline #endif diff --git a/src/options.cpp b/src/options.cpp index f4bf8be7..d8553699 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -75,7 +75,7 @@ options_t *opt = &global_options; **************************************************************************/ template -static void test_options(const char *(&a)[N]) { +static inline void test_options(const char *(&a)[N]) { (void) main_get_options((int) (N - 1), ACC_UNCONST_CAST(char **, a)); } @@ -85,42 +85,59 @@ TEST_CASE("getopt") { opt = &local_options; opt->reset(); opt->debug.getopt_throw_instead_of_exit = true; - const char a0[] = ""; + static const char a0[] = ""; - SUBCASE("issue 587a") { + SUBCASE("issue 587") { const char *a[] = {a0, "--brute", "--lzma", nullptr}; - CHECK(!opt->all_methods); test_options(a); CHECK(opt->all_methods); CHECK(opt->all_methods_use_lzma == 1); } - SUBCASE("issue 587b") { + SUBCASE("issue 587") { const char *a[] = {a0, "--lzma", "--brute", nullptr}; - CHECK(!opt->all_methods); test_options(a); CHECK(opt->all_methods); CHECK(opt->all_methods_use_lzma == 1); } - SUBCASE("issue 587c") { + SUBCASE("issue 587") { const char *a[] = {a0, "--brute", "--no-lzma", nullptr}; - CHECK(!opt->all_methods); test_options(a); CHECK(opt->all_methods); CHECK(opt->all_methods_use_lzma == -1); } - SUBCASE("issue 587d") { + SUBCASE("issue 587") { const char *a[] = {a0, "--no-lzma", "--brute", nullptr}; - CHECK(!opt->all_methods); test_options(a); CHECK(opt->all_methods); CHECK(opt->all_methods_use_lzma == -1); } - SUBCASE("issue 587e") { - const char *a[] = {a0, "--no-lzma", "--all-methods", nullptr}; + SUBCASE("issue 587") { + const char *a[] = {a0, "--no-lzma", "--lzma", nullptr}; + test_options(a); CHECK(!opt->all_methods); + CHECK(opt->all_methods_use_lzma == 1); + CHECK(opt->method == M_LZMA); + } + SUBCASE("issue 587") { + const char *a[] = {a0, "--no-lzma", "--lzma", "--brute", nullptr}; + test_options(a); + CHECK(opt->all_methods); + CHECK(opt->all_methods_use_lzma == 1); + CHECK(opt->method == -1); + } + SUBCASE("issue 587") { + const char *a[] = {a0, "--lzma", "--no-lzma", nullptr}; + test_options(a); + CHECK(!opt->all_methods); + CHECK(opt->all_methods_use_lzma == -1); + CHECK(opt->method == -1); + } + SUBCASE("issue 587") { + const char *a[] = {a0, "--lzma", "--no-lzma", "--brute", nullptr}; test_options(a); CHECK(opt->all_methods); CHECK(opt->all_methods_use_lzma == -1); + CHECK(opt->method == -1); } opt = saved_opt; diff --git a/src/ui.cpp b/src/ui.cpp index a72f0ab3..10a93196 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -94,7 +94,7 @@ unsigned UiPacker::update_fu_len = 0; static const char header_line1[] = " File size Ratio Format Name\n"; static char header_line2[] = " -------------------- ------ ----------- -----------\n"; -static char progress_filler[] = ".*[]"; +static char progress_filler[4 + 1] = ".*[]"; static void init_global_constants(void) { #if 0 && (ACC_OS_DOS16 || ACC_OS_DOS32) @@ -399,7 +399,7 @@ void UiPacker::doCallback(unsigned isize, unsigned osize) { char *m = &s->msg_buf[s->bar_pos]; *m++ = progress_filler[2]; for (i = 0; i < s->bar_len; i++) - *m++ = progress_filler[i <= pos]; + *m++ = progress_filler[i <= pos ? 1 : 0]; *m++ = progress_filler[3]; // compute current compression ratio diff --git a/src/util/dt_check.cpp b/src/util/dt_check.cpp index 53ad11f6..0acaedea 100644 --- a/src/util/dt_check.cpp +++ b/src/util/dt_check.cpp @@ -141,10 +141,6 @@ struct TestBELE { COMPILE_TIME_ASSERT(sizeof(test2_t) == 1 + 3 * sizeof(T)) COMPILE_TIME_ASSERT_ALIGNED1(test2_t) COMPILE_TIME_ASSERT(sizeof(t2) == 7 + 21 * sizeof(T)) -#if defined(__acc_alignof) - COMPILE_TIME_ASSERT(__acc_alignof(t1) == 1) - COMPILE_TIME_ASSERT(__acc_alignof(t2) == 1) -#endif #if 1 T allbits; allbits = 0; diff --git a/src/util/membuffer.cpp b/src/util/membuffer.cpp index 52e49d3a..4802b9cc 100644 --- a/src/util/membuffer.cpp +++ b/src/util/membuffer.cpp @@ -107,9 +107,9 @@ static unsigned width(unsigned x) { static inline unsigned umax(unsigned a, unsigned b) { return (a >= b) ? a : b; } unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned extra) { - size_t const z = uncompressed_size; // fewer keystrokes and display columns - size_t const w = umax(8, width(z - 1)); // ignore tiny offsets - size_t bytes = mem_size(1, z); + unsigned const z = uncompressed_size; // fewer keystrokes and display columns + unsigned const w = umax(8, width(z - 1)); // ignore tiny offsets + unsigned bytes = ACC_ICONV(unsigned, mem_size(1, z)); // check // Worst matching: All match at max_offset, which implies 3==min_match // All literal: 1 bit overhead per literal byte bytes = umax(bytes, bytes + z / 8); @@ -119,11 +119,11 @@ unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned e bytes = umax(bytes, (z / 3 * (8 + 3 * (w - 7) / 2)) / 8); // extra + 256 safety for rounding bytes = mem_size(1, bytes, extra, 256); - return ACC_ICONV(unsigned, bytes); + return bytes; } unsigned MemBuffer::getSizeForUncompression(unsigned uncompressed_size, unsigned extra) { - size_t bytes = mem_size(1, uncompressed_size, extra); + size_t bytes = mem_size(1, uncompressed_size, extra); // check return ACC_ICONV(unsigned, bytes); } @@ -152,9 +152,9 @@ void MemBuffer::fill(unsigned off, unsigned len, int value) { // **************************************************************************/ -#define PTR(p) ((unsigned) ((upx_uintptr_t)(p) &0xffffffff)) -#define MAGIC1(p) (PTR(p) ^ 0xfefdbeeb) -#define MAGIC2(p) (PTR(p) ^ 0xfefdbeeb ^ 0x80024001) +#define PTR_BITS(p) ((unsigned) ((upx_uintptr_t)(p) &0xffffffff)) +#define MAGIC1(p) ((PTR_BITS(p) ^ 0xfefdbeeb) | 1) +#define MAGIC2(p) ((PTR_BITS(p) ^ 0xfefdbeeb ^ 0x80024011) | 1) unsigned MemBuffer::global_alloc_counter = 0; @@ -162,11 +162,11 @@ void MemBuffer::checkState() const { if (!b) throwInternalError("block not allocated"); if (use_simple_mcheck()) { - if (get_be32(b - 4) != MAGIC1(b)) + if (get_ne32(b - 4) != MAGIC1(b)) throwInternalError("memory clobbered before allocated block 1"); - if (get_be32(b - 8) != b_size_in_bytes) + if (get_ne32(b - 8) != b_size_in_bytes) throwInternalError("memory clobbered before allocated block 2"); - if (get_be32(b + b_size_in_bytes) != MAGIC2(b)) + if (get_ne32(b + b_size_in_bytes) != MAGIC2(b)) throwInternalError("memory clobbered past end of allocated block"); } } @@ -181,18 +181,17 @@ void MemBuffer::alloc(upx_uint64_t size) { unsigned char *p = (unsigned char *) malloc(bytes); if (!p) throwOutOfMemoryException(); + b = p; b_size_in_bytes = ACC_ICONV(unsigned, size); if (use_simple_mcheck()) { b = p + 16; // store magic constants to detect buffer overruns - set_be32(b - 8, b_size_in_bytes); - set_be32(b - 4, MAGIC1(b)); - set_be32(b + b_size_in_bytes, MAGIC2(b)); - set_be32(b + b_size_in_bytes + 4, global_alloc_counter++); - } else - b = p; - -#if defined(__SANITIZE_ADDRESS__) || DEBUG + set_ne32(b - 8, b_size_in_bytes); + set_ne32(b - 4, MAGIC1(b)); + set_ne32(b + b_size_in_bytes, MAGIC2(b)); + set_ne32(b + b_size_in_bytes + 4, global_alloc_counter++); + } +#if !defined(__SANITIZE_ADDRESS__) && 0 fill(0, b_size_in_bytes, (rand() & 0xff) | 1); // debug (void) VALGRIND_MAKE_MEM_UNDEFINED(b, b_size_in_bytes); #endif @@ -203,10 +202,10 @@ void MemBuffer::dealloc() { checkState(); if (use_simple_mcheck()) { // clear magic constants - set_be32(b - 8, 0); - set_be32(b - 4, 0); - set_be32(b + b_size_in_bytes, 0); - set_be32(b + b_size_in_bytes + 4, 0); + set_ne32(b - 8, 0); + set_ne32(b - 4, 0); + set_ne32(b + b_size_in_bytes, 0); + set_ne32(b + b_size_in_bytes + 4, 0); // ::free(b - 16); } else @@ -218,4 +217,29 @@ void MemBuffer::dealloc() { } } +/************************************************************************* +// +**************************************************************************/ + +TEST_CASE("MemBuffer") { + MemBuffer mb; + CHECK_THROWS(mb.checkState()); + CHECK_THROWS(mb.alloc(0x30000000 + 1)); + CHECK(raw_bytes(mb, 0) == nullptr); + CHECK_THROWS(raw_bytes(mb, 1)); + mb.alloc(64); + mb.checkState(); + CHECK(raw_bytes(mb, 64) != nullptr); + CHECK(raw_bytes(mb, 64) == mb.getVoidPtr()); + CHECK_THROWS(raw_bytes(mb, 65)); + if (use_simple_mcheck()) { + upx_byte *b = raw_bytes(mb, 0); + unsigned magic1 = get_ne32(b - 4); + set_ne32(b - 4, magic1 ^ 1); + CHECK_THROWS(mb.checkState()); + set_ne32(b - 4, magic1); + mb.checkState(); + } +} + /* vim:set ts=4 sw=4 et: */ diff --git a/src/util/membuffer.h b/src/util/membuffer.h index 7aa31677..d509d780 100644 --- a/src/util/membuffer.h +++ b/src/util/membuffer.h @@ -48,20 +48,24 @@ public: // NOTE: for fully bound-checked pointer use SPAN_S from xspan.h operator pointer() const { return b; } - template ::value, U>::type> - pointer operator+(V n) const { - size_t bytes = mem_size(sizeof(T), n); // check - return raw_bytes(bytes) + n; + template ::value, U>::type> + pointer operator+(U n) const { + size_t bytes = mem_size(sizeof(T), n); // check mem_size + return raw_bytes(bytes) + n; // and check bytes } // NOT allowed; use raw_bytes() instead - template ::value, U>::type> - pointer operator-(V n) const = delete; + template ::value, U>::type> + pointer operator-(U n) const = delete; pointer raw_bytes(size_t bytes) const { if (bytes > 0) { - assert(b != nullptr); - assert(bytes <= b_size_in_bytes); + if __acc_very_unlikely (b == nullptr) + throwInternalError("MemBuffer raw_bytes unexpected NULL ptr"); + if __acc_very_unlikely (bytes > b_size_in_bytes) + throwInternalError("MemBuffer raw_bytes invalid size"); } return b; } diff --git a/src/util/snprintf.cpp b/src/util/snprintf.cpp index f1c42110..c0cbbcda 100644 --- a/src/util/snprintf.cpp +++ b/src/util/snprintf.cpp @@ -31,8 +31,8 @@ // UPX version of string functions, with assertions and sane limits **************************************************************************/ -#undef vsnprintf int upx_safe_vsnprintf(char *str, upx_rsize_t max_size, const char *format, va_list ap) { +#undef vsnprintf size_t size; // preconditions @@ -56,6 +56,7 @@ int upx_safe_vsnprintf(char *str, upx_rsize_t max_size, const char *format, va_l } return ACC_ICONV(int, size - 1); // snprintf() returns length, not size +#define vsnprintf upx_safe_vsnprintf } int upx_safe_snprintf(char *str, upx_rsize_t max_size, const char *format, ...) { @@ -113,12 +114,13 @@ char *upx_safe_xprintf(const char *format, ...) { return ptr; } -#undef strlen upx_rsize_t upx_safe_strlen(const char *s) { +#undef strlen assert(s != nullptr); size_t len = strlen(s); assert(len < UPX_RSIZE_MAX_STR); return len; +#define strlen upx_safe_strlen } /* vim:set ts=4 sw=4 et: */ diff --git a/src/util/util.cpp b/src/util/util.cpp index bb200f52..ff094daa 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -249,20 +249,20 @@ int __acc_cdecl_qsort le64_compare_signed(const void *e1, const void *e2) { } /************************************************************************* -// find util +// find and mem_replace util **************************************************************************/ -int find(const void *b, int blen, const void *what, int wlen) { - if (b == nullptr || blen <= 0 || what == nullptr || wlen <= 0) +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) return -1; - int i; - const unsigned char *base = (const unsigned char *) b; - unsigned char firstc = *(const unsigned char *) what; + const unsigned char *b = (const unsigned char *) buf; + unsigned char first_byte = *(const unsigned char *) what; blen -= wlen; - for (i = 0; i <= blen; i++, base++) - if (*base == firstc && memcmp(base, what, wlen) == 0) + for (int i = 0; i <= blen; i++, b++) + if (*b == first_byte && memcmp(b, what, wlen) == 0) return i; return -1; @@ -305,6 +305,7 @@ int find_le64(const void *b, int blen, upx_uint64_t what) { } TEST_CASE("find") { + CHECK(find(nullptr, -1, nullptr, -1) == -1); static const unsigned char b[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; CHECK(find(b, 16, b, 0) == -1); for (int i = 0; i < 16; i++) { @@ -320,10 +321,12 @@ TEST_CASE("find") { CHECK(find_le32(b, 16, 0x07060504) == 4); CHECK(find_be64(b, 16, 0x08090a0b0c0d0e0fULL) == 8); CHECK(find_le64(b, 16, 0x0f0e0d0c0b0a0908ULL) == 8); + CHECK(find_be64(b, 15, 0x08090a0b0c0d0e0fULL) == -1); + CHECK(find_le64(b, 15, 0x0f0e0d0c0b0a0908ULL) == -1); } -int mem_replace(void *bb, int blen, const void *what, int wlen, const void *r) { - unsigned char *b = (unsigned char *) bb; +int mem_replace(void *buf, int blen, const void *what, int wlen, const void *replacement) { + unsigned char *b = (unsigned char *) buf; int boff = 0; int n = 0; @@ -332,7 +335,7 @@ int mem_replace(void *bb, int blen, const void *what, int wlen, const void *r) { if (off < 0) break; boff += off; - memcpy(b + boff, r, wlen); + memcpy(b + boff, replacement, wlen); boff += wlen; n++; } diff --git a/src/util/util.h b/src/util/util.h index e4329222..5b3e14d6 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -40,7 +40,7 @@ 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 failure +// "new" with asserted size; will throw on failure #define New(type, n) new type[mem_size_get_n(sizeof(type), n)] // will throw on invalid size @@ -75,8 +75,8 @@ inline void mem_clear(void *p, size_t n) { memset(p, 0, n); } -// ptrdiff_t with nullptr check and asserted size; will throw on failure -// WARNING: returns size_in_bytes, not number of elements! +// 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); unsigned ptr_udiff_bytes(const void *a, const void *b); // asserts a >= b @@ -96,6 +96,16 @@ ptr_udiff(const T *a, const U *b) { // misc. support functions **************************************************************************/ +int find(const void *b, int blen, const void *what, int wlen); +int find_be16(const void *b, int blen, unsigned what); +int find_be32(const void *b, int blen, unsigned what); +int find_be64(const void *b, int blen, upx_uint64_t what); +int find_le16(const void *b, int blen, unsigned what); +int find_le32(const void *b, int blen, unsigned what); +int find_le64(const void *b, int blen, upx_uint64_t what); + +int mem_replace(void *b, int blen, const void *what, int wlen, const void *r); + char *fn_basename(const char *name); int fn_strcmp(const char *n1, const char *n2); char *fn_strlwr(char *n); @@ -110,16 +120,6 @@ unsigned get_ratio(upx_uint64_t u_len, upx_uint64_t c_len); bool set_method_name(char *buf, size_t size, int method, int level); void center_string(char *buf, size_t size, const char *s); -int find(const void *b, int blen, const void *what, int wlen); -int find_be16(const void *b, int blen, unsigned what); -int find_be32(const void *b, int blen, unsigned what); -int find_be64(const void *b, int blen, upx_uint64_t what); -int find_le16(const void *b, int blen, unsigned what); -int find_le32(const void *b, int blen, unsigned what); -int find_le64(const void *b, int blen, upx_uint64_t what); - -int mem_replace(void *b, int blen, const void *what, int wlen, const void *r); - #endif /* already included */ /* vim:set ts=4 sw=4 et: */ diff --git a/src/util/xspan.cpp b/src/util/xspan.cpp index 1f62723e..97c95834 100644 --- a/src/util/xspan.cpp +++ b/src/util/xspan.cpp @@ -30,7 +30,7 @@ SPAN_NAMESPACE_BEGIN -unsigned long long span_check_stats_check_range; +unsigned long long span_check_stats_check_range = 0; __acc_noinline void span_fail_nullptr() { throwCantUnpack("span unexpected NULL pointer; take care!"); diff --git a/src/util/xspan_impl_common.h b/src/util/xspan_impl_common.h index 270564e8..e5b9b7fe 100644 --- a/src/util/xspan_impl_common.h +++ b/src/util/xspan_impl_common.h @@ -52,12 +52,20 @@ pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr pointer base; size_type size_in_bytes; -private: -// 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 SPAN_DELETED_FUNCTION; +// debug - internal sanity check; also serves as pseudo-documentation +#if DEBUG || 1 +__acc_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)) + span_check_range(ptr, base, size_in_bytes); +} +#else +__acc_forceinline void assertInvariants() const {} +#endif -private: static __acc_forceinline pointer makeNotNull(pointer p) { if __acc_very_unlikely (p == nullptr) span_fail_nullptr(); @@ -85,19 +93,6 @@ __acc_forceinline pointer ensureBase() const { span_fail_nullptr(); return ptr; } -// debug - extra internal sanity checks -#if DEBUG || 1 -__acc_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)) - span_check_range(ptr, base, size_in_bytes); -} -#else -__acc_forceinline void assertInvariants() const {} -#endif public: inline ~CSelf() {} @@ -397,6 +392,10 @@ pointer check_add(pointer p, ptrdiff_t n) const { 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 SPAN_DELETED_FUNCTION; + public: // raw access pointer raw_ptr() const { return ptr; } pointer raw_base() const { return base; } diff --git a/src/util/xspan_impl_ptr.h b/src/util/xspan_impl_ptr.h index 02ac34da..e3a60674 100644 --- a/src/util/xspan_impl_ptr.h +++ b/src/util/xspan_impl_ptr.h @@ -64,17 +64,21 @@ public: #endif inline ~CSelf() {} - inline CSelf() {} + inline CSelf() { assertInvariants(); } // constructors from pointers - CSelf(pointer p) : ptr(makePtr(p)) {} + CSelf(pointer p) : ptr(makePtr(p)) { assertInvariants(); } template - CSelf(U *p, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(makePtr(p)) {} + CSelf(U *p, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(makePtr(p)) { + assertInvariants(); + } // constructors - CSelf(const Self &other) : ptr(other.ptr) {} + CSelf(const Self &other) : ptr(other.ptr) { assertInvariants(); } template - CSelf(const CSelf &other, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(other.ptr) {} + CSelf(const CSelf &other, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(other.ptr) { + assertInvariants(); + } Self &assign(const Self &other) { assertInvariants(); @@ -87,10 +91,11 @@ public: // assignment Self &operator=(const Self &other) { return assign(other); } + // FIXME: this is not called !! template SPAN_REQUIRES_CONVERTIBLE_R(Self &) operator=(U *other) { - assert(0); + // assert(0); return assign(Self(other)); } @@ -98,7 +103,7 @@ public: template SPAN_REQUIRES_CONVERTIBLE_R(Self &) operator=(const CSelf &other) { - assert(0); + // assert(0); return assign(Self(other)); } @@ -187,6 +192,7 @@ public: // raw access #undef CSelf }; +// raw_bytes overload template inline T *raw_bytes(const Ptr &a, size_t size_in_bytes) { return a.raw_bytes(size_in_bytes); diff --git a/src/util/xspan_impl_ptr_or_null.h b/src/util/xspan_impl_ptr_or_null.h index a499f6f7..ec0f169d 100644 --- a/src/util/xspan_impl_ptr_or_null.h +++ b/src/util/xspan_impl_ptr_or_null.h @@ -48,22 +48,30 @@ private: #include "xspan_impl_common.h" public: // constructors from pointers - CSelf(pointer first) : ptr(first), base(nullptr), size_in_bytes(0) {} + CSelf(pointer first) : ptr(first), base(nullptr), size_in_bytes(0) { assertInvariants(); } // constructors CSelf(const Self &other) - : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } template CSelf(const CSelf &other, SPAN_REQUIRES_CONVERTIBLE_A) - : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } // constructors from Span friends template CSelf(const PtrOrSpan &other, SPAN_REQUIRES_CONVERTIBLE_A) - : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } template CSelf(const Span &other, SPAN_REQUIRES_CONVERTIBLE_A) - : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } // assignment from Span friends template @@ -82,6 +90,7 @@ public: #undef CSelf }; +// raw_bytes overload template inline T *raw_bytes(const PtrOrSpanOrNull &a, size_t size_in_bytes) { return a.raw_bytes(size_in_bytes); diff --git a/src/util/xspan_impl_ptr_or_span.h b/src/util/xspan_impl_ptr_or_span.h index caf2b49d..7918ddba 100644 --- a/src/util/xspan_impl_ptr_or_span.h +++ b/src/util/xspan_impl_ptr_or_span.h @@ -48,23 +48,33 @@ private: #include "xspan_impl_common.h" public: // constructors from pointers - CSelf(pointer first) : ptr(makePtr(first)), base(nullptr), size_in_bytes(0) {} + CSelf(pointer first) : ptr(makePtr(first)), base(nullptr), size_in_bytes(0) { + assertInvariants(); + } // constructors CSelf(const Self &other) - : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } template CSelf(const CSelf &other, SPAN_REQUIRES_CONVERTIBLE_A) - : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } // constructors from Span friends template CSelf(const Span &other, SPAN_REQUIRES_CONVERTIBLE_A) - : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } #if SPAN_CONFIG_ENABLE_SPAN_CONVERSION template CSelf(const PtrOrSpanOrNull &other, SPAN_REQUIRES_CONVERTIBLE_A) - : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } #endif // assignment from Span friends @@ -107,6 +117,7 @@ public: #undef CSelf }; +// raw_bytes overload template inline T *raw_bytes(const PtrOrSpan &a, size_t size_in_bytes) { return a.raw_bytes(size_in_bytes); diff --git a/src/util/xspan_impl_span.h b/src/util/xspan_impl_span.h index a17c9110..bfdd1d6b 100644 --- a/src/util/xspan_impl_span.h +++ b/src/util/xspan_impl_span.h @@ -52,19 +52,27 @@ public: // constructors CSelf(const Self &other) - : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } template CSelf(const CSelf &other, SPAN_REQUIRES_CONVERTIBLE_A) - : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } // constructors from Span friends #if SPAN_CONFIG_ENABLE_SPAN_CONVERSION template CSelf(const PtrOrSpanOrNull &other, SPAN_REQUIRES_CONVERTIBLE_A) - : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } template CSelf(const PtrOrSpan &other, SPAN_REQUIRES_CONVERTIBLE_A) - : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {} + : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) { + assertInvariants(); + } #endif // assignment from Span friends @@ -109,6 +117,7 @@ public: #undef CSelf }; +// raw_bytes overload template inline T *raw_bytes(const Span &a, size_t size_in_bytes) { return a.raw_bytes(size_in_bytes);