src: major cleanups, introduce new eXtended Span class
- initial minimally invasive eXtended Span implementation - rename ptr_diff to ptr_diff_bytes - move some files to util subdir - lots of cleanups - start using the new checked pointers - this needs some real-world testing
This commit is contained in:
+142
@@ -0,0 +1,142 @@
|
||||
/* bptr.h --
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2022 Laszlo Molnar
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef UPX_BPTR_H__
|
||||
#define UPX_BPTR_H__ 1
|
||||
|
||||
/*************************************************************************
|
||||
// BoundedPtr
|
||||
**************************************************************************/
|
||||
|
||||
template <class T>
|
||||
class BoundedPtr {
|
||||
public:
|
||||
~BoundedPtr() {}
|
||||
|
||||
BoundedPtr(void *base, size_t size_in_bytes, T *ptr = nullptr)
|
||||
: ptr_(ptr), base_(base), size_in_bytes_(0) {
|
||||
assert(base_ != nullptr);
|
||||
size_in_bytes_ = mem_size(1, size_in_bytes);
|
||||
check();
|
||||
}
|
||||
|
||||
// assignment
|
||||
BoundedPtr &operator=(const BoundedPtr &other) {
|
||||
assert(base_ == other.base_);
|
||||
assert(size_in_bytes_ == other.size_in_bytes_);
|
||||
ptr_ = other.ptr_;
|
||||
check();
|
||||
return *this;
|
||||
}
|
||||
BoundedPtr &operator=(T *other) {
|
||||
ptr_ = other;
|
||||
check();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// dereference
|
||||
T &operator*() {
|
||||
checkNULL();
|
||||
checkRange(ptr_ + 1);
|
||||
return *ptr_;
|
||||
}
|
||||
const T &operator*() const {
|
||||
checkNULL();
|
||||
checkRange(ptr_ + 1);
|
||||
return *ptr_;
|
||||
}
|
||||
|
||||
operator T *() { return ptr_; }
|
||||
operator const T *() const { return ptr_; }
|
||||
|
||||
BoundedPtr &operator+=(size_t n) {
|
||||
checkNULL();
|
||||
ptr_ += n;
|
||||
checkRange();
|
||||
return *this;
|
||||
}
|
||||
BoundedPtr &operator-=(size_t n) {
|
||||
checkNULL();
|
||||
ptr_ -= n;
|
||||
checkRange();
|
||||
return *this;
|
||||
}
|
||||
BoundedPtr &operator++(void) {
|
||||
checkNULL();
|
||||
ptr_ += 1;
|
||||
checkRange();
|
||||
return *this;
|
||||
}
|
||||
|
||||
T *raw_bytes(size_t bytes) const {
|
||||
checkNULL();
|
||||
if (bytes > 0)
|
||||
checkRange((const char *) (const void *) ptr_ + bytes);
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
private:
|
||||
void checkNULL() const {
|
||||
if __acc_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_); }
|
||||
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)
|
||||
throwCantUnpack("pointer out of range; take care!");
|
||||
}
|
||||
void check() const { // check ptr_ invariant: either NULL or valid checkRange()
|
||||
if (ptr_ != nullptr)
|
||||
checkRange();
|
||||
}
|
||||
|
||||
T *ptr_;
|
||||
void *base_;
|
||||
size_t size_in_bytes_;
|
||||
|
||||
// disable copy
|
||||
BoundedPtr(const BoundedPtr &) = delete;
|
||||
// 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]
|
||||
BoundedPtr<T> *operator&() const = delete;
|
||||
};
|
||||
|
||||
// raw_bytes overload
|
||||
template <class T>
|
||||
inline T *raw_bytes(const BoundedPtr<T> &a, size_t size_in_bytes) {
|
||||
return a.raw_bytes(size_in_bytes);
|
||||
}
|
||||
|
||||
#endif /* already included */
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,426 @@
|
||||
/* dt_check.cpp -- doctest check
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2022 Laszlo Molnar
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../conf.h"
|
||||
|
||||
/*************************************************************************
|
||||
// upx_doctest_check()
|
||||
**************************************************************************/
|
||||
|
||||
bool upx_doctest_check(int argc, char **argv) {
|
||||
bool minimal = true; // only show failing tests
|
||||
bool duration = false; // show timings
|
||||
bool success = false; // show all tests
|
||||
const char *e = getenv("UPX_DEBUG_DOCTEST_VERBOSE");
|
||||
if (e && e[0] && strcmp(e, "0") != 0) {
|
||||
minimal = false;
|
||||
if (strcmp(e, "2") == 0)
|
||||
duration = true;
|
||||
if (strcmp(e, "3") == 0) {
|
||||
duration = true;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
minimal = false;
|
||||
// duration = true;
|
||||
#endif
|
||||
doctest::Context context;
|
||||
#if 0
|
||||
if (argc > 0 && argv != nullptr)
|
||||
context.applyCommandLine(argc, argv);
|
||||
#else
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
#endif
|
||||
if (minimal)
|
||||
context.setOption("dt-minimal", true);
|
||||
if (duration)
|
||||
context.setOption("dt-duration", true);
|
||||
if (success)
|
||||
context.setOption("dt-success", true);
|
||||
int r = context.run();
|
||||
if (context.shouldExit() || r != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool upx_doctest_check() { return upx_doctest_check(0, nullptr); }
|
||||
|
||||
/*************************************************************************
|
||||
// compile-time checks
|
||||
**************************************************************************/
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((std::is_same<short, upx_int16_t>::value))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((std::is_same<unsigned short, upx_uint16_t>::value))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((std::is_same<int, upx_int32_t>::value))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((std::is_same<unsigned, upx_uint32_t>::value))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((std::is_same<long long, upx_int64_t>::value))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((std::is_same<unsigned long long, upx_uint64_t>::value))
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(no_bswap16(0x04030201) == 0x0201)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(no_bswap32(0x04030201) == 0x04030201)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(no_bswap64(0x0807060504030201ull) == 0x0807060504030201ull)
|
||||
#if !(ACC_CC_MSC)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(bswap16(0x04030201) == 0x0102)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(bswap32(0x04030201) == 0x01020304)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(bswap64(0x0807060504030201ull) == 0x0102030405060708ull)
|
||||
#endif
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_eq("", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("a", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("", "a"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_eq("abc", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("ab", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("abc", "ab"))
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("a", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_lt("", "a"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("abc", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_lt("ab", "abc"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("abc", "ab"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_lt("abc", "aba"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_lt("abc", "abz"))
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_ne("abc", "abz"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_gt("abc", "abz"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_ge("abc", "abz"))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_le("abc", "abz"))
|
||||
|
||||
/*************************************************************************
|
||||
// upx_compiler_sanity_check()
|
||||
// assert a sane architecture and compiler
|
||||
**************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
template <class T>
|
||||
struct TestBELE {
|
||||
__acc_static_noinline bool test(void) {
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(T)
|
||||
struct alignas(1) test1_t {
|
||||
char a;
|
||||
T b;
|
||||
};
|
||||
struct alignas(1) test2_t {
|
||||
char a;
|
||||
T b[3];
|
||||
};
|
||||
test1_t t1[7];
|
||||
UNUSED(t1);
|
||||
test2_t t2[7];
|
||||
UNUSED(t2);
|
||||
COMPILE_TIME_ASSERT(sizeof(test1_t) == 1 + sizeof(T))
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(test1_t)
|
||||
COMPILE_TIME_ASSERT(sizeof(t1) == 7 + 7 * sizeof(T))
|
||||
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;
|
||||
allbits += 1;
|
||||
allbits -= 2;
|
||||
T v1;
|
||||
v1 = 1;
|
||||
v1 *= 2;
|
||||
v1 -= 1;
|
||||
T v2;
|
||||
v2 = 1;
|
||||
assert((v1 == v2));
|
||||
assert(!(v1 != v2));
|
||||
assert((v1 <= v2));
|
||||
assert((v1 >= v2));
|
||||
assert(!(v1 < v2));
|
||||
assert(!(v1 > v2));
|
||||
v2 ^= allbits;
|
||||
assert(!(v1 == v2));
|
||||
assert((v1 != v2));
|
||||
assert((v1 <= v2));
|
||||
assert(!(v1 >= v2));
|
||||
assert((v1 < v2));
|
||||
assert(!(v1 > v2));
|
||||
v2 += 2;
|
||||
assert(v1 == 1);
|
||||
assert(v2 == 0);
|
||||
v1 <<= 1;
|
||||
v1 |= v2;
|
||||
v1 >>= 1;
|
||||
v2 &= v1;
|
||||
v2 /= v1;
|
||||
v2 *= v1;
|
||||
assert(v1 == 1);
|
||||
assert(v2 == 0);
|
||||
if ((v1 ^ v2) != 1)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class A, class B>
|
||||
struct TestNoAliasingStruct {
|
||||
__acc_static_noinline bool test(A *a, B *b) {
|
||||
*a = 0;
|
||||
*b = 0;
|
||||
*b -= 3;
|
||||
return *a != 0;
|
||||
}
|
||||
};
|
||||
template <class A, class B>
|
||||
__acc_static_forceinline bool testNoAliasing(A *a, B *b) {
|
||||
return TestNoAliasingStruct<A, B>::test(a, b);
|
||||
}
|
||||
template <class T>
|
||||
struct TestIntegerWrap {
|
||||
static inline bool inc(T x) { return x + 1 > x; }
|
||||
static inline bool dec(T x) { return x - 1 < x; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#define ACC_WANT_ACC_CHK_CH 1
|
||||
#undef ACCCHK_ASSERT
|
||||
#include "../miniacc.h"
|
||||
|
||||
void upx_compiler_sanity_check(void) {
|
||||
#define ACC_WANT_ACC_CHK_CH 1
|
||||
#undef ACCCHK_ASSERT
|
||||
#define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT(expr)
|
||||
#include "../miniacc.h"
|
||||
#undef ACCCHK_ASSERT
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(char) == 1)
|
||||
COMPILE_TIME_ASSERT(sizeof(short) == 2)
|
||||
COMPILE_TIME_ASSERT(sizeof(int) == 4)
|
||||
COMPILE_TIME_ASSERT(sizeof(long) >= 4)
|
||||
COMPILE_TIME_ASSERT(sizeof(void *) >= 4)
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(BE16) == 2)
|
||||
COMPILE_TIME_ASSERT(sizeof(BE32) == 4)
|
||||
COMPILE_TIME_ASSERT(sizeof(BE64) == 8)
|
||||
COMPILE_TIME_ASSERT(sizeof(LE16) == 2)
|
||||
COMPILE_TIME_ASSERT(sizeof(LE32) == 4)
|
||||
COMPILE_TIME_ASSERT(sizeof(LE64) == 8)
|
||||
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(BE16)
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(BE32)
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(BE64)
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(LE16)
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(LE32)
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(LE64)
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_STRING4) == 4 + 1)
|
||||
assert(strlen(UPX_VERSION_STRING4) == 4);
|
||||
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_YEAR) == 4 + 1)
|
||||
assert(strlen(UPX_VERSION_YEAR) == 4);
|
||||
assert(memcmp(UPX_VERSION_DATE_ISO, UPX_VERSION_YEAR, 4) == 0);
|
||||
assert(memcmp(&UPX_VERSION_DATE[sizeof(UPX_VERSION_DATE) - 1 - 4], UPX_VERSION_YEAR, 4) == 0);
|
||||
if (gitrev[0]) {
|
||||
size_t revlen = strlen(gitrev);
|
||||
if (strncmp(gitrev, "ERROR", 5) == 0) {
|
||||
assert(revlen == 5 || revlen == 6);
|
||||
} else {
|
||||
assert(revlen == 12 || revlen == 13);
|
||||
}
|
||||
if (revlen == 6 || revlen == 13) {
|
||||
assert(gitrev[revlen - 1] == '+');
|
||||
}
|
||||
}
|
||||
assert(UPX_RSIZE_MAX_MEM == 805306368);
|
||||
|
||||
#if 1
|
||||
assert(TestBELE<LE16>::test());
|
||||
assert(TestBELE<LE32>::test());
|
||||
assert(TestBELE<LE64>::test());
|
||||
assert(TestBELE<BE16>::test());
|
||||
assert(TestBELE<BE32>::test());
|
||||
assert(TestBELE<BE64>::test());
|
||||
{
|
||||
alignas(16) static const unsigned char dd[32] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0,
|
||||
0, 0, 0, 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0, 0, 0, 0, 0};
|
||||
const unsigned char *d;
|
||||
const N_BELE_RTP::AbstractPolicy *bele;
|
||||
d = dd + 7;
|
||||
assert(upx_adler32(d, 4) == 0x09f003f7);
|
||||
assert(upx_adler32(d, 4, 0) == 0x09ec03f6);
|
||||
assert(upx_adler32(d, 4, 1) == 0x09f003f7);
|
||||
bele = &N_BELE_RTP::be_policy;
|
||||
assert(get_be16(d) == 0xfffe);
|
||||
assert(bele->get16(d) == 0xfffe);
|
||||
assert(get_be16_signed(d) == -2);
|
||||
assert(get_be24(d) == 0xfffefd);
|
||||
assert(bele->get24(d) == 0xfffefd);
|
||||
assert(get_be24_signed(d) == -259);
|
||||
assert(get_be32(d) == 0xfffefdfc);
|
||||
assert(bele->get32(d) == 0xfffefdfc);
|
||||
assert(get_be32_signed(d) == -66052);
|
||||
bele = &N_BELE_RTP::le_policy;
|
||||
assert(get_le16(d) == 0xfeff);
|
||||
assert(bele->get16(d) == 0xfeff);
|
||||
assert(get_le16_signed(d) == -257);
|
||||
assert(get_le24(d) == 0xfdfeff);
|
||||
assert(bele->get24(d) == 0xfdfeff);
|
||||
assert(get_le24_signed(d) == -131329);
|
||||
assert(get_le32(d) == 0xfcfdfeff);
|
||||
assert(bele->get32(d) == 0xfcfdfeff);
|
||||
assert(get_le32_signed(d) == -50462977);
|
||||
assert(get_le64_signed(d) == -506097522914230529LL);
|
||||
assert(find_be16(d, 2, 0xfffe) == 0);
|
||||
assert(find_le16(d, 2, 0xfeff) == 0);
|
||||
assert(find_be32(d, 4, 0xfffefdfc) == 0);
|
||||
assert(find_le32(d, 4, 0xfcfdfeff) == 0);
|
||||
d += 12;
|
||||
assert(get_be16_signed(d) == 32638);
|
||||
assert(get_be24_signed(d) == 8355453);
|
||||
assert(get_be32_signed(d) == 2138996092);
|
||||
assert(get_be64_signed(d) == 9186918263483431288LL);
|
||||
}
|
||||
{
|
||||
unsigned dd;
|
||||
void *const d = ⅆ
|
||||
dd = ne32_to_le32(0xf7f6f5f4);
|
||||
assert(get_le26(d) == 0x03f6f5f4);
|
||||
set_le26(d, 0);
|
||||
assert(get_le26(d) == 0);
|
||||
assert(dd == ne32_to_le32(0xf4000000));
|
||||
set_le26(d, 0xff020304);
|
||||
assert(get_le26(d) == 0x03020304);
|
||||
assert(dd == ne32_to_le32(0xf7020304));
|
||||
}
|
||||
#endif
|
||||
union {
|
||||
short v_short;
|
||||
int v_int;
|
||||
long v_long;
|
||||
long long v_llong;
|
||||
BE16 b16;
|
||||
BE32 b32;
|
||||
BE64 b64;
|
||||
LE16 l16;
|
||||
LE32 l32;
|
||||
LE64 l64;
|
||||
} u;
|
||||
assert(testNoAliasing(&u.v_short, &u.b32));
|
||||
assert(testNoAliasing(&u.v_short, &u.l32));
|
||||
assert(testNoAliasing(&u.v_int, &u.b64));
|
||||
assert(testNoAliasing(&u.v_int, &u.l64));
|
||||
// check working -fno-strict-aliasing
|
||||
assert(testNoAliasing(&u.v_short, &u.v_int));
|
||||
assert(testNoAliasing(&u.v_int, &u.v_long));
|
||||
assert(testNoAliasing(&u.v_int, &u.v_llong));
|
||||
assert(testNoAliasing(&u.v_long, &u.v_llong));
|
||||
|
||||
assert(TestIntegerWrap<unsigned>::inc(0));
|
||||
assert(!TestIntegerWrap<unsigned>::inc(UINT_MAX));
|
||||
assert(TestIntegerWrap<unsigned>::dec(1));
|
||||
assert(!TestIntegerWrap<unsigned>::dec(0));
|
||||
// check working -fno-strict-overflow
|
||||
assert(TestIntegerWrap<int>::inc(0));
|
||||
assert(!TestIntegerWrap<int>::inc(INT_MAX));
|
||||
assert(TestIntegerWrap<int>::dec(0));
|
||||
assert(!TestIntegerWrap<int>::dec(INT_MIN));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// some doctest test cases
|
||||
**************************************************************************/
|
||||
|
||||
TEST_CASE("acc_vget") {
|
||||
CHECK_EQ(acc_vget_int(0, 0), 0);
|
||||
CHECK_EQ(acc_vget_long(1, -1), 1);
|
||||
CHECK_EQ(acc_vget_acc_int64l_t(2, 1), 2);
|
||||
CHECK_EQ(acc_vget_acc_hvoid_p(nullptr, 0), nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE("working -fno-strict-aliasing") {
|
||||
bool ok;
|
||||
long v = 0;
|
||||
short *ps = ACC_STATIC_CAST(short *, acc_vget_acc_hvoid_p(&v, 0));
|
||||
int *pi = ACC_STATIC_CAST(int *, acc_vget_acc_hvoid_p(&v, 0));
|
||||
long *pl = ACC_STATIC_CAST(long *, acc_vget_acc_hvoid_p(&v, 0));
|
||||
*ps = 0;
|
||||
*pl = -1;
|
||||
ok = *ps == -1;
|
||||
CHECK(ok);
|
||||
*pi = 0;
|
||||
*pl = -1;
|
||||
ok = *pi == -1;
|
||||
CHECK(ok);
|
||||
*pl = 0;
|
||||
*ps = -1;
|
||||
ok = *pl != 0;
|
||||
CHECK(ok);
|
||||
*pl = 0;
|
||||
*pi = -1;
|
||||
ok = *pl != 0;
|
||||
CHECK(ok);
|
||||
}
|
||||
|
||||
TEST_CASE("working -fno-strict-overflow") {
|
||||
CHECK_EQ(acc_vget_int(INT_MAX, 0) + 1, INT_MIN);
|
||||
CHECK_EQ(acc_vget_int(INT_MIN, 0) - 1, INT_MAX);
|
||||
CHECK_EQ(acc_vget_long(LONG_MAX, 0) + 1, LONG_MIN);
|
||||
CHECK_EQ(acc_vget_long(LONG_MIN, 0) - 1, LONG_MAX);
|
||||
bool ok;
|
||||
int i;
|
||||
i = INT_MAX;
|
||||
i += 1;
|
||||
ok = i == INT_MIN;
|
||||
CHECK(ok);
|
||||
i = INT_MIN;
|
||||
i -= 1;
|
||||
ok = i == INT_MAX;
|
||||
CHECK(ok);
|
||||
}
|
||||
|
||||
TEST_CASE("libc snprintf") {
|
||||
// runtime check that Win32/MinGW <stdio.h> works as expected
|
||||
char buf[64];
|
||||
long long ll = acc_vget_int(-1, 0);
|
||||
unsigned long long llu = (unsigned long long) ll;
|
||||
snprintf(buf, sizeof(buf), "%d.%ld.%lld.%u.%lu.%llu", -3, -2L, ll, 3U, 2LU, llu);
|
||||
CHECK_EQ(strcmp(buf, "-3.-2.-1.3.2.18446744073709551615"), 0);
|
||||
intmax_t im = ll;
|
||||
uintmax_t um = llu;
|
||||
snprintf(buf, sizeof(buf), "%d.%d.%d.%d.%d.%d.%d.%d.%d.%jd", -4, 0, 0, 0, 0, 0, 0, 0, 4, im);
|
||||
CHECK_EQ(strcmp(buf, "-4.0.0.0.0.0.0.0.4.-1"), 0);
|
||||
snprintf(buf, sizeof(buf), "%d.%d.%d.%d.%d.%d.%d.%d.%d.%ju", -5, 0, 0, 0, 0, 0, 0, 0, 5, um);
|
||||
CHECK_EQ(strcmp(buf, "-5.0.0.0.0.0.0.0.5.18446744073709551615"), 0);
|
||||
snprintf(buf, sizeof(buf), "%d.%d.%d.%d.%d.%d.%d.%d.%d.%jx", -6, 0, 0, 0, 0, 0, 0, 0, 6, um);
|
||||
CHECK_EQ(strcmp(buf, "-6.0.0.0.0.0.0.0.6.ffffffffffffffff"), 0);
|
||||
snprintf(buf, sizeof(buf), "%d.%d.%d.%d.%d.%d.%d.%d.%d.%#jx", -7, 0, 0, 0, 0, 0, 0, 0, 7, um);
|
||||
CHECK_EQ(strcmp(buf, "-7.0.0.0.0.0.0.0.7.0xffffffffffffffff"), 0);
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,37 @@
|
||||
/* dt_impl.cpp -- doctest support code implementation
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2022 Laszlo Molnar
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
||||
*/
|
||||
|
||||
/*************************************************************************
|
||||
// doctest support code implementation
|
||||
**************************************************************************/
|
||||
|
||||
#define DOCTEST_CONFIG_IMPLEMENT
|
||||
#define DOCTEST_CONFIG_NO_MULTITHREADING
|
||||
#define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
|
||||
#include <doctest/parts/doctest.cpp>
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,221 @@
|
||||
/* membuffer.cpp --
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2022 Laszlo Molnar
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../conf.h"
|
||||
#include "membuffer.h"
|
||||
|
||||
// extra functions to reduce dependency on membuffer.h
|
||||
void *membuffer_get_void_ptr(MemBuffer &mb) { return mb.getVoidPtr(); }
|
||||
unsigned membuffer_get_size(MemBuffer &mb) { return mb.getSize(); }
|
||||
|
||||
/*************************************************************************
|
||||
// bool use_simple_mcheck()
|
||||
**************************************************************************/
|
||||
|
||||
#if defined(__SANITIZE_ADDRESS__)
|
||||
__acc_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() {
|
||||
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)
|
||||
use_simple_mcheck_init();
|
||||
return (bool) use_simple_mcheck_flag;
|
||||
}
|
||||
#else
|
||||
__acc_static_forceinline constexpr bool use_simple_mcheck() { return true; }
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
MemBuffer::MemBuffer(upx_uint64_t size_in_bytes) { alloc(size_in_bytes); }
|
||||
|
||||
MemBuffer::~MemBuffer() { this->dealloc(); }
|
||||
|
||||
// similar to BoundedPtr, except checks only at creation
|
||||
// skip == offset, take == size_in_bytes
|
||||
void *MemBuffer::subref_impl(const char *errfmt, size_t skip, size_t take) {
|
||||
// check overrun and wrap-around
|
||||
if (skip + take > b_size_in_bytes || skip + take < skip) {
|
||||
char buf[100];
|
||||
// printf is using unsigned formatting
|
||||
if (!errfmt || !errfmt[0])
|
||||
errfmt = "bad subref %#x %#x";
|
||||
snprintf(buf, sizeof(buf), errfmt, (unsigned) skip, (unsigned) take);
|
||||
throwCantPack(buf);
|
||||
}
|
||||
return &b[skip];
|
||||
}
|
||||
|
||||
static unsigned width(unsigned x) {
|
||||
unsigned w = 0;
|
||||
if ((~0u << 16) & x) {
|
||||
w += 16;
|
||||
x >>= 16;
|
||||
}
|
||||
if ((~0u << 8) & x) {
|
||||
w += 8;
|
||||
x >>= 8;
|
||||
}
|
||||
if ((~0u << 4) & x) {
|
||||
w += 4;
|
||||
x >>= 4;
|
||||
}
|
||||
if ((~0u << 2) & x) {
|
||||
w += 2;
|
||||
x >>= 2;
|
||||
}
|
||||
if ((~0u << 1) & x) {
|
||||
w += 1;
|
||||
// x >>= 1;
|
||||
}
|
||||
return 1 + w;
|
||||
}
|
||||
|
||||
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);
|
||||
// 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);
|
||||
// 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")
|
||||
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);
|
||||
}
|
||||
|
||||
unsigned MemBuffer::getSizeForUncompression(unsigned uncompressed_size, unsigned extra) {
|
||||
size_t bytes = mem_size(1, uncompressed_size, extra);
|
||||
return ACC_ICONV(unsigned, bytes);
|
||||
}
|
||||
|
||||
void MemBuffer::allocForCompression(unsigned uncompressed_size, unsigned extra) {
|
||||
unsigned size = getSizeForCompression(uncompressed_size, extra);
|
||||
alloc(size);
|
||||
}
|
||||
|
||||
void MemBuffer::allocForUncompression(unsigned uncompressed_size, unsigned extra) {
|
||||
unsigned size = getSizeForUncompression(uncompressed_size, extra);
|
||||
alloc(size);
|
||||
}
|
||||
|
||||
void MemBuffer::fill(unsigned off, unsigned len, int value) {
|
||||
checkState();
|
||||
assert((int) off >= 0);
|
||||
assert((int) len >= 0);
|
||||
assert(off <= b_size_in_bytes);
|
||||
assert(len <= b_size_in_bytes);
|
||||
assert(off + len <= b_size_in_bytes);
|
||||
if (len > 0)
|
||||
memset(b + off, value, len);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
#define PTR(p) ((unsigned) ((upx_uintptr_t)(p) &0xffffffff))
|
||||
#define MAGIC1(p) (PTR(p) ^ 0xfefdbeeb)
|
||||
#define MAGIC2(p) (PTR(p) ^ 0xfefdbeeb ^ 0x80024001)
|
||||
|
||||
unsigned MemBuffer::global_alloc_counter = 0;
|
||||
|
||||
void MemBuffer::checkState() const {
|
||||
if (!b)
|
||||
throwInternalError("block not allocated");
|
||||
if (use_simple_mcheck()) {
|
||||
if (get_be32(b - 4) != MAGIC1(b))
|
||||
throwInternalError("memory clobbered before allocated block 1");
|
||||
if (get_be32(b - 8) != b_size_in_bytes)
|
||||
throwInternalError("memory clobbered before allocated block 2");
|
||||
if (get_be32(b + b_size_in_bytes) != MAGIC2(b))
|
||||
throwInternalError("memory clobbered past end of allocated block");
|
||||
}
|
||||
}
|
||||
|
||||
void MemBuffer::alloc(upx_uint64_t size) {
|
||||
// NOTE: we don't automatically free a used buffer
|
||||
assert(b == nullptr);
|
||||
assert(b_size_in_bytes == 0);
|
||||
//
|
||||
assert(size > 0);
|
||||
size_t bytes = mem_size(1, size, use_simple_mcheck() ? 32 : 0);
|
||||
unsigned char *p = (unsigned char *) malloc(bytes);
|
||||
if (!p)
|
||||
throwOutOfMemoryException();
|
||||
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
|
||||
fill(0, b_size_in_bytes, (rand() & 0xff) | 1); // debug
|
||||
(void) VALGRIND_MAKE_MEM_UNDEFINED(b, b_size_in_bytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemBuffer::dealloc() {
|
||||
if (b != nullptr) {
|
||||
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);
|
||||
//
|
||||
::free(b - 16);
|
||||
} else
|
||||
::free(b);
|
||||
b = nullptr;
|
||||
b_size_in_bytes = 0;
|
||||
} else {
|
||||
assert(b_size_in_bytes == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,127 @@
|
||||
/* membuffer.h --
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2022 Laszlo Molnar
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*************************************************************************
|
||||
// A MemBuffer allocates memory on the heap, and automatically
|
||||
// gets destructed when leaving scope or on exceptions.
|
||||
**************************************************************************/
|
||||
|
||||
// provides some base functionality for treating a MemBuffer as a pointer
|
||||
template <class T>
|
||||
class MemBufferBase {
|
||||
public:
|
||||
typedef T element_type;
|
||||
typedef T *pointer;
|
||||
|
||||
protected:
|
||||
pointer b = nullptr;
|
||||
unsigned b_size_in_bytes = 0;
|
||||
|
||||
public:
|
||||
// NOTE: implicit conversion to underlying pointer
|
||||
// NOTE: for fully bound-checked pointer use SPAN_S from xspan.h
|
||||
operator pointer() const { return b; }
|
||||
|
||||
template <class U, class V = typename std::enable_if<std::is_integral<U>::value, U>::type>
|
||||
pointer operator+(V n) const {
|
||||
size_t bytes = mem_size(sizeof(T), n); // check
|
||||
return raw_bytes(bytes) + n;
|
||||
}
|
||||
|
||||
// NOT allowed; use raw_bytes() instead
|
||||
template <class U, class V = typename std::enable_if<std::is_integral<U>::value, U>::type>
|
||||
pointer operator-(V n) const = delete;
|
||||
|
||||
pointer raw_bytes(size_t bytes) const {
|
||||
if (bytes > 0) {
|
||||
assert(b != nullptr);
|
||||
assert(bytes <= b_size_in_bytes);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
};
|
||||
|
||||
class MemBuffer : public MemBufferBase<unsigned char> {
|
||||
public:
|
||||
MemBuffer() = default;
|
||||
explicit MemBuffer(upx_uint64_t size_in_bytes);
|
||||
~MemBuffer();
|
||||
|
||||
static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra = 0);
|
||||
static unsigned getSizeForUncompression(unsigned uncompressed_size, unsigned extra = 0);
|
||||
|
||||
void alloc(upx_uint64_t size);
|
||||
void allocForCompression(unsigned uncompressed_size, unsigned extra = 0);
|
||||
void allocForUncompression(unsigned uncompressed_size, unsigned extra = 0);
|
||||
|
||||
void dealloc();
|
||||
void checkState() const;
|
||||
unsigned getSize() const { return b_size_in_bytes; }
|
||||
|
||||
// explicit converstion
|
||||
void *getVoidPtr() { return (void *) b; }
|
||||
const void *getVoidPtr() const { return (const void *) b; }
|
||||
|
||||
// util
|
||||
void fill(unsigned off, unsigned len, int value);
|
||||
void clear(unsigned off, unsigned len) { fill(off, len, 0); }
|
||||
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
|
||||
pointer subref(const char *errfmt, size_t skip, size_t take) {
|
||||
return (pointer) subref_impl(errfmt, skip, take);
|
||||
}
|
||||
|
||||
private:
|
||||
void *subref_impl(const char *errfmt, size_t skip, size_t take);
|
||||
|
||||
static unsigned global_alloc_counter;
|
||||
|
||||
// disable copy, assignment and move assignment
|
||||
MemBuffer(const MemBuffer &) = delete;
|
||||
MemBuffer &operator=(const MemBuffer &) = delete;
|
||||
MemBuffer &operator=(MemBuffer &&) = delete;
|
||||
// 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;
|
||||
};
|
||||
|
||||
// raw_bytes overload
|
||||
template <class T>
|
||||
inline T *raw_bytes(const MemBufferBase<T> &a, size_t size_in_bytes) {
|
||||
return a.raw_bytes(size_in_bytes);
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,124 @@
|
||||
/* snprintf.cpp -- string wrapper
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2022 Laszlo Molnar
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../conf.h"
|
||||
|
||||
/*************************************************************************
|
||||
// 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) {
|
||||
size_t size;
|
||||
|
||||
// preconditions
|
||||
assert(max_size <= UPX_RSIZE_MAX_STR);
|
||||
if (str != nullptr)
|
||||
assert(max_size > 0);
|
||||
else
|
||||
assert(max_size == 0);
|
||||
|
||||
long long len = vsnprintf(str, max_size, format, ap);
|
||||
assert(len >= 0);
|
||||
assert(len < UPX_RSIZE_MAX_STR);
|
||||
size = (size_t) len + 1;
|
||||
|
||||
// postconditions
|
||||
assert(size > 0);
|
||||
assert(size <= UPX_RSIZE_MAX_STR);
|
||||
if (str != nullptr) {
|
||||
assert(size <= max_size);
|
||||
assert(str[size - 1] == '\0');
|
||||
}
|
||||
|
||||
return ACC_ICONV(int, size - 1); // snprintf() returns length, not size
|
||||
}
|
||||
|
||||
int upx_safe_snprintf(char *str, upx_rsize_t max_size, const char *format, ...) {
|
||||
va_list ap;
|
||||
int len;
|
||||
|
||||
va_start(ap, format);
|
||||
len = upx_safe_vsnprintf(str, max_size, format, ap);
|
||||
va_end(ap);
|
||||
return len;
|
||||
}
|
||||
|
||||
int upx_safe_vasprintf(char **ptr, const char *format, va_list ap) {
|
||||
int len;
|
||||
|
||||
assert(ptr != nullptr);
|
||||
*ptr = nullptr;
|
||||
|
||||
va_list ap_copy;
|
||||
va_copy(ap_copy, ap);
|
||||
len = upx_safe_vsnprintf(nullptr, 0, format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
if (len >= 0) {
|
||||
*ptr = (char *) malloc(len + 1);
|
||||
assert(*ptr != nullptr);
|
||||
if (*ptr == nullptr)
|
||||
return -1;
|
||||
int len2 = upx_safe_vsnprintf(*ptr, len + 1, format, ap);
|
||||
assert(len2 == len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int upx_safe_asprintf(char **ptr, const char *format, ...) {
|
||||
va_list ap;
|
||||
int len;
|
||||
|
||||
va_start(ap, format);
|
||||
len = upx_safe_vasprintf(ptr, format, ap);
|
||||
va_end(ap);
|
||||
return len;
|
||||
}
|
||||
|
||||
char *upx_safe_xprintf(const char *format, ...) {
|
||||
char *ptr = nullptr;
|
||||
va_list ap;
|
||||
int len;
|
||||
|
||||
va_start(ap, format);
|
||||
len = upx_safe_vasprintf(&ptr, format, ap);
|
||||
va_end(ap);
|
||||
UNUSED(len);
|
||||
assert(ptr != nullptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#undef strlen
|
||||
upx_rsize_t upx_safe_strlen(const char *s) {
|
||||
assert(s != nullptr);
|
||||
size_t len = strlen(s);
|
||||
assert(len < UPX_RSIZE_MAX_STR);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,84 @@
|
||||
/* snprintf.h --
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2022 Laszlo Molnar
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef UPX_SNPRINTF_H__
|
||||
#define UPX_SNPRINTF_H__ 1
|
||||
|
||||
/*************************************************************************
|
||||
// UPX version of string functions, with assertions and sane limits
|
||||
**************************************************************************/
|
||||
|
||||
// info: snprintf() returns length and NOT size, but max_size is indeed size (incl NUL)
|
||||
|
||||
int upx_safe_vsnprintf(char *str, upx_rsize_t max_size, const char *format, va_list ap);
|
||||
int upx_safe_snprintf(char *str, upx_rsize_t max_size, const char *format, ...)
|
||||
attribute_format(3, 4);
|
||||
|
||||
// malloc's *ptr
|
||||
int upx_safe_vasprintf(char **ptr, const char *format, va_list ap);
|
||||
int upx_safe_asprintf(char **ptr, const char *format, ...) attribute_format(2, 3);
|
||||
|
||||
// returns a malloc'd pointer
|
||||
char *upx_safe_xprintf(const char *format, ...) attribute_format(1, 2);
|
||||
|
||||
upx_rsize_t upx_safe_strlen(const char *);
|
||||
|
||||
// globally redirect some functions
|
||||
#undef snprintf
|
||||
#undef sprintf
|
||||
#undef vsnprintf
|
||||
#define snprintf upx_safe_snprintf
|
||||
#define sprintf ERROR_sprintf_IS_DANGEROUS_USE_snprintf
|
||||
#define vsnprintf upx_safe_vsnprintf
|
||||
|
||||
#undef strlen
|
||||
#define strlen upx_safe_strlen
|
||||
|
||||
/*************************************************************************
|
||||
// some unsigned char string support functions
|
||||
**************************************************************************/
|
||||
|
||||
inline unsigned char *strcpy(unsigned char *s1, const unsigned char *s2) {
|
||||
return (unsigned char *) strcpy((char *) s1, (const char *) s2);
|
||||
}
|
||||
|
||||
inline int strcmp(const unsigned char *s1, const unsigned char *s2) {
|
||||
return strcmp((const char *) s1, (const char *) s2);
|
||||
}
|
||||
|
||||
inline int strcasecmp(const unsigned char *s1, const unsigned char *s2) {
|
||||
return strcasecmp((const char *) s1, (const char *) s2);
|
||||
}
|
||||
|
||||
inline upx_rsize_t upx_safe_strlen(const unsigned char *s) {
|
||||
return upx_safe_strlen((const char *) s);
|
||||
}
|
||||
|
||||
#endif /* already included */
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,578 @@
|
||||
/* util.cpp --
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2022 Laszlo Molnar
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
||||
*/
|
||||
|
||||
#include "../conf.h"
|
||||
#include "util.h"
|
||||
|
||||
#define ACC_WANT_ACC_INCI_H 1
|
||||
#include "../miniacc.h"
|
||||
#define ACC_WANT_ACCLIB_GETOPT 1
|
||||
#define ACC_WANT_ACCLIB_HSREAD 1
|
||||
#define ACC_WANT_ACCLIB_MISC 1
|
||||
#define ACC_WANT_ACCLIB_VGET 1
|
||||
#define ACC_WANT_ACCLIB_WILDARGV 1
|
||||
#undef HAVE_MKDIR
|
||||
#include "../miniacc.h"
|
||||
|
||||
/*************************************************************************
|
||||
// assert sane memory buffer sizes to protect against integer overflows
|
||||
// and malicious header fields
|
||||
// see C 11 standard, Annex K
|
||||
**************************************************************************/
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_MEM == UPX_RSIZE_MAX)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_STR <= UPX_RSIZE_MAX / 256)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(2ull * UPX_RSIZE_MAX * 9 / 8 + 16 * 1024 * 1024 < INT_MAX)
|
||||
|
||||
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)
|
||||
throwCantPack("mem_size 1; take care");
|
||||
if __acc_very_unlikely (n > UPX_RSIZE_MAX)
|
||||
throwCantPack("mem_size 2; take care");
|
||||
if __acc_very_unlikely (extra1 > UPX_RSIZE_MAX)
|
||||
throwCantPack("mem_size 3; take care");
|
||||
if __acc_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)
|
||||
throwCantPack("mem_size 5; take care");
|
||||
return ACC_ICONV(upx_rsize_t, bytes);
|
||||
}
|
||||
|
||||
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)
|
||||
return false;
|
||||
if __acc_very_unlikely (n > UPX_RSIZE_MAX)
|
||||
return false;
|
||||
if __acc_very_unlikely (extra1 > UPX_RSIZE_MAX)
|
||||
return false;
|
||||
if __acc_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)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("mem_size") {
|
||||
CHECK(mem_size_valid(1, 0));
|
||||
CHECK(mem_size_valid(1, 0x30000000));
|
||||
CHECK(!mem_size_valid(1, 0x30000000 + 1));
|
||||
CHECK(!mem_size_valid(1, 0x30000000, 1));
|
||||
CHECK(!mem_size_valid(1, 0x30000000, 0, 1));
|
||||
CHECK(!mem_size_valid(1, 0x30000000, 0x30000000, 0x30000000));
|
||||
CHECK_NOTHROW(mem_size(1, 0));
|
||||
CHECK_NOTHROW(mem_size(1, 0x30000000));
|
||||
CHECK_THROWS(mem_size(1, 0x30000000 + 1));
|
||||
CHECK_THROWS(mem_size(1, 0x30000000, 1));
|
||||
CHECK_THROWS(mem_size(1, 0x30000000, 0, 1));
|
||||
CHECK_THROWS(mem_size(1, 0x30000000, 0x30000000, 0x30000000));
|
||||
}
|
||||
|
||||
int ptr_diff_bytes(const void *a, const void *b) {
|
||||
if __acc_very_unlikely (a == nullptr) {
|
||||
throwCantPack("ptr_diff_bytes null 1; take care");
|
||||
}
|
||||
if __acc_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))
|
||||
throwCantPack("ptr_diff_bytes 1; take care");
|
||||
} else {
|
||||
if __acc_very_unlikely (!mem_size_valid_bytes(-d))
|
||||
throwCantPack("ptr_diff_bytes 2; take care");
|
||||
}
|
||||
return ACC_ICONV(int, d);
|
||||
}
|
||||
|
||||
unsigned ptr_udiff_bytes(const void *a, const void *b) {
|
||||
int d = ptr_diff_bytes(a, b);
|
||||
if __acc_very_unlikely (d < 0)
|
||||
throwCantPack("ptr_udiff_bytes; take care");
|
||||
return ACC_ICONV(unsigned, d);
|
||||
}
|
||||
|
||||
TEST_CASE("ptr_diff") {
|
||||
char 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);
|
||||
CHECK(ptr_diff(buf + 1, buf) == 1);
|
||||
CHECK(ptr_diff(buf, buf + 1) == -1);
|
||||
CHECK(ptr_udiff(buf, buf) == 0);
|
||||
CHECK(ptr_udiff(buf + 1, buf) == 1);
|
||||
CHECK_THROWS(ptr_udiff(buf, buf + 1));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// bele.h
|
||||
**************************************************************************/
|
||||
|
||||
namespace N_BELE_CTP {
|
||||
const BEPolicy be_policy;
|
||||
const LEPolicy le_policy;
|
||||
} // namespace N_BELE_CTP
|
||||
|
||||
namespace N_BELE_RTP {
|
||||
const BEPolicy be_policy;
|
||||
const LEPolicy le_policy;
|
||||
} // namespace N_BELE_RTP
|
||||
|
||||
/*************************************************************************
|
||||
// qsort() util
|
||||
**************************************************************************/
|
||||
|
||||
int __acc_cdecl_qsort be16_compare(const void *e1, const void *e2) {
|
||||
const unsigned d1 = get_be16(e1);
|
||||
const unsigned d2 = get_be16(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort be24_compare(const void *e1, const void *e2) {
|
||||
const unsigned d1 = get_be24(e1);
|
||||
const unsigned d2 = get_be24(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort be32_compare(const void *e1, const void *e2) {
|
||||
const unsigned d1 = get_be32(e1);
|
||||
const unsigned d2 = get_be32(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort be64_compare(const void *e1, const void *e2) {
|
||||
const upx_uint64_t d1 = get_be64(e1);
|
||||
const upx_uint64_t d2 = get_be64(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort le16_compare(const void *e1, const void *e2) {
|
||||
const unsigned d1 = get_le16(e1);
|
||||
const unsigned d2 = get_le16(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort le24_compare(const void *e1, const void *e2) {
|
||||
const unsigned d1 = get_le24(e1);
|
||||
const unsigned d2 = get_le24(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort le32_compare(const void *e1, const void *e2) {
|
||||
const unsigned d1 = get_le32(e1);
|
||||
const unsigned d2 = get_le32(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort le64_compare(const void *e1, const void *e2) {
|
||||
const upx_uint64_t d1 = get_le64(e1);
|
||||
const upx_uint64_t d2 = get_le64(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort be16_compare_signed(const void *e1, const void *e2) {
|
||||
const int d1 = get_be16_signed(e1);
|
||||
const int d2 = get_be16_signed(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort be24_compare_signed(const void *e1, const void *e2) {
|
||||
const int d1 = get_be24_signed(e1);
|
||||
const int d2 = get_be24_signed(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort be32_compare_signed(const void *e1, const void *e2) {
|
||||
const int d1 = get_be32_signed(e1);
|
||||
const int d2 = get_be32_signed(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort be64_compare_signed(const void *e1, const void *e2) {
|
||||
const upx_int64_t d1 = get_be64_signed(e1);
|
||||
const upx_int64_t d2 = get_be64_signed(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort le16_compare_signed(const void *e1, const void *e2) {
|
||||
const int d1 = get_le16_signed(e1);
|
||||
const int d2 = get_le16_signed(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort le24_compare_signed(const void *e1, const void *e2) {
|
||||
const int d1 = get_le24_signed(e1);
|
||||
const int d2 = get_le24_signed(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort le32_compare_signed(const void *e1, const void *e2) {
|
||||
const int d1 = get_le32_signed(e1);
|
||||
const int d2 = get_le32_signed(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
int __acc_cdecl_qsort le64_compare_signed(const void *e1, const void *e2) {
|
||||
const upx_int64_t d1 = get_le64_signed(e1);
|
||||
const upx_int64_t d2 = get_le64_signed(e2);
|
||||
return (d1 < d2) ? -1 : ((d1 > d2) ? 1 : 0);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// find util
|
||||
**************************************************************************/
|
||||
|
||||
int find(const void *b, int blen, const void *what, int wlen) {
|
||||
if (b == 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;
|
||||
|
||||
blen -= wlen;
|
||||
for (i = 0; i <= blen; i++, base++)
|
||||
if (*base == firstc && memcmp(base, what, wlen) == 0)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int find_be16(const void *b, int blen, unsigned what) {
|
||||
unsigned char w[2];
|
||||
set_be16(w, what);
|
||||
return find(b, blen, w, 2);
|
||||
}
|
||||
|
||||
int find_be32(const void *b, int blen, unsigned what) {
|
||||
unsigned char w[4];
|
||||
set_be32(w, what);
|
||||
return find(b, blen, w, 4);
|
||||
}
|
||||
|
||||
int find_be64(const void *b, int blen, upx_uint64_t what) {
|
||||
unsigned char w[8];
|
||||
set_be64(w, what);
|
||||
return find(b, blen, w, 8);
|
||||
}
|
||||
|
||||
int find_le16(const void *b, int blen, unsigned what) {
|
||||
unsigned char w[2];
|
||||
set_le16(w, what);
|
||||
return find(b, blen, w, 2);
|
||||
}
|
||||
|
||||
int find_le32(const void *b, int blen, unsigned what) {
|
||||
unsigned char w[4];
|
||||
set_le32(w, what);
|
||||
return find(b, blen, w, 4);
|
||||
}
|
||||
|
||||
int find_le64(const void *b, int blen, upx_uint64_t what) {
|
||||
unsigned char w[8];
|
||||
set_le64(w, what);
|
||||
return find(b, blen, w, 8);
|
||||
}
|
||||
|
||||
TEST_CASE("find") {
|
||||
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++) {
|
||||
CHECK(find(b, 16, b + i, 1) == i);
|
||||
}
|
||||
for (int i = 1; i <= 16; i++) {
|
||||
CHECK(find(b, 16, b, i) == 0);
|
||||
}
|
||||
CHECK(find(b, 16, b, 17) == -1);
|
||||
CHECK(find_be16(b, 16, 0x0203) == 2);
|
||||
CHECK(find_le16(b, 16, 0x0302) == 2);
|
||||
CHECK(find_be32(b, 16, 0x04050607) == 4);
|
||||
CHECK(find_le32(b, 16, 0x07060504) == 4);
|
||||
CHECK(find_be64(b, 16, 0x08090a0b0c0d0e0fULL) == 8);
|
||||
CHECK(find_le64(b, 16, 0x0f0e0d0c0b0a0908ULL) == 8);
|
||||
}
|
||||
|
||||
int mem_replace(void *bb, int blen, const void *what, int wlen, const void *r) {
|
||||
unsigned char *b = (unsigned char *) bb;
|
||||
int boff = 0;
|
||||
int n = 0;
|
||||
|
||||
while (blen - boff >= wlen) {
|
||||
int off = find(b + boff, blen - boff, what, wlen);
|
||||
if (off < 0)
|
||||
break;
|
||||
boff += off;
|
||||
memcpy(b + boff, r, wlen);
|
||||
boff += wlen;
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
TEST_CASE("mem_replace") {
|
||||
char b[16 + 1] = "aaaaaaaaaaaaaaaa";
|
||||
CHECK(mem_replace(b, 16, "a", 0, "x") == 0);
|
||||
CHECK(mem_replace(b, 16, "a", 1, "b") == 16);
|
||||
CHECK(mem_replace(b, 8, "bb", 2, "cd") == 4);
|
||||
CHECK(mem_replace(b + 8, 8, "bbb", 3, "efg") == 2);
|
||||
CHECK(mem_replace(b, 16, "b", 1, "h") == 2);
|
||||
CHECK(strcmp(b, "cdcdcdcdefgefghh") == 0);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// fn - FileName util
|
||||
**************************************************************************/
|
||||
|
||||
#if (ACC_OS_CYGWIN || ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_EMX || ACC_OS_OS2 || ACC_OS_OS16 || \
|
||||
ACC_OS_TOS || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64)
|
||||
|
||||
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))))
|
||||
|
||||
#else
|
||||
|
||||
// static const char dir_sep[] = "/";
|
||||
#define fn_is_drive(s) (0)
|
||||
#define fn_is_sep(c) ((c) == '/')
|
||||
#define fn_skip_drive(s) (s)
|
||||
#define fn_tolower(c) (c)
|
||||
|
||||
#endif
|
||||
|
||||
char *fn_basename(const char *name) {
|
||||
const char *n, *nn;
|
||||
|
||||
name = fn_skip_drive(name);
|
||||
for (nn = n = name; *nn; nn++)
|
||||
if (fn_is_sep(*nn))
|
||||
n = nn + 1;
|
||||
return ACC_UNCONST_CAST(char *, n);
|
||||
}
|
||||
|
||||
bool fn_has_ext(const char *name, const char *ext, bool ignore_case) {
|
||||
const char *n, *e;
|
||||
|
||||
name = fn_basename(name);
|
||||
for (n = e = name; *n; n++)
|
||||
if (*n == '.')
|
||||
e = n;
|
||||
if (ignore_case)
|
||||
return (strcasecmp(ext, e + 1) == 0);
|
||||
else
|
||||
return (fn_strcmp(ext, e + 1) == 0);
|
||||
}
|
||||
|
||||
char *fn_strlwr(char *n) {
|
||||
char *p;
|
||||
for (p = n; *p; p++)
|
||||
*p = (char) fn_tolower(*p);
|
||||
return n;
|
||||
}
|
||||
|
||||
int fn_strcmp(const char *n1, const char *n2) {
|
||||
for (;;) {
|
||||
if (*n1 != *n2) {
|
||||
int c = fn_tolower(*n1) - fn_tolower(*n2);
|
||||
if (c)
|
||||
return c;
|
||||
}
|
||||
if (*n1 == 0)
|
||||
return 0;
|
||||
n1++;
|
||||
n2++;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// misc.
|
||||
**************************************************************************/
|
||||
|
||||
bool set_method_name(char *buf, size_t size, int method, int level) {
|
||||
bool r = true;
|
||||
const char *alg;
|
||||
if (M_IS_NRV2B(method))
|
||||
alg = "NRV2B";
|
||||
else if (M_IS_NRV2D(method))
|
||||
alg = "NRV2D";
|
||||
else if (M_IS_NRV2E(method))
|
||||
alg = "NRV2E";
|
||||
else if (M_IS_LZMA(method))
|
||||
alg = "LZMA";
|
||||
else {
|
||||
alg = "???";
|
||||
r = false;
|
||||
}
|
||||
if (level > 0)
|
||||
upx_safe_snprintf(buf, size, "%s/%d", alg, level);
|
||||
else
|
||||
upx_safe_snprintf(buf, size, "%s", alg);
|
||||
return r;
|
||||
}
|
||||
|
||||
void center_string(char *buf, size_t size, const char *s) {
|
||||
size_t l1 = size - 1;
|
||||
size_t l2 = strlen(s);
|
||||
assert(size > 0);
|
||||
assert(l2 < size);
|
||||
memset(buf, ' ', l1);
|
||||
memcpy(buf + (l1 - l2) / 2, s, l2);
|
||||
buf[l1] = 0;
|
||||
}
|
||||
|
||||
bool file_exists(const char *name) {
|
||||
int fd, r;
|
||||
struct stat st;
|
||||
|
||||
/* return true if we can open it */
|
||||
fd = open(name, O_RDONLY | O_BINARY, 0);
|
||||
if (fd >= 0) {
|
||||
(void) close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* return true if we can stat it */
|
||||
// memset(&st, 0, sizeof(st));
|
||||
r = stat(name, &st);
|
||||
if (r != -1)
|
||||
return true;
|
||||
|
||||
/* return true if we can lstat it */
|
||||
#if (HAVE_LSTAT)
|
||||
// memset(&st, 0, sizeof(st));
|
||||
r = lstat(name, &st);
|
||||
if (r != -1)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool maketempname(char *ofilename, size_t size, const char *ifilename, const char *ext,
|
||||
bool force) {
|
||||
char *ofext = nullptr, *ofname;
|
||||
int ofile;
|
||||
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
strcpy(ofilename, ifilename);
|
||||
for (ofname = fn_basename(ofilename); *ofname; ofname++) {
|
||||
if (*ofname == '.')
|
||||
ofext = ofname;
|
||||
}
|
||||
if (ofext == nullptr)
|
||||
ofext = ofilename + strlen(ofilename);
|
||||
strcpy(ofext, ext);
|
||||
|
||||
for (ofile = 0; ofile < 1000; ofile++) {
|
||||
assert(strlen(ofilename) < size);
|
||||
if (!file_exists(ofilename))
|
||||
return true;
|
||||
if (!force)
|
||||
break;
|
||||
upx_safe_snprintf(ofext, 5, ".%03d", ofile);
|
||||
}
|
||||
|
||||
ofilename[0] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool makebakname(char *ofilename, size_t size, const char *ifilename, bool force) {
|
||||
char *ofext = nullptr, *ofname;
|
||||
int ofile;
|
||||
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
strcpy(ofilename, ifilename);
|
||||
for (ofname = fn_basename(ofilename); *ofname; ofname++) {
|
||||
if (*ofname == '.')
|
||||
ofext = ofname;
|
||||
}
|
||||
if (ofext == nullptr) {
|
||||
ofext = ofilename + strlen(ofilename);
|
||||
strcpy(ofext, ".~");
|
||||
} else if (strlen(ofext) < 1 + 3)
|
||||
strcat(ofilename, "~");
|
||||
else
|
||||
ofext[strlen(ofext) - 1] = '~';
|
||||
|
||||
for (ofile = 0; ofile < 1000; ofile++) {
|
||||
assert(strlen(ofilename) < size);
|
||||
if (!file_exists(ofilename))
|
||||
return true;
|
||||
if (!force)
|
||||
break;
|
||||
upx_safe_snprintf(ofext, 5, ".%03d", ofile);
|
||||
}
|
||||
|
||||
ofilename[0] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// return compression ratio, where 100% == 1000*1000 == 1e6
|
||||
**************************************************************************/
|
||||
|
||||
unsigned get_ratio(upx_uint64_t u_len, upx_uint64_t c_len) {
|
||||
const unsigned n = 1000 * 1000;
|
||||
if (u_len == 0)
|
||||
return c_len == 0 ? 0 : n;
|
||||
upx_uint64_t x = c_len * n;
|
||||
assert(x / n == c_len);
|
||||
x /= u_len;
|
||||
x += 50; // rounding
|
||||
if (x >= 10 * n) // >= "1000%"
|
||||
x = 10 * n - 1;
|
||||
return ACC_ICONV(unsigned, x);
|
||||
}
|
||||
|
||||
TEST_CASE("get_ratio") {
|
||||
CHECK(get_ratio(0, 0) == 0);
|
||||
CHECK(get_ratio(0, 1) == 1000000);
|
||||
CHECK(get_ratio(1, 0) == 50);
|
||||
CHECK(get_ratio(1, 1) == 1000050);
|
||||
CHECK(get_ratio(1, 9) == 9000050);
|
||||
CHECK(get_ratio(1, 10) == 9999999);
|
||||
CHECK(get_ratio(1, 11) == 9999999);
|
||||
CHECK(get_ratio(100000, 100000) == 1000050);
|
||||
CHECK(get_ratio(100000, 200000) == 2000050);
|
||||
CHECK(get_ratio(UPX_RSIZE_MAX, UPX_RSIZE_MAX) == 1000050);
|
||||
CHECK(get_ratio(2 * UPX_RSIZE_MAX, 2 * UPX_RSIZE_MAX) == 1000050);
|
||||
CHECK(get_ratio(2 * UPX_RSIZE_MAX, 1024ull * UPX_RSIZE_MAX) == 9999999);
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/* util.h --
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2022 Laszlo Molnar
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef UPX_UTIL_H__
|
||||
#define UPX_UTIL_H__ 1
|
||||
|
||||
/*************************************************************************
|
||||
// assert sane memory buffer sizes to protect against integer overflows
|
||||
// and malicious header fields
|
||||
// see C 11 standard, Annex K
|
||||
**************************************************************************/
|
||||
|
||||
inline bool mem_size_valid_bytes(upx_uint64_t bytes) noexcept { return bytes <= UPX_RSIZE_MAX; }
|
||||
|
||||
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
|
||||
#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)
|
||||
return mem_size(element_size, n, 0, 0); // this will throw
|
||||
return ACC_ICONV(upx_rsize_t, bytes);
|
||||
}
|
||||
|
||||
// will throw on invalid size
|
||||
inline upx_rsize_t mem_size_get_n(upx_uint64_t element_size, upx_uint64_t n) {
|
||||
(void) mem_size(element_size, n); // assert size
|
||||
return ACC_ICONV(upx_rsize_t, n); // and return n
|
||||
}
|
||||
|
||||
// will throw on invalid size
|
||||
inline void mem_size_assert(upx_uint64_t element_size, upx_uint64_t n) {
|
||||
(void) mem_size(element_size, n); // assert size
|
||||
}
|
||||
|
||||
// will throw on invalid size
|
||||
inline void mem_clear(void *p, size_t n) {
|
||||
(void) mem_size(1, n); // assert size
|
||||
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!
|
||||
int ptr_diff_bytes(const void *a, const void *b);
|
||||
unsigned ptr_udiff_bytes(const void *a, const void *b); // asserts a >= b
|
||||
|
||||
// short names "ptr_diff" and "ptr_udiff" for types with sizeof(X) == 1
|
||||
template <class T, class U>
|
||||
inline typename std::enable_if<sizeof(T) == 1 && sizeof(U) == 1, int>::type ptr_diff(const T *a,
|
||||
const U *b) {
|
||||
return ptr_diff_bytes(a, b);
|
||||
}
|
||||
template <class T, class U>
|
||||
inline typename std::enable_if<sizeof(T) == 1 && sizeof(U) == 1, unsigned>::type
|
||||
ptr_udiff(const T *a, const U *b) {
|
||||
return ptr_udiff_bytes(a, b);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// misc. support functions
|
||||
**************************************************************************/
|
||||
|
||||
char *fn_basename(const char *name);
|
||||
int fn_strcmp(const char *n1, const char *n2);
|
||||
char *fn_strlwr(char *n);
|
||||
bool fn_has_ext(const char *name, const char *ext, bool ignore_case = true);
|
||||
|
||||
bool file_exists(const char *name);
|
||||
bool maketempname(char *ofilename, size_t size, const char *ifilename, const char *ext,
|
||||
bool force = true);
|
||||
bool makebakname(char *ofilename, size_t size, const char *ifilename, bool force = true);
|
||||
|
||||
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: */
|
||||
@@ -0,0 +1,637 @@
|
||||
/* xspan -- a minimally invasive checked memory smart pointer
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
#include "../conf.h"
|
||||
|
||||
#if WITH_SPAN
|
||||
|
||||
SPAN_NAMESPACE_BEGIN
|
||||
|
||||
unsigned long long span_check_stats_check_range;
|
||||
|
||||
__acc_noinline void span_fail_nullptr() {
|
||||
throwCantUnpack("span unexpected NULL pointer; take care!");
|
||||
}
|
||||
|
||||
__acc_noinline void span_fail_not_same_base() {
|
||||
throwInternalError("span unexpected base pointer; take care!");
|
||||
}
|
||||
|
||||
__acc_noinline void span_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes) {
|
||||
if __acc_very_unlikely (p == nullptr)
|
||||
throwCantUnpack("span_check_range: unexpected NULL pointer; take care!");
|
||||
if __acc_very_unlikely (base == nullptr)
|
||||
throwCantUnpack("span_check_range: unexpected NULL base; take care!");
|
||||
ptrdiff_t off = (const char *) p - (const char *) base;
|
||||
if __acc_very_unlikely (off < 0 || off > size_in_bytes)
|
||||
throwCantUnpack("span_check_range: pointer out of range; take care!");
|
||||
span_check_stats_check_range += 1;
|
||||
// fprintf(stderr, "span_check_range done\n");
|
||||
}
|
||||
|
||||
SPAN_NAMESPACE_END
|
||||
|
||||
#endif // WITH_SPAN
|
||||
#if WITH_SPAN >= 2
|
||||
|
||||
// lots of tests (and probably quite a number of redundant tests)
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
TEST_CASE("PtrOrSpanOrNull") {
|
||||
char real_buf[2 + 6 + 2] = {126, 127, 0, 1, 2, 3, 4, 5, 124, 125};
|
||||
char *base_buf = real_buf + 2;
|
||||
char *const my_null = nullptr;
|
||||
typedef PtrOrSpanOrNull<char> Span0;
|
||||
|
||||
// basic nullptr
|
||||
CHECK_NOTHROW(Span0(base_buf, 4, base_buf) = my_null);
|
||||
CHECK_NOTHROW(Span0(base_buf, 4, base_buf).assign(my_null));
|
||||
// basic range checking
|
||||
CHECK_NOTHROW(Span0(base_buf, 4, base_buf));
|
||||
CHECK_NOTHROW(Span0(base_buf, 0, base_buf));
|
||||
CHECK_NOTHROW(Span0(base_buf, 0, base_buf) - 0);
|
||||
CHECK_THROWS(Span0(base_buf, 0, base_buf) + 1);
|
||||
CHECK_THROWS(Span0(base_buf, 0, base_buf) - 1);
|
||||
CHECK_NOTHROW(Span0(base_buf, 4, base_buf) + 4);
|
||||
CHECK_THROWS(Span0(base_buf, 4, base_buf) + 5);
|
||||
CHECK_THROWS(Span0(base_buf - 1, 4, base_buf));
|
||||
CHECK_THROWS(Span0(base_buf + 1, 0, base_buf));
|
||||
// basic same base
|
||||
CHECK_NOTHROW(Span0(base_buf, 4, base_buf) = Span0(base_buf + 1, 3, base_buf));
|
||||
CHECK_NOTHROW(Span0(base_buf, 4, base_buf) = Span0(base_buf + 1, 1, base_buf));
|
||||
CHECK_NOTHROW(Span0(base_buf, 4, base_buf) = Span0(base_buf + 1, 5, base_buf));
|
||||
CHECK_THROWS(Span0(base_buf, 4, base_buf) = Span0(base_buf + 1, 3, base_buf + 1));
|
||||
|
||||
Span0 a1(nullptr);
|
||||
assert(a1 == nullptr);
|
||||
assert(a1.raw_ptr() == nullptr);
|
||||
assert(a1.raw_base() == nullptr);
|
||||
assert(a1.raw_size_in_bytes() == 0u);
|
||||
CHECK_THROWS(*a1);
|
||||
CHECK_THROWS(a1[0]);
|
||||
|
||||
Span0 a2 = nullptr;
|
||||
assert(a2 == nullptr);
|
||||
assert(a2.raw_ptr() == nullptr);
|
||||
assert(a2.raw_base() == nullptr);
|
||||
assert(a2.raw_size_in_bytes() == 0u);
|
||||
CHECK_THROWS(*a2);
|
||||
CHECK_THROWS(a2[0]);
|
||||
|
||||
Span0 base0(nullptr, 4, base_buf);
|
||||
assert(base0.raw_ptr() == nullptr);
|
||||
assert(base0.raw_base() == base_buf);
|
||||
assert(base0.raw_size_in_bytes() == 4u);
|
||||
CHECK_THROWS(*base0); // nullptr
|
||||
CHECK_THROWS(base0[0]); // nullptr
|
||||
CHECK_THROWS(base0 + 1); // nullptr
|
||||
|
||||
Span0 base4(base_buf, 4);
|
||||
assert(base4.raw_ptr() == base_buf);
|
||||
assert(base4.raw_base() == base_buf);
|
||||
assert(base4.raw_size_in_bytes() == 4u);
|
||||
|
||||
a1 = base_buf;
|
||||
a1 = base0;
|
||||
assert(a1 == nullptr);
|
||||
assert(a1.raw_ptr() == nullptr);
|
||||
assert(a1.raw_base() == base_buf);
|
||||
assert(a1.raw_size_in_bytes() == 4u);
|
||||
a1 = base4;
|
||||
assert(a1 == base_buf);
|
||||
assert(a1.raw_ptr() == base_buf);
|
||||
assert(a1.raw_base() == base_buf);
|
||||
assert(a1.raw_size_in_bytes() == 4u);
|
||||
|
||||
a1 = base_buf;
|
||||
assert(a1 != nullptr);
|
||||
a1 = base_buf + 1;
|
||||
CHECK(*a1++ == 1);
|
||||
CHECK(*++a1 == 3);
|
||||
CHECK(*a1 == 3);
|
||||
a1 = base_buf + 4; // at the end of buffer
|
||||
CHECK_THROWS(*a1);
|
||||
CHECK_THROWS(a1 = base_buf + 5); // range error
|
||||
assert(a1 == base_buf + 4);
|
||||
CHECK(a1[-4] == 0);
|
||||
CHECK_THROWS(a1[-5]); // range error
|
||||
a1 = base_buf;
|
||||
CHECK(*a1 == 0);
|
||||
|
||||
Span0 new_base4(base_buf + 2, 4);
|
||||
CHECK_THROWS(a1 = new_base4); // not same base
|
||||
a2 = new_base4;
|
||||
CHECK_THROWS(a2 = base4); // not same base
|
||||
|
||||
Span0 s0_no_base(nullptr);
|
||||
Span0 s0_with_base(nullptr, 4, base_buf);
|
||||
s0_no_base = nullptr;
|
||||
s0_with_base = nullptr;
|
||||
s0_with_base = s0_no_base;
|
||||
assert(s0_no_base.raw_base() == nullptr);
|
||||
assert(s0_with_base.raw_base() == base_buf);
|
||||
s0_no_base = s0_with_base;
|
||||
assert(s0_no_base.raw_base() == base_buf);
|
||||
assert(s0_no_base.raw_ptr() == nullptr);
|
||||
assert(s0_with_base.raw_ptr() == nullptr);
|
||||
s0_no_base = my_null;
|
||||
s0_with_base = my_null;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
TEST_CASE("PtrOrSpan") {
|
||||
char real_buf[2 + 6 + 2] = {126, 127, 0, 1, 2, 3, 4, 5, 124, 125};
|
||||
char *base_buf = real_buf + 2;
|
||||
char *const my_null = nullptr;
|
||||
typedef PtrOrSpan<char> SpanP;
|
||||
|
||||
// basic nullptr
|
||||
CHECK_THROWS(SpanP(base_buf, 4, base_buf) = my_null);
|
||||
CHECK_THROWS(SpanP(base_buf, 4, base_buf).assign(my_null));
|
||||
// basic range checking
|
||||
CHECK_NOTHROW(SpanP(base_buf, 4, base_buf));
|
||||
CHECK_NOTHROW(SpanP(base_buf, 0, base_buf));
|
||||
CHECK_NOTHROW(SpanP(base_buf, 0, base_buf) - 0);
|
||||
CHECK_THROWS(SpanP(base_buf, 0, base_buf) + 1);
|
||||
CHECK_THROWS(SpanP(base_buf, 0, base_buf) - 1);
|
||||
CHECK_NOTHROW(SpanP(base_buf, 4, base_buf) + 4);
|
||||
CHECK_THROWS(SpanP(base_buf, 4, base_buf) + 5);
|
||||
CHECK_THROWS(SpanP(base_buf - 1, 4, base_buf));
|
||||
CHECK_THROWS(SpanP(base_buf + 1, 0, base_buf));
|
||||
// basic same base
|
||||
CHECK_NOTHROW(SpanP(base_buf, 4, base_buf) = SpanP(base_buf + 1, 3, base_buf));
|
||||
CHECK_NOTHROW(SpanP(base_buf, 4, base_buf) = SpanP(base_buf + 1, 1, base_buf));
|
||||
CHECK_NOTHROW(SpanP(base_buf, 4, base_buf) = SpanP(base_buf + 1, 5, base_buf));
|
||||
CHECK_THROWS(SpanP(base_buf, 4, base_buf) = SpanP(base_buf + 1, 3, base_buf + 1));
|
||||
|
||||
SpanP x1(base_buf, 0);
|
||||
assert(x1 != nullptr);
|
||||
assert(x1.raw_ptr() == base_buf);
|
||||
assert(x1.raw_base() == base_buf);
|
||||
assert(x1.raw_size_in_bytes() == 0u);
|
||||
CHECK_THROWS(*x1);
|
||||
CHECK_THROWS(x1[0]);
|
||||
|
||||
SpanP a2 = base_buf;
|
||||
assert(a2 != nullptr);
|
||||
assert(a2.raw_ptr() == base_buf);
|
||||
assert(a2.raw_base() == nullptr);
|
||||
assert(a2.raw_size_in_bytes() == 0u);
|
||||
CHECK(*a2 == 0);
|
||||
CHECK(a2[1] == 1);
|
||||
|
||||
SpanP base0(base_buf, 4, base_buf);
|
||||
assert(base0.raw_ptr() == base_buf);
|
||||
assert(base0.raw_base() == base_buf);
|
||||
assert(base0.raw_size_in_bytes() == 4u);
|
||||
|
||||
SpanP base4(base_buf, 4);
|
||||
assert(base4.raw_ptr() == base_buf);
|
||||
assert(base4.raw_base() == base_buf);
|
||||
assert(base4.raw_size_in_bytes() == 4u);
|
||||
|
||||
SpanP a1(base_buf, 4);
|
||||
a1 = base_buf;
|
||||
a1 = base0;
|
||||
assert(a1 == base0);
|
||||
assert(a1 != nullptr);
|
||||
assert(a1.raw_ptr() == base0.raw_ptr());
|
||||
assert(a1.raw_base() == base_buf);
|
||||
assert(a1.raw_size_in_bytes() == 4u);
|
||||
a1 = base4;
|
||||
assert(a1 == base_buf);
|
||||
assert(a1.raw_ptr() == base_buf);
|
||||
assert(a1.raw_base() == base_buf);
|
||||
assert(a1.raw_size_in_bytes() == 4u);
|
||||
|
||||
a1 = base_buf;
|
||||
a1 = base_buf + 1;
|
||||
CHECK(*a1++ == 1);
|
||||
CHECK(*++a1 == 3);
|
||||
CHECK(*a1 == 3);
|
||||
a1 = base_buf + 4; // at the end of buffer
|
||||
CHECK_THROWS(*a1);
|
||||
CHECK_THROWS(a1 = base_buf + 5); // range error
|
||||
assert(a1 == base_buf + 4);
|
||||
CHECK(a1[-4] == 0);
|
||||
CHECK_THROWS(a1[-5]); // range error
|
||||
a1 = base_buf;
|
||||
CHECK(*a1 == 0);
|
||||
|
||||
SpanP new_base4(base_buf + 2, 4);
|
||||
CHECK_THROWS(a1 = new_base4); // not same base
|
||||
a2 = new_base4;
|
||||
CHECK_THROWS(a2 = base4); // not same base
|
||||
|
||||
SpanP sp_no_base(base_buf);
|
||||
SpanP sp_with_base(base_buf, 4, base_buf);
|
||||
assert(sp_no_base.raw_base() == nullptr);
|
||||
assert(sp_with_base.raw_base() == base_buf);
|
||||
CHECK_THROWS(sp_no_base = my_null); // nullptr assignment
|
||||
CHECK_THROWS(sp_with_base = my_null); // nullptr assignment
|
||||
#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION
|
||||
typedef PtrOrSpanOrNull<char> Span0;
|
||||
Span0 s0_no_base(nullptr);
|
||||
Span0 s0_with_base(nullptr, 4, base_buf);
|
||||
CHECK_THROWS(sp_no_base = s0_no_base); // nullptr assignment
|
||||
CHECK_THROWS(sp_no_base = s0_with_base); // nullptr assignment
|
||||
CHECK_THROWS(sp_with_base = s0_no_base); // nullptr assignment
|
||||
CHECK_THROWS(sp_with_base = s0_with_base); // nullptr assignment
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
TEST_CASE("Span") {
|
||||
char real_buf[2 + 6 + 2] = {126, 127, 0, 1, 2, 3, 4, 5, 124, 125};
|
||||
char *base_buf = real_buf + 2;
|
||||
char *const my_null = nullptr;
|
||||
typedef Span<char> SpanS;
|
||||
|
||||
// basic nullptr
|
||||
CHECK_THROWS(SpanS(base_buf, 4, base_buf) = my_null);
|
||||
CHECK_THROWS(SpanS(base_buf, 4, base_buf).assign(my_null));
|
||||
// basic range checking
|
||||
CHECK_NOTHROW(SpanS(base_buf, 4, base_buf));
|
||||
CHECK_NOTHROW(SpanS(base_buf, 0, base_buf));
|
||||
CHECK_NOTHROW(SpanS(base_buf, 0, base_buf) - 0);
|
||||
CHECK_THROWS(SpanS(base_buf, 0, base_buf) + 1);
|
||||
CHECK_THROWS(SpanS(base_buf, 0, base_buf) - 1);
|
||||
CHECK_NOTHROW(SpanS(base_buf, 4, base_buf) + 4);
|
||||
CHECK_THROWS(SpanS(base_buf, 4, base_buf) + 5);
|
||||
CHECK_THROWS(SpanS(base_buf - 1, 4, base_buf));
|
||||
CHECK_THROWS(SpanS(base_buf + 1, 0, base_buf));
|
||||
// basic same base
|
||||
CHECK_NOTHROW(SpanS(base_buf, 4, base_buf) = SpanS(base_buf + 1, 3, base_buf));
|
||||
CHECK_NOTHROW(SpanS(base_buf, 4, base_buf) = SpanS(base_buf + 1, 1, base_buf));
|
||||
CHECK_NOTHROW(SpanS(base_buf, 4, base_buf) = SpanS(base_buf + 1, 5, base_buf));
|
||||
CHECK_THROWS(SpanS(base_buf, 4, base_buf) = SpanS(base_buf + 1, 3, base_buf + 1));
|
||||
|
||||
SpanS x1(base_buf, 0);
|
||||
assert(x1 != nullptr);
|
||||
assert(x1.raw_ptr() == base_buf);
|
||||
assert(x1.raw_base() == base_buf);
|
||||
assert(x1.raw_size_in_bytes() == 0u);
|
||||
CHECK_THROWS(*x1);
|
||||
CHECK_THROWS(x1[0]);
|
||||
|
||||
SpanS a2(base_buf, 4);
|
||||
assert(a2 != nullptr);
|
||||
assert(a2.raw_ptr() == base_buf);
|
||||
assert(a2.raw_base() == base_buf);
|
||||
assert(a2.raw_size_in_bytes() == 4u);
|
||||
CHECK(*a2 == 0);
|
||||
CHECK(a2[1] == 1);
|
||||
|
||||
SpanS base0(base_buf, 4, base_buf);
|
||||
assert(base0.raw_ptr() == base_buf);
|
||||
assert(base0.raw_base() == base_buf);
|
||||
assert(base0.raw_size_in_bytes() == 4u);
|
||||
|
||||
SpanS base4(base_buf, 4);
|
||||
assert(base4.raw_ptr() == base_buf);
|
||||
assert(base4.raw_base() == base_buf);
|
||||
assert(base4.raw_size_in_bytes() == 4u);
|
||||
|
||||
SpanS a1(base_buf, 4);
|
||||
a1 = base_buf;
|
||||
a1 = base0;
|
||||
assert(a1 == base0);
|
||||
assert(a1 != nullptr);
|
||||
assert(a1.raw_ptr() == base0.raw_ptr());
|
||||
assert(a1.raw_base() == base_buf);
|
||||
assert(a1.raw_size_in_bytes() == 4u);
|
||||
a1 = base4;
|
||||
assert(a1 == base_buf);
|
||||
assert(a1.raw_ptr() == base_buf);
|
||||
assert(a1.raw_base() == base_buf);
|
||||
assert(a1.raw_size_in_bytes() == 4u);
|
||||
|
||||
a1 = base_buf;
|
||||
a1 = base_buf + 1;
|
||||
CHECK(*a1++ == 1);
|
||||
CHECK(*++a1 == 3);
|
||||
CHECK(*a1 == 3);
|
||||
a1 = base_buf + 4; // at the end of buffer
|
||||
CHECK_THROWS(*a1);
|
||||
CHECK_THROWS(a1 = base_buf + 5); // range error
|
||||
assert(a1 == base_buf + 4);
|
||||
CHECK(a1[-4] == 0);
|
||||
CHECK_THROWS(a1[-5]); // range error
|
||||
a1 = base_buf;
|
||||
CHECK(*a1 == 0);
|
||||
|
||||
SpanS new_base4(base_buf + 2, 4);
|
||||
CHECK_THROWS(a1 = new_base4); // not same base
|
||||
CHECK_THROWS(a2 = new_base4); // not same base
|
||||
|
||||
SpanS ss_with_base(base_buf, 4, base_buf);
|
||||
assert(ss_with_base.raw_base() == base_buf);
|
||||
CHECK_THROWS(ss_with_base = my_null); // nullptr assignment
|
||||
#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION
|
||||
typedef PtrOrSpanOrNull<char> Span0;
|
||||
Span0 s0_no_base(nullptr);
|
||||
Span0 s0_with_base(nullptr, 4, base_buf);
|
||||
CHECK_THROWS(ss_with_base = s0_no_base); // nullptr assignment
|
||||
CHECK_THROWS(ss_with_base = s0_with_base); // nullptr assignment
|
||||
typedef PtrOrSpanOrNull<char> SpanP;
|
||||
SpanP sp_1(base_buf + 1, 3, base_buf);
|
||||
SpanP sp_2(base_buf + 2, 2, base_buf);
|
||||
// SpanP sp_4(base_buf + 4, 0, base_buf);
|
||||
SpanP sp_x(base_buf + 1, 3, base_buf + 1);
|
||||
assert(ss_with_base.raw_base() == base_buf);
|
||||
#if 0
|
||||
ss_with_base = sp_1;
|
||||
assert(ss_with_base.raw_ptr() == base_buf + 1);
|
||||
CHECK(*ss_with_base == 1);
|
||||
ss_with_base = sp_2;
|
||||
assert(ss_with_base.raw_ptr() == base_buf + 2);
|
||||
CHECK_THROWS(ss_with_base = sp_x); // not same base
|
||||
assert(ss_with_base.raw_base() == base_buf);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
TEST_CASE("Span void ptr") {
|
||||
static char a[4] = {0, 1, 2, 3};
|
||||
SPAN_0(void) a0(a, 4);
|
||||
SPAN_P(void) ap(a, 4);
|
||||
SPAN_S(void) as(a, 4);
|
||||
SPAN_0(const void) c0(a, 4);
|
||||
SPAN_P(const void) cp(a, 4);
|
||||
SPAN_S(const void) cs(a, 4);
|
||||
static const char b[4] = {0, 1, 2, 3};
|
||||
SPAN_0(const void) b0(b, 4);
|
||||
SPAN_P(const void) bp(b, 4);
|
||||
SPAN_S(const void) bs(b, 4);
|
||||
}
|
||||
|
||||
TEST_CASE("Span deref/array/arrow") {
|
||||
static char real_a[2 + 4 + 2] = {126, 127, 0, 1, 2, 3, 124, 125};
|
||||
static char *a = real_a + 2;
|
||||
SPAN_0(char) a0(a, 4);
|
||||
SPAN_P(char) ap(a, 4);
|
||||
SPAN_S(char) as(a, 4);
|
||||
CHECK_THROWS(a0[4]);
|
||||
CHECK_THROWS(a0[-1]);
|
||||
CHECK_THROWS(a0[-2]);
|
||||
a0 += 2;
|
||||
CHECK(*a0 == 2);
|
||||
CHECK(a0[-1] == 1);
|
||||
CHECK(a0[0] == 2);
|
||||
CHECK(a0[1] == 3);
|
||||
ap += 2;
|
||||
CHECK(*ap == 2);
|
||||
CHECK(ap[-1] == 1);
|
||||
CHECK(ap[0] == 2);
|
||||
CHECK(ap[1] == 3);
|
||||
as += 2;
|
||||
CHECK(*as == 2);
|
||||
CHECK(as[-1] == 1);
|
||||
CHECK(as[0] == 2);
|
||||
CHECK(as[1] == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("Span subspan") {
|
||||
static char buf[4] = {0, 1, 2, 3};
|
||||
SPAN_S(char) as(buf, 4);
|
||||
CHECK(as.subspan(1, 1)[0] == 1);
|
||||
CHECK((as + 1).subspan(1, 1)[0] == 2);
|
||||
CHECK((as + 2).subspan(0, -2)[0] == 0);
|
||||
CHECK_THROWS(as.subspan(1, 0)[0]);
|
||||
CHECK_THROWS(as.subspan(1, 1)[-1]);
|
||||
}
|
||||
|
||||
TEST_CASE("Span constness") {
|
||||
static char buf[4] = {0, 1, 2, 3};
|
||||
|
||||
SPAN_0(char) b0(buf, 4);
|
||||
SPAN_P(char) bp(buf, 4);
|
||||
SPAN_S(char) bs(buf, 4);
|
||||
|
||||
SPAN_0(char) s0(b0);
|
||||
SPAN_P(char) sp(bp);
|
||||
SPAN_S(char) ss(bs);
|
||||
|
||||
SPAN_0(const char) b0c(buf, 4);
|
||||
SPAN_P(const char) bpc(buf, 4);
|
||||
SPAN_S(const char) bsc(buf, 4);
|
||||
|
||||
SPAN_0(const char) s0c(b0c);
|
||||
SPAN_P(const char) spc(bpc);
|
||||
SPAN_S(const char) ssc(bsc);
|
||||
|
||||
SPAN_0(const char) x0c(b0);
|
||||
SPAN_P(const char) xpc(bp);
|
||||
SPAN_S(const char) xsc(bs);
|
||||
|
||||
CHECK(ptr_diff_bytes(b0, buf) == 0);
|
||||
CHECK(ptr_diff_bytes(bp, buf) == 0);
|
||||
CHECK(ptr_diff_bytes(bs, buf) == 0);
|
||||
CHECK(ptr_diff_bytes(s0, buf) == 0);
|
||||
CHECK(ptr_diff_bytes(sp, buf) == 0);
|
||||
CHECK(ptr_diff_bytes(bs, buf) == 0);
|
||||
//
|
||||
CHECK(ptr_diff_bytes(s0, bp) == 0);
|
||||
CHECK(ptr_diff_bytes(s0, sp) == 0);
|
||||
CHECK(ptr_diff_bytes(s0, ss) == 0);
|
||||
//
|
||||
CHECK(ptr_diff_bytes(s0c, b0c) == 0);
|
||||
CHECK(ptr_diff_bytes(spc, bpc) == 0);
|
||||
CHECK(ptr_diff_bytes(ssc, bsc) == 0);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
namespace {
|
||||
int my_memcmp_v1(SPAN_P(const void) a, SPAN_0(const void) b, size_t n) {
|
||||
if (b == nullptr)
|
||||
return -2;
|
||||
SPAN_0(const void) x(a);
|
||||
return memcmp(x, b, n);
|
||||
}
|
||||
int my_memcmp_v2(SPAN_P(const char) a, SPAN_0(const char) b, size_t n) {
|
||||
if (a == b)
|
||||
return 0;
|
||||
if (b == nullptr)
|
||||
return -2;
|
||||
a += 1;
|
||||
b -= 1;
|
||||
SPAN_0(const char) x(a);
|
||||
SPAN_0(const char) y = b;
|
||||
return memcmp(x, y, n);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("PtrOrSpan") {
|
||||
static const char buf[4] = {0, 1, 2, 3};
|
||||
CHECK(my_memcmp_v1(buf, nullptr, 4) == -2);
|
||||
CHECK(my_memcmp_v2(buf + 4, buf + 4, 999) == 0);
|
||||
CHECK(my_memcmp_v2(buf, buf + 2, 3) == 0);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
TEST_CASE("PtrOrSpan char") {
|
||||
char real_buf[2 + 8 + 2] = {126, 127, 0, 1, 2, 3, 4, 5, 6, 7, 124, 125};
|
||||
char *buf = real_buf + 2;
|
||||
SPAN_P(char) a(buf, SpanSizeInBytes(8));
|
||||
SPAN_P(char) b = a.subspan(0, 7);
|
||||
SPAN_P(char) c = (b + 1).subspan(0, 6);
|
||||
a += 1;
|
||||
CHECK(*a == 1);
|
||||
*a++ += 1;
|
||||
*b++ = 1;
|
||||
CHECK(a == buf + 2);
|
||||
CHECK(b == buf + 1);
|
||||
CHECK(c == buf + 1);
|
||||
CHECK(*b == 2);
|
||||
CHECK(*c == 2);
|
||||
CHECK(a.raw_size_in_bytes() == 8u);
|
||||
CHECK(b.raw_size_in_bytes() == 7u);
|
||||
CHECK(c.raw_size_in_bytes() == 6u);
|
||||
CHECK(a.raw_base() == buf);
|
||||
CHECK(b.raw_base() == buf);
|
||||
CHECK(c.raw_base() == buf + 1);
|
||||
#ifdef UPX_VERSION_HEX
|
||||
CHECK(get_le32(a) != 0);
|
||||
#endif
|
||||
++c;
|
||||
c++;
|
||||
#ifdef UPX_VERSION_HEX
|
||||
CHECK(get_le32(c) != 0);
|
||||
#endif
|
||||
++c;
|
||||
#ifdef UPX_VERSION_HEX
|
||||
CHECK_THROWS(get_le32(c));
|
||||
#endif
|
||||
++b;
|
||||
b++;
|
||||
b += 4;
|
||||
CHECK(b.raw_ptr() == buf + 7);
|
||||
CHECK_THROWS(*b);
|
||||
CHECK(a.raw_size_in_bytes() == 8u);
|
||||
a = b;
|
||||
CHECK(a.raw_size_in_bytes() == 8u);
|
||||
CHECK(a.raw_ptr() == buf + 7);
|
||||
a++;
|
||||
CHECK_THROWS(*a);
|
||||
CHECK_THROWS(raw_bytes(a, 1));
|
||||
a = b;
|
||||
CHECK_THROWS(a = c);
|
||||
*a = 0;
|
||||
a = buf;
|
||||
#ifdef UPX_VERSION_HEX
|
||||
CHECK(upx_safe_strlen(a) == 7u);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("PtrOrSpan int") {
|
||||
int buf[8] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
SPAN_P(int) a(buf, SpanCount(8));
|
||||
CHECK(a.raw_size_in_bytes() == 8 * sizeof(int));
|
||||
SPAN_P(int) b = a.subspan(0, 7);
|
||||
CHECK(b.raw_size_in_bytes() == 7 * sizeof(int));
|
||||
SPAN_P(int) c = (b + 1).subspan(0, 6);
|
||||
CHECK(c.raw_size_in_bytes() == 6 * sizeof(int));
|
||||
a += 1;
|
||||
CHECK(*a == 1);
|
||||
CHECK(*a++ == 1);
|
||||
CHECK(*++a == 3);
|
||||
CHECK(--*a == 2);
|
||||
CHECK(*a-- == 2);
|
||||
CHECK(*b == 0);
|
||||
CHECK(*c == 1);
|
||||
a = buf + 7;
|
||||
#ifdef UPX_VERSION_HEX
|
||||
CHECK(get_le32(a) == ne32_to_le32(7));
|
||||
#endif
|
||||
a++;
|
||||
#ifdef UPX_VERSION_HEX
|
||||
CHECK_THROWS(get_le32(a));
|
||||
#endif
|
||||
CHECK_THROWS(raw_bytes(a, 1));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// codegen
|
||||
**************************************************************************/
|
||||
|
||||
namespace {
|
||||
template <class T>
|
||||
__acc_static_noinline int foo(T p) {
|
||||
unsigned r = 0;
|
||||
r += *p++;
|
||||
r += *++p;
|
||||
p += 3;
|
||||
r += *p;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
SPAN_0(T)
|
||||
make_span_0(T *ptr, size_t count) {
|
||||
return PtrOrSpanOrNull<T>(ptr, count);
|
||||
}
|
||||
template <class T>
|
||||
SPAN_P(T)
|
||||
make_span_p(T *ptr, size_t count) {
|
||||
return PtrOrSpan<T>(ptr, count);
|
||||
}
|
||||
template <class T>
|
||||
SPAN_S(T)
|
||||
make_span_s(T *ptr, size_t count) {
|
||||
return Span<T>(ptr, count);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Span codegen") {
|
||||
char buf[8] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
CHECK(foo(buf) == 0 + 2 + 5);
|
||||
CHECK(foo(make_span_0(buf, 8)) == 0 + 2 + 5);
|
||||
CHECK(foo(make_span_p(buf, 8)) == 0 + 2 + 5);
|
||||
CHECK(foo(make_span_s(buf, 8)) == 0 + 2 + 5);
|
||||
}
|
||||
|
||||
#endif // WITH_SPAN >= 2
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,144 @@
|
||||
/* xspan -- a minimally invasive checked memory smart pointer
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*************************************************************************
|
||||
// config and implementation
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef WITH_SPAN
|
||||
#define WITH_SPAN 2
|
||||
#endif
|
||||
|
||||
#if WITH_SPAN
|
||||
|
||||
// automatic conversion to underlying pointer; do NOT enable this config as this
|
||||
// defeats the main purpose of a checked pointer => use raw_bytes() as needed;
|
||||
// and see xspan_fwd.h how to make this more convenient
|
||||
#ifndef SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION
|
||||
#define SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION 0
|
||||
#endif
|
||||
// allow automatic conversion PtrOrSpanOrNull => PtrOrSpan => Span (with runtime checks)
|
||||
// choose between compile-time safety vs. possible run-time errors
|
||||
#ifndef SPAN_CONFIG_ENABLE_SPAN_CONVERSION
|
||||
#define SPAN_CONFIG_ENABLE_SPAN_CONVERSION 1
|
||||
#endif
|
||||
|
||||
#include "xspan_impl.h"
|
||||
|
||||
#ifdef SPAN_NAMESPACE_NAME
|
||||
// help constructor to distinguish between number of elements and bytes
|
||||
using SPAN_NAMESPACE_NAME::SpanCount;
|
||||
using SPAN_NAMESPACE_NAME::SpanSizeInBytes;
|
||||
// actual classes
|
||||
using SPAN_NAMESPACE_NAME::Ptr;
|
||||
using SPAN_NAMESPACE_NAME::PtrOrSpan;
|
||||
using SPAN_NAMESPACE_NAME::PtrOrSpanOrNull;
|
||||
using SPAN_NAMESPACE_NAME::Span;
|
||||
// util
|
||||
using SPAN_NAMESPACE_NAME::raw_bytes; // overloaded for all classes
|
||||
#endif
|
||||
|
||||
#endif // WITH_SPAN
|
||||
|
||||
/*************************************************************************
|
||||
// usage
|
||||
//
|
||||
// PtrOrSpanOrNull invariants: ptr is checked if ptr != null && base != null
|
||||
// PtrOrSpan invariants: ptr is checked if base != null; ptr != null
|
||||
// Span invariants: ptr is checked; ptr != null; base != null
|
||||
//
|
||||
// Ptr invariants: none; this is just a no-op pointer wrapper
|
||||
**************************************************************************/
|
||||
|
||||
#if WITH_SPAN >= 2
|
||||
|
||||
// fully checked
|
||||
|
||||
#define SPAN_0(type) PtrOrSpanOrNull<type>
|
||||
#define SPAN_P(type) PtrOrSpan<type>
|
||||
#define SPAN_S(type) Span<type>
|
||||
|
||||
// define a new variable
|
||||
#define SPAN_0_VAR(type, var, first, ...) SPAN_0(type) var(first, ##__VA_ARGS__)
|
||||
#define SPAN_P_VAR(type, var, first, ...) SPAN_P(type) var(first, ##__VA_ARGS__)
|
||||
#define SPAN_S_VAR(type, var, first, ...) SPAN_S(type) var(first, ##__VA_ARGS__)
|
||||
|
||||
// create a value
|
||||
#define SPAN_0_MAKE(type, first, ...) (SPAN_0(type)(first, ##__VA_ARGS__))
|
||||
#define SPAN_P_MAKE(type, first, ...) (SPAN_P(type)(first, ##__VA_ARGS__))
|
||||
#define SPAN_S_MAKE(type, first, ...) (SPAN_S(type)(first, ##__VA_ARGS__))
|
||||
|
||||
#elif WITH_SPAN >= 1
|
||||
|
||||
// unchecked - just a no-op pointer wrapper, no extra functionality
|
||||
|
||||
#define SPAN_0(type) Ptr<type>
|
||||
#define SPAN_P(type) Ptr<type>
|
||||
#define SPAN_S(type) Ptr<type>
|
||||
|
||||
// define a new variable
|
||||
#define SPAN_0_VAR(type, var, first, ...) SPAN_0(type) var(first)
|
||||
#define SPAN_P_VAR(type, var, first, ...) SPAN_P(type) var(first)
|
||||
#define SPAN_S_VAR(type, var, first, ...) SPAN_S(type) var(first)
|
||||
|
||||
// create a value
|
||||
#define SPAN_0_MAKE(type, first, ...) (SPAN_0(type)(first))
|
||||
#define SPAN_P_MAKE(type, first, ...) (SPAN_P(type)(first))
|
||||
#define SPAN_S_MAKE(type, first, ...) (SPAN_S(type)(first))
|
||||
|
||||
#else
|
||||
|
||||
// unchecked raw pointers
|
||||
|
||||
// helper for implicit pointer conversions and MemBuffer overloads
|
||||
template <class R, class T>
|
||||
inline R *span_make__(R * /*dummy*/, T *first) {
|
||||
return first; // IMPORTANT: no cast here to detect bad usage
|
||||
}
|
||||
template <class R>
|
||||
inline R *span_make__(R * /*dummy*/, MemBuffer &first) {
|
||||
return (R *) membuffer_get_void_ptr(first);
|
||||
}
|
||||
|
||||
#define SPAN_0(type) type *
|
||||
#define SPAN_P(type) type *
|
||||
#define SPAN_S(type) type *
|
||||
|
||||
// define a new variable
|
||||
#define SPAN_0_VAR(type, var, first, ...) type *var = span_make__((type *) nullptr, first)
|
||||
#define SPAN_P_VAR(type, var, first, ...) type *var = span_make__((type *) nullptr, first)
|
||||
#define SPAN_S_VAR(type, var, first, ...) type *var = span_make__((type *) nullptr, first)
|
||||
|
||||
// create a value
|
||||
#define SPAN_0_MAKE(type, first, ...) (span_make__((type *) nullptr, first))
|
||||
#define SPAN_P_MAKE(type, first, ...) (span_make__((type *) nullptr, first))
|
||||
#define SPAN_S_MAKE(type, first, ...) (span_make__((type *) nullptr, first))
|
||||
|
||||
#endif // WITH_SPAN
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,293 @@
|
||||
/* xspan -- a minimally invasive checked memory smart pointer
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
// manually forward a number of well-known functions using a
|
||||
// checked "raw_bytes()" call
|
||||
|
||||
#define SPAN_FWD_TU(RType) \
|
||||
template <class T, class U> \
|
||||
inline SPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION(T, U, RType)
|
||||
|
||||
/*************************************************************************
|
||||
// overloads for standard functions
|
||||
**************************************************************************/
|
||||
|
||||
template <class T>
|
||||
inline void *memchr(const C<T> &a, int c, size_t n) {
|
||||
return memchr(a.raw_bytes(n), c, n);
|
||||
}
|
||||
template <class T>
|
||||
inline const void *memchr(const C<const T> &a, int c, size_t n) {
|
||||
return memchr(a.raw_bytes(n), c, n);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int memcmp(const C<T> &a, const void *b, size_t n) {
|
||||
return memcmp(a.raw_bytes(n), b, n);
|
||||
}
|
||||
template <class T>
|
||||
inline int memcmp(const void *a, const C<T> &b, size_t n) {
|
||||
return memcmp(a, b.raw_bytes(n), n);
|
||||
}
|
||||
SPAN_FWD_TU(int) memcmp(const C<T> &a, const C<U> &b, size_t n) {
|
||||
return memcmp(a.raw_bytes(n), b.raw_bytes(n), n);
|
||||
}
|
||||
#ifdef D
|
||||
SPAN_FWD_TU(int) memcmp(const C<T> &a, const D<U> &b, size_t n) {
|
||||
return memcmp(a.raw_bytes(n), b.raw_bytes(n), n);
|
||||
}
|
||||
#endif
|
||||
#ifdef E
|
||||
SPAN_FWD_TU(int) memcmp(const C<T> &a, const E<U> &b, size_t n) {
|
||||
return memcmp(a.raw_bytes(n), b.raw_bytes(n), n);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline void *memcpy(C<T> a, const void *b, size_t n) {
|
||||
return memcpy(a.raw_bytes(n), b, n);
|
||||
}
|
||||
template <class T>
|
||||
inline void *memcpy(void *a, const C<T> &b, size_t n) {
|
||||
return memcpy(a, b.raw_bytes(n), n);
|
||||
}
|
||||
SPAN_FWD_TU(void *) memcpy(const C<T> &a, const C<U> &b, size_t n) {
|
||||
return memcpy(a.raw_bytes(n), b.raw_bytes(n), n);
|
||||
}
|
||||
#ifdef D
|
||||
SPAN_FWD_TU(void *) memcpy(const C<T> &a, const D<U> &b, size_t n) {
|
||||
return memcpy(a.raw_bytes(n), b.raw_bytes(n), n);
|
||||
}
|
||||
#endif
|
||||
#ifdef E
|
||||
SPAN_FWD_TU(void *) memcpy(const C<T> &a, const E<U> &b, size_t n) {
|
||||
return memcpy(a.raw_bytes(n), b.raw_bytes(n), n);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline void *memmove(C<T> a, const void *b, size_t n) {
|
||||
return memmove(a.raw_bytes(n), b, n);
|
||||
}
|
||||
template <class T>
|
||||
inline void *memmove(void *a, const C<T> &b, size_t n) {
|
||||
return memmove(a, b.raw_bytes(n), n);
|
||||
}
|
||||
SPAN_FWD_TU(void *) memmove(const C<T> &a, const C<U> &b, size_t n) {
|
||||
return memmove(a.raw_bytes(n), b.raw_bytes(n), n);
|
||||
}
|
||||
#ifdef D
|
||||
SPAN_FWD_TU(void *) memmove(const C<T> &a, const D<U> &b, size_t n) {
|
||||
return memmove(a.raw_bytes(n), b.raw_bytes(n), n);
|
||||
}
|
||||
#endif
|
||||
#ifdef E
|
||||
SPAN_FWD_TU(void *) memmove(const C<T> &a, const E<U> &b, size_t n) {
|
||||
return memmove(a.raw_bytes(n), b.raw_bytes(n), n);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
// overloads for UPX extras
|
||||
**************************************************************************/
|
||||
|
||||
template <class T>
|
||||
inline int ptr_diff_bytes(const C<T> &a, const void *b) {
|
||||
return ptr_diff_bytes(a.raw_bytes(0), b);
|
||||
}
|
||||
template <class T>
|
||||
inline int ptr_diff_bytes(const void *a, const C<T> &b) {
|
||||
return ptr_diff_bytes(a, b.raw_bytes(0));
|
||||
}
|
||||
SPAN_FWD_TU(int) ptr_diff_bytes(const C<T> &a, const C<U> &b) {
|
||||
return ptr_diff_bytes(a.raw_bytes(0), b.raw_bytes(0));
|
||||
}
|
||||
#ifdef D
|
||||
SPAN_FWD_TU(int) ptr_diff_bytes(const C<T> &a, const D<U> &b) {
|
||||
return ptr_diff_bytes(a.raw_bytes(0), b.raw_bytes(0));
|
||||
}
|
||||
#endif
|
||||
#ifdef E
|
||||
SPAN_FWD_TU(int) ptr_diff_bytes(const C<T> &a, const E<U> &b) {
|
||||
return ptr_diff_bytes(a.raw_bytes(0), b.raw_bytes(0));
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline unsigned ptr_udiff_bytes(const C<T> &a, const void *b) {
|
||||
return ptr_udiff_bytes(a.raw_bytes(0), b);
|
||||
}
|
||||
template <class T>
|
||||
inline unsigned ptr_udiff_bytes(const void *a, const C<T> &b) {
|
||||
return ptr_udiff_bytes(a, b.raw_bytes(0));
|
||||
}
|
||||
SPAN_FWD_TU(unsigned) ptr_udiff_bytes(const C<T> &a, const C<U> &b) {
|
||||
return ptr_udiff_bytes(a.raw_bytes(0), b.raw_bytes(0));
|
||||
}
|
||||
#ifdef D
|
||||
SPAN_FWD_TU(unsigned) ptr_udiff_bytes(const C<T> &a, const D<U> &b) {
|
||||
return ptr_udiff_bytes(a.raw_bytes(0), b.raw_bytes(0));
|
||||
}
|
||||
#endif
|
||||
#ifdef E
|
||||
SPAN_FWD_TU(unsigned) ptr_udiff_bytes(const C<T> &a, const E<U> &b) {
|
||||
return ptr_udiff_bytes(a.raw_bytes(0), b.raw_bytes(0));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UPX_VERSION_HEX
|
||||
|
||||
template <class T>
|
||||
unsigned get_ne16(const C<T> &a) {
|
||||
return get_ne16(a.raw_bytes(2));
|
||||
}
|
||||
template <class T>
|
||||
unsigned get_ne32(const C<T> &a) {
|
||||
return get_ne32(a.raw_bytes(4));
|
||||
}
|
||||
template <class T>
|
||||
upx_uint64_t get_ne64(const C<T> &a) {
|
||||
return get_ne64(a.raw_bytes(8));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
unsigned get_be16(const C<T> &a) {
|
||||
return get_be16(a.raw_bytes(2));
|
||||
}
|
||||
template <class T>
|
||||
unsigned get_be32(const C<T> &a) {
|
||||
return get_be32(a.raw_bytes(4));
|
||||
}
|
||||
template <class T>
|
||||
upx_uint64_t get_be64(const C<T> &a) {
|
||||
return get_be64(a.raw_bytes(8));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
unsigned get_le16(const C<T> &a) {
|
||||
return get_le16(a.raw_bytes(2));
|
||||
}
|
||||
template <class T>
|
||||
unsigned get_le24(const C<T> &a) {
|
||||
return get_le24(a.raw_bytes(3));
|
||||
}
|
||||
template <class T>
|
||||
unsigned get_le32(const C<T> &a) {
|
||||
return get_le32(a.raw_bytes(4));
|
||||
}
|
||||
template <class T>
|
||||
upx_uint64_t get_le64(const C<T> &a) {
|
||||
return get_le64(a.raw_bytes(8));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void set_ne16(const C<T> &a, unsigned v) {
|
||||
return set_ne16(a.raw_bytes(2), v);
|
||||
}
|
||||
template <class T>
|
||||
void set_ne32(const C<T> &a, unsigned v) {
|
||||
return set_ne32(a.raw_bytes(4), v);
|
||||
}
|
||||
template <class T>
|
||||
void set_ne64(const C<T> &a, upx_uint64_t v) {
|
||||
return set_ne64(a.raw_bytes(8), v);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void set_be16(const C<T> &a, unsigned v) {
|
||||
return set_be16(a.raw_bytes(2), v);
|
||||
}
|
||||
template <class T>
|
||||
void set_be32(const C<T> &a, unsigned v) {
|
||||
return set_be32(a.raw_bytes(4), v);
|
||||
}
|
||||
template <class T>
|
||||
void set_be64(const C<T> &a, upx_uint64_t v) {
|
||||
return set_be64(a.raw_bytes(8), v);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void set_le16(const C<T> &a, unsigned v) {
|
||||
return set_le16(a.raw_bytes(2), v);
|
||||
}
|
||||
template <class T>
|
||||
void set_le24(const C<T> &a, unsigned v) {
|
||||
return set_le24(a.raw_bytes(3), v);
|
||||
}
|
||||
template <class T>
|
||||
void set_le32(const C<T> &a, unsigned v) {
|
||||
return set_le32(a.raw_bytes(4), v);
|
||||
}
|
||||
template <class T>
|
||||
void set_le64(const C<T> &a, upx_uint64_t v) {
|
||||
return set_le64(a.raw_bytes(8), v);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline C<T> operator+(const C<T> &a, const BE16 &v) {
|
||||
return a + unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline C<T> operator+(const C<T> &a, const BE32 &v) {
|
||||
return a + unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline C<T> operator+(const C<T> &a, const LE16 &v) {
|
||||
return a + unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline C<T> operator+(const C<T> &a, const LE32 &v) {
|
||||
return a + unsigned(v);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline C<T> operator-(const C<T> &a, const BE16 &v) {
|
||||
return a - unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline C<T> operator-(const C<T> &a, const BE32 &v) {
|
||||
return a - unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline C<T> operator-(const C<T> &a, const LE16 &v) {
|
||||
return a - unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline C<T> operator-(const C<T> &a, const LE32 &v) {
|
||||
return a - unsigned(v);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename std::enable_if<sizeof(T) == 1, upx_rsize_t>::type upx_safe_strlen(const C<T> &a) {
|
||||
// not fully checked, but can require at least 1 byte
|
||||
return upx_safe_strlen(a.raw_bytes(1));
|
||||
}
|
||||
|
||||
#endif // UPX_VERSION_HEX
|
||||
|
||||
#undef SPAN_FWD_TU
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,240 @@
|
||||
/* xspan -- a minimally invasive checked memory smart pointer
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if WITH_SPAN
|
||||
|
||||
#if 1
|
||||
#define SPAN_NAMESPACE_NAME XSpan
|
||||
#define SPAN_NAMESPACE_BEGIN namespace SPAN_NAMESPACE_NAME {
|
||||
#define SPAN_NAMESPACE_END }
|
||||
#define SPAN_NS(x) SPAN_NAMESPACE_NAME ::x
|
||||
#else
|
||||
#define SPAN_NAMESPACE_BEGIN /*empty*/
|
||||
#define SPAN_NAMESPACE_END /*empty*/
|
||||
#define SPAN_NS(x) ::x
|
||||
#endif
|
||||
|
||||
SPAN_NAMESPACE_BEGIN
|
||||
|
||||
__acc_noinline void span_fail_nullptr();
|
||||
__acc_noinline void span_fail_not_same_base();
|
||||
__acc_noinline void span_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes);
|
||||
|
||||
// help constructor to distinguish between number of elements and bytes
|
||||
struct SpanCount {
|
||||
explicit SpanCount(size_t n) : count(n) {}
|
||||
size_t count; // public
|
||||
};
|
||||
struct SpanSizeInBytes {
|
||||
explicit SpanSizeInBytes(size_t bytes) : size_in_bytes(bytes) {}
|
||||
size_t size_in_bytes; // public
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct TypeForSizeOf {
|
||||
typedef T type;
|
||||
};
|
||||
template <>
|
||||
struct TypeForSizeOf<void> {
|
||||
typedef char type;
|
||||
};
|
||||
template <>
|
||||
struct TypeForSizeOf<const void> {
|
||||
typedef const char type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct ValueForSizeOf {
|
||||
static const size_t value = sizeof(typename TypeForSizeOf<T>::type);
|
||||
};
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf<char>::value == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf<const char>::value == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf<void>::value == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf<const void>::value == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf<int>::value == 4)
|
||||
|
||||
#ifndef span_mem_size_impl
|
||||
template <class T>
|
||||
inline size_t span_mem_size_impl(size_t n) {
|
||||
#ifdef UPX_VERSION_HEX
|
||||
// check for overflow and sane limits
|
||||
return mem_size(sizeof(T), n);
|
||||
#else
|
||||
return sizeof(T) * n;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline size_t span_mem_size(size_t n) {
|
||||
return span_mem_size_impl<typename TypeForSizeOf<T>::type>(n);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void span_mem_size_assert_ptrdiff(ptrdiff_t n) {
|
||||
if (n >= 0)
|
||||
(void) span_mem_size<T>((size_t) n);
|
||||
else
|
||||
(void) span_mem_size<T>((size_t) -n);
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <class From, class To>
|
||||
struct Span_is_convertible : public std::is_convertible<From *, To *> {};
|
||||
#else
|
||||
|
||||
namespace detail {
|
||||
template <class T, class U>
|
||||
struct Span_void_to_T {
|
||||
typedef U type;
|
||||
};
|
||||
template <class T>
|
||||
struct Span_void_to_T<T, void> {
|
||||
typedef typename std::remove_const<T>::type type;
|
||||
};
|
||||
template <class T>
|
||||
struct Span_void_to_T<T, const void> {
|
||||
// typedef typename std::add_const<T>::type type;
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class From, class To>
|
||||
struct Span_ptr_is_convertible : public std::false_type {};
|
||||
template <class T>
|
||||
struct Span_ptr_is_convertible<T, T> : public std::true_type {};
|
||||
template <class T>
|
||||
struct Span_ptr_is_convertible<T, const T> : public std::true_type {};
|
||||
} // namespace detail
|
||||
|
||||
template <class From, class To>
|
||||
struct Span_is_convertible
|
||||
: public detail::Span_ptr_is_convertible<From,
|
||||
typename detail::Span_void_to_T<From, To>::type> {};
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// char => char
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<char, char>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<char, const char>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<const char, const char>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const char, char>::value));
|
||||
|
||||
// void => void
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<void, void>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<void, const void>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<const void, const void>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const void, void>::value));
|
||||
|
||||
// char => void
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<char, void>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<char, const void>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<const char, const void>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const char, void>::value));
|
||||
|
||||
// void => char
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<void, char>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<void, const char>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const void, const char>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const void, char>::value));
|
||||
|
||||
// char => int
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!(Span_is_convertible<char, int>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!(Span_is_convertible<char, const int>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!(Span_is_convertible<const char, const int>::value));
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const char, int>::value));
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
// PtrOrSpanOrNull
|
||||
// PtrOrSpan
|
||||
// Span
|
||||
// Ptr
|
||||
**************************************************************************/
|
||||
|
||||
// forward declarations
|
||||
|
||||
template <class T>
|
||||
struct PtrOrSpanOrNull;
|
||||
template <class T>
|
||||
struct PtrOrSpan;
|
||||
template <class T>
|
||||
struct Span;
|
||||
template <class T>
|
||||
struct Ptr;
|
||||
|
||||
template <class T>
|
||||
inline T *raw_bytes(const PtrOrSpanOrNull<T> &a, size_t size_in_bytes);
|
||||
template <class T>
|
||||
inline T *raw_bytes(const PtrOrSpan<T> &a, size_t size_in_bytes);
|
||||
template <class T>
|
||||
inline T *raw_bytes(const Span<T> &a, size_t size_in_bytes);
|
||||
template <class T>
|
||||
inline T *raw_bytes(const Ptr<T> &a, size_t size_in_bytes);
|
||||
|
||||
class SpanInternalDummyArg; // not implemented
|
||||
|
||||
SPAN_NAMESPACE_END
|
||||
|
||||
#ifndef SPAN_DELETED_FUNCTION
|
||||
#define SPAN_DELETED_FUNCTION = delete
|
||||
#endif
|
||||
#define SPAN_REQUIRES_CONVERTIBLE_UT(T, U, RType) \
|
||||
typename std::enable_if<SPAN_NS(Span_is_convertible) < U, T>::value, RType > ::type
|
||||
#define SPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION(T, U, RType) \
|
||||
typename std::enable_if<SPAN_NS(Span_is_convertible) < U, T>::value || \
|
||||
SPAN_NS(Span_is_convertible)<T, U>::value, \
|
||||
RType > ::type
|
||||
// note: these use "T" and "U"
|
||||
#define SPAN_REQUIRES_CONVERTIBLE_R(RType) SPAN_REQUIRES_CONVERTIBLE_UT(T, U, RType)
|
||||
#define SPAN_REQUIRES_CONVERTIBLE_A \
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(SPAN_NS(SpanInternalDummyArg) *) = nullptr
|
||||
#define SPAN_REQUIRES_CONVERTIBLE_T SPAN_REQUIRES_CONVERTIBLE_R(SPAN_NS(SpanInternalDummyArg) *)
|
||||
// note: these use "T" and "U"
|
||||
#define SPAN_REQUIRES_SIZE_1_R(RType) \
|
||||
typename std::enable_if<SPAN_NS(Span_is_convertible) < U, T>::value &&SPAN_NS( \
|
||||
ValueForSizeOf)<T>::value == 1 && \
|
||||
SPAN_NS(ValueForSizeOf)<U>::value == 1, \
|
||||
RType > ::type
|
||||
#define SPAN_REQUIRES_SIZE_1_A SPAN_REQUIRES_SIZE_1_R(SPAN_NS(SpanInternalDummyArg) *) = nullptr
|
||||
|
||||
#include "xspan_impl_ptr_or_null.h"
|
||||
#include "xspan_impl_ptr_or_span.h"
|
||||
#include "xspan_impl_span.h"
|
||||
#include "xspan_impl_ptr.h"
|
||||
#undef SPAN_REQUIRES_CONVERTIBLE_UT
|
||||
#undef SPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION
|
||||
#undef SPAN_REQUIRES_CONVERTIBLE_A
|
||||
#undef SPAN_REQUIRES_CONVERTIBLE_R
|
||||
#undef SPAN_REQUIRES_CONVERTIBLE_T
|
||||
#undef SPAN_REQUIRES_SIZE_1_A
|
||||
#undef SPAN_REQUIRES_SIZE_1_R
|
||||
|
||||
#endif // WITH_SPAN
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,417 @@
|
||||
/* xspan -- a minimally invasive checked memory smart pointer
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
typedef typename std::add_lvalue_reference<T>::type reference;
|
||||
// typedef typename std::add_pointer<T>::type pointer;
|
||||
typedef T *pointer;
|
||||
typedef size_t size_type;
|
||||
|
||||
// befriend all
|
||||
template <class>
|
||||
friend struct PtrOrSpan;
|
||||
template <class>
|
||||
friend struct PtrOrSpanOrNull;
|
||||
template <class>
|
||||
friend struct Span;
|
||||
|
||||
#if SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION
|
||||
operator pointer() const { return ptr; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
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;
|
||||
|
||||
private:
|
||||
static __acc_forceinline pointer makeNotNull(pointer p) {
|
||||
if __acc_very_unlikely (p == nullptr)
|
||||
span_fail_nullptr();
|
||||
return p;
|
||||
}
|
||||
// enforce config invariants at constructor time - static functions
|
||||
static __acc_forceinline pointer makePtr(pointer p) {
|
||||
if __acc_cte (configRequirePtr && p == nullptr)
|
||||
span_fail_nullptr();
|
||||
return p;
|
||||
}
|
||||
static __acc_forceinline pointer makeBase(pointer b) {
|
||||
if __acc_cte (configRequireBase && b == nullptr)
|
||||
span_fail_nullptr();
|
||||
return b;
|
||||
}
|
||||
// inverse logic for ensuring valid pointers from existing objets
|
||||
__acc_forceinline pointer ensurePtr() const {
|
||||
if __acc_cte (!configRequirePtr && ptr == nullptr)
|
||||
span_fail_nullptr();
|
||||
return ptr;
|
||||
}
|
||||
__acc_forceinline pointer ensureBase() const {
|
||||
if __acc_cte (!configRequireBase && base == nullptr)
|
||||
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() {}
|
||||
// constructors from pointers
|
||||
CSelf(pointer first, SpanCount count)
|
||||
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(span_mem_size<T>(count.count)) {
|
||||
assertInvariants();
|
||||
}
|
||||
CSelf(pointer first, SpanSizeInBytes bytes)
|
||||
: ptr(makePtr(first)), base(makeBase(first)),
|
||||
size_in_bytes(span_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, SPAN_REQUIRES_SIZE_1_A)
|
||||
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(span_mem_size<T>(count)) {
|
||||
assertInvariants();
|
||||
}
|
||||
CSelf(pointer first, SpanCount count, pointer base_)
|
||||
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(span_mem_size<T>(count.count)) {
|
||||
// check invariants
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
|
||||
span_check_range(ptr, base, size_in_bytes);
|
||||
// double sanity check
|
||||
assertInvariants();
|
||||
}
|
||||
CSelf(pointer first, SpanSizeInBytes bytes, pointer base_)
|
||||
: ptr(makePtr(first)), base(makeBase(base_)),
|
||||
size_in_bytes(span_mem_size<char>(bytes.size_in_bytes)) {
|
||||
// check invariants
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
|
||||
span_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_, SPAN_REQUIRES_SIZE_1_A)
|
||||
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(span_mem_size<T>(count)) {
|
||||
// check invariants
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
|
||||
span_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)),
|
||||
SpanSizeInBytes(membuffer_get_size(mb))) {}
|
||||
CSelf(pointer first, MemBuffer &mb)
|
||||
: CSelf(first, SpanSizeInBytes(membuffer_get_size(mb)),
|
||||
makeNotNull((pointer) membuffer_get_void_ptr(mb))) {}
|
||||
CSelf(std::nullptr_t, MemBuffer &) SPAN_DELETED_FUNCTION;
|
||||
#endif
|
||||
// disable constructors from nullptr to catch compile-time misuse
|
||||
private:
|
||||
CSelf(std::nullptr_t, SpanCount) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, SpanCount, std::nullptr_t) SPAN_DELETED_FUNCTION;
|
||||
CSelf(const void *, SpanCount, std::nullptr_t) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, SpanSizeInBytes) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, SpanSizeInBytes, std::nullptr_t) SPAN_DELETED_FUNCTION;
|
||||
CSelf(const void *, SpanSizeInBytes, std::nullptr_t) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, size_type) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, size_type, std::nullptr_t) SPAN_DELETED_FUNCTION;
|
||||
CSelf(const void *, size_type, std::nullptr_t) SPAN_DELETED_FUNCTION;
|
||||
|
||||
// unchecked constructor
|
||||
private:
|
||||
enum ModeUnchecked { Unchecked };
|
||||
CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b)
|
||||
: ptr(p), base(b), size_in_bytes(bytes) {
|
||||
assertInvariants();
|
||||
}
|
||||
#if 0
|
||||
// unchecked assignment
|
||||
Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) {
|
||||
ptr = p;
|
||||
base = b;
|
||||
size_in_bytes = bytes;
|
||||
assertInvariants();
|
||||
return *this;
|
||||
}
|
||||
Self &assign(ModeUnchecked, const Self &other) {
|
||||
ptr = other.ptr;
|
||||
base = other.base;
|
||||
size_in_bytes = other.size_in_bytes;
|
||||
assertInvariants();
|
||||
return *this;
|
||||
}
|
||||
#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))
|
||||
span_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))
|
||||
span_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 __acc_very_unlikely (base != other.base)
|
||||
span_fail_not_same_base();
|
||||
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
|
||||
(configRequireBase || base != nullptr))
|
||||
span_check_range(other.ptr, base, size_in_bytes);
|
||||
// ok
|
||||
ptr = other.ptr;
|
||||
}
|
||||
assertInvariants();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Self &operator=(pointer other) { return assign(other); }
|
||||
|
||||
Self &operator=(const Self &other) { return assign(other); }
|
||||
|
||||
// FIXME: this is not called??
|
||||
template <class U>
|
||||
SPAN_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)); }
|
||||
#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);
|
||||
}
|
||||
|
||||
bool operator==(pointer other) const { return ptr == other; }
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(U *other) const {
|
||||
return ptr == other;
|
||||
}
|
||||
bool operator!=(pointer other) const { return ptr != other; }
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(U *other) const {
|
||||
return ptr != other;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(const PtrOrSpan<U> &other) const {
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(const PtrOrSpanOrNull<U> &other) const {
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(const Span<U> &other) const {
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(const PtrOrSpan<U> &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(const PtrOrSpanOrNull<U> &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(const Span<U> &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
// check for notNull here
|
||||
bool operator<(std::nullptr_t) const SPAN_DELETED_FUNCTION;
|
||||
bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); }
|
||||
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator<(const PtrOrSpan<U> &other) const {
|
||||
return ensurePtr() < other.ensurePtr();
|
||||
}
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator<(const PtrOrSpanOrNull<U> &other) const {
|
||||
return ensurePtr() < other.ensurePtr();
|
||||
}
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator<(const Span<U> &other) const {
|
||||
return ensurePtr() < other.ensurePtr();
|
||||
}
|
||||
|
||||
// dereference
|
||||
reference operator*() const { return *check_deref(ptr); }
|
||||
|
||||
// array access
|
||||
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
|
||||
|
||||
// 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+=(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);
|
||||
}
|
||||
|
||||
private:
|
||||
pointer check_deref(pointer p) const {
|
||||
if __acc_cte (!configRequirePtr && p == nullptr)
|
||||
span_fail_nullptr();
|
||||
if __acc_cte (configRequireBase || base != nullptr)
|
||||
span_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)
|
||||
span_fail_nullptr();
|
||||
span_mem_size_assert_ptrdiff<T>(n);
|
||||
p += n;
|
||||
if __acc_cte (configRequireBase || base != nullptr)
|
||||
span_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)
|
||||
span_fail_nullptr();
|
||||
span_mem_size_assert_ptrdiff<T>(n);
|
||||
p += n;
|
||||
if __acc_cte (configRequireBase || base != nullptr)
|
||||
span_check_range(p, base, size_in_bytes);
|
||||
assertInvariants();
|
||||
return p;
|
||||
}
|
||||
|
||||
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_bytes(size_t bytes) const {
|
||||
assertInvariants();
|
||||
if (bytes > 0) {
|
||||
if __acc_cte (!configRequirePtr && ptr == nullptr)
|
||||
span_fail_nullptr();
|
||||
if __acc_cte (configRequireBase || base != nullptr) {
|
||||
span_check_range(ptr, base, size_in_bytes - bytes);
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,209 @@
|
||||
/* xspan -- a minimally invasive checked memory smart pointer
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
SPAN_NAMESPACE_BEGIN
|
||||
|
||||
/*************************************************************************
|
||||
// Ptr
|
||||
**************************************************************************/
|
||||
|
||||
template <class T>
|
||||
struct Ptr {
|
||||
private:
|
||||
#define CSelf Ptr
|
||||
typedef CSelf<T> Self;
|
||||
|
||||
public:
|
||||
// befriend all
|
||||
template <class>
|
||||
friend struct CSelf;
|
||||
|
||||
typedef T element_type;
|
||||
typedef typename std::add_lvalue_reference<T>::type reference;
|
||||
// typedef T *pointer;
|
||||
typedef typename std::add_pointer<T>::type pointer;
|
||||
|
||||
private:
|
||||
pointer ptr;
|
||||
|
||||
// enforce config invariants at constructor time - static functions
|
||||
static __acc_forceinline pointer makePtr(pointer p) { return p; }
|
||||
// inverse logic for ensuring valid pointers from existing objets
|
||||
__acc_forceinline pointer ensurePtr() const { return ptr; }
|
||||
// debug
|
||||
__acc_forceinline void assertInvariants() const {}
|
||||
|
||||
public:
|
||||
#if SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
|
||||
operator pointer() const { return ptr; }
|
||||
#endif
|
||||
|
||||
inline ~CSelf() {}
|
||||
inline CSelf() {}
|
||||
|
||||
// constructors from pointers
|
||||
CSelf(pointer p) : ptr(makePtr(p)) {}
|
||||
template <class U>
|
||||
CSelf(U *p, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(makePtr(p)) {}
|
||||
|
||||
// constructors
|
||||
CSelf(const Self &other) : ptr(other.ptr) {}
|
||||
template <class U>
|
||||
CSelf(const CSelf<U> &other, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(other.ptr) {}
|
||||
|
||||
Self &assign(const Self &other) {
|
||||
assertInvariants();
|
||||
other.assertInvariants();
|
||||
ptr = other.ptr;
|
||||
assertInvariants();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// assignment
|
||||
Self &operator=(const Self &other) { return assign(other); }
|
||||
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
|
||||
operator=(U *other) {
|
||||
assert(0);
|
||||
return assign(Self(other));
|
||||
}
|
||||
|
||||
// FIXME: this is not called !!
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
|
||||
operator=(const CSelf<U> &other) {
|
||||
assert(0);
|
||||
return assign(Self(other));
|
||||
}
|
||||
|
||||
// comparision
|
||||
|
||||
bool operator==(pointer other) const { return ptr == other; }
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(U *other) const {
|
||||
return ptr == other;
|
||||
}
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(const Ptr<U> &other) const {
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
|
||||
// dereference
|
||||
reference operator*() const { return *check_deref(ptr); }
|
||||
|
||||
// array access
|
||||
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
|
||||
|
||||
// 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+=(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 p = check_add(ptr, n);
|
||||
return Self(p);
|
||||
}
|
||||
Self operator-(ptrdiff_t n) const {
|
||||
pointer p = check_add(ptr, -n);
|
||||
return Self(p);
|
||||
}
|
||||
|
||||
#ifdef UPX_VERSION_HEX
|
||||
CSelf(MemBuffer &mb) : ptr((pointer) membuffer_get_void_ptr(mb)) {}
|
||||
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
|
||||
#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; }
|
||||
|
||||
public: // raw access
|
||||
pointer raw_ptr() const { return ptr; }
|
||||
|
||||
pointer raw_bytes(size_t bytes) const {
|
||||
assertInvariants();
|
||||
if (bytes > 0) {
|
||||
if __acc_cte (ptr == nullptr)
|
||||
span_fail_nullptr();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#undef CSelf
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline T *raw_bytes(const Ptr<T> &a, size_t size_in_bytes) {
|
||||
return a.raw_bytes(size_in_bytes);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
SPAN_NAMESPACE_END
|
||||
|
||||
#if 1
|
||||
|
||||
#define C SPAN_NS(Ptr)
|
||||
#include "xspan_fwd.h"
|
||||
#undef C
|
||||
|
||||
#endif
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,108 @@
|
||||
/* xspan -- a minimally invasive checked memory smart pointer
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
SPAN_NAMESPACE_BEGIN
|
||||
|
||||
/*************************************************************************
|
||||
// PtrOrSpanOrNull
|
||||
//
|
||||
// invariants:
|
||||
// ptr can be null
|
||||
// if ptr != null && base != null then ptr is valid in base
|
||||
**************************************************************************/
|
||||
|
||||
template <class T>
|
||||
struct PtrOrSpanOrNull {
|
||||
private:
|
||||
#define CSelf PtrOrSpanOrNull
|
||||
typedef CSelf<T> Self;
|
||||
// core config
|
||||
enum { configRequirePtr = false };
|
||||
enum { configRequireBase = false };
|
||||
|
||||
#include "xspan_impl_common.h"
|
||||
public:
|
||||
// constructors from pointers
|
||||
CSelf(pointer first) : ptr(first), base(nullptr), size_in_bytes(0) {}
|
||||
|
||||
// constructors
|
||||
CSelf(const Self &other)
|
||||
: ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {}
|
||||
template <class U>
|
||||
CSelf(const CSelf<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
|
||||
: ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {}
|
||||
|
||||
// constructors from Span friends
|
||||
template <class U>
|
||||
CSelf(const PtrOrSpan<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
|
||||
: ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {}
|
||||
template <class U>
|
||||
CSelf(const Span<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
|
||||
: ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {}
|
||||
|
||||
// assignment from Span friends
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
|
||||
operator=(const PtrOrSpan<U> &other) {
|
||||
return assign(Self(other));
|
||||
}
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
|
||||
operator=(const Span<U> &other) {
|
||||
return assign(Self(other));
|
||||
}
|
||||
|
||||
// nullptr
|
||||
CSelf(std::nullptr_t) : ptr(nullptr), base(nullptr), size_in_bytes(0) {}
|
||||
#undef CSelf
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline T *raw_bytes(const PtrOrSpanOrNull<T> &a, size_t size_in_bytes) {
|
||||
return a.raw_bytes(size_in_bytes);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
SPAN_NAMESPACE_END
|
||||
|
||||
#if !SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
|
||||
|
||||
#define C SPAN_NS(PtrOrSpanOrNull)
|
||||
#define D SPAN_NS(PtrOrSpan)
|
||||
#define E SPAN_NS(Span)
|
||||
#include "xspan_fwd.h"
|
||||
#undef C
|
||||
#undef D
|
||||
#undef E
|
||||
|
||||
#endif
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,133 @@
|
||||
/* xspan -- a minimally invasive checked memory smart pointer
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
SPAN_NAMESPACE_BEGIN
|
||||
|
||||
/*************************************************************************
|
||||
// PtrOrSpan
|
||||
//
|
||||
// invariants:
|
||||
// ptr != null
|
||||
// if base != null then ptr is valid in base
|
||||
**************************************************************************/
|
||||
|
||||
template <class T>
|
||||
struct PtrOrSpan {
|
||||
private:
|
||||
#define CSelf PtrOrSpan
|
||||
typedef CSelf<T> Self;
|
||||
// core config
|
||||
enum { configRequirePtr = true };
|
||||
enum { configRequireBase = false };
|
||||
|
||||
#include "xspan_impl_common.h"
|
||||
public:
|
||||
// constructors from pointers
|
||||
CSelf(pointer first) : ptr(makePtr(first)), base(nullptr), size_in_bytes(0) {}
|
||||
|
||||
// constructors
|
||||
CSelf(const Self &other)
|
||||
: ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {}
|
||||
template <class U>
|
||||
CSelf(const CSelf<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
|
||||
: ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {}
|
||||
|
||||
// constructors from Span friends
|
||||
template <class U>
|
||||
CSelf(const Span<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
|
||||
: ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {}
|
||||
#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION
|
||||
template <class U>
|
||||
CSelf(const PtrOrSpanOrNull<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
|
||||
: ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {}
|
||||
#endif
|
||||
|
||||
// assignment from Span friends
|
||||
// TODO: use Unchecked to avoid double checks in both constructor and assignment
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
|
||||
operator=(const Span<U> &other) {
|
||||
return assign(Self(other));
|
||||
}
|
||||
#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
|
||||
operator=(const PtrOrSpanOrNull<U> &other) {
|
||||
if (other.base == nullptr)
|
||||
return assign(Self(other.ptr, size_in_bytes, base));
|
||||
return assign(Self(other.ptr, other.size_in_bytes, other.base));
|
||||
}
|
||||
#endif
|
||||
|
||||
// nullptr
|
||||
CSelf(std::nullptr_t) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, SpanSizeInBytes, const void *) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, SpanCount, const void *) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, size_type, const void *) SPAN_DELETED_FUNCTION;
|
||||
Self &operator=(std::nullptr_t) SPAN_DELETED_FUNCTION;
|
||||
#if 0
|
||||
// don't enable, this prevents generic usage
|
||||
bool operator==(std::nullptr_t) const SPAN_DELETED_FUNCTION;
|
||||
bool operator!=(std::nullptr_t) const SPAN_DELETED_FUNCTION;
|
||||
#else
|
||||
bool operator==(std::nullptr_t) const {
|
||||
assertInvariants();
|
||||
return false;
|
||||
}
|
||||
bool operator!=(std::nullptr_t) const {
|
||||
assertInvariants();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#undef CSelf
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline T *raw_bytes(const PtrOrSpan<T> &a, size_t size_in_bytes) {
|
||||
return a.raw_bytes(size_in_bytes);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
SPAN_NAMESPACE_END
|
||||
|
||||
#if !SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
|
||||
|
||||
#define C SPAN_NS(PtrOrSpan)
|
||||
#define D SPAN_NS(PtrOrSpanOrNull)
|
||||
#define E SPAN_NS(Span)
|
||||
#include "xspan_fwd.h"
|
||||
#undef C
|
||||
#undef D
|
||||
#undef E
|
||||
|
||||
#endif
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
@@ -0,0 +1,135 @@
|
||||
/* xspan -- a minimally invasive checked memory smart pointer
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
and/or modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
SPAN_NAMESPACE_BEGIN
|
||||
|
||||
/*************************************************************************
|
||||
// Span
|
||||
//
|
||||
// invariants:
|
||||
// ptr != null, base != null
|
||||
// ptr is valid in base
|
||||
**************************************************************************/
|
||||
|
||||
template <class T>
|
||||
struct Span {
|
||||
private:
|
||||
#define CSelf Span
|
||||
typedef CSelf<T> Self;
|
||||
// core config
|
||||
enum { configRequirePtr = true };
|
||||
enum { configRequireBase = true };
|
||||
|
||||
#include "xspan_impl_common.h"
|
||||
public:
|
||||
// constructors from pointers
|
||||
CSelf(pointer first) SPAN_DELETED_FUNCTION;
|
||||
|
||||
// constructors
|
||||
CSelf(const Self &other)
|
||||
: ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {}
|
||||
template <class U>
|
||||
CSelf(const CSelf<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
|
||||
: ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {}
|
||||
|
||||
// constructors from Span friends
|
||||
#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION
|
||||
template <class U>
|
||||
CSelf(const PtrOrSpanOrNull<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
|
||||
: ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {}
|
||||
template <class U>
|
||||
CSelf(const PtrOrSpan<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
|
||||
: ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {}
|
||||
#endif
|
||||
|
||||
// assignment from Span friends
|
||||
#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION
|
||||
// TODO: use Unchecked to avoid double checks in both constructor and assignment
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
|
||||
operator=(const PtrOrSpan<U> &other) {
|
||||
if (other.base == nullptr)
|
||||
return assign(Self(other.ptr, size_in_bytes, base));
|
||||
return assign(Self(other.ptr, other.size_in_bytes, other.base));
|
||||
}
|
||||
template <class U>
|
||||
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
|
||||
operator=(const PtrOrSpanOrNull<U> &other) {
|
||||
if (other.base == nullptr)
|
||||
return assign(Self(other.ptr, size_in_bytes, base));
|
||||
return assign(Self(other.ptr, other.size_in_bytes, other.base));
|
||||
}
|
||||
#endif
|
||||
|
||||
// nullptr
|
||||
CSelf(std::nullptr_t) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, SpanSizeInBytes, const void *) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, SpanCount, const void *) SPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, size_type, const void *) SPAN_DELETED_FUNCTION;
|
||||
Self &operator=(std::nullptr_t) SPAN_DELETED_FUNCTION;
|
||||
#if 0
|
||||
// don't enable, this prevents generic usage
|
||||
bool operator==(std::nullptr_t) const SPAN_DELETED_FUNCTION;
|
||||
bool operator!=(std::nullptr_t) const SPAN_DELETED_FUNCTION;
|
||||
#else
|
||||
bool operator==(std::nullptr_t) const {
|
||||
assertInvariants();
|
||||
return false;
|
||||
}
|
||||
bool operator!=(std::nullptr_t) const {
|
||||
assertInvariants();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#undef CSelf
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline T *raw_bytes(const Span<T> &a, size_t size_in_bytes) {
|
||||
return a.raw_bytes(size_in_bytes);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
SPAN_NAMESPACE_END
|
||||
|
||||
#if !SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
|
||||
|
||||
#define C SPAN_NS(Span)
|
||||
#define D SPAN_NS(PtrOrSpanOrNull)
|
||||
#define E SPAN_NS(PtrOrSpan)
|
||||
#include "xspan_fwd.h"
|
||||
#undef C
|
||||
#undef D
|
||||
#undef E
|
||||
|
||||
#endif
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
Reference in New Issue
Block a user