diff --git a/src/check/dt_check.cpp b/src/check/dt_check.cpp index d3ad5920..04ef8f92 100644 --- a/src/check/dt_check.cpp +++ b/src/check/dt_check.cpp @@ -196,7 +196,7 @@ struct CheckIntegral { static constexpr U z[2] = {}; }; template - static void checkU(void) { + static void checkU(void) noexcept { { U a = {}; const U b = {}; @@ -204,21 +204,21 @@ struct CheckIntegral { U x[2] = {}; const U y[2] = {}; constexpr U z[2] = {}; - assert(a == 0); - assert(b == 0); - assert(c == 0); - assert(x[0] == 0 && x[1] == 0); - assert(y[0] == 0 && y[1] == 0); - assert(z[0] == 0 && z[1] == 0); + assert_noexcept(a == 0); + assert_noexcept(b == 0); + assert_noexcept(c == 0); + assert_noexcept(x[0] == 0 && x[1] == 0); + assert_noexcept(y[0] == 0 && y[1] == 0); + assert_noexcept(z[0] == 0 && z[1] == 0); } { TestU t; - assert(t.a == 0); - assert(t.b == 0); - assert(t.c == 0); - assert(t.x[0] == 0 && t.x[1] == 0); - assert(t.y[0] == 0 && t.y[1] == 0); - assert(t.z[0] == 0 && t.z[1] == 0); + assert_noexcept(t.a == 0); + assert_noexcept(t.b == 0); + assert_noexcept(t.c == 0); + assert_noexcept(t.x[0] == 0 && t.x[1] == 0); + assert_noexcept(t.y[0] == 0 && t.y[1] == 0); + assert_noexcept(t.z[0] == 0 && t.z[1] == 0); } #if __cplusplus < 202002L COMPILE_TIME_ASSERT(std::is_pod::value) // std::is_pod is deprecated in C++20 @@ -233,27 +233,27 @@ struct CheckIntegral { COMPILE_TIME_ASSERT(upx_is_integral::value) COMPILE_TIME_ASSERT(upx_is_integral_v) } - static void check(void) { + static void check(void) noexcept { { TestT t = {}; - assert(t.a == 0); - assert(t.x[0] == 0 && t.x[1] == 0); + assert_noexcept(t.a == 0); + assert_noexcept(t.x[0] == 0 && t.x[1] == 0); } { const TestT t = {}; - assert(t.a == 0); - assert(t.x[0] == 0 && t.x[1] == 0); + assert_noexcept(t.a == 0); + assert_noexcept(t.x[0] == 0 && t.x[1] == 0); } { constexpr TestT t = {}; - assert(t.a == 0); - assert(t.x[0] == 0 && t.x[1] == 0); + assert_noexcept(t.a == 0); + assert_noexcept(t.x[0] == 0 && t.x[1] == 0); } { TestT t; mem_clear(&t); - assert(t.a == 0); - assert(t.x[0] == 0 && t.x[1] == 0); + assert_noexcept(t.a == 0); + assert_noexcept(t.x[0] == 0 && t.x[1] == 0); } checkU(); checkU::type>(); @@ -261,7 +261,7 @@ struct CheckIntegral { }; template struct CheckAlignment { - static void check(void) { + static void check(void) noexcept { COMPILE_TIME_ASSERT_ALIGNED1(T) struct alignas(1) Test1 { char a; @@ -285,12 +285,12 @@ struct CheckAlignment { }; template struct TestBELE { - static noinline bool test(void) { + static noinline bool test(void) noexcept { CheckIntegral::check(); CheckAlignment::check(); // arithmetic checks T allbits = {}; - assert(allbits == 0); + assert_noexcept(allbits == 0); allbits += 1; allbits -= 2; T v1; @@ -300,22 +300,22 @@ struct TestBELE { v1 -= 1; T v2; v2 = 1; - assert((v1 == v2)); - assert(!(v1 != v2)); - assert((v1 <= v2)); - assert((v1 >= v2)); - assert(!(v1 < v2)); - assert(!(v1 > v2)); + assert_noexcept((v1 == v2)); + assert_noexcept(!(v1 != v2)); + assert_noexcept((v1 <= v2)); + assert_noexcept((v1 >= v2)); + assert_noexcept(!(v1 < v2)); + assert_noexcept(!(v1 > v2)); v2 ^= allbits; - assert(!(v1 == v2)); - assert((v1 != v2)); - assert((v1 <= v2)); - assert(!(v1 >= v2)); - assert((v1 < v2)); - assert(!(v1 > v2)); + assert_noexcept(!(v1 == v2)); + assert_noexcept((v1 != v2)); + assert_noexcept((v1 <= v2)); + assert_noexcept(!(v1 >= v2)); + assert_noexcept((v1 < v2)); + assert_noexcept(!(v1 > v2)); v2 += 2; - assert(v1 == 1); - assert(v2 == 0); + assert_noexcept(v1 == 1); + assert_noexcept(v2 == 0); v1 <<= 1; v1 |= v2; v1 >>= 1; @@ -324,8 +324,8 @@ struct TestBELE { v2 *= v1; v1 += v2; v1 -= v2; - assert(v1 == 1); - assert(v2 == 0); + assert_noexcept(v1 == 1); + assert_noexcept(v2 == 0); if ((v1 ^ v2) != 1) return false; return true; @@ -358,7 +358,7 @@ struct TestIntegerWrap { #undef ACCCHK_ASSERT #include "../miniacc.h" -void upx_compiler_sanity_check(void) { +void upx_compiler_sanity_check(void) noexcept { #define ACC_WANT_ACC_CHK_CH 1 #undef ACCCHK_ASSERT #define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT(expr) @@ -402,31 +402,32 @@ void upx_compiler_sanity_check(void) { COMPILE_TIME_ASSERT(sizeof(*((charptr) nullptr)) == 1) COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_STRING4) == 4 + 1) - assert(strlen(UPX_VERSION_STRING4) == 4); + assert_noexcept(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); + assert_noexcept(strlen(UPX_VERSION_YEAR) == 4); + assert_noexcept(memcmp(UPX_VERSION_DATE_ISO, UPX_VERSION_YEAR, 4) == 0); + assert_noexcept( + 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); + assert_noexcept(revlen == 5 || revlen == 6); } else { - assert(revlen == 12 || revlen == 13); + assert_noexcept(revlen == 12 || revlen == 13); } if (revlen == 6 || revlen == 13) { - assert(gitrev[revlen - 1] == '+'); + assert_noexcept(gitrev[revlen - 1] == '+'); } } - assert(UPX_RSIZE_MAX_MEM == 805306368); + assert_noexcept(UPX_RSIZE_MAX_MEM == 805306368); #if DEBUG || 1 - assert(TestBELE::test()); - assert(TestBELE::test()); - assert(TestBELE::test()); - assert(TestBELE::test()); - assert(TestBELE::test()); - assert(TestBELE::test()); + assert_noexcept(TestBELE::test()); + assert_noexcept(TestBELE::test()); + assert_noexcept(TestBELE::test()); + assert_noexcept(TestBELE::test()); + assert_noexcept(TestBELE::test()); + assert_noexcept(TestBELE::test()); { alignas(16) static const byte dd[32] = { 0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0, @@ -434,51 +435,51 @@ void upx_compiler_sanity_check(void) { const byte *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); + assert_noexcept(upx_adler32(d, 4) == 0x09f003f7); + assert_noexcept(upx_adler32(d, 4, 0) == 0x09ec03f6); + assert_noexcept(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); + assert_noexcept(get_be16(d) == 0xfffe); + assert_noexcept(bele->get16(d) == 0xfffe); + assert_noexcept(get_be16_signed(d) == -2); + assert_noexcept(get_be24(d) == 0xfffefd); + assert_noexcept(bele->get24(d) == 0xfffefd); + assert_noexcept(get_be24_signed(d) == -259); + assert_noexcept(get_be32(d) == 0xfffefdfc); + assert_noexcept(bele->get32(d) == 0xfffefdfc); + assert_noexcept(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); + assert_noexcept(get_le16(d) == 0xfeff); + assert_noexcept(bele->get16(d) == 0xfeff); + assert_noexcept(get_le16_signed(d) == -257); + assert_noexcept(get_le24(d) == 0xfdfeff); + assert_noexcept(bele->get24(d) == 0xfdfeff); + assert_noexcept(get_le24_signed(d) == -131329); + assert_noexcept(get_le32(d) == 0xfcfdfeff); + assert_noexcept(bele->get32(d) == 0xfcfdfeff); + assert_noexcept(get_le32_signed(d) == -50462977); + assert_noexcept(get_le64_signed(d) == -506097522914230529LL); + assert_noexcept(find_be16(d, 2, 0xfffe) == 0); + assert_noexcept(find_le16(d, 2, 0xfeff) == 0); + assert_noexcept(find_be32(d, 4, 0xfffefdfc) == 0); + assert_noexcept(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); + assert_noexcept(get_be16_signed(d) == 32638); + assert_noexcept(get_be24_signed(d) == 8355453); + assert_noexcept(get_be32_signed(d) == 2138996092); + assert_noexcept(get_be64_signed(d) == 9186918263483431288LL); } { unsigned dd; void *const d = ⅆ dd = ne32_to_le32(0xf7f6f5f4); - assert(get_le26(d) == 0x03f6f5f4); + assert_noexcept(get_le26(d) == 0x03f6f5f4); set_le26(d, 0); - assert(get_le26(d) == 0); - assert(dd == ne32_to_le32(0xf4000000)); + assert_noexcept(get_le26(d) == 0); + assert_noexcept(dd == ne32_to_le32(0xf4000000)); set_le26(d, 0xff020304); - assert(get_le26(d) == 0x03020304); - assert(dd == ne32_to_le32(0xf7020304)); + assert_noexcept(get_le26(d) == 0x03020304); + assert_noexcept(dd == ne32_to_le32(0xf7020304)); } { upx_uint16_t a = 0; @@ -487,12 +488,12 @@ void upx_compiler_sanity_check(void) { set_ne16(&a, 0x04030201); // ignore upper bits set_ne32(&b, 0x04030201); set_ne64(&c, 0x0807060504030201ull); - assert(a == 0x0201); - assert(b == 0x04030201); - assert(c == 0x0807060504030201ull); - assert(get_ne16(&a) == 0x0201); - assert(get_ne32(&b) == 0x04030201); - assert(get_ne64(&c) == 0x0807060504030201ull); + assert_noexcept(a == 0x0201); + assert_noexcept(b == 0x04030201); + assert_noexcept(c == 0x0807060504030201ull); + assert_noexcept(get_ne16(&a) == 0x0201); + assert_noexcept(get_ne32(&b) == 0x04030201); + assert_noexcept(get_ne64(&c) == 0x0807060504030201ull); } #endif // DEBUG union { @@ -507,38 +508,53 @@ void upx_compiler_sanity_check(void) { 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)); + assert_noexcept(testNoAliasing(&u.v_short, &u.b32)); + assert_noexcept(testNoAliasing(&u.v_short, &u.l32)); + assert_noexcept(testNoAliasing(&u.v_int, &u.b64)); + assert_noexcept(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_noexcept(testNoAliasing(&u.v_short, &u.v_int)); + assert_noexcept(testNoAliasing(&u.v_int, &u.v_long)); + assert_noexcept(testNoAliasing(&u.v_int, &u.v_llong)); + assert_noexcept(testNoAliasing(&u.v_long, &u.v_llong)); - assert(TestIntegerWrap::inc_gt(0)); - assert(!TestIntegerWrap::inc_gt(UINT_MAX)); - assert(TestIntegerWrap::dec_lt(1)); - assert(!TestIntegerWrap::dec_lt(0)); - assert(TestIntegerWrap::neg_eq(0)); - assert(!TestIntegerWrap::neg_eq(1)); - assert(!TestIntegerWrap::neg_eq(UINT_MAX)); + assert_noexcept(TestIntegerWrap::inc_gt(0)); + assert_noexcept(!TestIntegerWrap::inc_gt(UINT_MAX)); + assert_noexcept(TestIntegerWrap::dec_lt(1)); + assert_noexcept(!TestIntegerWrap::dec_lt(0)); + assert_noexcept(TestIntegerWrap::neg_eq(0)); + assert_noexcept(!TestIntegerWrap::neg_eq(1)); + assert_noexcept(!TestIntegerWrap::neg_eq(UINT_MAX)); // check working -fno-strict-overflow - assert(TestIntegerWrap::inc_gt(0)); - assert(!TestIntegerWrap::inc_gt(INT_MAX)); - assert(TestIntegerWrap::dec_lt(0)); - assert(!TestIntegerWrap::dec_lt(INT_MIN)); - assert(TestIntegerWrap::neg_eq(0)); - assert(!TestIntegerWrap::neg_eq(1)); - assert(!TestIntegerWrap::neg_eq(INT_MAX)); - assert(TestIntegerWrap::neg_eq(INT_MIN)); // !! + assert_noexcept(TestIntegerWrap::inc_gt(0)); + assert_noexcept(!TestIntegerWrap::inc_gt(INT_MAX)); + assert_noexcept(TestIntegerWrap::dec_lt(0)); + assert_noexcept(!TestIntegerWrap::dec_lt(INT_MIN)); + assert_noexcept(TestIntegerWrap::neg_eq(0)); + assert_noexcept(!TestIntegerWrap::neg_eq(1)); + assert_noexcept(!TestIntegerWrap::neg_eq(INT_MAX)); + assert_noexcept(TestIntegerWrap::neg_eq(INT_MIN)); // !! } /************************************************************************* // some doctest test cases **************************************************************************/ +TEST_CASE("assert_noexcept") { + // just to make sure that our assert macros don't generate any warnings + byte dummy = 0; + byte *ptr1 = &dummy; + const byte *const ptr2 = &dummy; + assert(true); + assert(1); + assert(ptr1); + assert(ptr2); + assert_noexcept(true); + assert_noexcept(1); + assert_noexcept(ptr1); + assert_noexcept(ptr2); +} + TEST_CASE("noncopyable") { struct Test : private noncopyable { int v = 1; diff --git a/src/conf.h b/src/conf.h index ad6ce759..b3a1a3d2 100644 --- a/src/conf.h +++ b/src/conf.h @@ -406,6 +406,22 @@ inline void mem_clear(T (&array)[N]) noexcept = delete; #define ByteArray(var, n) Array(byte, var, (n)) +// assert_noexcept() +noinline void assertFailed(const char *expr, const char *file, int line, const char *func) noexcept; +noinline void throwAssertFailed(const char *expr, const char *file, int line, const char *func); +#if defined(__GNUC__) +#undef assert +#if DEBUG || 0 +// generate a warning if assert() is used inside a "noexcept" function +#define assert(e) ((void)(__acc_cte(e) || (assertFailed(#e, __FILE__, __LINE__, __func__), throw 1, 0))) +#else +// turn assertion failures into exceptions +#define assert(e) ((void)(__acc_cte(e) || (throwAssertFailed(#e, __FILE__, __LINE__, __func__), throw 1, 0))) +#endif +#define assert_noexcept(e) ((void)(__acc_cte(e) || (assertFailed(#e, __FILE__, __LINE__, __func__), 0))) +#else +#define assert_noexcept assert +#endif class noncopyable { protected: @@ -614,24 +630,25 @@ struct upx_callback_t { template struct OptVar { + static_assert(std::is_integral_v); typedef T value_type; static constexpr T default_value = default_value_; static constexpr T min_value = min_value_; static constexpr T max_value = max_value_; static_assert(min_value <= default_value && default_value <= max_value); - static void assertValue(const T &v) { + static void assertValue(const T &v) noexcept { // info: this generates annoying warnings "unsigned >= 0 is always true" - //assert(v >= min_value); - assert(v == min_value || v >= min_value + 1); - assert(v <= max_value); + //assert_noexcept(v >= min_value); + assert_noexcept(v == min_value || v >= min_value + 1); + assert_noexcept(v <= max_value); } - void assertValue() const { + void assertValue() const noexcept { assertValue(v); } OptVar() noexcept : v(default_value), is_set(false) { } - OptVar& operator= (const T &other) { + OptVar& operator= (const T &other) noexcept { assertValue(other); v = other; is_set = true; @@ -648,11 +665,11 @@ struct OptVar { // optional assignments template -inline void oassign(OptVar &self, const OptVar &other) { +inline void oassign(OptVar &self, const OptVar &other) noexcept { if (other.is_set) { self.v = other.v; self.is_set = true; } } template -inline void oassign(T &v, const OptVar &other) { +inline void oassign(T &v, const OptVar &other) noexcept { if (other.is_set) { v = other.v; } } @@ -782,7 +799,7 @@ void *membuffer_get_void_ptr(MemBuffer &mb) noexcept; unsigned membuffer_get_size(MemBuffer &mb) noexcept; // util/dt_check.cpp -void upx_compiler_sanity_check(); +void upx_compiler_sanity_check() noexcept; int upx_doctest_check(); int upx_doctest_check(int argc, char **argv); @@ -794,12 +811,12 @@ void main_get_envoptions(); int upx_main(int argc, char *argv[]); // msg.cpp -void printSetNl(int need_nl); -void printClearLine(FILE *f = nullptr); -void printErr(const char *iname, const Throwable *e); -void printUnhandledException(const char *iname, const std::exception *e); -void printErr(const char *iname, const char *format, ...) attribute_format(2, 3); -void printWarn(const char *iname, const char *format, ...) attribute_format(2, 3); +void printSetNl(int need_nl) noexcept; +void printClearLine(FILE *f = nullptr) noexcept; +void printErr(const char *iname, const Throwable &e) noexcept; +void printUnhandledException(const char *iname, const std::exception *e) noexcept; +void printErr(const char *iname, const char *format, ...) noexcept attribute_format(2, 3); +void printWarn(const char *iname, const char *format, ...) noexcept attribute_format(2, 3); void infoWarning(const char *format, ...) attribute_format(1, 2); void infoHeader(const char *format, ...) attribute_format(1, 2); diff --git a/src/except.cpp b/src/except.cpp index 0a2f3332..2509fc21 100644 --- a/src/except.cpp +++ b/src/except.cpp @@ -72,7 +72,9 @@ Throwable::~Throwable() noexcept { void throwCantPack(const char *msg) { // UGLY, but makes things easier - if (opt->cmd == CMD_COMPRESS) + if (opt->cmd == CMD_NONE) + throw CantPackException(msg); + else if (opt->cmd == CMD_COMPRESS) throw CantPackException(msg); else if (opt->cmd == CMD_FILEINFO) throw CantPackException(msg); @@ -167,6 +169,20 @@ void throwCantUnpack(const char *format, ...) { // **************************************************************************/ +void assertFailed(const char *expr, const char *file, int line, const char *func) noexcept { + fflush(stdout); + fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line); + std::terminate(); +} + +void throwAssertFailed(const char *expr, const char *file, int line, const char *func) { + if (opt->debug.debug_level >= 1) { + throwCantPack("corrupted file; details: %s (%s: %s: %d)", expr, file, func, line); + } else { + throwCantPack("corrupted file; try '--debug' for more details"); + } +} + const char *prettyName(const char *n) noexcept { if (n == nullptr) return "(null)"; diff --git a/src/except.h b/src/except.h index 3445301c..63151ea9 100644 --- a/src/except.h +++ b/src/except.h @@ -29,6 +29,9 @@ const char *prettyName(const char *n) noexcept; +noinline void assertFailed(const char *expr, const char *file, int line, const char *func) noexcept; +noinline void throwAssertFailed(const char *expr, const char *file, int line, const char *func); + /************************************************************************* // exceptions **************************************************************************/ @@ -57,6 +60,9 @@ private: Throwable &operator=(const Throwable &) = delete; // disable dynamic allocation => force throwing by value 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] + Throwable *operator&() const noexcept = delete; private: static upx_std_atomic(size_t) debug_counter; // for debugging @@ -173,9 +179,9 @@ public: #undef NORET #if 1 && defined(__GNUC__) -#define NORET __acc_noinline __attribute__((__noreturn__)) +#define NORET noinline __attribute__((__noreturn__)) #else -#define NORET __acc_noinline +#define NORET noinline #endif NORET void throwCantPack(const char *msg); diff --git a/src/filter.cpp b/src/filter.cpp index 67bb06b2..46562172 100644 --- a/src/filter.cpp +++ b/src/filter.cpp @@ -50,12 +50,12 @@ static void initFilter(Filter *f, byte *buf, unsigned buf_len) { upx_std_call_once(init_done, []() noexcept { // init the filter_map[] (using a lambda function) - assert(n_filters <= 254); // as 0xff means "empty slot" + assert_noexcept(n_filters <= 254); // as 0xff means "empty slot" memset(filter_map, 0xff, sizeof(filter_map)); for (int i = 0; i < n_filters; i++) { int filter_id = filters[i].id; - assert(filter_id >= 0 && filter_id <= 255); - assert(filter_map[filter_id] == 0xff); + assert_noexcept(filter_id >= 0 && filter_id <= 255); + assert_noexcept(filter_map[filter_id] == 0xff); filter_map[filter_id] = (upx_uint8_t) i; } }); diff --git a/src/lefile.cpp b/src/lefile.cpp index 76ce9d58..a483088f 100644 --- a/src/lefile.cpp +++ b/src/lefile.cpp @@ -217,6 +217,9 @@ bool LeFile::readFileHeader() { return false; fif->seek(le_offset, SEEK_SET); fif->readx(&ih, sizeof(ih)); + if (mps < 512 || mps > 2097152 || (mps & (mps - 1)) != 0 || ih.bytes_on_last_page > mps) + throwCantPack("bad file header"); + (void) mem_size(mps, pages); // assert size return true; #undef H } @@ -224,7 +227,7 @@ bool LeFile::readFileHeader() { void LeFile::writeFile(OutputFile *f, bool le) { fof = f; memcpy(&oh, &ih, - (char *) &oh.memory_pages - (char *) &oh); // copy some members of the orig. header + (charptr) &oh.memory_pages - (charptr) &oh); // copy some members of the orig. header oh.memory_page_size = mps; oh.object_table_offset = sizeof(oh); oh.object_table_entries = soobject_table; diff --git a/src/main.cpp b/src/main.cpp index 66dc4e89..6e37cca6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,7 +41,7 @@ #endif static const char *argv0 = ""; -const char *progname = ""; +const char *progname = "upx"; static acc_getopt_t mfx_getopt; #define mfx_optarg mfx_getopt.optarg @@ -1317,10 +1317,23 @@ int __acc_cdecl_main main(int argc, char *argv[]) { // srand((int) time(nullptr)); srand((int) clock()); + // info: calling upx_main() here violates implicit "noexcept", so we need a try block +#if 0 int r = upx_main(argc, argv); +#else + int r = EXIT_INTERNAL; + try { + r = upx_main(argc, argv); + } catch (const Throwable &e) { + printErr("unknown", e); + std::terminate(); + } catch (...) { + std::terminate(); + } +#endif #if 0 && defined(__GLIBC__) - //malloc_stats(); + // malloc_stats(); #endif return r; } diff --git a/src/msg.cpp b/src/msg.cpp index 72914452..42bc2177 100644 --- a/src/msg.cpp +++ b/src/msg.cpp @@ -35,9 +35,9 @@ static int pr_need_nl = 0; -void printSetNl(int need_nl) { pr_need_nl = need_nl; } +void printSetNl(int need_nl) noexcept { pr_need_nl = need_nl; } -void printClearLine(FILE *f) { +void printClearLine(FILE *f) noexcept { static char clear_line_msg[1 + 79 + 1 + 1]; if (!clear_line_msg[0]) { char *msg = clear_line_msg; @@ -56,14 +56,14 @@ void printClearLine(FILE *f) { printSetNl(0); } -static void pr_print(bool c, const char *msg) { +static void pr_print(bool c, const char *msg) noexcept { if (c && !opt->to_stdout) con_fprintf(stderr, "%s", msg); else fprintf(stderr, "%s", msg); } -static void pr_error(const char *iname, const char *msg, bool is_warning) { +static void pr_error(const char *iname, const char *msg, bool is_warning) noexcept { fflush(stdout); fflush(stderr); char buf[1024]; @@ -98,17 +98,17 @@ static void pr_error(const char *iname, const char *msg, bool is_warning) { UNUSED(fg); } -void printErr(const char *iname, const Throwable *e) { +void printErr(const char *iname, const Throwable &e) noexcept { char buf[1024]; size_t l; - snprintf(buf, sizeof(buf), "%s", prettyName(typeid(*e).name())); + snprintf(buf, sizeof(buf), "%s", prettyName(typeid(e).name())); l = strlen(buf); - if (l < sizeof(buf) && e->getMsg()) - snprintf(buf + l, sizeof(buf) - l, ": %s", e->getMsg()); + if (l < sizeof(buf) && e.getMsg()) + snprintf(buf + l, sizeof(buf) - l, ": %s", e.getMsg()); l = strlen(buf); - if (l < sizeof(buf) && e->getErrno()) { - snprintf(buf + l, sizeof(buf) - l, ": %s", strerror(e->getErrno())); + if (l < sizeof(buf) && e.getErrno()) { + snprintf(buf + l, sizeof(buf) - l, ": %s", strerror(e.getErrno())); #if 1 // some compilers (e.g. Borland C++) put a trailing '\n' // into the strerror() result @@ -117,10 +117,10 @@ void printErr(const char *iname, const Throwable *e) { buf[l] = 0; #endif } - pr_error(iname, buf, e->isWarning()); + pr_error(iname, buf, e.isWarning()); } -void printErr(const char *iname, const char *format, ...) { +void printErr(const char *iname, const char *format, ...) noexcept { va_list args; char buf[1024]; @@ -131,7 +131,7 @@ void printErr(const char *iname, const char *format, ...) { pr_error(iname, buf, false); } -void printWarn(const char *iname, const char *format, ...) { +void printWarn(const char *iname, const char *format, ...) noexcept { va_list args; char buf[1024]; @@ -142,7 +142,7 @@ void printWarn(const char *iname, const char *format, ...) { pr_error(iname, buf, true); } -void printUnhandledException(const char *iname, const std::exception *e) { +void printUnhandledException(const char *iname, const std::exception *e) noexcept { if (e) printErr(iname, "unhandled exception: %s\n", prettyName(e->what())); else diff --git a/src/packer.cpp b/src/packer.cpp index 5ef092b2..aa33a763 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -172,7 +172,7 @@ int forced_method(int method) noexcept // extract the forced method { if (is_forced_method(method)) method &= ~(0x80ul << 24); - assert(method > 0); + assert_noexcept(method > 0); return method; } diff --git a/src/util/membuffer.cpp b/src/util/membuffer.cpp index f89f4b54..75314e0b 100644 --- a/src/util/membuffer.cpp +++ b/src/util/membuffer.cpp @@ -233,7 +233,17 @@ void MemBuffer::alloc(upx_uint64_t bytes) { void MemBuffer::dealloc() noexcept { if (ptr != nullptr) { debug_set(debug.last_return_address_dealloc, upx_return_address()); - checkState(); +#if DEBUG || 1 + // info: calling checkState() here violates "noexcept", so we need a try block + try { + checkState(); + } catch (const Throwable &e) { + printErr("unknown", e); + std::terminate(); + } catch (...) { + std::terminate(); + } +#endif stats.global_dealloc_counter += 1; stats.global_total_active_bytes -= size_in_bytes; if (use_simple_mcheck()) { @@ -251,7 +261,7 @@ void MemBuffer::dealloc() noexcept { ptr = nullptr; size_in_bytes = 0; } else { - assert(size_in_bytes == 0); + assert_noexcept(size_in_bytes == 0); } } diff --git a/src/util/util.cpp b/src/util/util.cpp index e96df8ef..f3c08470 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -56,7 +56,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_STR >= 1024) upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1, upx_uint64_t extra2) { assert(element_size > 0); - if very_unlikely (element_size > UPX_RSIZE_MAX) + if very_unlikely (element_size == 0 || element_size > UPX_RSIZE_MAX) throwCantPack("mem_size 1; take care"); if very_unlikely (n > UPX_RSIZE_MAX) throwCantPack("mem_size 2; take care"); @@ -72,8 +72,8 @@ upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t ext bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1, upx_uint64_t extra2) noexcept { - assert(element_size > 0); - if very_unlikely (element_size > UPX_RSIZE_MAX) + assert_noexcept(element_size > 0); + if very_unlikely (element_size == 0 || element_size > UPX_RSIZE_MAX) return false; if very_unlikely (n > UPX_RSIZE_MAX) return false; diff --git a/src/work.cpp b/src/work.cpp index 8d26db9f..a52fd59e 100644 --- a/src/work.cpp +++ b/src/work.cpp @@ -250,7 +250,7 @@ void do_one_file(const char *iname, char *oname) { // process all files from the commandline **************************************************************************/ -static void unlink_ofile(char *oname) { +static void unlink_ofile(char *oname) noexcept { if (oname && oname[0]) { #if HAVE_CHMOD int r; @@ -281,12 +281,12 @@ int do_files(int i, int argc, char *argv[]) { } catch (const Exception &e) { unlink_ofile(oname); if (opt->verbose >= 1 || (opt->verbose >= 0 && !e.isWarning())) - printErr(iname, &e); + printErr(iname, e); main_set_exit_code(e.isWarning() ? EXIT_WARN : EXIT_ERROR); // this is not fatal, continue processing more files } catch (const Error &e) { unlink_ofile(oname); - printErr(iname, &e); + printErr(iname, e); main_set_exit_code(EXIT_ERROR); return -1; // fatal error } catch (std::bad_alloc *e) {