diff --git a/.clang-format b/.clang-format index d052c8fc..5c712459 100644 --- a/.clang-format +++ b/.clang-format @@ -1,11 +1,15 @@ -# "Gofmt's style is nobody's favourite, but gofmt is everybody's favourite." --Rob Pike -# +# vim:set ft=yaml ts=2 sw=2 et: +# Copyright (C) Markus Franz Xaver Johannes Oberhumer # for clang-format-15.0.6 from https://github.com/upx/upx-stubtools/releases +# +# "Gofmt's style is nobody's favourite, but gofmt is everybody's favourite." --Rob Pike + --- BasedOnStyle: LLVM ColumnLimit: 100 IndentWidth: 4 --- +# settings for C and C++ Language: Cpp AccessModifierOffset: -4 AlignConsecutiveMacros: AcrossComments diff --git a/.clang-tidy b/.clang-tidy index 8297518b..e4202aa2 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,4 +1,7 @@ +# vim:set ft=yaml ts=2 sw=2 et: +# Copyright (C) Markus Franz Xaver Johannes Oberhumer # for clang-tidy-16 from https://clang.llvm.org/extra/clang-tidy/ + --- Checks: > -*, diff --git a/.clangd b/.clangd new file mode 100644 index 00000000..9cbc3fd3 --- /dev/null +++ b/.clangd @@ -0,0 +1,36 @@ +# vim:set ft=yaml ts=2 sw=2 et: +# Copyright (C) Markus Franz Xaver Johannes Oberhumer +# for clangd-17 from https://clangd.llvm.org/ + +--- +# treat *.h files as C++ source code +If: + PathMatch: src/.*\.h + PathExclude: vendor/.* +CompileFlags: + Add: + - -xc++ +--- +# common C++ flags +If: + PathMatch: [ src/.*\.h, src/.*\.cpp ] + PathExclude: vendor/.* +CompileFlags: + Add: + - -std=gnu++17 + # see https://github.com/clangd/clangd/issues/1038 : Support deterministic relative include path + - -Ivendor + - -I../vendor + - -I../../vendor + - -DDEBUG + - -fno-strict-aliasing + - -fno-strict-overflow + - -funsigned-char +Diagnostics: + Includes: + # IgnoreHeader: A list of regexes. Include Cleaner will not produce diagnostics + # for headers whose path is a suffix match for any of these. + IgnoreHeader: + - src/.*\.h + UnusedIncludes: None +... diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb82523d..1782e42b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ env: DEBIAN_FRONTEND: noninteractive UPX_CMAKE_BUILD_FLAGS: --verbose UPX_CMAKE_CONFIG_FLAGS: -Wdev --warn-uninitialized + UPX_DEBUG_TEST_FLOAT_DIVISION_BY_ZERO: 1 # 2024-01-25 ZIG_DIST_VERSION: 0.12.0-dev.2341+92211135f @@ -463,8 +464,8 @@ jobs: - { zig_target: aarch64-windows-gnu } - { zig_target: arm-linux-musleabihf, qemu: qemu-arm } # { zig_target: arm-linux-musleabihf, qemu: qemu-arm, zig_pic: -fPIE } - - { zig_target: i386-linux-musl, qemu: qemu-i386 } - # { zig_target: i386-linux-musl, qemu: qemu-i386, zig_pic: -fPIE } + - { zig_target: i386-linux-musl, qemu: qemu-i386 -cpu Conroe } + # { zig_target: i386-linux-musl, qemu: qemu-i386 -cpu Conroe, zig_pic: -fPIE } - { zig_target: i386-windows-gnu } # mips and mipsel: bad hard-float code generation; see https://github.com/upx/upx/issues/788 - { zig_target: mips-linux-musl, zig_flags: -msoft-float, qemu: qemu-mips } @@ -576,7 +577,7 @@ jobs: if: ${{ matrix.qemu }} run: | qemu="${{ matrix.qemu }}" - apk add coreutils $qemu + apk add coreutils "${qemu%% *}" export upx_exe_runner="$qemu" env -C build/zig/${ZIG_TARGET}${ZIG_PIC}/debug bash "$PWD"/misc/testsuite/mimic_ctest.sh env -C build/zig/${ZIG_TARGET}${ZIG_PIC}/release bash "$PWD"/misc/testsuite/mimic_ctest.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index d7165faa..9c329c6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ option(UPX_CONFIG_DISABLE_SELF_PACK_TEST "Do not test packing UPX with itself" O # init #*********************************************************************** -set(UPX_VERSION_STRING "4.3.0") +set(UPX_VERSION_STRING "4.3.0") # this should match src/version.h upx_cmake_include_hook(2_init) @@ -129,7 +129,7 @@ else() endif() # CMake init -upx_set_default_build_type(Release) +upx_set_default_build_type(Release) # default is CMAKE_BUILD_TYPE=Release project(upx VERSION "${UPX_VERSION_STRING}" LANGUAGES C CXX) upx_apply_build_type() @@ -496,7 +496,9 @@ upx_cmake_include_hook(8_summary) upx_print_var(CMAKE_VERSION UPX_CONFIG_CMAKE_MINIMUM_REQUIRED_VERSION CMAKE_GENERATOR) if(NOT UPX_CONFIG_CMAKE_DISABLE_PRINT_INFO) -upx_print_var(CMAKE_BINARY_DIR CMAKE_SOURCE_DIR CMAKE_CURRENT_BINARY_DIR CMAKE_CURRENT_SOURCE_DIR) +if(NOT ",${CMAKE_BINARY_DIR}," STREQUAL ",${CMAKE_CURRENT_BINARY_DIR}," OR NOT ",${CMAKE_SOURCE_DIR}," STREQUAL ",${CMAKE_CURRENT_SOURCE_DIR},") + upx_print_var(CMAKE_BINARY_DIR CMAKE_SOURCE_DIR CMAKE_CURRENT_BINARY_DIR CMAKE_CURRENT_SOURCE_DIR) +endif() upx_print_var(CMAKE_HOST_SYSTEM_NAME CMAKE_HOST_SYSTEM_VERSION CMAKE_HOST_SYSTEM_PROCESSOR CMAKE_APPLE_SILICON_PROCESSOR) upx_print_var(CMAKE_SYSTEM_NAME CMAKE_SYSTEM_VERSION CMAKE_SYSTEM_PROCESSOR CMAKE_CROSSCOMPILING CMAKE_CROSSCOMPILING_EMULATOR) upx_print_var(CMAKE_OSX_DEPLOYMENT_TARGET CMAKE_OSX_SYSROOT) diff --git a/misc/make/Makefile-extra.mk b/misc/make/Makefile-extra.mk index a7bc3054..1e4ae959 100644 --- a/misc/make/Makefile-extra.mk +++ b/misc/make/Makefile-extra.mk @@ -242,7 +242,9 @@ endif # assemble cmake config flags; useful for CI jobs #*********************************************************************** -ifneq ($(origin UPX_CMAKE_CONFIG_FLAGS),command line) # needed to work around a GNU make bug +ifneq ($(origin UPX_CMAKE_CONFIG_FLAGS),command line) # GNU make bug work-around +# GNU make bug, see https://savannah.gnu.org/bugs/index.php?64822 +# and commit https://git.savannah.gnu.org/cgit/make.git/commit/?id=07187db947ba25e6c59b55f10660a04f8e9c5229 # info: by default CMake only honors the CC and CXX environment variables; make # it easy to set other variables like CMAKE_AR or CMAKE_RANLIB diff --git a/misc/scripts/upx-clang-format.sh b/misc/scripts/upx-clang-format.sh index 2d7a5a11..4a0f4981 100755 --- a/misc/scripts/upx-clang-format.sh +++ b/misc/scripts/upx-clang-format.sh @@ -2,13 +2,14 @@ ## vim:set ts=4 sw=4 et: set -e; set -o pipefail +# Copyright (C) Markus Franz Xaver Johannes Oberhumer +# # "Gofmt's style is nobody's favourite, but gofmt is everybody's favourite." --Rob Pike # # NOTE: we are using clang-format-15.0.6 from upx-stubtools # see https://github.com/upx/upx-stubtools/releases # # NOTE: we use .clang-format config from upx.git/.clang-format -# Copyright (C) Markus Franz Xaver Johannes Oberhumer if [[ ! -f $UPX_CLANG_FORMAT ]]; then UPX_CLANG_FORMAT="$HOME/local/bin/bin-upx/clang-format-15.0.6" diff --git a/src/Makefile b/src/Makefile index 11299dd9..d1157062 100644 --- a/src/Makefile +++ b/src/Makefile @@ -13,11 +13,11 @@ ifndef top_srcdir top_srcdir := $(srcdir)/.. endif -# +#*********************************************************************** # redirect to top-level CMake build -# +#*********************************************************************** -# NOTE that top-level Makefile .DEFAULT_GOAL is build/release +# NOTE that the top-level Makefile .DEFAULT_GOAL is build/release .DEFAULT_GOAL = build/all build/debug: $(top_srcdir)/build/debug @@ -42,10 +42,10 @@ CTEST = ctest test:: $(top_srcdir)/build/debug PHONY; cd $< && $(CTEST) test:: $(top_srcdir)/build/release PHONY; cd $< && $(CTEST) -# -# "make run-testsuite" +#*********************************************************************** +# make run-testsuite # git clone https://github.com/upx/upx-testsuite.git -# +#*********************************************************************** # search for the UPX testsuite # you also can override upx_testsuite_SRCDIR @@ -78,24 +78,28 @@ run-testsuite-release: $(top_srcdir)/build/release PHONY endif endif -# -# "make check-whitespace" -# +#*********************************************************************** +# make check-whitespace +#*********************************************************************** ifneq ($(wildcard /usr/bin/env),) # need Unix utils like bash, perl, sed, xargs, etc. + CHECK_WHITESPACE = bash $(top_srcdir)/misc/scripts/check_whitespace.sh $(top_srcdir) ifneq ($(wildcard $(top_srcdir)/.git/.),) CHECK_WHITESPACE = bash $(top_srcdir)/misc/scripts/check_whitespace_git.sh $(top_srcdir) endif check-whitespace: PHONY; $(CHECK_WHITESPACE) -endif -# -# "make clang-format" -# +endif # /usr/bin/env + +#*********************************************************************** +# make clang-format +#*********************************************************************** # automatically format some C++ source code files +ifneq ($(wildcard /usr/bin/env),) ifeq ($(shell uname),Linux) + # Markus loves clang-format, but John hates it; find a compromise CLANG_FORMAT_EXCLUDE_FILES += miniacc.h stub/%.h CLANG_FORMAT_EXCLUDE_FILES += p_lx_% p_mach% p_unix% p_vmlin% @@ -105,7 +109,9 @@ CLANG_FORMAT_FILES += $(sort $(wildcard ../misc/cmake/try_compile/*.[ch]*)) CLANG_FORMAT_FILES := $(filter-out $(CLANG_FORMAT_EXCLUDE_FILES),$(CLANG_FORMAT_FILES)) clang-format: $(CLANG_FORMAT_FILES) PHONY @echo "running upx-clang-format" - @$(top_srcdir)/misc/scripts/upx-clang-format.sh -i $(CLANG_FORMAT_FILES) -endif + @bash $(top_srcdir)/misc/scripts/upx-clang-format.sh -i $(CLANG_FORMAT_FILES) + +endif # Linux +endif # /usr/bin/env # vim:set ts=8 sw=8 noet: diff --git a/src/check/dt_check.cpp b/src/check/dt_check.cpp index 1368466c..a5c4a9d2 100644 --- a/src/check/dt_check.cpp +++ b/src/check/dt_check.cpp @@ -24,6 +24,8 @@ */ +#include "../headers.h" +#include // std::isnan #include "../conf.h" /************************************************************************* @@ -324,7 +326,7 @@ struct TestIntegerWrap { }; // -// basic exception handling +// basic exception handling checks to early catch toolchain/qemu/wine/etc problems // static noinline void throwSomeValue(int x) may_throw { @@ -347,20 +349,66 @@ static noinline void check_basic_cxx_exception_handling(void (*func)(int)) noexc } // -// basic floating point to early catch bad codegen -// (this has happened in the past with some exotic LLVM targets) +// basic floating point checks to early catch toolchain/qemu/wine/etc problems // -static noinline double sadd_a_b_div(upx_int64_t a, upx_int64_t b) { return (a + b) / 1000000.0; } -static noinline double uadd_a_b_div(upx_uint64_t a, upx_uint64_t b) { return (a + b) / 1000000.0; } -static noinline double ssub_a_b_div(upx_int64_t a, upx_int64_t b) { return (a - b) / 1000000.0; } -static noinline double usub_a_b_div(upx_uint64_t a, upx_uint64_t b) { return (a - b) / 1000000.0; } +static noinline float i64_f32_add_div(upx_int64_t a, upx_int64_t b) { return (a + b) / 1000000.0f; } +static noinline float u64_f32_add_div(upx_uint64_t a, upx_uint64_t b) { + return (a + b) / 1000000.0f; +} +static noinline float i64_f32_sub_div(upx_int64_t a, upx_int64_t b) { return (a - b) / 1000000.0f; } +static noinline float u64_f32_sub_div(upx_uint64_t a, upx_uint64_t b) { + return (a - b) / 1000000.0f; +} + +static noinline double i64_f64_add_div(upx_int64_t a, upx_int64_t b) { return (a + b) / 1000000.0; } +static noinline double u64_f64_add_div(upx_uint64_t a, upx_uint64_t b) { + return (a + b) / 1000000.0; +} +static noinline double i64_f64_sub_div(upx_int64_t a, upx_int64_t b) { return (a - b) / 1000000.0; } +static noinline double u64_f64_sub_div(upx_uint64_t a, upx_uint64_t b) { + return (a - b) / 1000000.0; +} + +template +struct TestFloat { + static constexpr Int X = 1000000; + static noinline Float div(Int a, Float f) { return a / f; } + static noinline Float add_div(Int a, Int b, Float f) { return Float(a + b) / f; } + static noinline Float sub_div(Int a, Int b, Float f) { return Float(a - b) / f; } + static noinline Float add_div_x(Int a, Int b) { return Float(a + b) / Float(X); } + static noinline Float sub_div_x(Int a, Int b) { return Float(a - b) / Float(X); } + static noinline void check() noexcept { + assert_noexcept(add_div(X, X, Float(X)) == Float(2)); + assert_noexcept(add_div_x(X, X) == Float(2)); + assert_noexcept(sub_div(3 * X, X, Float(X)) == Float(2)); + assert_noexcept(sub_div_x(3 * X, X) == Float(2)); + // extra debugging hack + const char *e = getenv("UPX_DEBUG_TEST_FLOAT_DIVISION_BY_ZERO"); + if (e && e[0] && strcmp(e, "0") != 0) { + assert_noexcept(std::isnan(div(0, Float(0)))); + assert_noexcept(std::isinf(div(X, Float(0)))); + } + } +}; static noinline void check_basic_floating_point(void) noexcept { - assert_noexcept(sadd_a_b_div(1000000, 1000000) == 2.0); - assert_noexcept(uadd_a_b_div(1000000, 1000000) == 2.0); - assert_noexcept(ssub_a_b_div(3000000, 1000000) == 2.0); - assert_noexcept(usub_a_b_div(3000000, 1000000) == 2.0); + assert_noexcept(i64_f32_add_div(1000000, 1000000) == 2.0f); + assert_noexcept(u64_f32_add_div(1000000, 1000000) == 2.0f); + assert_noexcept(i64_f32_sub_div(3000000, 1000000) == 2.0f); + assert_noexcept(u64_f32_sub_div(3000000, 1000000) == 2.0f); + assert_noexcept(i64_f64_add_div(1000000, 1000000) == 2.0); + assert_noexcept(u64_f64_add_div(1000000, 1000000) == 2.0); + assert_noexcept(i64_f64_sub_div(3000000, 1000000) == 2.0); + assert_noexcept(u64_f64_sub_div(3000000, 1000000) == 2.0); + TestFloat::check(); + TestFloat::check(); + TestFloat::check(); + TestFloat::check(); + TestFloat::check(); + TestFloat::check(); + TestFloat::check(); + TestFloat::check(); } } // namespace @@ -377,7 +425,7 @@ void upx_compiler_sanity_check(void) noexcept { // If UPX_DEBUG_DOCTEST_DISABLE is set then we don't want to throw any // exceptions in order to improve debugging experience. } else { - // check working C++ exception handling to catch toolchain/qemu/wine/etc problems + // check working C++ exception handling to early catch toolchain/qemu/wine/etc problems check_basic_cxx_exception_handling(throwSomeValue); } diff --git a/src/check/dt_impl.cpp b/src/check/dt_impl.cpp index 15b9e55d..1e2a2881 100644 --- a/src/check/dt_impl.cpp +++ b/src/check/dt_impl.cpp @@ -24,6 +24,8 @@ */ +#include "../util/system_defs.h" + /************************************************************************* // doctest support code implementation **************************************************************************/ @@ -50,7 +52,8 @@ #endif #endif // aligned_alloc() was added in glibc-2.16 -#if defined(__ELF__) && (__GLIBC__ + 0 == 2) && (__GLIBC_MINOR__ + 0 < 16) +#if defined(__ELF__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && (__GLIBC__ + 0 == 2) && \ + (__GLIBC_MINOR__ + 0 < 16) #define _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION #endif diff --git a/src/headers.h b/src/headers.h index 84c65501..904f179c 100644 --- a/src/headers.h +++ b/src/headers.h @@ -26,6 +26,8 @@ #pragma once +#include "util/system_defs.h" + #if !(__cplusplus + 0 >= 201703L) #error "C++17 is required" #endif @@ -54,30 +56,6 @@ static_assert(sizeof(long) == 4); static_assert(sizeof(void *) == 8); #endif -#if !defined(_FILE_OFFSET_BITS) -#define _FILE_OFFSET_BITS 64 -#endif -#if defined(_WIN32) && defined(__MINGW32__) && (defined(__clang__) || defined(__GNUC__)) -#if !defined(__USE_MINGW_ANSI_STDIO) -#define __USE_MINGW_ANSI_STDIO 1 -#endif -#endif -#if defined(_WIN32) -// disable silly warnings about using "deprecated" POSIX functions like fopen() -#if !defined(_CRT_NONSTDC_NO_DEPRECATE) -#define _CRT_NONSTDC_NO_DEPRECATE 1 -#endif -#if !defined(_CRT_NONSTDC_NO_WARNINGS) -#define _CRT_NONSTDC_NO_WARNINGS 1 -#endif -#if !defined(_CRT_SECURE_NO_DEPRECATE) -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif -#if !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS 1 -#endif -#endif // _WIN32 - // ACC and C system headers #ifndef ACC_CFG_USE_NEW_STYLE_CASTS #define ACC_CFG_USE_NEW_STYLE_CASTS 1 diff --git a/src/util/membuffer.cpp b/src/util/membuffer.cpp index cdc0364d..89036256 100644 --- a/src/util/membuffer.cpp +++ b/src/util/membuffer.cpp @@ -74,6 +74,7 @@ static forceinline constexpr bool use_simple_mcheck() noexcept { return true; } **************************************************************************/ MemBuffer::MemBuffer(upx_uint64_t bytes) : MemBufferBase() { + static_assert(element_size == 1); alloc(bytes); debug_set(debug.last_return_address_alloc, upx_return_address()); } diff --git a/src/util/membuffer.h b/src/util/membuffer.h index 3f76e61d..a8c179bd 100644 --- a/src/util/membuffer.h +++ b/src/util/membuffer.h @@ -204,7 +204,8 @@ public: // explicit conversion void *getVoidPtr() noexcept { return (void *) ptr; } const void *getVoidPtr() const noexcept { return (const void *) ptr; } - unsigned getSize() const noexcept { return size_in_bytes; } + unsigned getSizeInBytes() const noexcept { return size_in_bytes; } + unsigned getSize() const noexcept { return size_in_bytes; } // note: element_size == 1 // util noinline void fill(unsigned off, unsigned len, int value) may_throw; diff --git a/src/util/system_defs.h b/src/util/system_defs.h new file mode 100644 index 00000000..3eeb4f8f --- /dev/null +++ b/src/util/system_defs.h @@ -0,0 +1,59 @@ +/* system_defs.h -- system defines + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2024 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 + + */ + +#pragma once + +#if !defined(_FILE_OFFSET_BITS) +#define _FILE_OFFSET_BITS 64 +#endif + +#if !defined(__STDC_FORMAT_MACROS) // this is needed for some older glibc/mingw versions +#define __STDC_FORMAT_MACROS 1 +#endif + +#if defined(_WIN32) && defined(__MINGW32__) && (defined(__clang__) || defined(__GNUC__)) +#if !defined(__USE_MINGW_ANSI_STDIO) +#define __USE_MINGW_ANSI_STDIO 1 +#endif +#endif + +#if defined(_WIN32) +// disable silly warnings about using "deprecated" POSIX functions like fopen() +#if !defined(_CRT_NONSTDC_NO_DEPRECATE) +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#endif +#if !defined(_CRT_NONSTDC_NO_WARNINGS) +#define _CRT_NONSTDC_NO_WARNINGS 1 +#endif +#if !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS 1 +#endif +#endif // _WIN32 + +/* vim:set ts=4 sw=4 et: */