mirror of
https://github.com/upx/upx.git
synced 2024-11-23 12:49:56 +00:00
src: add a check for libc qsort(); cleanups
This commit is contained in:
parent
3c4b959f78
commit
0ac6c36af2
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -12,8 +12,8 @@ env:
|
||||
CMAKE_REQUIRED_QUIET: OFF
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
UPX_CMAKE_BUILD_FLAGS: --verbose
|
||||
# 2023-08-26
|
||||
ZIG_DIST_VERSION: 0.12.0-dev.170+750998eef
|
||||
# 2023-08-31
|
||||
ZIG_DIST_VERSION: 0.12.0-dev.244+f4c9e19bc
|
||||
|
||||
jobs:
|
||||
job-rebuild-and-verify-stubs:
|
||||
|
4
.github/workflows/weekly-ci-cc-zigcc.yml
vendored
4
.github/workflows/weekly-ci-cc-zigcc.yml
vendored
@ -10,8 +10,8 @@ on:
|
||||
env:
|
||||
CMAKE_REQUIRED_QUIET: OFF
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
# 2023-08-26
|
||||
ZIG_DIST_VERSION: 0.12.0-dev.170+750998eef
|
||||
# 2023-08-31
|
||||
ZIG_DIST_VERSION: 0.12.0-dev.244+f4c9e19bc
|
||||
|
||||
jobs:
|
||||
job-linux-zigcc: # uses cmake + make
|
||||
|
@ -103,6 +103,7 @@ all_errors=
|
||||
export UPX="--prefer-ucl --no-color --no-progress"
|
||||
export UPX_DEBUG_DISABLE_GITREV_WARNING=1
|
||||
export UPX_DEBUG_DOCTEST_VERBOSE=0
|
||||
export NO_COLOR=1
|
||||
|
||||
rm -rf ./testsuite_1
|
||||
mkdir testsuite_1 || exit 1
|
||||
|
12
src/bele.h
12
src/bele.h
@ -69,7 +69,7 @@ struct LE32;
|
||||
struct LE64;
|
||||
|
||||
// Note:
|
||||
// void is explicitly allowed, but there is no automatic pointer conversion because of template
|
||||
// void is explicitly allowed (but there is no automatic pointer conversion because of template!)
|
||||
// char is explicitly allowed
|
||||
// byte is explicitly allowed
|
||||
template <class T>
|
||||
@ -161,13 +161,19 @@ static forceinline upx_uint64_t bswap64(upx_uint64_t v) noexcept { return _bytes
|
||||
#else
|
||||
|
||||
static forceinline constexpr unsigned bswap16(unsigned v) noexcept {
|
||||
#if defined(__riscv) && __riscv_xlen == 64
|
||||
return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48);
|
||||
#else
|
||||
// return __builtin_bswap16((upx_uint16_t) (v & 0xffff));
|
||||
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48);
|
||||
return __builtin_bswap32(v << 16);
|
||||
#endif
|
||||
}
|
||||
static forceinline constexpr unsigned bswap32(unsigned v) noexcept {
|
||||
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 32);
|
||||
#if defined(__riscv) && __riscv_xlen == 64
|
||||
return (unsigned) __builtin_bswap64((upx_uint64_t) v << 32);
|
||||
#else
|
||||
return __builtin_bswap32(v);
|
||||
#endif
|
||||
}
|
||||
static forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) noexcept {
|
||||
return __builtin_bswap64(v);
|
||||
|
@ -43,6 +43,8 @@ int upx_doctest_check(int argc, char **argv) {
|
||||
return 0;
|
||||
#else
|
||||
const char *e = getenv("UPX_DEBUG_DOCTEST_DISABLE");
|
||||
if (!e)
|
||||
e = getenv("UPX_DEBUG_DISABLE_DOCTEST"); // allow alternate spelling
|
||||
if (e && e[0] && strcmp(e, "0") != 0)
|
||||
return 0;
|
||||
bool minimal = true; // don't show summary
|
||||
@ -319,7 +321,7 @@ struct TestIntegerWrap {
|
||||
static inline bool neg_eq(const T x) noexcept { return T(0) - x == x; }
|
||||
};
|
||||
|
||||
static noinline void throwSomeValue(int x) {
|
||||
static noinline void throwSomeValue(int x) may_throw {
|
||||
if (x < 0)
|
||||
throw int(x);
|
||||
else
|
||||
@ -346,6 +348,8 @@ static noinline void check_basic_cxx_exception_handling(void (*func)(int)) noexc
|
||||
|
||||
void upx_compiler_sanity_check(void) noexcept {
|
||||
const char *e = getenv("UPX_DEBUG_DOCTEST_DISABLE");
|
||||
if (!e)
|
||||
e = getenv("UPX_DEBUG_DISABLE_DOCTEST"); // allow alternate spelling
|
||||
if (e && e[0] && strcmp(e, "0") != 0) {
|
||||
// If UPX_DEBUG_DOCTEST_DISABLE is set then we don't want to throw any
|
||||
// exceptions in order to improve debugging experience.
|
||||
@ -622,4 +626,36 @@ TEST_CASE("libc snprintf") {
|
||||
CHECK_EQ(strcmp(buf, "-7.0.0.0.0.0.0.0.7.0xffffffffffffffff"), 0);
|
||||
}
|
||||
|
||||
TEST_CASE("libc qsort") {
|
||||
// runtime check that libc qsort() never compares identical objects
|
||||
struct Elem {
|
||||
upx_uint16_t id;
|
||||
upx_uint16_t value;
|
||||
static int compare(const void *aa, const void *bb) noexcept {
|
||||
const Elem *a = (const Elem *) aa;
|
||||
const Elem *b = (const Elem *) bb;
|
||||
assert_noexcept(a->id != b->id); // check not IDENTICAL
|
||||
return a->value < b->value ? -1 : (a->value == b->value ? 0 : 1);
|
||||
}
|
||||
static bool qsort_check(Elem *e, size_t n) {
|
||||
upx_uint32_t x = n + 5381;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
e[i].id = (upx_uint16_t) i;
|
||||
x = x * 33 + (i & 255);
|
||||
e[i].value = (upx_uint16_t) x;
|
||||
}
|
||||
qsort(e, n, sizeof(*e), Elem::compare);
|
||||
bool sorted_ok = true;
|
||||
for (size_t i = 1; i < n; i++)
|
||||
sorted_ok &= e[i - 1].value <= e[i].value;
|
||||
return sorted_ok;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr size_t N = 4096;
|
||||
Elem e[N];
|
||||
for (size_t n = 1; n <= N; n <<= 1)
|
||||
CHECK(Elem::qsort_check(e, n));
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
36
src/except.h
36
src/except.h
@ -186,32 +186,32 @@ public:
|
||||
#define NORET noinline
|
||||
#endif
|
||||
|
||||
NORET void throwCantPack(const char *msg);
|
||||
NORET void throwCantPackExact();
|
||||
NORET void throwUnknownExecutableFormat(const char *msg = nullptr, bool warn = false);
|
||||
NORET void throwNotCompressible(const char *msg = nullptr);
|
||||
NORET void throwAlreadyPacked(const char *msg = nullptr);
|
||||
NORET void throwAlreadyPackedByUPX(const char *msg = nullptr);
|
||||
NORET void throwCantUnpack(const char *msg);
|
||||
NORET void throwNotPacked(const char *msg = nullptr);
|
||||
NORET void throwFilterException();
|
||||
NORET void throwBadLoader();
|
||||
NORET void throwChecksumError();
|
||||
NORET void throwCompressedDataViolation();
|
||||
NORET void throwInternalError(const char *msg);
|
||||
NORET void throwOutOfMemoryException(const char *msg = nullptr);
|
||||
NORET void throwIOException(const char *msg = nullptr, int e = 0);
|
||||
NORET void throwEOFException(const char *msg = nullptr, int e = 0);
|
||||
NORET void throwCantPack(const char *msg) may_throw;
|
||||
NORET void throwCantPackExact() may_throw;
|
||||
NORET void throwUnknownExecutableFormat(const char *msg = nullptr, bool warn = false) may_throw;
|
||||
NORET void throwNotCompressible(const char *msg = nullptr) may_throw;
|
||||
NORET void throwAlreadyPacked(const char *msg = nullptr) may_throw;
|
||||
NORET void throwAlreadyPackedByUPX(const char *msg = nullptr) may_throw;
|
||||
NORET void throwCantUnpack(const char *msg) may_throw;
|
||||
NORET void throwNotPacked(const char *msg = nullptr) may_throw;
|
||||
NORET void throwFilterException() may_throw;
|
||||
NORET void throwBadLoader() may_throw;
|
||||
NORET void throwChecksumError() may_throw;
|
||||
NORET void throwCompressedDataViolation() may_throw;
|
||||
NORET void throwInternalError(const char *msg) may_throw;
|
||||
NORET void throwOutOfMemoryException(const char *msg = nullptr) may_throw;
|
||||
NORET void throwIOException(const char *msg = nullptr, int e = 0) may_throw;
|
||||
NORET void throwEOFException(const char *msg = nullptr, int e = 0) may_throw;
|
||||
|
||||
// some C++ template wizardry is needed to overload throwCantPack() for varargs
|
||||
template <class T>
|
||||
void throwCantPack(const T *, ...) DELETED_FUNCTION;
|
||||
template <>
|
||||
NORET void throwCantPack(const char *format, ...) attribute_format(1, 2);
|
||||
NORET void throwCantPack(const char *format, ...) may_throw attribute_format(1, 2);
|
||||
template <class T>
|
||||
void throwCantUnpack(const T *, ...) DELETED_FUNCTION;
|
||||
template <>
|
||||
NORET void throwCantUnpack(const char *format, ...) attribute_format(1, 2);
|
||||
NORET void throwCantUnpack(const char *format, ...) may_throw attribute_format(1, 2);
|
||||
|
||||
#undef NORET
|
||||
|
||||
|
@ -1238,8 +1238,9 @@ Linker* PackVmlinuxAMD64::newLinker() const
|
||||
|
||||
|
||||
// instantiate instances
|
||||
template class PackVmlinuxBase<ElfClass_LE32>;
|
||||
template class PackVmlinuxBase<ElfClass_BE32>;
|
||||
// template class PackVmlinuxBase<ElfClass_BE64>; // not used
|
||||
template class PackVmlinuxBase<ElfClass_LE32>;
|
||||
template class PackVmlinuxBase<ElfClass_LE64>;
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
@ -91,7 +91,7 @@ PackMaster::~PackMaster() noexcept {
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
static tribool try_can_pack(PackerBase *pb, void *user) may_throw {
|
||||
static noinline tribool try_can_pack(PackerBase *pb, void *user) may_throw {
|
||||
InputFile *f = (InputFile *) user;
|
||||
try {
|
||||
pb->initPackHeader();
|
||||
@ -111,7 +111,7 @@ static tribool try_can_pack(PackerBase *pb, void *user) may_throw {
|
||||
return false;
|
||||
}
|
||||
|
||||
static tribool try_can_unpack(PackerBase *pb, void *user) may_throw {
|
||||
static noinline tribool try_can_unpack(PackerBase *pb, void *user) may_throw {
|
||||
InputFile *f = (InputFile *) user;
|
||||
try {
|
||||
pb->initPackHeader();
|
||||
|
@ -40,11 +40,11 @@ public:
|
||||
explicit PackMaster(InputFile *f, Options *o = nullptr) noexcept;
|
||||
~PackMaster() noexcept;
|
||||
|
||||
void pack(OutputFile *fo);
|
||||
void unpack(OutputFile *fo);
|
||||
void test();
|
||||
void list();
|
||||
void fileInfo();
|
||||
void pack(OutputFile *fo) may_throw;
|
||||
void unpack(OutputFile *fo) may_throw;
|
||||
void test() may_throw;
|
||||
void list() may_throw;
|
||||
void fileInfo() may_throw;
|
||||
|
||||
typedef tribool (*visit_func_t)(PackerBase *pb, void *user);
|
||||
static PackerBase *visitAllPackers(visit_func_t, InputFile *f, const Options *, void *user)
|
||||
@ -54,8 +54,8 @@ private:
|
||||
OwningPointer(PackerBase) packer = nullptr; // owner
|
||||
InputFile *const fi; // reference, required
|
||||
|
||||
static PackerBase *getPacker(InputFile *f);
|
||||
static PackerBase *getUnpacker(InputFile *f);
|
||||
static PackerBase *getPacker(InputFile *f) may_throw;
|
||||
static PackerBase *getUnpacker(InputFile *f) may_throw;
|
||||
|
||||
// setup local options for each file
|
||||
Options local_options;
|
||||
|
@ -704,8 +704,9 @@ class PeFile::ImportLinker final : public ElfLinkerAMD64 {
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
// What could remain?
|
||||
// make sort order deterministic
|
||||
assert_noexcept(a->sort_id != b->sort_id);
|
||||
return a->sort_id < b->sort_id ? -1 : 1; // make sort order deterministic
|
||||
return a->sort_id < b->sort_id ? -1 : 1;
|
||||
}
|
||||
|
||||
virtual void alignCode(unsigned len) override { alignWithByte(len, 0); }
|
||||
|
@ -42,13 +42,13 @@
|
||||
XSPAN_NAMESPACE_BEGIN
|
||||
|
||||
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
|
||||
noinline void xspan_fail_nullptr(void);
|
||||
noinline void xspan_fail_nullbase(void);
|
||||
noinline void xspan_fail_not_same_base(void);
|
||||
noinline void xspan_fail_range_nullptr(void);
|
||||
noinline void xspan_fail_range_nullbase(void);
|
||||
noinline void xspan_fail_range_range(void);
|
||||
void xspan_check_range(const void *ptr, const void *base, ptrdiff_t size_in_bytes);
|
||||
noinline void xspan_fail_nullptr(void) may_throw;
|
||||
noinline void xspan_fail_nullbase(void) may_throw;
|
||||
noinline void xspan_fail_not_same_base(void) may_throw;
|
||||
noinline void xspan_fail_range_nullptr(void) may_throw;
|
||||
noinline void xspan_fail_range_nullbase(void) may_throw;
|
||||
noinline void xspan_fail_range_range(void) may_throw;
|
||||
void xspan_check_range(const void *ptr, const void *base, ptrdiff_t size_in_bytes) may_throw;
|
||||
|
||||
// help constructor to distinguish between number of elements and bytes
|
||||
struct XSpanCount {
|
||||
|
Loading…
Reference in New Issue
Block a user