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:
@@ -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();
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user