all: more cleanups; NFCI
This commit is contained in:
+4
-4
@@ -109,14 +109,14 @@ public:
|
||||
|
||||
private:
|
||||
void checkNULL() const {
|
||||
if __acc_very_unlikely (!ptr_)
|
||||
if very_unlikely (!ptr_)
|
||||
throwCantUnpack("unexpected NULL pointer; take care!");
|
||||
}
|
||||
__acc_forceinline void checkRange() const { checkRange(ptr_, base_, size_in_bytes_); }
|
||||
__acc_forceinline void checkRange(const void *p) const { checkRange(p, base_, size_in_bytes_); }
|
||||
forceinline void checkRange() const { checkRange(ptr_, base_, size_in_bytes_); }
|
||||
forceinline void checkRange(const void *p) const { checkRange(p, base_, size_in_bytes_); }
|
||||
static void checkRange(const void *ptr, const void *base, size_t size_in_bytes) {
|
||||
size_t off = (const char *) ptr - (const char *) base;
|
||||
if __acc_very_unlikely (off > size_in_bytes)
|
||||
if very_unlikely (off > size_in_bytes)
|
||||
throwCantUnpack("pointer out of range; take care!");
|
||||
}
|
||||
void check() const { // check ptr_ invariant: either NULL or valid checkRange()
|
||||
|
||||
+32
-9
@@ -32,7 +32,7 @@
|
||||
void *membuffer_get_void_ptr(MemBuffer &mb) { return mb.getVoidPtr(); }
|
||||
unsigned membuffer_get_size(MemBuffer &mb) { return mb.getSize(); }
|
||||
|
||||
MemBuffer::Stats MemBuffer::stats;
|
||||
/*static*/ MemBuffer::Stats MemBuffer::stats;
|
||||
|
||||
#if DEBUG
|
||||
#define debug_set(var, expr) (var) = (expr)
|
||||
@@ -45,23 +45,23 @@ MemBuffer::Stats MemBuffer::stats;
|
||||
**************************************************************************/
|
||||
|
||||
#if defined(__SANITIZE_ADDRESS__)
|
||||
__acc_static_forceinline constexpr bool use_simple_mcheck() { return false; }
|
||||
static forceinline constexpr bool use_simple_mcheck() { return false; }
|
||||
#elif (WITH_VALGRIND) && defined(RUNNING_ON_VALGRIND)
|
||||
static int use_simple_mcheck_flag = -1;
|
||||
__acc_static_noinline void use_simple_mcheck_init() {
|
||||
static noinline void use_simple_mcheck_init() {
|
||||
use_simple_mcheck_flag = 1;
|
||||
if (RUNNING_ON_VALGRIND) {
|
||||
use_simple_mcheck_flag = 0;
|
||||
// fprintf(stderr, "upx: detected RUNNING_ON_VALGRIND\n");
|
||||
}
|
||||
}
|
||||
__acc_static_forceinline bool use_simple_mcheck() {
|
||||
if __acc_unlikely (use_simple_mcheck_flag < 0)
|
||||
static forceinline bool use_simple_mcheck() {
|
||||
if very_unlikely (use_simple_mcheck_flag < 0)
|
||||
use_simple_mcheck_init();
|
||||
return (bool) use_simple_mcheck_flag;
|
||||
}
|
||||
#else
|
||||
__acc_static_forceinline constexpr bool use_simple_mcheck() { return true; }
|
||||
static forceinline constexpr bool use_simple_mcheck() { return true; }
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
@@ -119,12 +119,14 @@ 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) {
|
||||
unsigned const z = uncompressed_size; // fewer keystrokes and display columns
|
||||
unsigned const w = umax(8, width(z - 1)); // ignore tiny offsets
|
||||
if (uncompressed_size == 0)
|
||||
throwCantPack("invalid uncompressed_size");
|
||||
const unsigned z = uncompressed_size; // fewer keystrokes and display columns
|
||||
const unsigned 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);
|
||||
bytes = umax(bytes, z + z / 8);
|
||||
// NRV2B: 1 byte plus 2 bits per width exceeding 8 ("ss11")
|
||||
bytes = umax(bytes, (z / 3 * (8 + 2 * (w - 8) / 1)) / 8);
|
||||
// NRV2E: 1 byte plus 3 bits per pair of width exceeding 7 ("ss12")
|
||||
@@ -133,21 +135,28 @@ unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned e
|
||||
bytes = umax(bytes, z + (z >> 8) + ((z < (128 << 10)) ? (((128 << 10) - z) >> 11) : 0));
|
||||
// extra + 256 safety for rounding
|
||||
bytes = mem_size(1, bytes, extra, 256);
|
||||
UNUSED(w);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
unsigned MemBuffer::getSizeForDecompression(unsigned uncompressed_size, unsigned extra) {
|
||||
if (uncompressed_size == 0)
|
||||
throwCantPack("invalid uncompressed_size");
|
||||
size_t bytes = mem_size(1, uncompressed_size, extra); // check
|
||||
return ACC_ICONV(unsigned, bytes);
|
||||
}
|
||||
|
||||
void MemBuffer::allocForCompression(unsigned uncompressed_size, unsigned extra) {
|
||||
if (uncompressed_size == 0)
|
||||
throwCantPack("invalid uncompressed_size");
|
||||
unsigned size = getSizeForCompression(uncompressed_size, extra);
|
||||
alloc(size);
|
||||
debug_set(debug.last_return_address_alloc, upx_return_address());
|
||||
}
|
||||
|
||||
void MemBuffer::allocForDecompression(unsigned uncompressed_size, unsigned extra) {
|
||||
if (uncompressed_size == 0)
|
||||
throwCantPack("invalid uncompressed_size");
|
||||
unsigned size = getSizeForDecompression(uncompressed_size, extra);
|
||||
alloc(size);
|
||||
debug_set(debug.last_return_address_alloc, upx_return_address());
|
||||
@@ -254,6 +263,10 @@ TEST_CASE("MemBuffer") {
|
||||
CHECK(raw_bytes(mb, 64) != nullptr);
|
||||
CHECK(raw_bytes(mb, 64) == mb.getVoidPtr());
|
||||
CHECK_THROWS(raw_bytes(mb, 65));
|
||||
CHECK_NOTHROW(mb + 64);
|
||||
CHECK_NOTHROW(64 + mb);
|
||||
CHECK_THROWS(mb + 65);
|
||||
CHECK_THROWS(65 + mb);
|
||||
if (use_simple_mcheck()) {
|
||||
upx_byte *b = raw_bytes(mb, 0);
|
||||
unsigned magic1 = get_ne32(b - 4);
|
||||
@@ -264,4 +277,14 @@ TEST_CASE("MemBuffer") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MemBuffer::getSizeForCompression") {
|
||||
CHECK_THROWS(MemBuffer::getSizeForCompression(0));
|
||||
CHECK_THROWS(MemBuffer::getSizeForDecompression(0));
|
||||
CHECK(MemBuffer::getSizeForCompression(1) == 320);
|
||||
CHECK(MemBuffer::getSizeForCompression(256) == 576);
|
||||
CHECK(MemBuffer::getSizeForCompression(1024) == 1408);
|
||||
// CHECK(MemBuffer::getSizeForCompression(1024 * 1024) == 0); // TODO
|
||||
// CHECK(MemBuffer::getSizeForCompression(UPX_RSIZE_MAX) == 0); // TODO
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
||||
+34
-27
@@ -40,31 +40,34 @@ public:
|
||||
typedef typename std::add_pointer<T>::type pointer;
|
||||
|
||||
protected:
|
||||
pointer b = nullptr;
|
||||
unsigned b_size_in_bytes = 0;
|
||||
pointer b;
|
||||
unsigned b_size_in_bytes;
|
||||
|
||||
public:
|
||||
MemBufferBase() : b(nullptr), b_size_in_bytes(0) {}
|
||||
|
||||
// NOTE: implicit conversion to underlying pointer
|
||||
// NOTE: for fully bound-checked pointer use XSPAN_S from xspan.h
|
||||
operator pointer() const { return b; }
|
||||
|
||||
template <class U,
|
||||
class /*Dummy*/ = typename std::enable_if<std::is_integral<U>::value, U>::type>
|
||||
pointer operator+(U n) const {
|
||||
template <class U>
|
||||
typename std::enable_if<std::is_integral<U>::value, pointer>::type operator+(U n) const {
|
||||
size_t bytes = mem_size(sizeof(T), n); // check mem_size
|
||||
return raw_bytes(bytes) + n; // and check bytes
|
||||
}
|
||||
|
||||
private:
|
||||
// NOT allowed; use raw_bytes() instead
|
||||
template <class U,
|
||||
class /*Dummy*/ = typename std::enable_if<std::is_integral<U>::value, U>::type>
|
||||
pointer operator-(U n) const = delete;
|
||||
template <class U>
|
||||
typename std::enable_if<std::is_integral<U>::value, pointer>::type
|
||||
operator-(U n) const DELETED_FUNCTION;
|
||||
|
||||
public:
|
||||
pointer raw_bytes(size_t bytes) const {
|
||||
if (bytes > 0) {
|
||||
if __acc_very_unlikely (b == nullptr)
|
||||
if very_unlikely (b == nullptr)
|
||||
throwInternalError("MemBuffer raw_bytes unexpected NULL ptr");
|
||||
if __acc_very_unlikely (bytes > b_size_in_bytes)
|
||||
if very_unlikely (bytes > b_size_in_bytes)
|
||||
throwInternalError("MemBuffer raw_bytes invalid size");
|
||||
}
|
||||
return b;
|
||||
@@ -73,7 +76,7 @@ public:
|
||||
|
||||
class MemBuffer final : public MemBufferBase<unsigned char> {
|
||||
public:
|
||||
MemBuffer() = default;
|
||||
MemBuffer() : MemBufferBase<unsigned char>() {}
|
||||
explicit MemBuffer(upx_uint64_t size_in_bytes);
|
||||
~MemBuffer();
|
||||
|
||||
@@ -94,14 +97,14 @@ public:
|
||||
|
||||
// util
|
||||
void fill(unsigned off, unsigned len, int value);
|
||||
__acc_forceinline void clear(unsigned off, unsigned len) { fill(off, len, 0); }
|
||||
__acc_forceinline void clear() { fill(0, b_size_in_bytes, 0); }
|
||||
forceinline void clear(unsigned off, unsigned len) { fill(off, len, 0); }
|
||||
forceinline void clear() { fill(0, b_size_in_bytes, 0); }
|
||||
|
||||
// If the entire range [skip, skip+take) is inside the buffer,
|
||||
// then return &b[skip]; else throwCantPack(sprintf(errfmt, skip, take)).
|
||||
// This is similar to BoundedPtr, except only checks once.
|
||||
// skip == offset, take == size_in_bytes
|
||||
__acc_forceinline pointer subref(const char *errfmt, size_t skip, size_t take) {
|
||||
forceinline pointer subref(const char *errfmt, size_t skip, size_t take) {
|
||||
return (pointer) subref_impl(errfmt, skip, take);
|
||||
}
|
||||
|
||||
@@ -118,24 +121,28 @@ private:
|
||||
#if DEBUG
|
||||
// debugging aid
|
||||
struct Debug {
|
||||
void *last_return_address_alloc = nullptr;
|
||||
void *last_return_address_dealloc = nullptr;
|
||||
void *last_return_address_fill = nullptr;
|
||||
void *last_return_address_subref = nullptr;
|
||||
void *last_return_address_alloc;
|
||||
void *last_return_address_dealloc;
|
||||
void *last_return_address_fill;
|
||||
void *last_return_address_subref;
|
||||
Debug() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
Debug debug;
|
||||
#endif
|
||||
|
||||
// disable copy, assignment and move assignment
|
||||
MemBuffer(const MemBuffer &) = delete;
|
||||
MemBuffer &operator=(const MemBuffer &) = delete;
|
||||
MemBuffer &operator=(MemBuffer &&) = delete;
|
||||
// disable copy, assignment and move
|
||||
MemBuffer(const MemBuffer &) DELETED_FUNCTION;
|
||||
MemBuffer &operator=(const MemBuffer &) DELETED_FUNCTION;
|
||||
#if __cplusplus >= 201103L
|
||||
MemBuffer(MemBuffer &&) DELETED_FUNCTION;
|
||||
MemBuffer &operator=(MemBuffer &&) DELETED_FUNCTION;
|
||||
#endif
|
||||
// disable dynamic allocation
|
||||
ACC_CXX_DISABLE_NEW_DELETE
|
||||
|
||||
// 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]
|
||||
MemBuffer *operator&() const = delete;
|
||||
MemBuffer *operator&() const DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
// raw_bytes overload
|
||||
@@ -148,14 +155,14 @@ template <class T>
|
||||
inline typename MemBufferBase<T>::pointer raw_index_bytes(const MemBufferBase<T> &mbb, size_t index,
|
||||
size_t size_in_bytes) {
|
||||
typedef typename MemBufferBase<T>::element_type element_type;
|
||||
return raw_bytes(mbb, mem_size(sizeof(element_type), index, size_in_bytes)) + index;
|
||||
return mbb.raw_bytes(mem_size(sizeof(element_type), index, size_in_bytes)) + index;
|
||||
}
|
||||
|
||||
// global operators
|
||||
// rewrite "n + membuffer" to "membuffer + n" so that this will get checked above
|
||||
template <class T, class U,
|
||||
class /*Dummy*/ = typename std::enable_if<std::is_integral<U>::value, U>::type>
|
||||
inline typename MemBufferBase<T>::pointer operator+(U n, const MemBufferBase<T> &mbb) {
|
||||
template <class T, class U>
|
||||
inline typename std::enable_if<std::is_integral<U>::value, typename MemBufferBase<T>::pointer>::type
|
||||
operator+(U n, const MemBufferBase<T> &mbb) {
|
||||
return mbb + n;
|
||||
}
|
||||
|
||||
|
||||
+15
-15
@@ -51,16 +51,16 @@ ACC_COMPILE_TIME_ASSERT_HEADER(2ull * UPX_RSIZE_MAX * 9 / 8 + 16 * 1024 * 1024 <
|
||||
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
|
||||
upx_uint64_t extra2) {
|
||||
assert(element_size > 0);
|
||||
if __acc_very_unlikely (element_size > UPX_RSIZE_MAX)
|
||||
if very_unlikely (element_size > UPX_RSIZE_MAX)
|
||||
throwCantPack("mem_size 1; take care");
|
||||
if __acc_very_unlikely (n > UPX_RSIZE_MAX)
|
||||
if very_unlikely (n > UPX_RSIZE_MAX)
|
||||
throwCantPack("mem_size 2; take care");
|
||||
if __acc_very_unlikely (extra1 > UPX_RSIZE_MAX)
|
||||
if very_unlikely (extra1 > UPX_RSIZE_MAX)
|
||||
throwCantPack("mem_size 3; take care");
|
||||
if __acc_very_unlikely (extra2 > UPX_RSIZE_MAX)
|
||||
if very_unlikely (extra2 > UPX_RSIZE_MAX)
|
||||
throwCantPack("mem_size 4; take care");
|
||||
upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow
|
||||
if __acc_very_unlikely (bytes > UPX_RSIZE_MAX)
|
||||
if very_unlikely (bytes > UPX_RSIZE_MAX)
|
||||
throwCantPack("mem_size 5; take care");
|
||||
return ACC_ICONV(upx_rsize_t, bytes);
|
||||
}
|
||||
@@ -68,16 +68,16 @@ upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t ext
|
||||
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
|
||||
upx_uint64_t extra2) noexcept {
|
||||
assert(element_size > 0);
|
||||
if __acc_very_unlikely (element_size > UPX_RSIZE_MAX)
|
||||
if very_unlikely (element_size > UPX_RSIZE_MAX)
|
||||
return false;
|
||||
if __acc_very_unlikely (n > UPX_RSIZE_MAX)
|
||||
if very_unlikely (n > UPX_RSIZE_MAX)
|
||||
return false;
|
||||
if __acc_very_unlikely (extra1 > UPX_RSIZE_MAX)
|
||||
if very_unlikely (extra1 > UPX_RSIZE_MAX)
|
||||
return false;
|
||||
if __acc_very_unlikely (extra2 > UPX_RSIZE_MAX)
|
||||
if very_unlikely (extra2 > UPX_RSIZE_MAX)
|
||||
return false;
|
||||
upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow
|
||||
if __acc_very_unlikely (bytes > UPX_RSIZE_MAX)
|
||||
if very_unlikely (bytes > UPX_RSIZE_MAX)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -98,18 +98,18 @@ TEST_CASE("mem_size") {
|
||||
}
|
||||
|
||||
int ptr_diff_bytes(const void *a, const void *b) {
|
||||
if __acc_very_unlikely (a == nullptr) {
|
||||
if very_unlikely (a == nullptr) {
|
||||
throwCantPack("ptr_diff_bytes null 1; take care");
|
||||
}
|
||||
if __acc_very_unlikely (b == nullptr) {
|
||||
if very_unlikely (b == nullptr) {
|
||||
throwCantPack("ptr_diff_bytes null 2; take care");
|
||||
}
|
||||
ptrdiff_t d = (const char *) a - (const char *) b;
|
||||
if (a >= b) {
|
||||
if __acc_very_unlikely (!mem_size_valid_bytes(d))
|
||||
if very_unlikely (!mem_size_valid_bytes(d))
|
||||
throwCantPack("ptr_diff_bytes 1; take care");
|
||||
} else {
|
||||
if __acc_very_unlikely (!mem_size_valid_bytes(-d))
|
||||
if very_unlikely (!mem_size_valid_bytes(-d))
|
||||
throwCantPack("ptr_diff_bytes 2; take care");
|
||||
}
|
||||
return ACC_ICONV(int, d);
|
||||
@@ -117,7 +117,7 @@ int ptr_diff_bytes(const void *a, const void *b) {
|
||||
|
||||
unsigned ptr_udiff_bytes(const void *a, const void *b) {
|
||||
int d = ptr_diff_bytes(a, b);
|
||||
if __acc_very_unlikely (d < 0)
|
||||
if very_unlikely (d < 0)
|
||||
throwCantPack("ptr_udiff_bytes; take care");
|
||||
return ACC_ICONV(unsigned, d);
|
||||
}
|
||||
|
||||
+5
-3
@@ -40,20 +40,22 @@ 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 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);
|
||||
|
||||
//
|
||||
// inline fast paths:
|
||||
//
|
||||
|
||||
// will throw on invalid size
|
||||
inline upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n) {
|
||||
upx_uint64_t bytes = element_size * n;
|
||||
if __acc_very_unlikely (element_size == 0 || element_size > UPX_RSIZE_MAX ||
|
||||
n > UPX_RSIZE_MAX || bytes > UPX_RSIZE_MAX)
|
||||
if very_unlikely (element_size == 0 || element_size > UPX_RSIZE_MAX || n > UPX_RSIZE_MAX ||
|
||||
bytes > UPX_RSIZE_MAX)
|
||||
return mem_size(element_size, n, 0, 0); // this will throw
|
||||
return ACC_ICONV(upx_rsize_t, bytes);
|
||||
}
|
||||
|
||||
+22
-9
@@ -33,37 +33,50 @@ XSPAN_NAMESPACE_BEGIN
|
||||
// debugging stats
|
||||
struct XSpanStats {
|
||||
upx_std_atomic(size_t) check_range_counter;
|
||||
// doctest checks will set these:
|
||||
upx_std_atomic(size_t) fail_nullptr;
|
||||
upx_std_atomic(size_t) fail_nullbase;
|
||||
upx_std_atomic(size_t) fail_not_same_base;
|
||||
upx_std_atomic(size_t) fail_range_nullptr;
|
||||
upx_std_atomic(size_t) fail_range_nullbase;
|
||||
upx_std_atomic(size_t) fail_range_range;
|
||||
};
|
||||
static XSpanStats xspan_stats;
|
||||
|
||||
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
|
||||
__acc_noinline void xspan_fail_nullptr() {
|
||||
noinline void xspan_fail_nullptr() {
|
||||
xspan_stats.fail_nullptr += 1;
|
||||
throwCantUnpack("xspan unexpected NULL pointer; take care!");
|
||||
}
|
||||
__acc_noinline void xspan_fail_nullbase() {
|
||||
noinline void xspan_fail_nullbase() {
|
||||
xspan_stats.fail_nullbase += 1;
|
||||
throwCantUnpack("xspan unexpected NULL base; take care!");
|
||||
}
|
||||
__acc_noinline void xspan_fail_not_same_base() {
|
||||
noinline void xspan_fail_not_same_base() {
|
||||
xspan_stats.fail_not_same_base += 1;
|
||||
throwInternalError("xspan unexpected base pointer; take care!");
|
||||
}
|
||||
|
||||
__acc_noinline void xspan_fail_range_nullptr() {
|
||||
noinline void xspan_fail_range_nullptr() {
|
||||
xspan_stats.fail_range_nullptr += 1;
|
||||
throwCantUnpack("xspan_check_range: unexpected NULL pointer; take care!");
|
||||
}
|
||||
__acc_noinline void xspan_fail_range_nullbase() {
|
||||
noinline void xspan_fail_range_nullbase() {
|
||||
xspan_stats.fail_range_nullbase += 1;
|
||||
throwCantUnpack("xspan_check_range: unexpected NULL base; take care!");
|
||||
}
|
||||
__acc_noinline void xspan_fail_range_range() {
|
||||
noinline void xspan_fail_range_range() {
|
||||
xspan_stats.fail_range_range += 1;
|
||||
throwCantUnpack("xspan_check_range: pointer out of range; take care!");
|
||||
}
|
||||
|
||||
void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes) {
|
||||
if __acc_very_unlikely (p == nullptr)
|
||||
if very_unlikely (p == nullptr)
|
||||
xspan_fail_range_nullptr();
|
||||
if __acc_very_unlikely (base == nullptr)
|
||||
if very_unlikely (base == nullptr)
|
||||
xspan_fail_range_nullbase();
|
||||
ptrdiff_t off = (const char *) p - (const char *) base;
|
||||
if __acc_very_unlikely (off < 0 || off > size_in_bytes)
|
||||
if very_unlikely (off < 0 || off > size_in_bytes)
|
||||
xspan_fail_range_range();
|
||||
xspan_stats.check_range_counter += 1;
|
||||
// fprintf(stderr, "xspan_check_range done\n");
|
||||
|
||||
@@ -159,4 +159,47 @@ inline R *xspan_make_helper__(R * /*dummy*/, MemBuffer &first) {
|
||||
#define SPAN_S_VAR XSPAN_S_VAR
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
// raw_bytes() - get underlying memory from checked buffers/pointers.
|
||||
// This is overloaded by various utility classes like BoundedPtr,
|
||||
// MemBuffer and XSpan.
|
||||
//
|
||||
// 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 <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) {
|
||||
if very_unlikely (size_in_bytes > 0 && ptr == nullptr)
|
||||
throwInternalError("raw_bytes unexpected NULL ptr");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if very_unlikely (ptr == nullptr)
|
||||
throwInternalError("raw_index_bytes unexpected NULL ptr");
|
||||
(void) mem_size(sizeof(T), index, size_in_bytes); // assert size
|
||||
return ptr + index;
|
||||
}
|
||||
|
||||
// same for bounded arrays
|
||||
template <class T, size_t N>
|
||||
inline T *raw_bytes(T (&a)[N], size_t size_in_bytes) {
|
||||
if very_unlikely (size_in_bytes > mem_size(sizeof(T), N))
|
||||
throwInternalError("raw_bytes out of range");
|
||||
return a;
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
inline T *raw_index_bytes(T (&a)[N], size_t index, size_t size_in_bytes) {
|
||||
return raw_bytes(a, mem_size(sizeof(T), index, size_in_bytes)) + index;
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
||||
@@ -42,12 +42,12 @@
|
||||
XSPAN_NAMESPACE_BEGIN
|
||||
|
||||
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
|
||||
__acc_noinline void xspan_fail_nullptr();
|
||||
__acc_noinline void xspan_fail_nullbase();
|
||||
__acc_noinline void xspan_fail_not_same_base();
|
||||
__acc_noinline void xspan_fail_range_nullptr();
|
||||
__acc_noinline void xspan_fail_range_nullbase();
|
||||
__acc_noinline void xspan_fail_range_range();
|
||||
noinline void xspan_fail_nullptr();
|
||||
noinline void xspan_fail_nullbase();
|
||||
noinline void xspan_fail_not_same_base();
|
||||
noinline void xspan_fail_range_nullptr();
|
||||
noinline void xspan_fail_range_nullbase();
|
||||
noinline void xspan_fail_range_range();
|
||||
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
|
||||
|
||||
@@ -53,7 +53,7 @@ size_type size_in_bytes;
|
||||
|
||||
// debug - internal sanity check; also serves as pseudo-documentation
|
||||
#if DEBUG
|
||||
__acc_noinline void assertInvariants() const {
|
||||
noinline void assertInvariants() const {
|
||||
if __acc_cte (configRequirePtr)
|
||||
assert(ptr != nullptr);
|
||||
if __acc_cte (configRequireBase)
|
||||
@@ -62,32 +62,32 @@ __acc_noinline void assertInvariants() const {
|
||||
xspan_check_range(ptr, base, size_in_bytes);
|
||||
}
|
||||
#else
|
||||
__acc_forceinline void assertInvariants() const {}
|
||||
forceinline void assertInvariants() const {}
|
||||
#endif
|
||||
|
||||
static __acc_forceinline pointer makeNotNull(pointer p) {
|
||||
if __acc_very_unlikely (p == nullptr)
|
||||
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 __acc_forceinline pointer makePtr(pointer p) {
|
||||
static forceinline pointer makePtr(pointer p) {
|
||||
if __acc_cte (configRequirePtr && p == nullptr)
|
||||
xspan_fail_nullptr();
|
||||
return p;
|
||||
}
|
||||
static __acc_forceinline pointer makeBase(pointer b) {
|
||||
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
|
||||
__acc_forceinline pointer ensurePtr() const {
|
||||
forceinline pointer ensurePtr() const {
|
||||
if __acc_cte (!configRequirePtr && ptr == nullptr)
|
||||
xspan_fail_nullptr();
|
||||
return ptr;
|
||||
}
|
||||
__acc_forceinline pointer ensureBase() const {
|
||||
forceinline pointer ensureBase() const {
|
||||
if __acc_cte (!configRequireBase && base == nullptr)
|
||||
xspan_fail_nullbase();
|
||||
return base;
|
||||
@@ -213,7 +213,7 @@ Self &assign(const Self &other) {
|
||||
} else {
|
||||
// magic 2: assert same base (but ignore size_in_bytes !)
|
||||
if __acc_cte (configRequireBase || other.base != nullptr)
|
||||
if __acc_very_unlikely (base != other.base)
|
||||
if very_unlikely (base != other.base)
|
||||
xspan_fail_not_same_base();
|
||||
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
|
||||
(configRequireBase || base != nullptr))
|
||||
|
||||
@@ -51,11 +51,11 @@ private:
|
||||
pointer ptr;
|
||||
|
||||
// enforce config invariants at constructor time - static functions
|
||||
static __acc_forceinline pointer makePtr(pointer p) { return p; }
|
||||
static forceinline pointer makePtr(pointer p) { return p; }
|
||||
// inverse logic for ensuring valid pointers from existing objets
|
||||
__acc_forceinline pointer ensurePtr() const { return ptr; }
|
||||
forceinline pointer ensurePtr() const { return ptr; }
|
||||
// debug
|
||||
__acc_forceinline void assertInvariants() const {}
|
||||
forceinline void assertInvariants() const {}
|
||||
|
||||
public:
|
||||
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
|
||||
@@ -172,9 +172,9 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
__acc_forceinline pointer check_deref(pointer p) const { return p; }
|
||||
__acc_forceinline pointer check_deref(pointer p, ptrdiff_t n) const { return p + n; }
|
||||
__acc_forceinline pointer check_add(pointer p, ptrdiff_t n) const { return p + n; }
|
||||
forceinline pointer check_deref(pointer p) const { return p; }
|
||||
forceinline pointer check_deref(pointer p, ptrdiff_t n) const { return p + n; }
|
||||
forceinline pointer check_add(pointer p, ptrdiff_t n) const { return p + n; }
|
||||
|
||||
public: // raw access
|
||||
pointer raw_ptr() const { return ptr; }
|
||||
|
||||
Reference in New Issue
Block a user