From 0500e7d01674331770e6fcbac8afb4b03008a8d5 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Thu, 28 Dec 2023 04:42:41 +0100 Subject: [PATCH] CI updates; cxxlib.h cleanups --- .github/workflows/misc-spell-check.yml | 2 +- .github/workflows/weekly-ci-rt-checkers.yml | 4 +- misc/cmake/functions.cmake | 6 +- src/bele_policy.h | 21 +-- src/check/dt_check.cpp | 11 ++ src/check/dt_cxxlib.cpp | 63 +++++++-- src/except.h | 11 +- src/packer.h | 5 +- src/util/cxxlib.h | 147 +++++++++++++------- src/util/membuffer.h | 13 +- src/util/util.h | 4 +- 11 files changed, 187 insertions(+), 100 deletions(-) diff --git a/.github/workflows/misc-spell-check.yml b/.github/workflows/misc-spell-check.yml index 8d9aa5a8..9d510eb2 100644 --- a/.github/workflows/misc-spell-check.yml +++ b/.github/workflows/misc-spell-check.yml @@ -17,5 +17,5 @@ jobs: uses: actions/checkout@v4 with: { submodules: false } - name: 'Spell check with crate-ci/typos' - uses: crate-ci/typos@5bd389de715c63ba86568420809e324fcea78660 # v1.16.25 + uses: crate-ci/typos@45a880d9f898547e8bfe6525b6059d4b3dea4d71 # v1.16.26 with: { config: ./.github/typos_config.toml } diff --git a/.github/workflows/weekly-ci-rt-checkers.yml b/.github/workflows/weekly-ci-rt-checkers.yml index 99d3316c..4e264b97 100644 --- a/.github/workflows/weekly-ci-rt-checkers.yml +++ b/.github/workflows/weekly-ci-rt-checkers.yml @@ -24,6 +24,7 @@ jobs: - { container: 'alpine:3.19', release: debug, qemu: 'qemu-x86_64 -cpu Nehalem' } - { container: 'alpine:3.19', release: release, qemu: 'qemu-x86_64 -cpu Nehalem' } - { container: 'alpine:edge', release: release, qemu: 'qemu-x86_64 -cpu Nehalem' } + - { container: 'i386/alpine:3.19', release: release, qemu: 'qemu-i386' } - { container: 'i386/alpine:edge', release: release, qemu: 'qemu-i386' } name: ${{ format('{0} {1}', matrix.container, matrix.release) }} runs-on: ubuntu-latest @@ -45,7 +46,8 @@ jobs: - name: 'Build clang-static' run: | - export CC="clang -static" CXX="clang++ -static" + flags="-static -fno-omit-frame-pointer" + export CC="clang $flags" CXX="clang++ $flags" make UPX_XTARGET=clang-static xtarget/$release - name: 'Build clang-asan' if: ${{ !startsWith(matrix.container, 'i386/') }} # i386: ASAN not supported diff --git a/misc/cmake/functions.cmake b/misc/cmake/functions.cmake index 7b4a23d5..c218faa5 100644 --- a/misc/cmake/functions.cmake +++ b/misc/cmake/functions.cmake @@ -72,7 +72,7 @@ function(upx_print_var) # ARGV endforeach() endfunction() -function(upx_print_have_symbol) # ARGV +function(upx_print_have_symbol) # ARGV; needs include(CheckSymbolExists) foreach(symbol ${ARGV}) set(cache_var_name "HAVE_symbol_${symbol}") check_symbol_exists(${symbol} "limits.h;stddef.h;stdint.h" ${cache_var_name}) @@ -147,7 +147,7 @@ endfunction() # compilation flags #*********************************************************************** -function(upx_internal_add_definitions_with_prefix) # ARGV +function(upx_internal_add_definitions_with_prefix) # ARGV; needs include(CheckCCompilerFlag) set(flag_prefix "${ARGV0}") if(flag_prefix MATCHES "^empty$") # need "empty" to work around bug in old CMake versions set(flag_prefix "") @@ -168,7 +168,7 @@ function(upx_internal_add_definitions_with_prefix) # ARGV set(failed_flags "${failed}" PARENT_SCOPE) # return value endfunction() -function(upx_add_definitions) # ARGV +function(upx_add_definitions) # ARGV; needs include(CheckCCompilerFlag) set(failed_flags "") if(MSVC_FRONTEND AND CMAKE_C_COMPILER_ID MATCHES "Clang") # for clang-cl try "-clang:" flag prefix first diff --git a/src/bele_policy.h b/src/bele_policy.h index 2aadad27..74c3dc31 100644 --- a/src/bele_policy.h +++ b/src/bele_policy.h @@ -79,12 +79,9 @@ struct AbstractPolicy { private: // disable copy and move - AbstractPolicy(const AbstractPolicy &) DELETED_FUNCTION; - AbstractPolicy &operator=(const AbstractPolicy &) DELETED_FUNCTION; - AbstractPolicy(AbstractPolicy &&) noexcept DELETED_FUNCTION; - AbstractPolicy &operator=(AbstractPolicy &&) noexcept DELETED_FUNCTION; + UPX_CXX_DISABLE_COPY_MOVE(AbstractPolicy) // disable dynamic allocation - UPX_CXX_DISABLE_NEW_DELETE + UPX_CXX_DISABLE_NEW_DELETE(AbstractPolicy) }; #endif @@ -147,12 +144,9 @@ struct BEPolicy private: // disable copy and move - BEPolicy(const BEPolicy &) DELETED_FUNCTION; - BEPolicy &operator=(const BEPolicy &) DELETED_FUNCTION; - BEPolicy(BEPolicy &&) noexcept DELETED_FUNCTION; - BEPolicy &operator=(BEPolicy &&) noexcept DELETED_FUNCTION; + UPX_CXX_DISABLE_COPY_MOVE(BEPolicy) // disable dynamic allocation - UPX_CXX_DISABLE_NEW_DELETE + UPX_CXX_DISABLE_NEW_DELETE(BEPolicy) }; struct LEPolicy @@ -209,12 +203,9 @@ struct LEPolicy private: // disable copy and move - LEPolicy(const LEPolicy &) DELETED_FUNCTION; - LEPolicy &operator=(const LEPolicy &) DELETED_FUNCTION; - LEPolicy(LEPolicy &&) noexcept DELETED_FUNCTION; - LEPolicy &operator=(LEPolicy &&) noexcept DELETED_FUNCTION; + UPX_CXX_DISABLE_COPY_MOVE(LEPolicy) // disable dynamic allocation - UPX_CXX_DISABLE_NEW_DELETE + UPX_CXX_DISABLE_NEW_DELETE(LEPolicy) }; // Native Endianness policy (aka host policy) diff --git a/src/check/dt_check.cpp b/src/check/dt_check.cpp index b5671ce5..6b456b24 100644 --- a/src/check/dt_check.cpp +++ b/src/check/dt_check.cpp @@ -564,6 +564,17 @@ TEST_CASE("acc_vget") { CHECK_EQ(acc_vget_acc_hvoid_p(nullptr, 0), nullptr); } +TEST_CASE("ptr_invalidate_and_poison") { + int *ip = nullptr; + ptr_invalidate_and_poison(ip); + assert(ip != nullptr); + (void) ip; + double *dp; + ptr_invalidate_and_poison(dp); + assert(dp != nullptr); + (void) dp; +} + TEST_CASE("working -fno-strict-aliasing") { bool ok; long v = 0; diff --git a/src/check/dt_cxxlib.cpp b/src/check/dt_cxxlib.cpp index 3e71f7c3..6ab036d7 100644 --- a/src/check/dt_cxxlib.cpp +++ b/src/check/dt_cxxlib.cpp @@ -98,9 +98,54 @@ ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_ge("abc", "abz")) ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_le("abc", "abz")) /************************************************************************* -// UPX_CXX_DISABLE_NEW_DELETE +// UPX_CXX_DISABLE_xxx **************************************************************************/ +namespace { +template +struct MyType1 { + MyType1() noexcept {} + UPX_CXX_DISABLE_ADDRESS(MyType1) + UPX_CXX_DISABLE_COPY_MOVE(MyType1) + UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(MyType1) +}; +template +struct MyType2 { + MyType2() noexcept {} + UPX_CXX_DISABLE_COPY_MOVE(MyType2) + typedef MyType2 Self; + UPX_CXX_DISABLE_ADDRESS(Self) + UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(Self) +}; +template +struct MyVType1 { + MyVType1() noexcept {} + virtual ~MyVType1() noexcept {} + UPX_CXX_DISABLE_ADDRESS(MyVType1) + UPX_CXX_DISABLE_COPY_MOVE(MyVType1) + UPX_CXX_DISABLE_NEW_DELETE(MyVType1) +}; +template +struct MyVType2 { + MyVType2() noexcept {} + virtual ~MyVType2() noexcept {} + UPX_CXX_DISABLE_COPY_MOVE(MyVType2) + typedef MyVType2 Self; + UPX_CXX_DISABLE_ADDRESS(Self) + UPX_CXX_DISABLE_NEW_DELETE(Self) +}; +TEST_CASE("upx_cxx_disable") { + MyType1 dummy1; + MyType2 dummy2; + MyVType1 vdummy1; + MyVType2 vdummy2; + (void) dummy1; + (void) dummy2; + (void) vdummy1; + (void) vdummy2; +} +} // namespace + namespace test_disable_new_delete { struct A1 { @@ -108,7 +153,7 @@ struct A1 { }; struct A2 { int a; - UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL + UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(A2) }; struct B1_A1 : public A1 { int b; @@ -118,11 +163,11 @@ struct B1_A2 : public A2 { }; struct B2_A1 : public A1 { int b; - UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL + UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(B2_A1) }; struct B2_A2 : public A2 { int b; - UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL + UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(B2_A2) }; struct X1 { @@ -132,7 +177,7 @@ struct X1 { struct X2 { virtual ~X2() noexcept {} int x; - UPX_CXX_DISABLE_NEW_DELETE + UPX_CXX_DISABLE_NEW_DELETE(X2) }; struct Y1_X1 : public X1 { int y; @@ -142,11 +187,11 @@ struct Y1_X2 : public X2 { }; struct Y2_X1 : public X1 { int y; - UPX_CXX_DISABLE_NEW_DELETE + UPX_CXX_DISABLE_NEW_DELETE(Y2_X1) }; struct Y2_X2 : public X2 { int y; - UPX_CXX_DISABLE_NEW_DELETE + UPX_CXX_DISABLE_NEW_DELETE(Y2_X2) }; struct Z1_X1 : public X1 { virtual ~Z1_X1() noexcept {} @@ -159,12 +204,12 @@ struct Z1_X2 : public X2 { struct Z2_X1 : public X1 { virtual ~Z2_X1() noexcept {} int z; - UPX_CXX_DISABLE_NEW_DELETE + UPX_CXX_DISABLE_NEW_DELETE(Z2_X1) }; struct Z2_X2 : public X2 { virtual ~Z2_X2() noexcept {} int z; - UPX_CXX_DISABLE_NEW_DELETE + UPX_CXX_DISABLE_NEW_DELETE(Z2_X2) }; } // namespace test_disable_new_delete diff --git a/src/except.h b/src/except.h index 0f9b666b..1942f023 100644 --- a/src/except.h +++ b/src/except.h @@ -43,7 +43,7 @@ protected: Throwable(const char *m = nullptr, int e = 0, bool w = false) noexcept; public: - Throwable(const Throwable &) noexcept; + Throwable(const Throwable &) noexcept; // copy constructor virtual ~Throwable() noexcept; const char *getMsg() const noexcept { return msg; } int getErrno() const noexcept { return err; } @@ -57,14 +57,13 @@ protected: private: // disable copy assignment and move - Throwable &operator=(const Throwable &) DELETED_FUNCTION; - Throwable(Throwable &&) noexcept DELETED_FUNCTION; - Throwable &operator=(Throwable &&) noexcept DELETED_FUNCTION; + Throwable &operator=(const Throwable &) noexcept DELETED_FUNCTION; // copy assignment + UPX_CXX_DISABLE_MOVE(Throwable) // disable dynamic allocation => force throwing by value - UPX_CXX_DISABLE_NEW_DELETE + UPX_CXX_DISABLE_NEW_DELETE(Throwable) // 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] - Throwable *operator&() const noexcept DELETED_FUNCTION; + UPX_CXX_DISABLE_ADDRESS(Throwable) private: static upx_std_atomic(size_t) debug_counter; // for debugging diff --git a/src/packer.h b/src/packer.h index c8f2788b..4bab6a3e 100644 --- a/src/packer.h +++ b/src/packer.h @@ -321,10 +321,7 @@ private: private: // disable copy and move - Packer(const Packer &) DELETED_FUNCTION; - Packer &operator=(const Packer &) DELETED_FUNCTION; - Packer(Packer &&) noexcept DELETED_FUNCTION; - Packer &operator=(Packer &&) noexcept DELETED_FUNCTION; + UPX_CXX_DISABLE_COPY_MOVE(Packer) }; /* vim:set ts=4 sw=4 et: */ diff --git a/src/util/cxxlib.h b/src/util/cxxlib.h index bde44147..90bd7ecd 100644 --- a/src/util/cxxlib.h +++ b/src/util/cxxlib.h @@ -33,55 +33,105 @@ namespace upx { /************************************************************************* -// core +// core util **************************************************************************/ +// disable taking the address => force passing by reference (instead of pointer) +#define UPX_CXX_DISABLE_ADDRESS(Klass) \ +private: \ + Klass *operator&() const noexcept DELETED_FUNCTION; + +// disable copy and move +#define UPX_CXX_DISABLE_COPY(KlassName) \ +private: \ + KlassName(const KlassName &) noexcept DELETED_FUNCTION; /* copy constructor */ \ + KlassName &operator=(const KlassName &) noexcept DELETED_FUNCTION; /* copy assignment */ +#define UPX_CXX_DISABLE_MOVE(KlassName) \ +private: \ + KlassName(KlassName &&) noexcept DELETED_FUNCTION; /* move constructor */ \ + KlassName &operator=(KlassName &&) noexcept DELETED_FUNCTION; /* move assignment */ +#define UPX_CXX_DISABLE_COPY_MOVE(KlassName) \ + UPX_CXX_DISABLE_COPY(KlassName) \ + UPX_CXX_DISABLE_MOVE(KlassName) + // fun with C++: disable common "new" and ALL "delete" operators -#define UPX_CXX_DISABLE_NEW_DELETE_COMMON__ \ +// https://en.cppreference.com/w/cpp/memory/new/operator_delete +#define UPX_CXX_DISABLE_NEW_DELETE_IMPL__(Klass) \ private: \ /* common allocation functions (4) */ \ - static void *operator new(std::size_t) = delete; \ - static void *operator new[](std::size_t) = delete; \ - static void *operator new(std::size_t, void *) = delete; \ - static void *operator new[](std::size_t, void *) = delete; \ + static void *operator new(std::size_t) DELETED_FUNCTION; \ + static void *operator new[](std::size_t) DELETED_FUNCTION; \ + static void *operator new(std::size_t, void *) DELETED_FUNCTION; \ + static void *operator new[](std::size_t, void *) DELETED_FUNCTION; \ /* replaceable placement deallocation functions (4) */ \ - static void operator delete(void *, const std::nothrow_t &) noexcept = delete; \ - static void operator delete[](void *, const std::nothrow_t &) noexcept = delete; \ - static void operator delete(void *, std::align_val_t, const std::nothrow_t &) noexcept = \ - delete; \ - static void operator delete[](void *, std::align_val_t, const std::nothrow_t &) noexcept = \ - delete; \ + static void operator delete(void *, const std::nothrow_t &) noexcept DELETED_FUNCTION; \ + static void operator delete[](void *, const std::nothrow_t &) noexcept DELETED_FUNCTION; \ + static void operator delete(void *, std::align_val_t, const std::nothrow_t &) \ + noexcept DELETED_FUNCTION; \ + static void operator delete[](void *, std::align_val_t, const std::nothrow_t &) \ + noexcept DELETED_FUNCTION; \ /* non-allocating placement deallocation functions (2) */ \ - static void operator delete(void *, void *) noexcept = delete; \ - static void operator delete[](void *, void *) noexcept = delete; + static void operator delete(void *, void *) noexcept DELETED_FUNCTION; \ + static void operator delete[](void *, void *) noexcept DELETED_FUNCTION; -// for classes with virtual methods -#define UPX_CXX_DISABLE_NEW_DELETE \ - UPX_CXX_DISABLE_NEW_DELETE_COMMON__ \ - /* replaceable usual deallocation functions (8) */ \ +/* class-specific usual deallocation functions (8) */ +#define UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDF_A__(Klass) \ protected: \ static void operator delete(void *) noexcept {} \ - static void operator delete[](void *) noexcept = delete; \ - static void operator delete(void *, std::align_val_t) {} \ - static void operator delete[](void *, std::align_val_t) noexcept = delete; \ - static void operator delete(void *, std::size_t) {} \ - static void operator delete[](void *, std::size_t) noexcept = delete; \ - static void operator delete(void *, std::size_t, std::align_val_t) {} \ - static void operator delete[](void *, std::size_t, std::align_val_t) noexcept = delete; \ -private: + static void operator delete(void *, std::align_val_t) noexcept {} \ + static void operator delete(void *, std::size_t) noexcept {} \ + static void operator delete(void *, std::size_t, std::align_val_t) noexcept {} \ +private: \ + static void operator delete[](void *) noexcept DELETED_FUNCTION; \ + static void operator delete[](void *, std::align_val_t) noexcept DELETED_FUNCTION; \ + static void operator delete[](void *, std::size_t) noexcept DELETED_FUNCTION; \ + static void operator delete[](void *, std::size_t, std::align_val_t) noexcept DELETED_FUNCTION; +#define UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDF_B__(Klass) \ +private: \ + static void operator delete(void *) noexcept DELETED_FUNCTION; \ + static void operator delete[](void *) noexcept DELETED_FUNCTION; \ + static void operator delete(void *, std::align_val_t) noexcept DELETED_FUNCTION; \ + static void operator delete[](void *, std::align_val_t) noexcept DELETED_FUNCTION; \ + static void operator delete(void *, std::size_t) noexcept DELETED_FUNCTION; \ + static void operator delete[](void *, std::size_t) noexcept DELETED_FUNCTION; \ + static void operator delete(void *, std::size_t, std::align_val_t) noexcept DELETED_FUNCTION; \ + static void operator delete[](void *, std::size_t, std::align_val_t) noexcept DELETED_FUNCTION; -// for classes WITHOUT any virtual methods -#define UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL \ - UPX_CXX_DISABLE_NEW_DELETE_COMMON__ \ - /* replaceable usual deallocation functions (8) */ \ - static void operator delete(void *) noexcept = delete; \ - static void operator delete[](void *) noexcept = delete; \ - static void operator delete(void *, std::align_val_t) = delete; \ - static void operator delete[](void *, std::align_val_t) noexcept = delete; \ - static void operator delete(void *, std::size_t) = delete; \ - static void operator delete[](void *, std::size_t) noexcept = delete; \ - static void operator delete(void *, std::size_t, std::align_val_t) = delete; \ - static void operator delete[](void *, std::size_t, std::align_val_t) noexcept = delete; +/* class-specific usual destroying deallocation functions (4) */ +#if __cplusplus >= 202002L +#define UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDDF_A__(Klass) \ +protected: \ + static void operator delete(Klass *, std::destroying_delete_t) noexcept {} \ + static void operator delete(Klass *, std::destroying_delete_t, std::align_val_t) noexcept {} \ + static void operator delete(Klass *, std::destroying_delete_t, std::size_t) noexcept {} \ + static void operator delete(Klass *, std::destroying_delete_t, std::size_t, std::align_val_t) \ + noexcept {} \ +private: +#define UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDDF_B__(Klass) \ +private: \ + static void operator delete(Klass *, std::destroying_delete_t) noexcept DELETED_FUNCTION; \ + static void operator delete(Klass *, std::destroying_delete_t, std::align_val_t) \ + noexcept DELETED_FUNCTION; \ + static void operator delete(Klass *, std::destroying_delete_t, std::size_t) \ + noexcept DELETED_FUNCTION; \ + static void operator delete(Klass *, std::destroying_delete_t, std::size_t, std::align_val_t) \ + noexcept DELETED_FUNCTION; +#else +#define UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDDF_A__(Klass) private: +#define UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDDF_B__(Klass) private: +#endif + +// for classes which may have virtual methods +#define UPX_CXX_DISABLE_NEW_DELETE(Klass) \ + UPX_CXX_DISABLE_NEW_DELETE_IMPL__(Klass) \ + UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDF_A__(Klass) \ + UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDDF_A__(Klass) + +// this only works for classes WITHOUT any virtual methods +#define UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(Klass) \ + UPX_CXX_DISABLE_NEW_DELETE_IMPL__(Klass) \ + UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDF_B__(Klass) \ + UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDDF_B__(Klass) /************************************************************************* // type_traits @@ -137,11 +187,7 @@ protected: #else forceinline ~noncopyable() noexcept = default; #endif -private: - noncopyable(const noncopyable &) noexcept DELETED_FUNCTION; // copy constructor - noncopyable &operator=(const noncopyable &) noexcept DELETED_FUNCTION; // copy assignment - noncopyable(noncopyable &&) noexcept DELETED_FUNCTION; // move constructor - noncopyable &operator=(noncopyable &&) noexcept DELETED_FUNCTION; // move assignment + UPX_CXX_DISABLE_COPY_MOVE(noncopyable) }; namespace compile_time { @@ -178,7 +224,7 @@ struct TriBool final { // constructors forceinline constexpr TriBool() noexcept {} forceinline constexpr TriBool(value_type x) noexcept : value(x) {} - // permissive, converts all other values to Third!! + // IMPORTANT NOTE: permissive, converts all other values to Third! constexpr TriBool(promoted_type x) noexcept : value(x == 0 ? False : (x == 1 ? True : Third)) {} #if __cplusplus >= 202002L forceinline constexpr ~TriBool() noexcept = default; @@ -214,8 +260,8 @@ struct TriBool final { #endif private: - value_type value = False; // the actual value of this type - UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL // UPX convention + value_type value = False; // the actual value of this type + UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(TriBool) // UPX convention }; typedef TriBool<> tribool; @@ -245,7 +291,7 @@ struct OptVar final { void assertValue() const noexcept { assertValue(value); } constexpr OptVar() noexcept {} - OptVar &operator=(const T &other) noexcept { + OptVar &operator=(const T &other) noexcept { // copy constructor assertValue(other); value = other; is_set = true; @@ -259,6 +305,7 @@ struct OptVar final { value_type value = default_value; bool is_set = false; + UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(OptVar) // UPX convention }; // optional assignments @@ -312,9 +359,9 @@ struct OwningPointer final { constexpr const_pointer operator->() const noexcept { return ptr; } private: pointer ptr; - reference operator[](std::ptrdiff_t) noexcept = delete; - const_reference operator[](std::ptrdiff_t) const noexcept = delete; - UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL // UPX convention + reference operator[](std::ptrdiff_t) noexcept DELETED_FUNCTION; + const_reference operator[](std::ptrdiff_t) const noexcept DELETED_FUNCTION; + UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(OwningPointer) // UPX convention }; // must overload mem_clear() template diff --git a/src/util/membuffer.h b/src/util/membuffer.h index 01a21560..99c00f2f 100644 --- a/src/util/membuffer.h +++ b/src/util/membuffer.h @@ -84,7 +84,7 @@ public: // raw access 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] - MemBufferBase *operator&() const noexcept DELETED_FUNCTION; + UPX_CXX_DISABLE_ADDRESS(MemBufferBase) }; /************************************************************************* @@ -209,15 +209,8 @@ private: Debug debug; #endif - // disable copy and move - MemBuffer(const MemBuffer &) DELETED_FUNCTION; - MemBuffer &operator=(const MemBuffer &) DELETED_FUNCTION; -#if __cplusplus >= 201103L - MemBuffer(MemBuffer &&) noexcept DELETED_FUNCTION; - MemBuffer &operator=(MemBuffer &&) noexcept DELETED_FUNCTION; -#endif - // disable dynamic allocation - UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL + UPX_CXX_DISABLE_COPY_MOVE(MemBuffer) // disable copy and move + UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(MemBuffer) // disable dynamic allocation }; /* vim:set ts=4 sw=4 et: */ diff --git a/src/util/util.h b/src/util/util.h index 027d7654..0fb3d91c 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -128,8 +128,10 @@ forceinline void ptr_check_no_overlap(const void *a, size_t a_size, const void * // invalidate and poison a pointer: point to a non-null invalid address // - resulting pointer should crash on dereference // - this should be efficient, so no mmap() guard page etc. -// - this should play nice with runtime checkers like ASAN, MSAN, valgrind, etc. +// - this should play nice with runtime checkers like ASAN, MSAN, UBSAN, valgrind, etc. // - this should play nice with static analyzers like clang-tidy etc. +// NOTE: this is clearly UB (Undefined Behaviour), and stricter compilers or +// architectures may need a more advanced/costly implementation in the future template inline void ptr_invalidate_and_poison(T *(&ptr)) noexcept { ptr = (T *) (void *) 251; // 0x000000fb // NOLINT(performance-no-int-to-ptr)