all: assorted cleanups and updates

Changes include:
  - add a bunch of "noexcept", mostly to operators and forceinline
  - use "uchar"
  - use "charptr"
  - rename options_t to Options
  - add ptr_check_no_overlap()
  - rewrite p_exe.cpp, NFCI
  - clang-format help.cpp
  - spelling fixes
This commit is contained in:
Markus F.X.J. Oberhumer 2023-03-15 00:19:55 +01:00
parent 127fd095e7
commit a627648249
65 changed files with 1492 additions and 1138 deletions

View File

@ -377,8 +377,8 @@ jobs:
- { zig_target: x86_64-macos.13-none } - { zig_target: x86_64-macos.13-none }
- { zig_target: x86_64-windows-gnu } - { zig_target: x86_64-windows-gnu }
env: env:
# 2023-02-19 # 2023-03-14
ZIG_DIST_VERSION: 0.11.0-dev.1650+5e7b09ce9 ZIG_DIST_VERSION: 0.11.0-dev.1970+962299157
# for zig-cc wrapper scripts (see below): # for zig-cc wrapper scripts (see below):
ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING
ZIG_FLAGS: ${{ matrix.zig_flags }} ZIG_FLAGS: ${{ matrix.zig_flags }}

View File

@ -27,7 +27,7 @@ jobs:
with: with:
operations-per-run: 300 operations-per-run: 300
exempt-all-milestones: true exempt-all-milestones: true
exempt-issue-labels: 'blocker,enhancement,regression' exempt-issue-labels: 'blocker,enhancement,help wanted,regression'
days-before-stale: 60 days-before-stale: 60
days-before-close: 30 days-before-close: 30
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Please remove the stale label or add a comment or this issue will be closed in 30 days.' stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Please remove the stale label or add a comment or this issue will be closed in 30 days.'

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR) cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR) # CMake >= 3.20.0 is recommended
# compilation config options # compilation config options
if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git") if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git")
@ -101,9 +101,13 @@ endif()
# targets # targets
#*********************************************************************** #***********************************************************************
#find_package(Threads) # multithreading is currently not used; maybe in UPX version 5 set(UPX_CONFIG_DISABLE_THREADS ON) # multithreading is currently not used; maybe in UPX version 5
set(UPX_CONFIG_DISABLE_ZSTD ON) # zstd is currently not used; maybe in UPX version 5 set(UPX_CONFIG_DISABLE_ZSTD ON) # zstd is currently not used; maybe in UPX version 5
if(NOT UPX_CONFIG_DISABLE_THREADS)
find_package(Threads)
endif()
file(GLOB ucl_SOURCES "vendor/ucl/src/*.c") file(GLOB ucl_SOURCES "vendor/ucl/src/*.c")
list(SORT ucl_SOURCES) list(SORT ucl_SOURCES)
add_library(upx_vendor_ucl STATIC ${ucl_SOURCES}) add_library(upx_vendor_ucl STATIC ${ucl_SOURCES})
@ -129,6 +133,9 @@ target_link_libraries(upx upx_vendor_ucl upx_vendor_zlib)
if(NOT UPX_CONFIG_DISABLE_ZSTD) if(NOT UPX_CONFIG_DISABLE_ZSTD)
target_link_libraries(upx upx_vendor_zstd) target_link_libraries(upx upx_vendor_zstd)
endif() endif()
if(Threads_FOUND)
target_link_libraries(upx Threads::Threads)
endif()
#*********************************************************************** #***********************************************************************
# compilation flags # compilation flags
@ -215,10 +222,11 @@ endif()
set(t upx_vendor_zlib) set(t upx_vendor_zlib)
upx_compile_target_debug_with_O2(${t}) upx_compile_target_debug_with_O2(${t})
upx_sanitize_target(${t}) upx_sanitize_target(${t})
target_compile_definitions(${t} PRIVATE HAVE_STDARG_H=1 HAVE_VSNPRINTF=1)
if(MSVC) if(MSVC)
target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_VSNPRINTF -J -W3 ${warn_WX}) target_compile_options(${t} PRIVATE -J -W3 ${warn_WX})
else() else()
target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_UNISTD_H -DHAVE_VSNPRINTF) target_compile_definitions(${t} PRIVATE HAVE_UNISTD_H=1)
# clang-15: -Wno-strict-prototypes is needed to silence the new -Wdeprecated-non-prototype warning # clang-15: -Wno-strict-prototypes is needed to silence the new -Wdeprecated-non-prototype warning
target_compile_options(${t} PRIVATE -Wall -Wno-strict-prototypes ${warn_Werror}) target_compile_options(${t} PRIVATE -Wall -Wno-strict-prototypes ${warn_Werror})
##target_compile_options(${t} PRIVATE ${warn_Wall} -Wno-cast-align -Wno-cast-qual -Wno-strict-prototypes ${warn_Werror}) ##target_compile_options(${t} PRIVATE ${warn_Wall} -Wno-cast-align -Wno-cast-qual -Wno-strict-prototypes ${warn_Werror})
@ -228,7 +236,7 @@ if(NOT UPX_CONFIG_DISABLE_ZSTD)
set(t upx_vendor_zstd) set(t upx_vendor_zstd)
upx_compile_target_debug_with_O2(${t}) upx_compile_target_debug_with_O2(${t})
upx_sanitize_target(${t}) upx_sanitize_target(${t})
target_compile_options(${t} PRIVATE -DDYNAMIC_BMI2=0 -DZSTD_DISABLE_ASM) target_compile_definitions(${t} PRIVATE DYNAMIC_BMI2=0 ZSTD_DISABLE_ASM=1)
if(MSVC) if(MSVC)
target_compile_options(${t} PRIVATE -J ${warn_WN} ${warn_WX}) target_compile_options(${t} PRIVATE -J ${warn_WN} ${warn_WX})
else() else()
@ -245,6 +253,9 @@ if(GITREV_SHORT)
target_compile_definitions(${t} PRIVATE UPX_VERSION_GIT_DESCRIBE="${GIT_DESCRIBE}") target_compile_definitions(${t} PRIVATE UPX_VERSION_GIT_DESCRIBE="${GIT_DESCRIBE}")
endif() endif()
endif() endif()
if(Threads_FOUND)
target_compile_definitions(${t} PRIVATE WITH_THREADS=1)
endif()
if(UPX_CONFIG_DISABLE_WSTRICT) if(UPX_CONFIG_DISABLE_WSTRICT)
target_compile_definitions(${t} PRIVATE UPX_CONFIG_DISABLE_WSTRICT=1) target_compile_definitions(${t} PRIVATE UPX_CONFIG_DISABLE_WSTRICT=1)
endif() endif()
@ -263,9 +274,9 @@ else()
endif() endif()
#*********************************************************************** #***********************************************************************
# "ctest" # ctest
# "make test" # make test
# "ninja test" # ninja test
#*********************************************************************** #***********************************************************************
if(NOT UPX_CONFIG_CMAKE_DISABLE_TEST) if(NOT UPX_CONFIG_CMAKE_DISABLE_TEST)
@ -302,9 +313,9 @@ endif()
endif() # UPX_CONFIG_CMAKE_DISABLE_TEST endif() # UPX_CONFIG_CMAKE_DISABLE_TEST
#*********************************************************************** #***********************************************************************
# "cmake --install ." # cmake --install .
# "make install" # make install
# "ninja install" # ninja install
#*********************************************************************** #***********************************************************************
if(NOT UPX_CONFIG_CMAKE_DISABLE_INSTALL) if(NOT UPX_CONFIG_CMAKE_DISABLE_INSTALL)
@ -350,12 +361,12 @@ print_var(CMAKE_C_COMPILER_ID CMAKE_C_COMPILER_VERSION CMAKE_C_COMPILER_ARCHITEC
print_var(CMAKE_CXX_COMPILER_ID CMAKE_CXX_COMPILER_VERSION CMAKE_CXX_COMPILER_ARCHITECTURE_ID CMAKE_CXX_PLATFORM_ID CMAKE_CXX_COMPILER_ABI) print_var(CMAKE_CXX_COMPILER_ID CMAKE_CXX_COMPILER_VERSION CMAKE_CXX_COMPILER_ARCHITECTURE_ID CMAKE_CXX_PLATFORM_ID CMAKE_CXX_COMPILER_ABI)
endif() # UPX_CONFIG_CMAKE_DISABLE_PRINT_INFO endif() # UPX_CONFIG_CMAKE_DISABLE_PRINT_INFO
print_var(CMAKE_INSTALL_PREFIX CMAKE_CONFIGURATION_TYPES CMAKE_BUILD_TYPE) print_var(CMAKE_INSTALL_PREFIX CMAKE_CONFIGURATION_TYPES CMAKE_BUILD_TYPE)
if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|Release)$") if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|None|Release)$")
message(WARNING "WARNING: unsupported CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}; please use \"Debug\" or \"Release\"") message(WARNING "WARNING: unsupported CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}; please use \"Debug\" or \"Release\"")
endif() endif()
if(NOT UPX_CONFIG_CMAKE_DISABLE_PLATFORM_CHECK)
# extra sanity checks to detect incompatible C vs CXX settings # extra sanity checks to detect incompatible C vs CXX settings
if(NOT UPX_CONFIG_CMAKE_DISABLE_PLATFORM_CHECK)
if(NOT ",${CMAKE_C_PLATFORM_ID}," STREQUAL ",${CMAKE_CXX_PLATFORM_ID},") if(NOT ",${CMAKE_C_PLATFORM_ID}," STREQUAL ",${CMAKE_CXX_PLATFORM_ID},")
message(FATAL_ERROR "ERROR: CMAKE_C_PLATFORM_ID CMAKE_CXX_PLATFORM_ID mismatch") message(FATAL_ERROR "ERROR: CMAKE_C_PLATFORM_ID CMAKE_CXX_PLATFORM_ID mismatch")
endif() endif()

View File

@ -44,8 +44,9 @@ all: build/debug build/release
debug: build/debug debug: build/debug
release: build/release release: build/release
.PHONY: PHONY
.NOTPARALLEL: # because the actual builds use "cmake --parallel" .NOTPARALLEL: # because the actual builds use "cmake --parallel"
.PHONY: PHONY
.SECONDEXPANSION:
.SUFFIXES: .SUFFIXES:
# END of Makefile; extra stuff follows # END of Makefile; extra stuff follows
@ -114,7 +115,7 @@ build/extra/scan-build/%: CMAKE := scan-build $(CMAKE)
build/extra/scan-build/%: export CCC_CC ?= clang build/extra/scan-build/%: export CCC_CC ?= clang
build/extra/scan-build/%: export CCC_CXX ?= clang++ build/extra/scan-build/%: export CCC_CXX ?= clang++
# cross compiler: Linux glibc aarch64-linux-gnu # cross compiler: Linux glibc aarch64-linux-gnu (arm64)
build/extra/cross-linux-aarch64/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/cross-linux-aarch64/debug: PHONY; $(call run_config_and_build,$@,Debug)
build/extra/cross-linux-aarch64/release: PHONY; $(call run_config_and_build,$@,Release) build/extra/cross-linux-aarch64/release: PHONY; $(call run_config_and_build,$@,Release)
build/extra/cross-linux-aarch64/%: export CC = aarch64-linux-gnu-gcc build/extra/cross-linux-aarch64/%: export CC = aarch64-linux-gnu-gcc
@ -126,13 +127,13 @@ build/extra/cross-linux-arm/release: PHONY; $(call run_config_and_build,$@,Relea
build/extra/cross-linux-arm/%: export CC = arm-linux-gnueabihf-gcc build/extra/cross-linux-arm/%: export CC = arm-linux-gnueabihf-gcc
build/extra/cross-linux-arm/%: export CXX = arm-linux-gnueabihf-g++ -Wno-psabi build/extra/cross-linux-arm/%: export CXX = arm-linux-gnueabihf-g++ -Wno-psabi
# cross compiler: Windows x86 win32 MinGW # cross compiler: Windows x86 win32 MinGW (i386)
build/extra/cross-windows-mingw32/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/cross-windows-mingw32/debug: PHONY; $(call run_config_and_build,$@,Debug)
build/extra/cross-windows-mingw32/release: PHONY; $(call run_config_and_build,$@,Release) build/extra/cross-windows-mingw32/release: PHONY; $(call run_config_and_build,$@,Release)
build/extra/cross-windows-mingw32/%: export CC = i686-w64-mingw32-gcc -static build/extra/cross-windows-mingw32/%: export CC = i686-w64-mingw32-gcc -static
build/extra/cross-windows-mingw32/%: export CXX = i686-w64-mingw32-g++ -static build/extra/cross-windows-mingw32/%: export CXX = i686-w64-mingw32-g++ -static
# cross compiler: Windows x64 win64 MinGW # cross compiler: Windows x64 win64 MinGW (amd64)
build/extra/cross-windows-mingw64/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/cross-windows-mingw64/debug: PHONY; $(call run_config_and_build,$@,Debug)
build/extra/cross-windows-mingw64/release: PHONY; $(call run_config_and_build,$@,Release) build/extra/cross-windows-mingw64/release: PHONY; $(call run_config_and_build,$@,Release)
build/extra/cross-windows-mingw64/%: export CC = x86_64-w64-mingw32-gcc -static build/extra/cross-windows-mingw64/%: export CC = x86_64-w64-mingw32-gcc -static
@ -144,7 +145,7 @@ build/extra/cross-darwin-arm64/release: PHONY; $(call run_config_and_build,$@,Re
build/extra/cross-darwin-arm64/%: export CC = clang -target arm64-apple-darwin build/extra/cross-darwin-arm64/%: export CC = clang -target arm64-apple-darwin
build/extra/cross-darwin-arm64/%: export CXX = clang++ -target arm64-apple-darwin build/extra/cross-darwin-arm64/%: export CXX = clang++ -target arm64-apple-darwin
# cross compiler: macOS x86_64 # cross compiler: macOS x86_64 (amd64)
build/extra/cross-darwin-x86_64/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/cross-darwin-x86_64/debug: PHONY; $(call run_config_and_build,$@,Debug)
build/extra/cross-darwin-x86_64/release: PHONY; $(call run_config_and_build,$@,Release) build/extra/cross-darwin-x86_64/release: PHONY; $(call run_config_and_build,$@,Release)
build/extra/cross-darwin-x86_64/%: export CC = clang -target x86_64-apple-darwin build/extra/cross-darwin-x86_64/%: export CC = clang -target x86_64-apple-darwin

4
THANKS
View File

@ -41,12 +41,14 @@ Joergen Ibsen <jibz@hotmail.com> and d'b
for the relocation & address optimization ideas for the relocation & address optimization ideas
John S. Fine <johnfine@erols.com> John S. Fine <johnfine@erols.com>
for the new version of the dos/exe decompressor for the new version of the dos/exe decompressor
Kornel Pal
for the EFI support
Lukundoo <Lukundoo@softhome.net> Lukundoo <Lukundoo@softhome.net>
for beta testing for beta testing
Michael Devore Michael Devore
for initial dos/exe device driver support for initial dos/exe device driver support
Oleg V. Volkov <rover@lglobus.ru> Oleg V. Volkov <rover@lglobus.ru>
for various FreeBSD specific informations for various FreeBSD specific information
The Owl & G-RoM The Owl & G-RoM
for the --compress-icons fix for the --compress-icons fix
Ralph Roth <RalphRoth@gmx.net> Ralph Roth <RalphRoth@gmx.net>

View File

@ -160,7 +160,7 @@ Copyright (c) 1996-2023 Markus Oberhumer, Laszlo Molnar &amp; John Reiser
<p>Info: An &quot;overlay&quot; means auxiliary data attached after the logical end of an executable, and it often contains application specific data (this is a common practice to avoid an extra data file, though it would be better to use resource sections).</p> <p>Info: An &quot;overlay&quot; means auxiliary data attached after the logical end of an executable, and it often contains application specific data (this is a common practice to avoid an extra data file, though it would be better to use resource sections).</p>
<p><b>UPX</b> handles overlays like many other executable packers do: it simply copies the overlay after the compressed image. This works with some files, but doesn&#39;t work with others, depending on how an application actually accesses this overlayed data.</p> <p><b>UPX</b> handles overlays like many other executable packers do: it simply copies the overlay after the compressed image. This works with some files, but doesn&#39;t work with others, depending on how an application actually accesses this overlaid data.</p>
<pre><code>--overlay=copy Copy any extra data attached to the file. [DEFAULT] <pre><code>--overlay=copy Copy any extra data attached to the file. [DEFAULT]

View File

@ -153,7 +153,7 @@ OVERLAY HANDLING OPTIONS
UPX handles overlays like many other executable packers do: it simply UPX handles overlays like many other executable packers do: it simply
copies the overlay after the compressed image. This works with some copies the overlay after the compressed image. This works with some
files, but doesn't work with others, depending on how an application files, but doesn't work with others, depending on how an application
actually accesses this overlayed data. actually accesses this overlaid data.
--overlay=copy Copy any extra data attached to the file. [DEFAULT] --overlay=copy Copy any extra data attached to the file. [DEFAULT]

View File

@ -296,7 +296,7 @@ it would be better to use resource sections).
\&\fB\s-1UPX\s0\fR handles overlays like many other executable packers do: it simply \&\fB\s-1UPX\s0\fR handles overlays like many other executable packers do: it simply
copies the overlay after the compressed image. This works with some copies the overlay after the compressed image. This works with some
files, but doesn't work with others, depending on how an application files, but doesn't work with others, depending on how an application
actually accesses this overlayed data. actually accesses this overlaid data.
.PP .PP
.Vb 1 .Vb 1
\& \-\-overlay=copy Copy any extra data attached to the file. [DEFAULT] \& \-\-overlay=copy Copy any extra data attached to the file. [DEFAULT]

View File

@ -208,7 +208,7 @@ it would be better to use resource sections).
B<UPX> handles overlays like many other executable packers do: it simply B<UPX> handles overlays like many other executable packers do: it simply
copies the overlay after the compressed image. This works with some copies the overlay after the compressed image. This works with some
files, but doesn't work with others, depending on how an application files, but doesn't work with others, depending on how an application
actually accesses this overlayed data. actually accesses this overlaid data.
--overlay=copy Copy any extra data attached to the file. [DEFAULT] --overlay=copy Copy any extra data attached to the file. [DEFAULT]

View File

@ -1,9 +1,10 @@
# #
# UPX Makefile - needs GNU make # UPX src Makefile - needs GNU make and CMake >= 3.13
# #
# IMPORTANT NOTE: this Makefile is deprecated - please # NOTE: this Makefile is deprecated - please directly use the CMake build
# directly use the CMake build instead! # instead. And see the top-level Makefile for some pre-defined CMake
# build configurations.
MAKEFLAGS += -r MAKEFLAGS += -r
.SUFFIXES: .SUFFIXES:
@ -21,6 +22,7 @@ endif
# redirect to top-level CMake build # redirect to top-level CMake build
# #
# note that top-level Makefile .DEFAULT_GOAL is build/release
.DEFAULT_GOAL = build/debug .DEFAULT_GOAL = build/debug
build/debug: $(top_srcdir)/build/debug/upx build/debug: $(top_srcdir)/build/debug/upx
@ -35,8 +37,10 @@ $(top_srcdir)/build/debug/upx: PHONY
$(top_srcdir)/build/release/upx: PHONY $(top_srcdir)/build/release/upx: PHONY
$(MAKE) -C $(top_srcdir) build/release $(MAKE) -C $(top_srcdir) build/release
.NOTPARALLEL: # because the actual builds use "cmake --parallel"
.PHONY: PHONY .PHONY: PHONY
.NOTPARALLEL: .SECONDEXPANSION:
.SUFFIXES:
# #
# "make run-testsuite" # "make run-testsuite"
@ -79,9 +83,8 @@ endif
# automatically format some C++ source code files # automatically format some C++ source code files
ifeq ($(shell uname),Linux) ifeq ($(shell uname),Linux)
# Markus loves clang-format, but John hates it; find a compromise # Markus loves clang-format, but John hates it; find a compromise
CLANG_FORMAT_EXCLUDE_FILES += conf.h miniacc.h version.h help.cpp CLANG_FORMAT_EXCLUDE_FILES += conf.h miniacc.h version.h packer_c.cpp
CLANG_FORMAT_EXCLUDE_FILES += p_elf.h p_elf_enum.h p_lx_% p_mach% p_unix% p_vmlin% CLANG_FORMAT_EXCLUDE_FILES += p_elf.h p_elf_enum.h p_lx_% p_mach% p_unix% p_vmlin%
CLANG_FORMAT_EXCLUDE_FILES += packer_c.cpp
CLANG_FORMAT_EXCLUDE_FILES += compress/compress.h filter/filter_impl.cpp CLANG_FORMAT_EXCLUDE_FILES += compress/compress.h filter/filter_impl.cpp
CLANG_FORMAT_FILES := $(sort $(wildcard *.[ch]* ../maint/src/*.[ch]* [cu]*/*.[ch]*)) CLANG_FORMAT_FILES := $(sort $(wildcard *.[ch]* ../maint/src/*.[ch]* [cu]*/*.[ch]*))
CLANG_FORMAT_FILES := $(filter-out $(CLANG_FORMAT_EXCLUDE_FILES),$(CLANG_FORMAT_FILES)) CLANG_FORMAT_FILES := $(filter-out $(CLANG_FORMAT_EXCLUDE_FILES),$(CLANG_FORMAT_FILES))

View File

@ -38,35 +38,35 @@
// core - NE // core - NE
**************************************************************************/ **************************************************************************/
static forceinline unsigned get_ne16(const void *p) { static forceinline unsigned get_ne16(const void *p) noexcept {
upx_uint16_t v = 0; upx_uint16_t v = 0;
upx_memcpy_inline(&v, p, sizeof(v)); upx_memcpy_inline(&v, p, sizeof(v));
return v; return v;
} }
static forceinline unsigned get_ne32(const void *p) { static forceinline unsigned get_ne32(const void *p) noexcept {
upx_uint32_t v = 0; upx_uint32_t v = 0;
upx_memcpy_inline(&v, p, sizeof(v)); upx_memcpy_inline(&v, p, sizeof(v));
return v; return v;
} }
static forceinline upx_uint64_t get_ne64(const void *p) { static forceinline upx_uint64_t get_ne64(const void *p) noexcept {
upx_uint64_t v = 0; upx_uint64_t v = 0;
upx_memcpy_inline(&v, p, sizeof(v)); upx_memcpy_inline(&v, p, sizeof(v));
return v; return v;
} }
static forceinline void set_ne16(void *p, unsigned vv) { static forceinline void set_ne16(void *p, unsigned vv) noexcept {
upx_uint16_t v = (upx_uint16_t) (vv & 0xffff); upx_uint16_t v = (upx_uint16_t) (vv & 0xffff);
upx_memcpy_inline(p, &v, sizeof(v)); upx_memcpy_inline(p, &v, sizeof(v));
} }
static forceinline void set_ne32(void *p, unsigned vv) { static forceinline void set_ne32(void *p, unsigned vv) noexcept {
upx_uint32_t v = vv; upx_uint32_t v = vv;
upx_memcpy_inline(p, &v, sizeof(v)); upx_memcpy_inline(p, &v, sizeof(v));
} }
static forceinline void set_ne64(void *p, upx_uint64_t vv) { static forceinline void set_ne64(void *p, upx_uint64_t vv) noexcept {
upx_uint64_t v = vv; upx_uint64_t v = vv;
upx_memcpy_inline(p, &v, sizeof(v)); upx_memcpy_inline(p, &v, sizeof(v));
} }
@ -79,31 +79,35 @@ static forceinline void set_ne64(void *p, upx_uint64_t vv) {
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4) ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)
// unfortunately *not* constexpr with MSVC // unfortunately *not* constexpr with current MSVC
static forceinline unsigned bswap16(unsigned v) { return (unsigned) _byteswap_ulong(v << 16); } static forceinline unsigned bswap16(unsigned v) noexcept {
static forceinline unsigned bswap32(unsigned v) { return (unsigned) _byteswap_ulong(v); } return (unsigned) _byteswap_ulong(v << 16);
static forceinline upx_uint64_t bswap64(upx_uint64_t v) { return _byteswap_uint64(v); } }
static forceinline unsigned bswap32(unsigned v) noexcept { return (unsigned) _byteswap_ulong(v); }
static forceinline upx_uint64_t bswap64(upx_uint64_t v) noexcept { return _byteswap_uint64(v); }
#else #else
static forceinline constexpr unsigned bswap16(unsigned v) { static forceinline constexpr unsigned bswap16(unsigned v) noexcept {
// return __builtin_bswap16((upx_uint16_t) (v & 0xffff)); // return __builtin_bswap16((upx_uint16_t) (v & 0xffff));
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48); // return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48);
return __builtin_bswap32(v << 16); return __builtin_bswap32(v << 16);
} }
static forceinline constexpr unsigned bswap32(unsigned v) { static forceinline constexpr unsigned bswap32(unsigned v) noexcept {
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 32); // return (unsigned) __builtin_bswap64((upx_uint64_t) v << 32);
return __builtin_bswap32(v); return __builtin_bswap32(v);
} }
static forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) { return __builtin_bswap64(v); } static forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) noexcept {
return __builtin_bswap64(v);
}
#endif #endif
static forceinline constexpr unsigned no_bswap16(unsigned v) { static forceinline constexpr unsigned no_bswap16(unsigned v) noexcept {
return v & 0xffff; // needed so that this is equivalent to bswap16() above return v & 0xffff; // needed so that this is equivalent to bswap16() above
} }
static forceinline constexpr unsigned no_bswap32(unsigned v) { return v; } static forceinline constexpr unsigned no_bswap32(unsigned v) noexcept { return v; }
static forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) { return v; } static forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) noexcept { return v; }
#if (ACC_ABI_BIG_ENDIAN) #if (ACC_ABI_BIG_ENDIAN)
#define ne16_to_be16(v) no_bswap16(v) #define ne16_to_be16(v) no_bswap16(v)
@ -170,30 +174,27 @@ inline unsigned get_le26(const void *p) { return get_le32(p) & 0x03ffffff; }
inline void set_le26(void *p, unsigned v) { inline void set_le26(void *p, unsigned v) {
// preserve the top 6 bits // preserve the top 6 bits
#if 0 // set_le32(p, (get_le32(p) & 0xfc000000) | (v & 0x03ffffff));
set_le32(p, (get_le32(p) & 0xfc000000) | (v & 0x03ffffff));
#else
// optimized version, saving a runtime bswap32 // optimized version, saving a runtime bswap32
set_ne32(p, (get_ne32(p) & ne32_to_le32(0xfc000000)) | set_ne32(p, (get_ne32(p) & ne32_to_le32(0xfc000000)) |
(ne32_to_le32(v) & ne32_to_le32(0x03ffffff))); (ne32_to_le32(v) & ne32_to_le32(0x03ffffff)));
#endif
} }
/************************************************************************* /*************************************************************************
// get signed values // get signed values
**************************************************************************/ **************************************************************************/
static forceinline int sign_extend(unsigned v, unsigned bits) { static forceinline int sign_extend(unsigned v, unsigned bits) noexcept {
const unsigned sign_bit = 1u << (bits - 1); const unsigned sign_bit = 1u << (bits - 1);
v &= sign_bit | (sign_bit - 1); v &= sign_bit | (sign_bit - 1);
v |= 0 - (v & sign_bit); v |= 0u - (v & sign_bit);
return ACC_ICAST(int, v); return ACC_ICAST(int, v);
} }
static forceinline upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) { static forceinline upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) noexcept {
const upx_uint64_t sign_bit = 1ull << (bits - 1); const upx_uint64_t sign_bit = 1ull << (bits - 1);
v &= sign_bit | (sign_bit - 1); v &= sign_bit | (sign_bit - 1);
v |= 0 - (v & sign_bit); v |= 0ull - (v & sign_bit);
return ACC_ICAST(upx_int64_t, v); return ACC_ICAST(upx_int64_t, v);
} }
@ -252,359 +253,348 @@ struct alignas(1) BE16 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[2]; byte d[2];
BE16 &operator=(unsigned v) { BE16 &operator=(unsigned v) noexcept {
set_be16(d, v); set_be16(d, v);
return *this; return *this;
} }
BE16 &operator+=(unsigned v) { BE16 &operator+=(unsigned v) noexcept {
set_be16(d, get_be16(d) + v); set_be16(d, get_be16(d) + v);
return *this; return *this;
} }
BE16 &operator-=(unsigned v) { BE16 &operator-=(unsigned v) noexcept {
set_be16(d, get_be16(d) - v); set_be16(d, get_be16(d) - v);
return *this; return *this;
} }
BE16 &operator*=(unsigned v) { BE16 &operator*=(unsigned v) noexcept {
set_be16(d, get_be16(d) * v); set_be16(d, get_be16(d) * v);
return *this; return *this;
} }
BE16 &operator/=(unsigned v) { BE16 &operator/=(unsigned v) noexcept {
set_be16(d, get_be16(d) / v); set_be16(d, get_be16(d) / v);
return *this; return *this;
} }
BE16 &operator&=(unsigned v) { BE16 &operator&=(unsigned v) noexcept {
set_be16(d, get_be16(d) & v); set_be16(d, get_be16(d) & v);
return *this; return *this;
} }
BE16 &operator|=(unsigned v) { BE16 &operator|=(unsigned v) noexcept {
set_be16(d, get_be16(d) | v); set_be16(d, get_be16(d) | v);
return *this; return *this;
} }
BE16 &operator^=(unsigned v) { BE16 &operator^=(unsigned v) noexcept {
set_be16(d, get_be16(d) ^ v); set_be16(d, get_be16(d) ^ v);
return *this; return *this;
} }
BE16 &operator<<=(unsigned v) { BE16 &operator<<=(unsigned v) noexcept {
set_be16(d, get_be16(d) << v); set_be16(d, get_be16(d) << v);
return *this; return *this;
} }
BE16 &operator>>=(unsigned v) { BE16 &operator>>=(unsigned v) noexcept {
set_be16(d, get_be16(d) >> v); set_be16(d, get_be16(d) >> v);
return *this; return *this;
} }
operator unsigned() const { return get_be16(d); } operator unsigned() const noexcept { return get_be16(d); }
bool operator<(const BE16 &v) const { return unsigned(*this) < unsigned(v); } bool operator<(const BE16 &v) const noexcept { return unsigned(*this) < unsigned(v); }
}; };
struct alignas(1) BE32 { struct alignas(1) BE32 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[4]; byte d[4];
BE32 &operator=(unsigned v) { BE32 &operator=(unsigned v) noexcept {
set_be32(d, v); set_be32(d, v);
return *this; return *this;
} }
BE32 &operator+=(unsigned v) { BE32 &operator+=(unsigned v) noexcept {
set_be32(d, get_be32(d) + v); set_be32(d, get_be32(d) + v);
return *this; return *this;
} }
BE32 &operator-=(unsigned v) { BE32 &operator-=(unsigned v) noexcept {
set_be32(d, get_be32(d) - v); set_be32(d, get_be32(d) - v);
return *this; return *this;
} }
BE32 &operator*=(unsigned v) { BE32 &operator*=(unsigned v) noexcept {
set_be32(d, get_be32(d) * v); set_be32(d, get_be32(d) * v);
return *this; return *this;
} }
BE32 &operator/=(unsigned v) { BE32 &operator/=(unsigned v) noexcept {
set_be32(d, get_be32(d) / v); set_be32(d, get_be32(d) / v);
return *this; return *this;
} }
BE32 &operator&=(unsigned v) { BE32 &operator&=(unsigned v) noexcept {
set_be32(d, get_be32(d) & v); set_be32(d, get_be32(d) & v);
return *this; return *this;
} }
BE32 &operator|=(unsigned v) { BE32 &operator|=(unsigned v) noexcept {
set_be32(d, get_be32(d) | v); set_be32(d, get_be32(d) | v);
return *this; return *this;
} }
BE32 &operator^=(unsigned v) { BE32 &operator^=(unsigned v) noexcept {
set_be32(d, get_be32(d) ^ v); set_be32(d, get_be32(d) ^ v);
return *this; return *this;
} }
BE32 &operator<<=(unsigned v) { BE32 &operator<<=(unsigned v) noexcept {
set_be32(d, get_be32(d) << v); set_be32(d, get_be32(d) << v);
return *this; return *this;
} }
BE32 &operator>>=(unsigned v) { BE32 &operator>>=(unsigned v) noexcept {
set_be32(d, get_be32(d) >> v); set_be32(d, get_be32(d) >> v);
return *this; return *this;
} }
operator unsigned() const { return get_be32(d); } operator unsigned() const noexcept { return get_be32(d); }
bool operator<(const BE32 &v) const { return unsigned(*this) < unsigned(v); } bool operator<(const BE32 &v) const noexcept { return unsigned(*this) < unsigned(v); }
}; };
struct alignas(1) BE64 { struct alignas(1) BE64 {
typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t
byte d[8]; byte d[8];
BE64 &operator=(upx_uint64_t v) { BE64 &operator=(upx_uint64_t v) noexcept {
set_be64(d, v); set_be64(d, v);
return *this; return *this;
} }
BE64 &operator+=(upx_uint64_t v) { BE64 &operator+=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) + v); set_be64(d, get_be64(d) + v);
return *this; return *this;
} }
BE64 &operator-=(upx_uint64_t v) { BE64 &operator-=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) - v); set_be64(d, get_be64(d) - v);
return *this; return *this;
} }
BE64 &operator*=(upx_uint64_t v) { BE64 &operator*=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) * v); set_be64(d, get_be64(d) * v);
return *this; return *this;
} }
BE64 &operator/=(upx_uint64_t v) { BE64 &operator/=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) / v); set_be64(d, get_be64(d) / v);
return *this; return *this;
} }
BE64 &operator&=(upx_uint64_t v) { BE64 &operator&=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) & v); set_be64(d, get_be64(d) & v);
return *this; return *this;
} }
BE64 &operator|=(upx_uint64_t v) { BE64 &operator|=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) | v); set_be64(d, get_be64(d) | v);
return *this; return *this;
} }
BE64 &operator^=(upx_uint64_t v) { BE64 &operator^=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) ^ v); set_be64(d, get_be64(d) ^ v);
return *this; return *this;
} }
BE64 &operator<<=(unsigned v) { BE64 &operator<<=(unsigned v) noexcept {
set_be64(d, get_be64(d) << v); set_be64(d, get_be64(d) << v);
return *this; return *this;
} }
BE64 &operator>>=(unsigned v) { BE64 &operator>>=(unsigned v) noexcept {
set_be64(d, get_be64(d) >> v); set_be64(d, get_be64(d) >> v);
return *this; return *this;
} }
operator upx_uint64_t() const { return get_be64(d); } operator upx_uint64_t() const noexcept { return get_be64(d); }
bool operator<(const BE64 &v) const { return upx_uint64_t(*this) < upx_uint64_t(v); } bool operator<(const BE64 &v) const noexcept { return upx_uint64_t(*this) < upx_uint64_t(v); }
}; };
struct alignas(1) LE16 { struct alignas(1) LE16 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[2]; byte d[2];
LE16 &operator=(unsigned v) { LE16 &operator=(unsigned v) noexcept {
set_le16(d, v); set_le16(d, v);
return *this; return *this;
} }
LE16 &operator+=(unsigned v) { LE16 &operator+=(unsigned v) noexcept {
set_le16(d, get_le16(d) + v); set_le16(d, get_le16(d) + v);
return *this; return *this;
} }
LE16 &operator-=(unsigned v) { LE16 &operator-=(unsigned v) noexcept {
set_le16(d, get_le16(d) - v); set_le16(d, get_le16(d) - v);
return *this; return *this;
} }
LE16 &operator*=(unsigned v) { LE16 &operator*=(unsigned v) noexcept {
set_le16(d, get_le16(d) * v); set_le16(d, get_le16(d) * v);
return *this; return *this;
} }
LE16 &operator/=(unsigned v) { LE16 &operator/=(unsigned v) noexcept {
set_le16(d, get_le16(d) / v); set_le16(d, get_le16(d) / v);
return *this; return *this;
} }
LE16 &operator&=(unsigned v) { LE16 &operator&=(unsigned v) noexcept {
set_le16(d, get_le16(d) & v); set_le16(d, get_le16(d) & v);
return *this; return *this;
} }
LE16 &operator|=(unsigned v) { LE16 &operator|=(unsigned v) noexcept {
set_le16(d, get_le16(d) | v); set_le16(d, get_le16(d) | v);
return *this; return *this;
} }
LE16 &operator^=(unsigned v) { LE16 &operator^=(unsigned v) noexcept {
set_le16(d, get_le16(d) ^ v); set_le16(d, get_le16(d) ^ v);
return *this; return *this;
} }
LE16 &operator<<=(unsigned v) { LE16 &operator<<=(unsigned v) noexcept {
set_le16(d, get_le16(d) << v); set_le16(d, get_le16(d) << v);
return *this; return *this;
} }
LE16 &operator>>=(unsigned v) { LE16 &operator>>=(unsigned v) noexcept {
set_le16(d, get_le16(d) >> v); set_le16(d, get_le16(d) >> v);
return *this; return *this;
} }
operator unsigned() const { return get_le16(d); } operator unsigned() const noexcept { return get_le16(d); }
bool operator<(const LE16 &v) const { return unsigned(*this) < unsigned(v); } bool operator<(const LE16 &v) const noexcept { return unsigned(*this) < unsigned(v); }
}; };
struct alignas(1) LE32 { struct alignas(1) LE32 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[4]; byte d[4];
LE32 &operator=(unsigned v) { LE32 &operator=(unsigned v) noexcept {
set_le32(d, v); set_le32(d, v);
return *this; return *this;
} }
LE32 &operator+=(unsigned v) { LE32 &operator+=(unsigned v) noexcept {
set_le32(d, get_le32(d) + v); set_le32(d, get_le32(d) + v);
return *this; return *this;
} }
LE32 &operator-=(unsigned v) { LE32 &operator-=(unsigned v) noexcept {
set_le32(d, get_le32(d) - v); set_le32(d, get_le32(d) - v);
return *this; return *this;
} }
LE32 &operator*=(unsigned v) { LE32 &operator*=(unsigned v) noexcept {
set_le32(d, get_le32(d) * v); set_le32(d, get_le32(d) * v);
return *this; return *this;
} }
LE32 &operator/=(unsigned v) { LE32 &operator/=(unsigned v) noexcept {
set_le32(d, get_le32(d) / v); set_le32(d, get_le32(d) / v);
return *this; return *this;
} }
LE32 &operator&=(unsigned v) { LE32 &operator&=(unsigned v) noexcept {
set_le32(d, get_le32(d) & v); set_le32(d, get_le32(d) & v);
return *this; return *this;
} }
LE32 &operator|=(unsigned v) { LE32 &operator|=(unsigned v) noexcept {
set_le32(d, get_le32(d) | v); set_le32(d, get_le32(d) | v);
return *this; return *this;
} }
LE32 &operator^=(unsigned v) { LE32 &operator^=(unsigned v) noexcept {
set_le32(d, get_le32(d) ^ v); set_le32(d, get_le32(d) ^ v);
return *this; return *this;
} }
LE32 &operator<<=(unsigned v) { LE32 &operator<<=(unsigned v) noexcept {
set_le32(d, get_le32(d) << v); set_le32(d, get_le32(d) << v);
return *this; return *this;
} }
LE32 &operator>>=(unsigned v) { LE32 &operator>>=(unsigned v) noexcept {
set_le32(d, get_le32(d) >> v); set_le32(d, get_le32(d) >> v);
return *this; return *this;
} }
operator unsigned() const { return get_le32(d); } operator unsigned() const noexcept { return get_le32(d); }
bool operator<(const LE32 &v) const { return unsigned(*this) < unsigned(v); } bool operator<(const LE32 &v) const noexcept { return unsigned(*this) < unsigned(v); }
}; };
struct alignas(1) LE64 { struct alignas(1) LE64 {
typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t
byte d[8]; byte d[8];
LE64 &operator=(upx_uint64_t v) { LE64 &operator=(upx_uint64_t v) noexcept {
set_le64(d, v); set_le64(d, v);
return *this; return *this;
} }
LE64 &operator+=(upx_uint64_t v) { LE64 &operator+=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) + v); set_le64(d, get_le64(d) + v);
return *this; return *this;
} }
LE64 &operator-=(upx_uint64_t v) { LE64 &operator-=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) - v); set_le64(d, get_le64(d) - v);
return *this; return *this;
} }
LE64 &operator*=(upx_uint64_t v) { LE64 &operator*=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) * v); set_le64(d, get_le64(d) * v);
return *this; return *this;
} }
LE64 &operator/=(upx_uint64_t v) { LE64 &operator/=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) / v); set_le64(d, get_le64(d) / v);
return *this; return *this;
} }
LE64 &operator&=(upx_uint64_t v) { LE64 &operator&=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) & v); set_le64(d, get_le64(d) & v);
return *this; return *this;
} }
LE64 &operator|=(upx_uint64_t v) { LE64 &operator|=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) | v); set_le64(d, get_le64(d) | v);
return *this; return *this;
} }
LE64 &operator^=(upx_uint64_t v) { LE64 &operator^=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) ^ v); set_le64(d, get_le64(d) ^ v);
return *this; return *this;
} }
LE64 &operator<<=(unsigned v) { LE64 &operator<<=(unsigned v) noexcept {
set_le64(d, get_le64(d) << v); set_le64(d, get_le64(d) << v);
return *this; return *this;
} }
LE64 &operator>>=(unsigned v) { LE64 &operator>>=(unsigned v) noexcept {
set_le64(d, get_le64(d) >> v); set_le64(d, get_le64(d) >> v);
return *this; return *this;
} }
operator upx_uint64_t() const { return get_le64(d); } operator upx_uint64_t() const noexcept { return get_le64(d); }
bool operator<(const LE64 &v) const { return upx_uint64_t(*this) < upx_uint64_t(v); } bool operator<(const LE64 &v) const noexcept { return upx_uint64_t(*this) < upx_uint64_t(v); }
}; };
// native types
#if (ACC_ABI_BIG_ENDIAN)
typedef BE16 NE16;
typedef BE32 NE32;
typedef BE64 NE64;
#else
typedef LE16 NE16;
typedef LE32 NE32;
typedef LE64 NE64;
#endif
/************************************************************************* /*************************************************************************
// global operators (pointer addition/subtraction) // global operators (pointer addition/subtraction)
**************************************************************************/ **************************************************************************/
template <class T> template <class T>
inline T *operator+(T *ptr, const BE16 &v) { inline T *operator+(T *ptr, const BE16 &v) noexcept {
return ptr + unsigned(v); return ptr + unsigned(v);
} }
template <class T> template <class T>
inline T *operator-(T *ptr, const BE16 &v) { inline T *operator-(T *ptr, const BE16 &v) noexcept {
return ptr - unsigned(v); return ptr - unsigned(v);
} }
template <class T> template <class T>
inline T *operator+(T *ptr, const BE32 &v) { inline T *operator+(T *ptr, const BE32 &v) noexcept {
return ptr + unsigned(v); return ptr + unsigned(v);
} }
template <class T> template <class T>
inline T *operator-(T *ptr, const BE32 &v) { inline T *operator-(T *ptr, const BE32 &v) noexcept {
return ptr - unsigned(v); return ptr - unsigned(v);
} }
template <class T> template <class T>
inline T *operator+(T *ptr, const LE16 &v) { inline T *operator+(T *ptr, const LE16 &v) noexcept {
return ptr + unsigned(v); return ptr + unsigned(v);
} }
template <class T> template <class T>
inline T *operator-(T *ptr, const LE16 &v) { inline T *operator-(T *ptr, const LE16 &v) noexcept {
return ptr - unsigned(v); return ptr - unsigned(v);
} }
template <class T> template <class T>
inline T *operator+(T *ptr, const LE32 &v) { inline T *operator+(T *ptr, const LE32 &v) noexcept {
return ptr + unsigned(v); return ptr + unsigned(v);
} }
template <class T> template <class T>
inline T *operator-(T *ptr, const LE32 &v) { inline T *operator-(T *ptr, const LE32 &v) noexcept {
return ptr - unsigned(v); return ptr - unsigned(v);
} }
// these are not implemented on purpose and will cause errors // these are not implemented on purpose and will cause errors
template <class T> template <class T>
T *operator+(T *ptr, const BE64 &v) DELETED_FUNCTION; T *operator+(T *ptr, const BE64 &v) noexcept DELETED_FUNCTION;
template <class T> template <class T>
T *operator-(T *ptr, const BE64 &v) DELETED_FUNCTION; T *operator-(T *ptr, const BE64 &v) noexcept DELETED_FUNCTION;
template <class T> template <class T>
T *operator+(T *ptr, const LE64 &v) DELETED_FUNCTION; T *operator+(T *ptr, const LE64 &v) noexcept DELETED_FUNCTION;
template <class T> template <class T>
T *operator-(T *ptr, const LE64 &v) DELETED_FUNCTION; T *operator-(T *ptr, const LE64 &v) noexcept DELETED_FUNCTION;
/************************************************************************* /*************************************************************************
// global overloads // global overloads
@ -644,6 +634,19 @@ inline unsigned UPX_MIN(const LE32 &a, unsigned b) { return UPX_MIN(unsigned(a),
// misc support // misc support
**************************************************************************/ **************************************************************************/
template <>
struct upx_is_integral<BE16> : public std::true_type {};
template <>
struct upx_is_integral<BE32> : public std::true_type {};
template <>
struct upx_is_integral<BE64> : public std::true_type {};
template <>
struct upx_is_integral<LE16> : public std::true_type {};
template <>
struct upx_is_integral<LE32> : public std::true_type {};
template <>
struct upx_is_integral<LE64> : public std::true_type {};
// for use with qsort() // for use with qsort()
extern "C" { extern "C" {
int __acc_cdecl_qsort be16_compare(const void *, const void *); int __acc_cdecl_qsort be16_compare(const void *, const void *);
@ -664,6 +667,23 @@ int __acc_cdecl_qsort le32_compare_signed(const void *, const void *);
int __acc_cdecl_qsort le64_compare_signed(const void *, const void *); int __acc_cdecl_qsort le64_compare_signed(const void *, const void *);
} // extern "C" } // extern "C"
// native types
#if (ACC_ABI_BIG_ENDIAN)
typedef BE16 NE16;
typedef BE32 NE32;
typedef BE64 NE64;
#define ne16_compare be16_compare
#define ne32_compare be32_compare
#define ne64_compare be64_compare
#else
typedef LE16 NE16;
typedef LE32 NE32;
typedef LE64 NE64;
#define ne16_compare le16_compare
#define ne32_compare le32_compare
#define ne64_compare le64_compare
#endif
/************************************************************************* /*************************************************************************
// Provide namespaces and classes to abstract endianness policies. // Provide namespaces and classes to abstract endianness policies.
// //

View File

@ -37,20 +37,20 @@
// CTP - Compile-Time Polymorphism (templates) // CTP - Compile-Time Polymorphism (templates)
#define V static inline #define V static inline
#define S static int __acc_cdecl_qsort #define S static int __acc_cdecl_qsort
#define C /*empty*/ #define C noexcept
#elif defined(BELE_RTP) #elif defined(BELE_RTP)
// RTP - Run-Time Polymorphism (virtual functions) // RTP - Run-Time Polymorphism (virtual functions)
#define V virtual #define V virtual
#define S virtual int #define S virtual int
#define C const #define C const noexcept
#else #else
#error #error
#endif #endif
#if defined(BELE_RTP) #if defined(BELE_RTP)
struct AbstractPolicy { struct AbstractPolicy {
inline AbstractPolicy() {} inline AbstractPolicy() noexcept {}
virtual inline ~AbstractPolicy() {} virtual inline ~AbstractPolicy() noexcept {}
V bool isBE() C = 0; V bool isBE() C = 0;
V bool isLE() C = 0; V bool isLE() C = 0;
@ -91,7 +91,7 @@ private:
#if defined(BELE_RTP) #if defined(BELE_RTP)
#undef C #undef C
#define C const override #define C const noexcept override
#endif #endif
struct BEPolicy struct BEPolicy
@ -99,7 +99,7 @@ struct BEPolicy
final : public AbstractPolicy final : public AbstractPolicy
#endif #endif
{ {
inline BEPolicy() {} inline BEPolicy() noexcept {}
#if defined(BELE_CTP) #if defined(BELE_CTP)
typedef N_BELE_RTP::BEPolicy RTP_Policy; typedef N_BELE_RTP::BEPolicy RTP_Policy;
#elif defined(BELE_RTP) #elif defined(BELE_RTP)
@ -160,7 +160,7 @@ struct LEPolicy
final : public AbstractPolicy final : public AbstractPolicy
#endif #endif
{ {
inline LEPolicy() {} inline LEPolicy() noexcept {}
#if defined(BELE_CTP) #if defined(BELE_CTP)
typedef N_BELE_RTP::LEPolicy RTP_Policy; typedef N_BELE_RTP::LEPolicy RTP_Policy;
#elif defined(BELE_RTP) #elif defined(BELE_RTP)
@ -225,24 +225,6 @@ typedef LEPolicy HostPolicy;
#error "ACC_ABI_ENDIAN" #error "ACC_ABI_ENDIAN"
#endif #endif
#if 0 /* UNUSED */
struct HostAlignedPolicy {
#if defined(BELE_CTP)
enum { isBE = HostPolicy::isBE, isLE = HostPolicy::isLE };
#endif
typedef upx_uint16_t U16;
typedef upx_uint32_t U32;
typedef upx_uint64_t U64;
static void compileTimeAssertions() {
COMPILE_TIME_ASSERT(sizeof(U16) == 2)
COMPILE_TIME_ASSERT(sizeof(U32) == 4)
COMPILE_TIME_ASSERT(sizeof(U64) == 8)
}
};
#endif
#undef V #undef V
#undef S #undef S
#undef C #undef C

View File

@ -39,7 +39,7 @@ int upx_doctest_check(int argc, char **argv) {
const char *e = getenv("UPX_DEBUG_DOCTEST_DISABLE"); const char *e = getenv("UPX_DEBUG_DOCTEST_DISABLE");
if (e && e[0] && strcmp(e, "0") != 0) if (e && e[0] && strcmp(e, "0") != 0)
return 0; return 0;
bool minimal = true; // only show failing tests bool minimal = true; // don't show summary
bool duration = false; // show timings bool duration = false; // show timings
bool success = false; // show all tests bool success = false; // show all tests
#if DEBUG #if DEBUG
@ -47,12 +47,13 @@ int upx_doctest_check(int argc, char **argv) {
#endif #endif
e = getenv("UPX_DEBUG_DOCTEST_VERBOSE"); e = getenv("UPX_DEBUG_DOCTEST_VERBOSE");
if (e && e[0]) { if (e && e[0]) {
minimal = false;
if (strcmp(e, "0") == 0) { if (strcmp(e, "0") == 0) {
minimal = true; minimal = true;
} else if (strcmp(e, "2") == 0) { } else if (strcmp(e, "2") == 0) {
minimal = false;
duration = true; duration = true;
} else if (strcmp(e, "3") == 0) { } else if (strcmp(e, "3") == 0) {
minimal = false;
duration = true; duration = true;
success = true; success = true;
} }
@ -100,6 +101,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER(bswap64(0x0807060504030201ull) == 0x0102030405060
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("") == 0) ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("") == 0)
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("a") == 1) ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("a") == 1)
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("ab") == 2)
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_eq("", "")) 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", ""))
@ -145,15 +147,18 @@ namespace {
template <class T> template <class T>
struct TestBELE { struct TestBELE {
__acc_static_noinline bool test(void) { static noinline bool test(void) {
// POD checks // POD checks
{ {
COMPILE_TIME_ASSERT(std::is_standard_layout<T>::value) COMPILE_TIME_ASSERT(std::is_standard_layout<T>::value)
COMPILE_TIME_ASSERT(std::is_trivial<T>::value) COMPILE_TIME_ASSERT(std::is_trivial<T>::value)
// extra checks, these are probably implied by std::is_trivial: // extra checks, these are probably implied by std::is_trivial
COMPILE_TIME_ASSERT(std::is_nothrow_default_constructible<T>::value) COMPILE_TIME_ASSERT(std::is_nothrow_default_constructible<T>::value)
COMPILE_TIME_ASSERT(std::is_trivially_copyable<T>::value) COMPILE_TIME_ASSERT(std::is_trivially_copyable<T>::value)
COMPILE_TIME_ASSERT(std::is_trivially_default_constructible<T>::value) COMPILE_TIME_ASSERT(std::is_trivially_default_constructible<T>::value)
// UPX
COMPILE_TIME_ASSERT(upx_is_integral<T>::value)
COMPILE_TIME_ASSERT(upx_is_integral_v<T>)
} }
// alignment checks // alignment checks
{ {
@ -177,8 +182,7 @@ struct TestBELE {
UNUSED(t1); UNUSED(t1);
UNUSED(t2); UNUSED(t2);
} }
#if 1 // arithmetic checks (modern compilers will optimize this away)
// arithmetic checks
{ {
T allbits; T allbits;
allbits = 0; allbits = 0;
@ -187,6 +191,7 @@ struct TestBELE {
T v1; T v1;
v1 = 1; v1 = 1;
v1 *= 2; v1 *= 2;
v1 /= 1;
v1 -= 1; v1 -= 1;
T v2; T v2;
v2 = 1; v2 = 1;
@ -217,14 +222,13 @@ struct TestBELE {
if ((v1 ^ v2) != 1) if ((v1 ^ v2) != 1)
return false; return false;
} }
#endif
return true; return true;
} }
}; };
template <class A, class B> template <class A, class B>
struct TestNoAliasingStruct { struct TestNoAliasingStruct {
__acc_static_noinline bool test(A *a, B *b) { static noinline bool test(A *a, B *b) {
*a = 0; *a = 0;
*b = 0; *b = 0;
*b -= 3; *b -= 3;
@ -232,7 +236,7 @@ struct TestNoAliasingStruct {
} }
}; };
template <class A, class B> template <class A, class B>
__acc_static_forceinline bool testNoAliasing(A *a, B *b) { static forceinline bool testNoAliasing(A *a, B *b) {
return TestNoAliasingStruct<A, B>::test(a, b); return TestNoAliasingStruct<A, B>::test(a, b);
} }
template <class T> template <class T>
@ -274,6 +278,10 @@ void upx_compiler_sanity_check(void) {
COMPILE_TIME_ASSERT_ALIGNED1(LE32) COMPILE_TIME_ASSERT_ALIGNED1(LE32)
COMPILE_TIME_ASSERT_ALIGNED1(LE64) COMPILE_TIME_ASSERT_ALIGNED1(LE64)
COMPILE_TIME_ASSERT(sizeof(upx_charptr_unit_type) == 1)
COMPILE_TIME_ASSERT_ALIGNED1(upx_charptr_unit_type)
COMPILE_TIME_ASSERT(sizeof(*((charptr) nullptr)) == 1)
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_STRING4) == 4 + 1) COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_STRING4) == 4 + 1)
assert(strlen(UPX_VERSION_STRING4) == 4); assert(strlen(UPX_VERSION_STRING4) == 4);
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_YEAR) == 4 + 1) COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_YEAR) == 4 + 1)
@ -293,7 +301,7 @@ void upx_compiler_sanity_check(void) {
} }
assert(UPX_RSIZE_MAX_MEM == 805306368); assert(UPX_RSIZE_MAX_MEM == 805306368);
#if 1 #if DEBUG || 1
assert(TestBELE<LE16>::test()); assert(TestBELE<LE16>::test());
assert(TestBELE<LE32>::test()); assert(TestBELE<LE32>::test());
assert(TestBELE<LE64>::test()); assert(TestBELE<LE64>::test());
@ -354,9 +362,9 @@ void upx_compiler_sanity_check(void) {
assert(dd == ne32_to_le32(0xf7020304)); assert(dd == ne32_to_le32(0xf7020304));
} }
{ {
upx_uint16_t a; upx_uint16_t a = 0;
upx_uint32_t b; upx_uint32_t b = 0;
upx_uint64_t c; upx_uint64_t c = 0;
set_ne16(&a, 0x04030201); // ignore upper bits set_ne16(&a, 0x04030201); // ignore upper bits
set_ne32(&b, 0x04030201); set_ne32(&b, 0x04030201);
set_ne64(&c, 0x0807060504030201ull); set_ne64(&c, 0x0807060504030201ull);
@ -454,7 +462,7 @@ TEST_CASE("working -fno-strict-overflow") {
} }
TEST_CASE("libc snprintf") { TEST_CASE("libc snprintf") {
// runtime check that Win32/MinGW <stdio.h> works as expected // runtime check that Windows/MinGW <stdio.h> works as expected
char buf[64]; char buf[64];
long long ll = acc_vget_int(-1, 0); long long ll = acc_vget_int(-1, 0);
unsigned long long llu = (unsigned long long) ll; unsigned long long llu = (unsigned long long) ll;

View File

@ -29,23 +29,30 @@
**************************************************************************/ **************************************************************************/
#define DOCTEST_CONFIG_IMPLEMENT #define DOCTEST_CONFIG_IMPLEMENT
#if !defined(UPX_DOCTEST_CONFIG_MULTITHREADING) #define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
#define DOCTEST_CONFIG_NO_MULTITHREADING
#endif #if !defined(DOCTEST_CONFIG_DISABLE)
#if defined(__i386__) && defined(__MSDOS__) && defined(__DJGPP__) && defined(__GNUC__) #if defined(__i386__) && defined(__MSDOS__) && defined(__DJGPP__) && defined(__GNUC__)
#define DOCTEST_CONFIG_NO_MULTITHREADING
#define DOCTEST_CONFIG_NO_POSIX_SIGNALS #define DOCTEST_CONFIG_NO_POSIX_SIGNALS
#elif defined(__m68k__) && defined(__atarist__) && defined(__GNUC__) #elif defined(__m68k__) && defined(__atarist__) && defined(__GNUC__)
#define DOCTEST_CONFIG_COLORS_NONE #define DOCTEST_CONFIG_COLORS_NONE
#define DOCTEST_CONFIG_NO_MULTITHREADING
#define DOCTEST_CONFIG_NO_POSIX_SIGNALS #define DOCTEST_CONFIG_NO_POSIX_SIGNALS
#pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Wshadow"
#endif #endif
#define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
#if !defined(DOCTEST_CONFIG_DISABLE) #if !defined(UPX_DOCTEST_CONFIG_MULTITHREADING)
#define DOCTEST_CONFIG_NO_MULTITHREADING
#endif
#if defined(__clang__) && defined(__FAST_MATH__) && defined(__INTEL_LLVM_COMPILER) #if defined(__clang__) && defined(__FAST_MATH__) && defined(__INTEL_LLVM_COMPILER)
// warning: comparison with NaN always evaluates to false in fast floating point modes // warning: comparison with NaN always evaluates to false in fast floating point modes
#pragma clang diagnostic ignored "-Wtautological-constant-compare" #pragma clang diagnostic ignored "-Wtautological-constant-compare"
#endif #endif
#include <doctest/doctest/parts/doctest.cpp> #include <doctest/doctest/parts/doctest.cpp>
#endif #endif // DOCTEST_CONFIG_DISABLE
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -91,6 +91,17 @@ TEST_CASE("basic xspan usage") {
CHECK_NOTHROW(raw_bytes(a0, 0)); CHECK_NOTHROW(raw_bytes(a0, 0));
CHECK_THROWS(raw_bytes(a0, 1)); CHECK_THROWS(raw_bytes(a0, 1));
CHECK_THROWS(raw_index_bytes(a0, 0, 0)); CHECK_THROWS(raw_index_bytes(a0, 0, 0));
CHECK(raw_bytes(b0, 0) == buf);
CHECK(raw_bytes(bp, 0) == buf);
// info: these will fail if we ever add an overload for bounded-arrays
#if WITH_XSPAN >= 2
CHECK(b0.raw_size_in_bytes() == 0u);
CHECK(bp.raw_size_in_bytes() == 0u);
#endif
CHECK(raw_bytes(b0, 999999) == buf);
CHECK(raw_bytes(bp, 999999) == buf);
CHECK(raw_bytes(c0, 4) == buf); CHECK(raw_bytes(c0, 4) == buf);
CHECK(raw_index_bytes(c0, 1, 3) == buf + 1); CHECK(raw_index_bytes(c0, 1, 3) == buf + 1);
CHECK(raw_bytes(cp, 4) == buf); CHECK(raw_bytes(cp, 4) == buf);
@ -136,6 +147,17 @@ TEST_CASE("basic xspan usage") {
CHECK_NOTHROW(raw_bytes(a0, 0)); CHECK_NOTHROW(raw_bytes(a0, 0));
CHECK_THROWS(raw_bytes(a0, 1)); CHECK_THROWS(raw_bytes(a0, 1));
CHECK_THROWS(raw_index_bytes(a0, 0, 0)); CHECK_THROWS(raw_index_bytes(a0, 0, 0));
CHECK(raw_bytes(b0, 0) == buf);
CHECK(raw_bytes(bp, 0) == buf);
// info: these will fail if we ever add an overload for bounded-arrays
#if WITH_XSPAN >= 2
CHECK(b0.raw_size_in_bytes() == 0u);
CHECK(bp.raw_size_in_bytes() == 0u);
#endif
CHECK(raw_bytes(b0, 999999) == buf);
CHECK(raw_bytes(bp, 999999) == buf);
CHECK(raw_bytes(c0, 4) == buf); CHECK(raw_bytes(c0, 4) == buf);
CHECK(raw_index_bytes(c0, 1, 3) == buf + 1); CHECK(raw_index_bytes(c0, 1, 3) == buf + 1);
CHECK(raw_bytes(cp, 4) == buf); CHECK(raw_bytes(cp, 4) == buf);

View File

@ -78,7 +78,7 @@ int upx_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned
// force users to provide *dst_len // force users to provide *dst_len
assert(*dst_len != 0); assert(*dst_len != 0);
#endif #endif
// for UPX, we always require a reasonably sized outbut buffer // for UPX, we always require a reasonably sized output buffer
assert(*dst_len >= MemBuffer::getSizeForCompression(src_len)); assert(*dst_len >= MemBuffer::getSizeForCompression(src_len));
if (!cresult) if (!cresult)

View File

@ -116,7 +116,7 @@ static bool prepare_result(lzma_compress_result_t *res, unsigned src_len, int me
res->lit_context_bits = (method >> 8) & 15; res->lit_context_bits = (method >> 8) & 15;
} }
#if 0 #if 0
// DEBUG - set sizes so that we use a maxmimum amount of stack. // DEBUG - set sizes so that we use a maximum amount of stack.
// These settings cause res->num_probs == 3147574, i.e. we will // These settings cause res->num_probs == 3147574, i.e. we will
// need about 6 MiB of stack during runtime decompression. // need about 6 MiB of stack during runtime decompression.
res->lit_pos_bits = 4; res->lit_pos_bits = 4;
@ -524,13 +524,12 @@ const char *upx_lzma_version_string(void) { return "4.43"; }
**************************************************************************/ **************************************************************************/
TEST_CASE("upx_lzma_decompress") { TEST_CASE("upx_lzma_decompress") {
typedef const upx_byte C; const byte *c_data;
C *c_data; byte d_buf[16];
upx_byte d_buf[16];
unsigned d_len; unsigned d_len;
int r; int r;
c_data = (C *) "\x1a\x03\x00\x7f\xed\x3c\x00\x00\x00"; c_data = (const byte *) "\x1a\x03\x00\x7f\xed\x3c\x00\x00\x00";
d_len = 16; d_len = 16;
r = upx_lzma_decompress(c_data, 9, d_buf, &d_len, M_LZMA, nullptr); r = upx_lzma_decompress(c_data, 9, d_buf, &d_len, M_LZMA, nullptr);
CHECK((r == 0 && d_len == 16)); CHECK((r == 0 && d_len == 16));

View File

@ -113,14 +113,14 @@ int upx_ucl_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsig
cconf.bb_endian = 0; cconf.bb_endian = 0;
cconf.bb_size = 0; cconf.bb_size = 0;
if (method >= M_NRV2B_LE32 && method <= M_NRV2E_LE16) { if (method >= M_NRV2B_LE32 && method <= M_NRV2E_LE16) {
static const unsigned char sizes[3] = {32, 8, 16}; static const upx_uint8_t sizes[3] = {32, 8, 16};
cconf.bb_size = sizes[(method - M_NRV2B_LE32) % 3]; cconf.bb_size = sizes[(method - M_NRV2B_LE32) % 3];
} else { } else {
throwInternalError("unknown compression method"); throwInternalError("unknown compression method");
return UPX_E_ERROR; return UPX_E_ERROR;
} }
// optimize compression parms // optimize compression params
if (level <= 3 && cconf.max_offset == UCL_UINT_MAX) if (level <= 3 && cconf.max_offset == UCL_UINT_MAX)
cconf.max_offset = 8 * 1024 - 1; cconf.max_offset = 8 * 1024 - 1;
else if (level == 4 && cconf.max_offset == UCL_UINT_MAX) else if (level == 4 && cconf.max_offset == UCL_UINT_MAX)
@ -241,9 +241,9 @@ int upx_ucl_test_overlap(const upx_bytep buf, const upx_bytep tbuf, unsigned src
**************************************************************************/ **************************************************************************/
extern "C" { extern "C" {
static ucl_voidp __UCL_CDECL my_malloc(ucl_uint n) { return calloc(1, n); } static ucl_voidp __UCL_CDECL my_malloc(ucl_uint n) { return upx_calloc(n, 1); }
static void __UCL_CDECL my_free(ucl_voidp p) { free(p); } static void __UCL_CDECL my_free(ucl_voidp p) { free(p); }
} } // extern "C"
int upx_ucl_init(void) { int upx_ucl_init(void) {
if (ucl_init() != UCL_E_OK) if (ucl_init() != UCL_E_OK)
@ -327,13 +327,12 @@ TEST_CASE("compress_ucl") {
#endif // DEBUG #endif // DEBUG
TEST_CASE("upx_ucl_decompress") { TEST_CASE("upx_ucl_decompress") {
typedef const upx_byte C; const byte *c_data;
C *c_data; byte d_buf[16];
upx_byte d_buf[16];
unsigned d_len; unsigned d_len;
int r; int r;
c_data = (C *) "\x92\xff\x10\x00\x00\x00\x00\x00\x48\xff"; c_data = (const byte *) "\x92\xff\x10\x00\x00\x00\x00\x00\x48\xff";
d_len = 16; d_len = 16;
r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr); r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr);
CHECK((r == 0 && d_len == 16)); CHECK((r == 0 && d_len == 16));
@ -343,7 +342,7 @@ TEST_CASE("upx_ucl_decompress") {
r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr); r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr);
CHECK(r == UPX_E_OUTPUT_OVERRUN); CHECK(r == UPX_E_OUTPUT_OVERRUN);
c_data = (C *) "\x92\xff\x10\x92\x49\x24\x92\xa0\xff"; c_data = (const byte *) "\x92\xff\x10\x92\x49\x24\x92\xa0\xff";
d_len = 16; d_len = 16;
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr); r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr);
CHECK((r == 0 && d_len == 16)); CHECK((r == 0 && d_len == 16));
@ -353,7 +352,7 @@ TEST_CASE("upx_ucl_decompress") {
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr); r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr);
CHECK(r == UPX_E_OUTPUT_OVERRUN); CHECK(r == UPX_E_OUTPUT_OVERRUN);
c_data = (C *) "\x90\xff\xb0\x92\x49\x24\x92\xa0\xff"; c_data = (const byte *) "\x90\xff\xb0\x92\x49\x24\x92\xa0\xff";
d_len = 16; d_len = 16;
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2E_8, nullptr); r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2E_8, nullptr);
CHECK((r == 0 && d_len == 16)); CHECK((r == 0 && d_len == 16));

View File

@ -287,13 +287,12 @@ TEST_CASE("compress_zlib") {
#endif // DEBUG #endif // DEBUG
TEST_CASE("upx_zlib_decompress") { TEST_CASE("upx_zlib_decompress") {
typedef const upx_byte C; const byte *c_data;
C *c_data; byte d_buf[16];
upx_byte d_buf[16];
unsigned d_len; unsigned d_len;
int r; int r;
c_data = (C *) "\xfb\xff\x1f\x15\x00\x00"; c_data = (const byte *) "\xfb\xff\x1f\x15\x00\x00";
d_len = 16; d_len = 16;
r = upx_zlib_decompress(c_data, 6, d_buf, &d_len, M_DEFLATE, nullptr); r = upx_zlib_decompress(c_data, 6, d_buf, &d_len, M_DEFLATE, nullptr);
CHECK((r == 0 && d_len == 16)); CHECK((r == 0 && d_len == 16));

View File

@ -207,13 +207,12 @@ TEST_CASE("compress_zstd") {
#endif // DEBUG #endif // DEBUG
TEST_CASE("upx_zstd_decompress") { TEST_CASE("upx_zstd_decompress") {
typedef const upx_byte C; const byte *c_data;
C *c_data; byte d_buf[32];
upx_byte d_buf[32];
unsigned d_len; unsigned d_len;
int r; int r;
c_data = (C *) "\x28\xb5\x2f\xfd\x20\x20\x3d\x00\x00\x08\xff\x01\x00\x34\x4e\x08"; c_data = (const byte *) "\x28\xb5\x2f\xfd\x20\x20\x3d\x00\x00\x08\xff\x01\x00\x34\x4e\x08";
d_len = 32; d_len = 32;
r = upx_zstd_decompress(c_data, 16, d_buf, &d_len, M_ZSTD, nullptr); r = upx_zstd_decompress(c_data, 16, d_buf, &d_len, M_ZSTD, nullptr);
CHECK((r == 0 && d_len == 32)); CHECK((r == 0 && d_len == 32));

View File

@ -100,6 +100,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
# pragma warning(error: 4805) # pragma warning(error: 4805)
#endif #endif
#endif // !UPX_CONFIG_DISABLE_WSTRICT && !UPX_CONFIG_DISABLE_WERROR #endif // !UPX_CONFIG_DISABLE_WSTRICT && !UPX_CONFIG_DISABLE_WERROR
// disable some warnings // disable some warnings
#if (ACC_CC_MSC) #if (ACC_CC_MSC)
# pragma warning(disable: 4244) // -Wconversion # pragma warning(disable: 4244) // -Wconversion
@ -124,22 +125,30 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
#include <new> #include <new>
#include <type_traits> #include <type_traits>
#include <typeinfo> #include <typeinfo>
#if __STDC_NO_ATOMICS__ || 1
// UPX currently does not use multithreading // multithreading (UPX currently does not use multithreading)
#define upx_std_atomic(Type) Type #ifndef WITH_THREADS
//#define upx_std_atomic(Type) typename std::add_volatile<Type>::type # define WITH_THREADS 0
#define upx_std_once_flag upx_std_atomic(size_t) #endif
template <class NoexceptCallable> #if __STDC_NO_ATOMICS__
inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) { # undef WITH_THREADS
if (__acc_unlikely(!flag)) { flag = 1; f(); } #endif
} #if (WITH_THREADS)
#else #define upx_thread_local thread_local
#include <atomic> #include <atomic>
#define upx_std_atomic(Type) std::atomic<Type> #define upx_std_atomic(Type) std::atomic<Type>
#include <mutex> #include <mutex>
#define upx_std_once_flag std::once_flag #define upx_std_once_flag std::once_flag
#define upx_std_call_once std::call_once #define upx_std_call_once std::call_once
#endif #else
#define upx_thread_local /*empty*/
#define upx_std_atomic(Type) Type
#define upx_std_once_flag upx_std_atomic(size_t)
template <class NoexceptCallable>
inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
if (__acc_unlikely(!flag)) { flag = 1; f(); }
}
#endif // WITH_THREADS
// C++ submodule headers // C++ submodule headers
#include <doctest/doctest/parts/doctest_fwd.h> #include <doctest/doctest/parts/doctest_fwd.h>
@ -166,16 +175,39 @@ inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
// <type_traits> C++20 std::is_bounded_array // <type_traits> C++20 std::is_bounded_array
template <class T> template <class T>
struct std_is_bounded_array : public std::false_type {}; struct upx_std_is_bounded_array : public std::false_type {};
template <class T, size_t N> template <class T, size_t N>
struct std_is_bounded_array<T[N]> : public std::true_type {}; struct upx_std_is_bounded_array<T[N]> : public std::true_type {};
template <class T>
inline constexpr bool upx_std_is_bounded_array_v = upx_std_is_bounded_array<T>::value;
// see bele.h
template <class T>
struct upx_is_integral : public std::is_integral<T> {};
template <class T>
inline constexpr bool upx_is_integral_v = upx_is_integral<T>::value;
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
// horrible hack for broken compiler
#define upx_fake_alignas_1 __attribute__((__aligned__(1),__packed__))
#define upx_fake_alignas_16 __attribute__((__aligned__(2))) // object file maximum 2 ???
#define upx_fake_alignas__(a) upx_fake_alignas_ ## a
#define alignas(x) upx_fake_alignas__(x)
#endif
/************************************************************************* /*************************************************************************
// core // core
**************************************************************************/ **************************************************************************/
// intergral types // protect against integer overflows and malicious header fields
// see C 11 standard, Annex K
typedef size_t upx_rsize_t;
#define UPX_RSIZE_MAX UPX_RSIZE_MAX_MEM
#define UPX_RSIZE_MAX_MEM (768 * 1024 * 1024) // DO NOT CHANGE !!!
#define UPX_RSIZE_MAX_STR (256 * 1024)
// integral types
typedef acc_int8_t upx_int8_t; typedef acc_int8_t upx_int8_t;
typedef acc_uint8_t upx_uint8_t; typedef acc_uint8_t upx_uint8_t;
typedef acc_int16_t upx_int16_t; typedef acc_int16_t upx_int16_t;
@ -186,16 +218,17 @@ typedef acc_int64_t upx_int64_t;
typedef acc_uint64_t upx_uint64_t; typedef acc_uint64_t upx_uint64_t;
typedef acc_uintptr_t upx_uintptr_t; typedef acc_uintptr_t upx_uintptr_t;
// convention: use "byte" when dealing with data; use "char/uchar" when dealing
// with strings; use "upx_uint8_t" when dealing with small integers
typedef unsigned char byte; typedef unsigned char byte;
#define upx_byte byte #define upx_byte byte
#define upx_bytep byte * #define upx_bytep byte *
typedef unsigned char uchar;
// protect against integer overflows and malicious header fields // use "charptr" when dealing with pointer arithmetics
// see C 11 standard, Annex K #define charptr upx_charptr_unit_type *
typedef size_t upx_rsize_t; // upx_charptr_unit_type is some opaque type with sizeof(type) == 1
#define UPX_RSIZE_MAX UPX_RSIZE_MAX_MEM struct alignas(1) upx_charptr_unit_type { char dummy; };
#define UPX_RSIZE_MAX_MEM (768 * 1024 * 1024) // DO NOT CHANGE !!! ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(upx_charptr_unit_type) == 1)
#define UPX_RSIZE_MAX_STR (1024 * 1024)
// using the system off_t was a bad idea even back in 199x... // using the system off_t was a bad idea even back in 199x...
typedef upx_int64_t upx_off_t; typedef upx_int64_t upx_off_t;
@ -244,8 +277,8 @@ typedef upx_int64_t upx_off_t;
#endif #endif
#if (ACC_OS_DOS32) && defined(__DJGPP__) #if (ACC_OS_DOS32) && defined(__DJGPP__)
# undef sopen # undef sopen
# undef __unix__
# undef __unix # undef __unix
# undef __unix__
#endif #endif
#ifndef STDIN_FILENO #ifndef STDIN_FILENO
@ -304,7 +337,7 @@ typedef upx_int64_t upx_off_t;
# endif # endif
#endif #endif
// avoid warnings about shadowing global functions // avoid warnings about shadowing global symbols
#undef _base #undef _base
#undef basename #undef basename
#undef index #undef index
@ -391,14 +424,6 @@ inline void NO_fprintf(FILE *, const char *, ...) {}
#define __packed_struct(s) struct alignas(1) s { #define __packed_struct(s) struct alignas(1) s {
#define __packed_struct_end() }; #define __packed_struct_end() };
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
// horrible hack for broken compiler
#define upx_fake_alignas_1 __attribute__((__aligned__(1),__packed__))
#define upx_fake_alignas_16 __attribute__((__aligned__(2))) // object file maximum 2 ???
#define upx_fake_alignas__(a) upx_fake_alignas_ ## a
#define alignas(x) upx_fake_alignas__(x)
#endif
#define COMPILE_TIME_ASSERT_ALIGNOF_USING_SIZEOF__(a,b) { \ #define COMPILE_TIME_ASSERT_ALIGNOF_USING_SIZEOF__(a,b) { \
typedef a acc_tmp_a_t; typedef b acc_tmp_b_t; \ typedef a acc_tmp_a_t; typedef b acc_tmp_b_t; \
struct alignas(1) acc_tmp_t { acc_tmp_b_t x; acc_tmp_a_t y; acc_tmp_b_t z; }; \ struct alignas(1) acc_tmp_t { acc_tmp_b_t x; acc_tmp_a_t y; acc_tmp_b_t z; }; \
@ -426,15 +451,13 @@ inline const T& UPX_MAX(const T& a, const T& b) { if (a < b) return b; return a;
template <class T> template <class T>
inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; } inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; }
template <size_t TypeSize> template <size_t Size>
struct USizeOfTypeImpl { struct UnsignedSizeOf {
static forceinline constexpr unsigned value() { static_assert(Size >= 1 && Size <= UPX_RSIZE_MAX_MEM);
COMPILE_TIME_ASSERT(TypeSize >= 1 && TypeSize <= 64 * 1024) // arbitrary limit static constexpr unsigned value = unsigned(Size);
return ACC_ICONV(unsigned, TypeSize);
}
}; };
#define usizeof(type) (USizeOfTypeImpl<sizeof(type)>::value()) #define usizeof(expr) (UnsignedSizeOf<sizeof(expr)>::value)
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == 4) ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == sizeof(int))
// An Array allocates memory on the heap, and automatically // An Array allocates memory on the heap, and automatically
// gets destructed when leaving scope or on exceptions. // gets destructed when leaving scope or on exceptions.
@ -442,16 +465,16 @@ ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == 4)
MemBuffer var ## _membuf(mem_size(sizeof(type), size)); \ MemBuffer var ## _membuf(mem_size(sizeof(type), size)); \
type * const var = ACC_STATIC_CAST(type *, var ## _membuf.getVoidPtr()) type * const var = ACC_STATIC_CAST(type *, var ## _membuf.getVoidPtr())
#define ByteArray(var, size) Array(unsigned char, var, size) #define ByteArray(var, size) Array(byte, var, size)
class noncopyable class noncopyable
{ {
protected: protected:
inline noncopyable() {} inline noncopyable() noexcept {}
inline ~noncopyable() {} inline ~noncopyable() noexcept {}
private: private:
noncopyable(const noncopyable &) DELETED_FUNCTION; // copy constuctor noncopyable(const noncopyable &) DELETED_FUNCTION; // copy constructor
noncopyable& operator=(const noncopyable &) DELETED_FUNCTION; // copy assignment noncopyable& operator=(const noncopyable &) DELETED_FUNCTION; // copy assignment
noncopyable(noncopyable &&) DELETED_FUNCTION; // move constructor noncopyable(noncopyable &&) DELETED_FUNCTION; // move constructor
noncopyable& operator=(noncopyable &&) DELETED_FUNCTION; // move assignment noncopyable& operator=(noncopyable &&) DELETED_FUNCTION; // move assignment
@ -466,7 +489,7 @@ constexpr bool string_eq(const char *a, const char *b) {
return *a == *b && (*a == '\0' || string_eq(a + 1, b + 1)); return *a == *b && (*a == '\0' || string_eq(a + 1, b + 1));
} }
constexpr bool string_lt(const char *a, const char *b) { constexpr bool string_lt(const char *a, const char *b) {
return (unsigned char)*a < (unsigned char)*b || (*a != '\0' && *a == *b && string_lt(a + 1, b + 1)); return (uchar)*a < (uchar)*b || (*a != '\0' && *a == *b && string_lt(a + 1, b + 1));
} }
constexpr bool string_ne(const char *a, const char *b) { constexpr bool string_ne(const char *a, const char *b) {
return !string_eq(a, b); return !string_eq(a, b);
@ -644,7 +667,7 @@ struct upx_callback_t
upx_progress_func_t nprogress; upx_progress_func_t nprogress;
void *user; void *user;
void reset() { memset(this, 0, sizeof(*this)); } void reset() noexcept { memset(this, 0, sizeof(*this)); }
}; };
@ -670,7 +693,7 @@ struct OptVar
assertValue(v); assertValue(v);
} }
OptVar() : v(default_value), is_set(false) { } OptVar() noexcept : v(default_value), is_set(false) { }
OptVar& operator= (const T &other) { OptVar& operator= (const T &other) {
assertValue(other); assertValue(other);
v = other; v = other;
@ -678,8 +701,8 @@ struct OptVar
return *this; return *this;
} }
void reset() { v = default_value; is_set = false; } void reset() noexcept { v = default_value; is_set = false; }
operator T () const { return v; } operator T () const noexcept { return v; }
T v; T v;
bool is_set; bool is_set;
@ -818,26 +841,16 @@ struct upx_compress_result_t
// globals // globals
**************************************************************************/ **************************************************************************/
#include "util/snprintf.h" // must get included first!
#include "options.h"
#include "except.h"
#include "bele.h"
#include "console/console.h"
#include "util/util.h"
// classes // classes
class ElfLinker; class ElfLinker;
typedef ElfLinker Linker; typedef ElfLinker Linker;
class Throwable;
// util/membuffer.h // util/membuffer.h
class MemBuffer; class MemBuffer;
void *membuffer_get_void_ptr(MemBuffer &mb); void *membuffer_get_void_ptr(MemBuffer &mb);
unsigned membuffer_get_size(MemBuffer &mb); unsigned membuffer_get_size(MemBuffer &mb);
// xspan
#include "util/raw_bytes.h"
#include "util/xspan.h"
// util/dt_check.cpp // util/dt_check.cpp
void upx_compiler_sanity_check(); void upx_compiler_sanity_check();
int upx_doctest_check(); int upx_doctest_check();
@ -870,7 +883,7 @@ int do_files(int i, int argc, char *argv[]);
// help.cpp // help.cpp
extern const char gitrev[]; extern const char gitrev[];
void show_head(); void show_header();
void show_help(int verbose=0); void show_help(int verbose=0);
void show_license(); void show_license();
void show_usage(); void show_usage();
@ -898,6 +911,17 @@ int upx_test_overlap ( const upx_bytep buf,
const upx_compress_result_t *cresult ); const upx_compress_result_t *cresult );
#include "util/snprintf.h" // must get included first!
#include "options.h"
#include "except.h"
#include "bele.h"
#include "console/console.h"
#include "util/util.h"
// xspan
#include "util/raw_bytes.h"
#include "util/xspan.h"
#if (ACC_OS_CYGWIN || ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_EMX || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64) #if (ACC_OS_CYGWIN || ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_EMX || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64)
# if defined(INVALID_HANDLE_VALUE) || defined(MAKEWORD) || defined(RT_CURSOR) # if defined(INVALID_HANDLE_VALUE) || defined(MAKEWORD) || defined(RT_CURSOR)
# error "something pulled in <windows.h>" # error "something pulled in <windows.h>"

View File

@ -269,6 +269,17 @@ void OutputFile::write(SPAN_0(const void) buf, int len) {
if (l != len) if (l != len)
throwIOException("write error", errno); throwIOException("write error", errno);
bytes_written += len; bytes_written += len;
#if TESTING && 0
static upx_std_atomic(bool) dumping;
if (!dumping) {
dumping = true;
char fn[64];
static int part = 0;
snprintf(fn, sizeof(fn), "upx-dump-%04d.data", part++);
OutputFile::dump(fn, buf, len);
dumping = false;
}
#endif
} }
upx_off_t OutputFile::st_size() const { upx_off_t OutputFile::st_size() const {

View File

@ -25,36 +25,33 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#include "conf.h" #include "conf.h"
#include "packmast.h" #include "packmast.h"
#include "packer.h" #include "packer.h"
#include "compress/compress.h" // upx_ucl_version_string() #include "compress/compress.h" // upx_ucl_version_string()
/************************************************************************* /*************************************************************************
// // header
**************************************************************************/ **************************************************************************/
static bool head_done = 0;
// also see UPX_CONFIG_DISABLE_GITREV in CMakeLists.txt // also see UPX_CONFIG_DISABLE_GITREV in CMakeLists.txt
#if defined(UPX_VERSION_GITREV) #if defined(UPX_VERSION_GITREV)
const char gitrev[] = UPX_VERSION_GITREV; const char gitrev[] = UPX_VERSION_GITREV;
#else #else
const char gitrev[1] = { 0 }; const char gitrev[1] = {0};
#endif #endif
void show_head(void) void show_header(void) {
{
FILE *f = con_term; FILE *f = con_term;
int fg; int fg;
if (head_done) static bool header_done;
if (header_done)
return; return;
head_done = 1; header_done = true;
fg = con_fg(f,FG_GREEN); fg = con_fg(f, FG_GREEN);
// clang-format off
con_fprintf(f, con_fprintf(f,
" Ultimate Packer for eXecutables\n" " Ultimate Packer for eXecutables\n"
" Copyright (C) 1996 - " UPX_VERSION_YEAR "\n" " Copyright (C) 1996 - " UPX_VERSION_YEAR "\n"
@ -71,22 +68,19 @@ void show_head(void)
UPX_VERSION_STRING, UPX_VERSION_STRING,
#endif #endif
UPX_VERSION_DATE); UPX_VERSION_DATE);
fg = con_fg(f,fg); // clang-format on
#undef V fg = con_fg(f, fg);
UNUSED(fg); UNUSED(fg);
} }
/************************************************************************* /*************************************************************************
// // usage
**************************************************************************/ **************************************************************************/
void show_usage(void) void show_usage(void) {
{
FILE *f = con_term; FILE *f = con_term;
con_fprintf(f,"Usage: %s [-123456789dlthVL] [-qvfk] [-o file] %sfile..\n", progname, con_fprintf(f, "Usage: %s [-123456789dlthVL] [-qvfk] [-o file] %sfile..\n", progname,
#if (ACC_OS_DOS32) && defined(__DJGPP__) #if (ACC_OS_DOS32) && defined(__DJGPP__)
"[@]"); "[@]");
#else #else
@ -94,34 +88,30 @@ void show_usage(void)
#endif #endif
} }
/************************************************************************* /*************************************************************************
// // util
**************************************************************************/ **************************************************************************/
struct PackerNames namespace {
{ struct PackerNames {
struct Entry { struct Entry {
const char* fname; const char *fname;
const char* sname; const char *sname;
}; };
Entry names[64]; Entry names[64];
size_t names_count; size_t names_count;
const options_t *o; const Options *o;
PackerNames() : names_count(0), o(nullptr) { } PackerNames() : names_count(0), o(nullptr) {}
void add(const Packer *p) void add(const Packer *p) {
{
p->assertPacker();
assert(names_count < 64); assert(names_count < 64);
names[names_count].fname = p->getFullName(o); names[names_count].fname = p->getFullName(o);
names[names_count].sname = p->getName(); names[names_count].sname = p->getName();
names_count++; names_count++;
} }
static Packer* visit(Packer *p, void *user) static Packer *visit(Packer *p, void *user) {
{
PackerNames *self = (PackerNames *) user; PackerNames *self = (PackerNames *) user;
self->add(p); self->add(p);
delete p; p = nullptr; delete p;
return nullptr; return nullptr;
} }
static int __acc_cdecl_qsort cmp_fname(const void *a, const void *b) { static int __acc_cdecl_qsort cmp_fname(const void *a, const void *b) {
@ -132,23 +122,20 @@ struct PackerNames
} }
}; };
static void show_all_packers(FILE *f, int verbose) static void show_all_packers(FILE *f, int verbose) {
{ Options o;
options_t o; o.reset(); o.reset();
PackerNames pn; pn.o = &o; PackerNames pn;
pn.o = &o;
PackMaster::visitAllPackers(PackerNames::visit, nullptr, &o, &pn); PackMaster::visitAllPackers(PackerNames::visit, nullptr, &o, &pn);
qsort(pn.names, pn.names_count, sizeof(PackerNames::Entry), PackerNames::cmp_fname); qsort(pn.names, pn.names_count, sizeof(PackerNames::Entry), PackerNames::cmp_fname);
size_t pos = 0; size_t pos = 0;
for (size_t i = 0; i < pn.names_count; ++i) for (size_t i = 0; i < pn.names_count; ++i) {
{
const char *fn = pn.names[i].fname; const char *fn = pn.names[i].fname;
const char *sn = pn.names[i].sname; const char *sn = pn.names[i].sname;
if (verbose > 0) if (verbose > 0) {
{
con_fprintf(f, " %-36s %s\n", fn, sn); con_fprintf(f, " %-36s %s\n", fn, sn);
} } else {
else
{
size_t fl = strlen(fn); size_t fl = strlen(fn);
if (pos == 0) { if (pos == 0) {
con_fprintf(f, " %s", fn); con_fprintf(f, " %s", fn);
@ -165,23 +152,23 @@ static void show_all_packers(FILE *f, int verbose)
if (verbose <= 0 && pn.names_count) if (verbose <= 0 && pn.names_count)
con_fprintf(f, "\n"); con_fprintf(f, "\n");
} }
} // namespace
/************************************************************************* /*************************************************************************
// // help
**************************************************************************/ **************************************************************************/
void show_help(int verbose) void show_help(int verbose) {
{
FILE *f = con_term; FILE *f = con_term;
int fg; int fg;
show_head(); show_header();
show_usage(); show_usage();
fg = con_fg(f,FG_YELLOW); // clang-format off
con_fprintf(f,"\nCommands:\n"); fg = con_fg(f, FG_YELLOW);
fg = con_fg(f,fg); con_fprintf(f, "\nCommands:\n");
fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" -1 compress faster -9 compress better\n" " -1 compress faster -9 compress better\n"
"%s" "%s"
@ -191,9 +178,9 @@ void show_help(int verbose)
verbose == 0 ? "" : " --best compress best (can be slow for big files)\n", verbose == 0 ? "" : " --best compress best (can be slow for big files)\n",
verbose == 0 ? "more" : "this", verbose == 0 ? "" : "\n"); verbose == 0 ? "more" : "this", verbose == 0 ? "" : "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Options:\n"); con_fprintf(f, "Options:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" -q be quiet -v be verbose\n" " -q be quiet -v be verbose\n"
@ -211,72 +198,72 @@ void show_help(int verbose)
if (verbose > 0) if (verbose > 0)
{ {
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"\nCompression tuning options:\n"); con_fprintf(f, "\nCompression tuning options:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" --lzma try LZMA [slower but tighter than NRV]\n" " --lzma try LZMA [slower but tighter than NRV]\n"
" --brute try all available compression methods & filters [slow]\n" " --brute try all available compression methods & filters [slow]\n"
" --ultra-brute try even more compression variants [very slow]\n" " --ultra-brute try even more compression variants [very slow]\n"
"\n"); "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Backup options:\n"); con_fprintf(f, "Backup options:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" -k, --backup keep backup files\n" " -k, --backup keep backup files\n"
" --no-backup no backup files [default]\n" " --no-backup no backup files [default]\n"
"\n"); "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Overlay options:\n"); con_fprintf(f, "Overlay options:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" --overlay=copy copy any extra data attached to the file [default]\n" " --overlay=copy copy any extra data attached to the file [default]\n"
" --overlay=strip strip any extra data attached to the file [DANGEROUS]\n" " --overlay=strip strip any extra data attached to the file [DANGEROUS]\n"
" --overlay=skip don't compress a file with an overlay\n" " --overlay=skip don't compress a file with an overlay\n"
"\n"); "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Options for djgpp2/coff:\n"); con_fprintf(f, "Options for djgpp2/coff:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" --coff produce COFF output [default: EXE]\n" " --coff produce COFF output [default: EXE]\n"
"\n"); "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Options for dos/com:\n"); con_fprintf(f, "Options for dos/com:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" --8086 make compressed com work on any 8086\n" " --8086 make compressed com work on any 8086\n"
"\n"); "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Options for dos/exe:\n"); con_fprintf(f, "Options for dos/exe:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" --8086 make compressed exe work on any 8086\n" " --8086 make compressed exe work on any 8086\n"
" --no-reloc put no relocations in to the exe header\n" " --no-reloc put no relocations in to the exe header\n"
"\n"); "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Options for dos/sys:\n"); con_fprintf(f, "Options for dos/sys:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" --8086 make compressed sys work on any 8086\n" " --8086 make compressed sys work on any 8086\n"
"\n"); "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Options for ps1/exe:\n"); con_fprintf(f, "Options for ps1/exe:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" --8-bit uses 8 bit size compression [default: 32 bit]\n" " --8-bit uses 8 bit size compression [default: 32 bit]\n"
" --8mib-ram 8 megabyte memory limit [default: 2 MiB]\n" " --8mib-ram 8 megabyte memory limit [default: 2 MiB]\n"
" --boot-only disables client/host transfer compatibility\n" " --boot-only disables client/host transfer compatibility\n"
" --no-align don't align to 2048 bytes [enables: --console-run]\n" " --no-align don't align to 2048 bytes [enables: --console-run]\n"
"\n"); "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Options for watcom/le:\n"); con_fprintf(f, "Options for watcom/le:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" --le produce LE output [default: EXE]\n" " --le produce LE output [default: EXE]\n"
"\n"); "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Options for win32/pe, win64/pe & rtm32/pe:\n"); con_fprintf(f, "Options for win32/pe, win64/pe & rtm32/pe:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" --compress-exports=0 do not compress the export section\n" " --compress-exports=0 do not compress the export section\n"
" --compress-exports=1 compress the export section [default]\n" " --compress-exports=1 compress the export section [default]\n"
@ -289,59 +276,55 @@ void show_help(int verbose)
" --strip-relocs=0 do not strip relocations\n" " --strip-relocs=0 do not strip relocations\n"
" --strip-relocs=1 strip relocations [default]\n" " --strip-relocs=1 strip relocations [default]\n"
"\n"); "\n");
fg = con_fg(f,FG_YELLOW); fg = con_fg(f, FG_YELLOW);
con_fprintf(f,"Options for linux/elf:\n"); con_fprintf(f, "Options for linux/elf:\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
con_fprintf(f, con_fprintf(f,
" --preserve-build-id copy .gnu.note.build-id to compressed output\n" " --preserve-build-id copy .gnu.note.build-id to compressed output\n"
"\n"); "\n");
} }
// clang-format on
con_fprintf(f, "file.. executables to (de)compress\n"); con_fprintf(f, "file.. executables to (de)compress\n");
if (verbose > 0) if (verbose > 0) {
{ fg = con_fg(f, FG_YELLOW);
fg = con_fg(f,FG_YELLOW); con_fprintf(f, "\nThis version supports:\n");
con_fprintf(f,"\nThis version supports:\n"); fg = con_fg(f, fg);
fg = con_fg(f,fg);
show_all_packers(f, verbose); show_all_packers(f, verbose);
} } else {
else con_fprintf(f, "\nType '%s --help' for more detailed help.\n", progname);
{
con_fprintf(f,"\nType '%s --help' for more detailed help.\n", progname);
} }
con_fprintf(f,"\nUPX comes with ABSOLUTELY NO WARRANTY; for details visit https://upx.github.io\n" con_fprintf(f, "\nUPX comes with ABSOLUTELY NO WARRANTY; "
// "\nUPX comes with ABSOLUTELY NO WARRANTY; for details type 'upx -L'.\n" "for details visit https://upx.github.io\n");
"");
#if DEBUG || TESTING #if DEBUG || TESTING
fg = con_fg(f,FG_RED); fg = con_fg(f, FG_RED);
con_fprintf(f,"\nWARNING: this version is compiled with" con_fprintf(f, "\nWARNING: this version is compiled with"
#if DEBUG #if DEBUG
" -DDEBUG" " -DDEBUG"
#endif #endif
#if TESTING #if TESTING
" -DTESTING" " -DTESTING"
#endif #endif
"\n"); "\n");
fg = con_fg(f,fg); fg = con_fg(f, fg);
#endif #endif
UNUSED(fg); UNUSED(fg);
} }
/************************************************************************* /*************************************************************************
// // license
**************************************************************************/ **************************************************************************/
void show_license(void) void show_license(void) {
{
FILE *f = con_term; FILE *f = con_term;
show_head(); show_header();
// clang-format off
con_fprintf(f, con_fprintf(f,
" This program may be used freely, and you are welcome to\n" " This program may be used freely, and you are welcome to\n"
" redistribute it under certain conditions.\n" " redistribute it under certain conditions.\n"
@ -356,29 +339,27 @@ void show_license(void)
" If not, visit one of the following pages:\n" " If not, visit one of the following pages:\n"
"\n" "\n"
); );
int fg = con_fg(f,FG_CYAN); int fg = con_fg(f, FG_CYAN);
con_fprintf(f, con_fprintf(f,
" https://upx.github.io\n" " https://upx.github.io\n"
" https://www.oberhumer.com/opensource/upx/\n" " https://www.oberhumer.com/opensource/upx/\n"
); );
(void)con_fg(f,FG_ORANGE); (void) con_fg(f, FG_ORANGE);
con_fprintf(f, con_fprintf(f,
"\n" "\n"
" Markus F.X.J. Oberhumer Laszlo Molnar\n" " Markus F.X.J. Oberhumer Laszlo Molnar\n"
" <markus@oberhumer.com> <ezerotven+github@gmail.com>\n" " <markus@oberhumer.com> <ezerotven+github@gmail.com>\n"
); );
fg = con_fg(f,fg); // clang-format on
fg = con_fg(f, fg);
UNUSED(fg); UNUSED(fg);
} }
/************************************************************************* /*************************************************************************
// // version
**************************************************************************/ **************************************************************************/
void show_version(bool one_line) void show_version(bool one_line) {
{
FILE *fp = stdout; FILE *fp = stdout;
const char *v; const char *v;
@ -391,6 +372,7 @@ void show_version(bool one_line)
#endif #endif
if (one_line) if (one_line)
return; return;
#if (WITH_NRV) #if (WITH_NRV)
v = upx_nrv_version_string(); v = upx_nrv_version_string();
if (v != nullptr && v[0]) if (v != nullptr && v[0])
@ -419,6 +401,7 @@ void show_version(bool one_line)
#if !defined(DOCTEST_CONFIG_DISABLE) #if !defined(DOCTEST_CONFIG_DISABLE)
fprintf(fp, "doctest C++ testing framework version %s\n", DOCTEST_VERSION_STR); fprintf(fp, "doctest C++ testing framework version %s\n", DOCTEST_VERSION_STR);
#endif #endif
// clang-format off
fprintf(fp, "Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer\n"); fprintf(fp, "Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer\n");
fprintf(fp, "Copyright (C) 1996-2023 Laszlo Molnar\n"); fprintf(fp, "Copyright (C) 1996-2023 Laszlo Molnar\n");
fprintf(fp, "Copyright (C) 2000-2023 John F. Reiser\n"); fprintf(fp, "Copyright (C) 2000-2023 John F. Reiser\n");
@ -437,6 +420,7 @@ void show_version(bool one_line)
fprintf(fp, "Copyright (C) 2016" "-2021 Viktor Kirilov\n"); fprintf(fp, "Copyright (C) 2016" "-2021 Viktor Kirilov\n");
#endif #endif
fprintf(fp, "UPX comes with ABSOLUTELY NO WARRANTY; for details type '%s -L'.\n", progname); fprintf(fp, "UPX comes with ABSOLUTELY NO WARRANTY; for details type '%s -L'.\n", progname);
// clang-format on
} }
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -28,7 +28,7 @@
#include "conf.h" #include "conf.h"
#include "linker.h" #include "linker.h"
static unsigned hex(unsigned char c) { return (c & 0xf) + (c > '9' ? 9 : 0); } static unsigned hex(uchar c) { return (c & 0xf) + (c > '9' ? 9 : 0); }
static bool update_capacity(unsigned size, unsigned *capacity) { static bool update_capacity(unsigned size, unsigned *capacity) {
if (size < *capacity) if (size < *capacity)
@ -67,7 +67,7 @@ ElfLinker::Section::Section(const char *n, const void *i, unsigned s, unsigned a
((char *) input)[s] = 0; ((char *) input)[s] = 0;
} }
ElfLinker::Section::~Section() { ElfLinker::Section::~Section() noexcept {
free(name); free(name);
free(input); free(input);
} }
@ -83,7 +83,7 @@ ElfLinker::Symbol::Symbol(const char *n, Section *s, upx_uint64_t o)
assert(section != nullptr); assert(section != nullptr);
} }
ElfLinker::Symbol::~Symbol() { free(name); } ElfLinker::Symbol::~Symbol() noexcept { free(name); }
/************************************************************************* /*************************************************************************
// Relocation // Relocation
@ -105,7 +105,7 @@ ElfLinker::ElfLinker()
nsections_capacity(0), nsymbols(0), nsymbols_capacity(0), nrelocations(0), nsections_capacity(0), nsymbols(0), nsymbols_capacity(0), nrelocations(0),
nrelocations_capacity(0), reloc_done(false) {} nrelocations_capacity(0), reloc_done(false) {}
ElfLinker::~ElfLinker() { ElfLinker::~ElfLinker() noexcept {
delete[] input; delete[] input;
delete[] output; delete[] output;
@ -548,7 +548,7 @@ upx_uint64_t ElfLinker::getSymbolOffset(const char *name) const {
return symbol->section->offset + symbol->offset; return symbol->section->offset + symbol->offset;
} }
void ElfLinker::alignWithByte(unsigned len, unsigned char b) { void ElfLinker::alignWithByte(unsigned len, byte b) {
memset(output + outputlen, b, len); memset(output + outputlen, b, len);
outputlen += len; outputlen += len;
} }
@ -559,7 +559,7 @@ void ElfLinker::relocate1(const Relocation *rel, byte *, upx_uint64_t, const cha
/************************************************************************* /*************************************************************************
// ElfLinker arch subclasses // ElfLinker arch subclasses
// FIXME: add more displacment overflow checks // FIXME: add more displacement overflow checks
// FIXME: add support for our special "ignore_reloc_overflow" section // FIXME: add support for our special "ignore_reloc_overflow" section
**************************************************************************/ **************************************************************************/
@ -802,12 +802,12 @@ void ElfLinkerPpc32::relocate1(const Relocation *rel, byte *location, upx_uint64
if (strcmp(type, "24") == 0) { if (strcmp(type, "24") == 0) {
if (3 & value) if (3 & value)
internal_error("unaligned word diplacement"); internal_error("unaligned word diplacement");
// FIXME: displacment overflow? // FIXME: displacement overflow?
set_be32(location, (0xfc000003 & get_be32(location)) + (0x03fffffc & value)); set_be32(location, (0xfc000003 & get_be32(location)) + (0x03fffffc & value));
} else if (strcmp(type, "14") == 0) { } else if (strcmp(type, "14") == 0) {
if (3 & value) if (3 & value)
internal_error("unaligned word diplacement"); internal_error("unaligned word diplacement");
// FIXME: displacment overflow? // FIXME: displacement overflow?
set_be32(location, (0xffff0003 & get_be32(location)) + (0x0000fffc & value)); set_be32(location, (0xffff0003 & get_be32(location)) + (0x0000fffc & value));
} else } else
super::relocate1(rel, location, value, type); super::relocate1(rel, location, value, type);

View File

@ -77,7 +77,7 @@ protected:
public: public:
ElfLinker(); ElfLinker();
virtual ~ElfLinker(); virtual ~ElfLinker() noexcept;
void init(const void *pdata, int plen, unsigned pxtra = 0); void init(const void *pdata, int plen, unsigned pxtra = 0);
// virtual void setLoaderAlignOffset(int phase); // virtual void setLoaderAlignOffset(int phase);
@ -98,7 +98,7 @@ public:
void dumpSymbol(const Symbol *, unsigned flags, FILE *fp) const; void dumpSymbol(const Symbol *, unsigned flags, FILE *fp) const;
void dumpSymbols(unsigned flags = 0, FILE *fp = nullptr) const; void dumpSymbols(unsigned flags = 0, FILE *fp = nullptr) const;
void alignWithByte(unsigned len, unsigned char b); void alignWithByte(unsigned len, byte b);
virtual void alignCode(unsigned len) { alignWithByte(len, 0); } virtual void alignCode(unsigned len) { alignWithByte(len, 0); }
virtual void alignData(unsigned len) { alignWithByte(len, 0); } virtual void alignData(unsigned len) { alignWithByte(len, 0); }
@ -133,7 +133,7 @@ struct ElfLinker::Section : private noncopyable {
Section *next = nullptr; Section *next = nullptr;
Section(const char *n, const void *i, unsigned s, unsigned a = 0); Section(const char *n, const void *i, unsigned s, unsigned a = 0);
~Section(); ~Section() noexcept;
}; };
struct ElfLinker::Symbol : private noncopyable { struct ElfLinker::Symbol : private noncopyable {
@ -142,7 +142,7 @@ struct ElfLinker::Symbol : private noncopyable {
upx_uint64_t offset = 0; upx_uint64_t offset = 0;
Symbol(const char *n, Section *s, upx_uint64_t o); Symbol(const char *n, Section *s, upx_uint64_t o);
~Symbol(); ~Symbol() noexcept;
}; };
struct ElfLinker::Relocation : private noncopyable { struct ElfLinker::Relocation : private noncopyable {
@ -153,6 +153,7 @@ struct ElfLinker::Relocation : private noncopyable {
upx_uint64_t add; // used in .rela relocations upx_uint64_t add; // used in .rela relocations
Relocation(const Section *s, unsigned o, const char *t, const Symbol *v, upx_uint64_t a); Relocation(const Section *s, unsigned o, const char *t, const Symbol *v, upx_uint64_t a);
~Relocation() noexcept {}
}; };
/************************************************************************* /*************************************************************************

View File

@ -626,7 +626,7 @@ static int do_option(int optc, const char *arg) {
opt->backup = 1; opt->backup = 1;
break; break;
case 541: case 541:
if (opt->backup != 1) // do not overide '--backup' if (opt->backup != 1) // do not override '--backup'
opt->backup = 0; opt->backup = 0;
break; break;
// overlay // overlay
@ -974,11 +974,10 @@ int main_get_options(int argc, char **argv) {
int optc, longind; int optc, longind;
char shortopts[256]; char shortopts[256];
prepare_shortopts(shortopts, "123456789hH?V", longopts), prepare_shortopts(shortopts, "123456789hH?V", longopts);
acc_getopt_init(&mfx_getopt, 1, argc, argv); acc_getopt_init(&mfx_getopt, 1, argc, argv);
mfx_getopt.progname = progname; mfx_getopt.progname = progname;
mfx_getopt.opterr = handle_opterr; mfx_getopt.opterr = handle_opterr;
opt->o_unix.osabi0 = Elf32_Ehdr::ELFOSABI_LINUX;
while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, &longind)) >= 0) { while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, &longind)) >= 0) {
if (do_option(optc, argv[mfx_optind - 1]) != 0) if (do_option(optc, argv[mfx_optind - 1]) != 0)
e_usage(); e_usage();
@ -1088,7 +1087,7 @@ void main_get_envoptions() {
/* alloc temp argv */ /* alloc temp argv */
if (targc > 1) if (targc > 1)
targv = (const char **) calloc(targc + 1, sizeof(char *)); targv = (const char **) upx_calloc(targc + 1, sizeof(char *));
if (targv == nullptr) { if (targv == nullptr) {
free(env); free(env);
return; return;
@ -1188,7 +1187,7 @@ int upx_main(int argc, char *argv[]) {
char *p; char *p;
bool allupper = true; bool allupper = true;
for (p = prog; *p; p++) for (p = prog; *p; p++)
if (islower((unsigned char) *p)) if (islower((uchar) *p))
allupper = false; allupper = false;
if (allupper) if (allupper)
fn_strlwr(prog); fn_strlwr(prog);

View File

@ -27,15 +27,19 @@
#include "conf.h" #include "conf.h"
static options_t global_options; static Options global_options;
options_t *opt = &global_options; // also see class PackMaster Options *opt = &global_options; // also see class PackMaster
#if WITH_THREADS
std::mutex opt_lock_mutex;
#endif
/************************************************************************* /*************************************************************************
// reset // reset
**************************************************************************/ **************************************************************************/
void options_t::reset() { void Options::reset() {
options_t *o = this; Options *const o = this;
mem_clear(o, sizeof(*o)); mem_clear(o, sizeof(*o));
o->crp.reset(); o->crp.reset();
@ -65,7 +69,7 @@ void options_t::reset() {
o->win32_pe.compress_exports = 1; o->win32_pe.compress_exports = 1;
o->win32_pe.compress_icons = 2; o->win32_pe.compress_icons = 2;
o->win32_pe.compress_resources = -1; o->win32_pe.compress_resources = -1;
for (unsigned i = 0; i < TABLESIZE(o->win32_pe.compress_rt); i++) for (size_t i = 0; i < TABLESIZE(o->win32_pe.compress_rt); i++)
o->win32_pe.compress_rt[i] = -1; o->win32_pe.compress_rt[i] = -1;
o->win32_pe.compress_rt[24] = false; // 24 == RT_MANIFEST o->win32_pe.compress_rt[24] = false; // 24 == RT_MANIFEST
o->win32_pe.strip_relocs = -1; o->win32_pe.strip_relocs = -1;
@ -76,9 +80,13 @@ void options_t::reset() {
// doctest checks // doctest checks
**************************************************************************/ **************************************************************************/
TEST_CASE("options_t::reset") { TEST_CASE("Options::reset") {
options_t local_options; COMPILE_TIME_ASSERT(std::is_standard_layout<Options>::value)
options_t *o = &local_options; COMPILE_TIME_ASSERT(std::is_nothrow_default_constructible<Options>::value)
COMPILE_TIME_ASSERT(std::is_trivially_copyable<Options>::value)
Options local_options;
Options *o = &local_options;
o->reset(); o->reset();
CHECK(o->o_unix.osabi0 == 3); CHECK(o->o_unix.osabi0 == 3);
} }
@ -89,8 +97,11 @@ static inline void test_options(const char *(&a)[N]) {
} }
TEST_CASE("getopt") { TEST_CASE("getopt") {
options_t *const saved_opt = opt; #if WITH_THREADS
options_t local_options; std::lock_guard<std::mutex> lock(opt_lock_mutex);
#endif
Options *const saved_opt = opt;
Options local_options;
opt = &local_options; opt = &local_options;
opt->reset(); opt->reset();
opt->debug.getopt_throw_instead_of_exit = true; opt->debug.getopt_throw_instead_of_exit = true;

View File

@ -29,6 +29,14 @@
#ifndef UPX_OPTIONS_H__ #ifndef UPX_OPTIONS_H__
#define UPX_OPTIONS_H__ 1 #define UPX_OPTIONS_H__ 1
struct Options;
extern Options *opt;
#define options_t Options // old name
#if WITH_THREADS
extern std::mutex opt_lock_mutex;
#endif
/************************************************************************* /*************************************************************************
// globals // globals
**************************************************************************/ **************************************************************************/
@ -46,7 +54,7 @@ enum {
CMD_VERSION, CMD_VERSION,
}; };
struct options_t final { struct Options final {
int cmd; int cmd;
// compression options // compression options
@ -164,8 +172,6 @@ struct options_t final {
void reset(); void reset();
}; };
extern struct options_t *opt;
#endif /* already included */ #endif /* already included */
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; } virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_DOS_COM; } virtual int getFormat() const override { return UPX_F_DOS_COM; }
virtual const char *getName() const override { return "dos/com"; } virtual const char *getName() const override { return "dos/com"; }
virtual const char *getFullName(const options_t *) const override { return "i086-dos16.com"; } virtual const char *getFullName(const Options *) const override { return "i086-dos16.com"; }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override; virtual const int *getFilters() const override;

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 14; } virtual int getVersion() const override { return 14; }
virtual int getFormat() const override { return UPX_F_DJGPP2_COFF; } virtual int getFormat() const override { return UPX_F_DJGPP2_COFF; }
virtual const char *getName() const override { return "djgpp2/coff"; } virtual const char *getName() const override { return "djgpp2/coff"; }
virtual const char *getFullName(const options_t *) const override { virtual const char *getFullName(const Options *) const override {
return "i386-dos32.djgpp2.coff"; return "i386-dos32.djgpp2.coff";
} }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;

View File

@ -35,9 +35,8 @@
static const CLANG_FORMAT_DUMMY_STATEMENT static const CLANG_FORMAT_DUMMY_STATEMENT
#include "stub/i086-dos16.exe.h" #include "stub/i086-dos16.exe.h"
#define RSFCRI 4096 // Reserved Space For Compressed Relocation Info
#define MAXMATCH 0x2000 #define MAXMATCH 0x2000
#define MAXRELOCS (0x8000 - MAXMATCH) #define MAXRELOCSIZE (0x8000 - MAXMATCH)
#define DI_LIMIT 0xff00 // see the assembly why #define DI_LIMIT 0xff00 // see the assembly why
@ -49,9 +48,6 @@ PackExe::PackExe(InputFile *f) : super(f) {
bele = &N_BELE_RTP::le_policy; bele = &N_BELE_RTP::le_policy;
COMPILE_TIME_ASSERT(sizeof(exe_header_t) == 32) COMPILE_TIME_ASSERT(sizeof(exe_header_t) == 32)
COMPILE_TIME_ASSERT_ALIGNED1(exe_header_t) COMPILE_TIME_ASSERT_ALIGNED1(exe_header_t)
ih_exesize = ih_imagesize = ih_overlay = 0;
stack_for_lzma = 0;
use_clear_dirty_stack = false;
} }
Linker *PackExe::newLinker() const { return new ElfLinkerX86(); } Linker *PackExe::newLinker() const { return new ElfLinkerX86(); }
@ -59,8 +55,7 @@ Linker *PackExe::newLinker() const { return new ElfLinkerX86(); }
const int *PackExe::getCompressionMethods(int method, int level) const { const int *PackExe::getCompressionMethods(int method, int level) const {
bool small = ih_imagesize <= 256 * 1024; bool small = ih_imagesize <= 256 * 1024;
// disable lzma for "--brute" unless explicitly given "--lzma" // disable lzma for "--brute" unless explicitly given "--lzma"
// WARNING: this side effect may persists for later files; // (note that class PackMaster creates per-file local options)
// but note that class PackMaster creates per-file local options
if (opt->all_methods_use_lzma == 1 && !opt->method_lzma_seen) if (opt->all_methods_use_lzma == 1 && !opt->method_lzma_seen)
opt->all_methods_use_lzma = 0; opt->all_methods_use_lzma = 0;
return Packer::getDefaultCompressionMethods_8(method, level, small); return Packer::getDefaultCompressionMethods_8(method, level, small);
@ -125,7 +120,7 @@ void PackExe::addLoaderEpilogue(int flag) {
linker->defineSymbol("original_ss", ih.ss); linker->defineSymbol("original_ss", ih.ss);
linker->defineSymbol( linker->defineSymbol(
"reloc_size", "reloc_size",
(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? 0 : MAXRELOCS) - relocsize); (ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? 0 : MAXRELOCSIZE) - relocsize);
} }
void PackExe::buildLoader(const Filter *) { void PackExe::buildLoader(const Filter *) {
@ -229,18 +224,18 @@ int PackExe::readFileHeader() {
ih_overlay = file_size - ih_exesize; ih_overlay = file_size - ih_exesize;
if (file_size_u < sizeof(ih) || ((ih.m512 | ih.p512) && ih.m512 + ih.p512 * 512u < sizeof(ih))) if (file_size_u < sizeof(ih) || ((ih.m512 | ih.p512) && ih.m512 + ih.p512 * 512u < sizeof(ih)))
throwCantPack("illegal exe header"); throwCantPack("illegal exe header");
if (file_size_u < ih_exesize || ih_imagesize <= 0 || ih_imagesize > ih_exesize) if (ih_exesize > file_size_u || ih_imagesize <= 0 || ih_imagesize > ih_exesize)
throwCantPack("exe header corrupted"); throwCantPack("exe header corrupted");
NO_printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay); NO_printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay);
return UPX_F_DOS_EXE; return UPX_F_DOS_EXE;
} }
bool PackExe::canPack() { bool PackExe::canPack() {
if (fn_has_ext(fi->getName(), "sys")) if (fn_has_ext(fi->getName(), "sys")) // dos/sys
return false; return false;
if (!readFileHeader()) if (!readFileHeader())
return false; return false;
if (file_size < 1024) if (file_size < 1024 || ih_imagesize < 512)
throwCantPack("file is too small for dos/exe"); throwCantPack("file is too small for dos/exe");
fi->seek(0x3c, SEEK_SET); fi->seek(0x3c, SEEK_SET);
LE32 offs; LE32 offs;
@ -258,13 +253,17 @@ bool PackExe::canPack() {
// //
**************************************************************************/ **************************************************************************/
static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs, static unsigned optimize_relocs(SPAN_S(byte) image, const unsigned image_size,
const unsigned nrelocs, byte *crel, bool *has_9a) { SPAN_S(const byte) relocs, const unsigned relocnum,
SPAN_S(byte) crel, bool *has_9a) {
#if WITH_XSPAN >= 2
ptr_check_no_overlap(image.data(image_size), image_size, relocs.data(), relocs.size_bytes(),
crel.data(), crel.size_bytes());
#endif
if (opt->exact) if (opt->exact)
throwCantPackExact(); throwCantPackExact();
byte *const crel_save = crel; SPAN_S_VAR(byte, const crel_start, crel);
unsigned i;
unsigned seg_high = 0; unsigned seg_high = 0;
#if 0 #if 0
unsigned seg_low = 0xffffffff; unsigned seg_low = 0xffffffff;
@ -274,19 +273,19 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
unsigned linear_high = 0; unsigned linear_high = 0;
#endif #endif
// pass 1 - find 0x9a bounds // pass 1 - find 0x9a bounds in image
for (i = 0; i < nrelocs; i++) { for (unsigned i = 0; i < relocnum; i++) {
unsigned addr = get_le32(relocs + 4 * i); unsigned addr = get_le32(relocs + 4 * i);
if (addr >= size - 1) if (addr >= image_size - 1)
throwCantPack("unexpected relocation 1"); throwCantPack("unexpected relocation 1");
if (addr >= 3 && b[addr - 3] == 0x9a) { if (addr >= 3 && image[addr - 3] == 0x9a) {
unsigned seg = get_le16(b + addr); unsigned seg = get_le16(image + addr);
if (seg > seg_high) if (seg > seg_high)
seg_high = seg; seg_high = seg;
#if 0 #if 0
if (seg < seg_low) if (seg < seg_low)
seg_low = seg; seg_low = seg;
unsigned off = get_le16(b+addr-2); unsigned off = get_le16(image + addr - 2);
if (off < off_low) if (off < off_low)
off_low = off; off_low = off;
if (off > off_high) if (off > off_high)
@ -308,19 +307,20 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
crel += 4; // to be filled in later crel += 4; // to be filled in later
unsigned ones = 0; unsigned ones = 0;
unsigned es = 0, di, t; unsigned es = 0;
i = 0; for (unsigned i = 0; i < relocnum;) {
do {
unsigned addr = get_le32(relocs + 4 * i); unsigned addr = get_le32(relocs + 4 * i);
set_le16(crel, di = addr & 0x0f); unsigned di = addr & 0x0f;
set_le16(crel + 0, di);
set_le16(crel + 2, (addr >> 4) - es); set_le16(crel + 2, (addr >> 4) - es);
es = addr >> 4;
crel += 4; crel += 4;
es = addr >> 4;
for (++i; i < nrelocs; i++) { for (++i; i < relocnum; i++) {
unsigned t;
addr = get_le32(relocs + 4 * i); addr = get_le32(relocs + 4 * i);
// printf ("%x\n",es*16+di); NO_printf("%x\n", es * 16 + di);
if ((addr - es * 16 > 0xfffe) || (i == nrelocs - 1 && addr - es * 16 > 0xff00)) { if ((addr - es * 16 > 0xfffe) || (i == relocnum - 1 && addr - es * 16 > 0xff00)) {
// segment change // segment change
t = 1 + (0xffff - di) / 254; t = 1 + (0xffff - di) / 254;
memset(crel, 1, t); memset(crel, 1, t);
@ -329,9 +329,9 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
break; break;
} }
unsigned offs = addr - es * 16; unsigned offs = addr - es * 16;
if (offs >= 3 && b[es * 16 + offs - 3] == 0x9a && offs > di + 3) { if (offs >= 3 && image[es * 16 + offs - 3] == 0x9a && offs > di + 3) {
for (t = di; t < offs - 3; t++) for (t = di; t < offs - 3; t++)
if (b[es * 16 + t] == 0x9a && get_le16(b + es * 16 + t + 3) <= seg_high) if (image[es * 16 + t] == 0x9a && get_le16(image + es * 16 + t + 3) <= seg_high)
break; break;
if (t == offs - 3) { if (t == offs - 3) {
// code 0: search for 0x9a // code 0: search for 0x9a
@ -342,9 +342,8 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
} }
} }
t = offs - di; t = offs - di;
if (t < 2) if ((int) t < 2)
throwCantPack("unexpected relocation 2"); throwCantPack("unexpected relocation 2");
while (t >= 256) { while (t >= 256) {
// code 1: add 254, don't reloc // code 1: add 254, don't reloc
*crel++ = 1; *crel++ = 1;
@ -354,14 +353,14 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
*crel++ = (byte) t; *crel++ = (byte) t;
di = offs; di = offs;
} }
} while (i < nrelocs); }
*crel++ = 1; *crel++ = 1;
ones++; ones++;
set_le16(crel_save, ones); set_le16(crel_start, ones);
set_le16(crel_save + 2, seg_high); set_le16(crel_start + 2, seg_high);
// OutputFile::dump("x.rel", crel_save, crel - crel_save); // OutputFile::dump("x.rel", crel_start, ptr_udiff_bytes(crel, crel_start));
return (unsigned) (crel - crel_save); return ptr_udiff_bytes(crel, crel_start);
} }
/************************************************************************* /*************************************************************************
@ -371,16 +370,14 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
void PackExe::pack(OutputFile *fo) { void PackExe::pack(OutputFile *fo) {
unsigned ic; unsigned ic;
if (ih.relocs > MAXRELOCS) const unsigned relocnum = ih.relocs;
if (relocnum > MAXRELOCSIZE) // early check
throwCantPack("too many relocations"); throwCantPack("too many relocations");
checkOverlay(ih_overlay); checkOverlay(ih_overlay);
// alloc buffers
relocsize = RSFCRI + 4 * ih.relocs;
ibuf.alloc(ih_imagesize + 16 + relocsize + 2);
obuf.allocForCompression(ih_imagesize + 16 + relocsize + 2);
// read image // read image
// image + space for optimized relocs + safety/alignments
ibuf.alloc(ih_imagesize + 4 * relocnum + 1024);
fi->seek(ih.headsize16 * 16, SEEK_SET); fi->seek(ih.headsize16 * 16, SEEK_SET);
fi->readx(ibuf, ih_imagesize); fi->readx(ibuf, ih_imagesize);
@ -389,37 +386,41 @@ void PackExe::pack(OutputFile *fo) {
device_driver = get_le32(ibuf) == 0xffffffffu; device_driver = get_le32(ibuf) == 0xffffffffu;
// relocations // relocations
relocsize = 0;
has_9a = false; has_9a = false;
byte *w = ibuf + ih_imagesize; if (relocnum) {
if (ih.relocs) { MemBuffer mb_relocs(4 * relocnum);
byte *wr = w + RSFCRI; SPAN_S_VAR(byte, relocs, mb_relocs);
fi->seek(ih.relocoffs, SEEK_SET); fi->seek(ih.relocoffs, SEEK_SET);
fi->readx(wr, 4 * ih.relocs); fi->readx(relocs, 4 * relocnum);
for (ic = 0; ic < ih.relocs; ic++) { // dos/exe runs in real-mode, so convert to linear addresses
unsigned jc = get_le32(wr + 4 * ic); for (ic = 0; ic < relocnum; ic++) {
set_le32(wr + 4 * ic, ((jc >> 16) * 16 + (jc & 0xffff)) & 0xfffff); unsigned jc = get_le32(relocs + 4 * ic);
set_le32(relocs + 4 * ic, ((jc >> 16) * 16 + (jc & 0xffff)) & 0xfffff);
} }
qsort(wr, ih.relocs, 4, le32_compare); qsort(raw_bytes(relocs, 4 * relocnum), relocnum, 4, le32_compare);
relocsize = optimize_relocs(ibuf, ih_imagesize, wr, ih.relocs, w, &has_9a);
set_le16(w + relocsize, relocsize + 2); SPAN_S_VAR(byte, image, ibuf + 0, ih_imagesize);
SPAN_S_VAR(byte, crel, ibuf + ih_imagesize, ibuf);
relocsize = optimize_relocs(image, ih_imagesize, relocs, relocnum, crel, &has_9a);
set_le16(crel + relocsize, relocsize + 2);
relocsize += 2; relocsize += 2;
if (relocsize > MAXRELOCS) assert(relocsize >= 11);
if (relocsize > MAXRELOCSIZE) // optimize_relocs did not help
throwCantPack("too many relocations"); throwCantPack("too many relocations");
#if 0 #if TESTING && 0
byte out[9*relocsize/8+1024]; unsigned rout_len = MemBuffer::getSizeForCompression(relocsize);
unsigned in_len = relocsize; MemBuffer rout(rout_len);
unsigned out_len = 0; ucl_nrv2b_99_compress(raw_bytes(crel, relocsize), relocsize, rout, &rout_len, nullptr, 9,
ucl_nrv2b_99_compress(w, in_len, out, &out_len, nullptr, 9, nullptr, nullptr); nullptr, nullptr);
printf("reloc compress: %d -> %d\n", in_len, out_len); printf("dos/exe reloc compress: %d -> %d\n", relocsize, rout_len);
#endif #endif
} else {
relocsize = 0;
} }
// prepare packheader // prepare packheader
ph.u_len = ih_imagesize + relocsize; ph.u_len = ih_imagesize + relocsize;
obuf.allocForCompression(ph.u_len);
// prepare filter // prepare filter
Filter ft(ph.level); Filter ft(ph.level);
// compress (max_match = 8192) // compress (max_match = 8192)
@ -511,9 +512,7 @@ void PackExe::pack(OutputFile *fo) {
oh.firstreloc = ih.cs * 0x10000 + ih.ip; oh.firstreloc = ih.cs * 0x10000 + ih.ip;
} }
// g++ 3.1 does not like the following line...
oh.relocoffs = offsetof(exe_header_t, firstreloc); oh.relocoffs = offsetof(exe_header_t, firstreloc);
// oh.relocoffs = ptr_udiff_bytes(&oh.firstreloc, &oh);
linker->defineSymbol("destination_segment", oh.ss - ph.c_len / 16 - e_len / 16); linker->defineSymbol("destination_segment", oh.ss - ph.c_len / 16 - e_len / 16);
linker->defineSymbol("source_segment", e_len / 16 + (copysize - firstcopy) / 16); linker->defineSymbol("source_segment", e_len / 16 + (copysize - firstcopy) / 16);
@ -526,7 +525,7 @@ void PackExe::pack(OutputFile *fo) {
linker->defineSymbol("attribute", get_le16(ibuf + 4)); linker->defineSymbol("attribute", get_le16(ibuf + 4));
linker->defineSymbol("orig_strategy", get_le16(ibuf + 6)); linker->defineSymbol("orig_strategy", get_le16(ibuf + 6));
const unsigned outputlen = sizeof(oh) + lsize + packedsize + eisize; const unsigned outputlen = sizeof(oh) + e_len + packedsize + d_len + eisize;
oh.m512 = outputlen & 511; oh.m512 = outputlen & 511;
oh.p512 = (outputlen + 511) >> 9; oh.p512 = (outputlen + 511) >> 9;
@ -538,20 +537,19 @@ void PackExe::pack(OutputFile *fo) {
memcpy(loader, getLoader(), lsize); memcpy(loader, getLoader(), lsize);
patchPackHeader(loader, e_len); patchPackHeader(loader, e_len);
NO_fprintf(stderr, "\ne_len=%x d_len=%x c_len=%x oo=%x ulen=%x destp=%x copys=%x images=%x", NO_fprintf(stderr, "\ne_len=%x d_len=%x c_len=%x oo=%x ulen=%x copysize=%x imagesize=%x", e_len,
e_len, d_len, packedsize, ph.overlap_overhead, ph.u_len, /*destpara*/ 0, copysize, d_len, packedsize, ph.overlap_overhead, ph.u_len, copysize, ih_imagesize);
ih_imagesize);
// write header + write loader + compressed file // write header + write loader + compressed file
#if TESTING #if TESTING
if (opt->debug.debug_level) if (opt->debug.debug_level)
printf("\n%d %d %d %d\n", (int) sizeof(oh), e_len, packedsize, d_len); printf("\n%d %d %d %d\n", (int) sizeof(oh), e_len, packedsize, d_len);
#endif #endif
fo->write(&oh, sizeof(oh)); fo->write(&oh, sizeof(oh)); // program header
fo->write(loader, e_len); // entry fo->write(loader, e_len); // entry code
fo->write(obuf, packedsize); fo->write(obuf, packedsize); // compressed data
fo->write(loader + e_len, d_len); // decompressor fo->write(loader + e_len, d_len); // decompressor code
fo->write(extra_info, eisize); fo->write(extra_info, eisize); // extra info for unpacking
assert(eisize <= 9); assert(eisize <= 9);
NO_printf("%-13s: program hdr : %8u bytes\n", getName(), usizeof(oh)); NO_printf("%-13s: program hdr : %8u bytes\n", getName(), usizeof(oh));
NO_printf("%-13s: entry : %8u bytes\n", getName(), e_len); NO_printf("%-13s: entry : %8u bytes\n", getName(), e_len);
@ -564,7 +562,7 @@ void PackExe::pack(OutputFile *fo) {
// copy the overlay // copy the overlay
copyOverlay(fo, ih_overlay, obuf); copyOverlay(fo, ih_overlay, obuf);
// fprintf (stderr,"%x %x\n",relocsize,ph.u_len); NO_fprintf(stderr, "dos/exe %x %x\n", relocsize, ph.u_len);
// finally check the compression ratio // finally check the compression ratio
if (!checkFinalCompressionRatio(fo)) if (!checkFinalCompressionRatio(fo))
@ -607,41 +605,46 @@ void PackExe::unpack(OutputFile *fo) {
decompress(ibuf + e_len, obuf); decompress(ibuf + e_len, obuf);
unsigned imagesize = ih_imagesize; unsigned imagesize = ih_imagesize;
imagesize--; imagesize -= 1;
const byte flag = ibuf[imagesize]; const byte flag = ibuf[imagesize];
unsigned relocn = 0; // relocations
SPAN_S_VAR(byte, relocs, obuf + ph.u_len, obuf); unsigned relocnum = 0;
SPAN_S_VAR(const byte, relocstart, obuf + ph.u_len, obuf);
MemBuffer mb_wrkmem; MemBuffer mb_relocs;
SPAN_0_VAR(byte, wrkmem, nullptr); SPAN_0_VAR(byte, relocs, nullptr);
if (!(flag & NORELOC)) { if (!(flag & NORELOC)) {
relocs -= get_le16(obuf + (ph.u_len - 2)); mb_relocs.alloc(4 * MAXRELOCSIZE);
relocs = mb_relocs; // => now a SPAN_S
relocsize = get_le16(obuf + ph.u_len - 2);
ph.u_len -= 2; ph.u_len -= 2;
if (relocsize < 11 || relocsize > MAXRELOCSIZE || relocsize >= imagesize)
throwCantUnpack("bad relocations");
relocstart -= relocsize;
mb_wrkmem.alloc(4 * MAXRELOCS); // unoptimize_relocs
wrkmem = mb_wrkmem; // => now a SPAN_S unsigned ones = get_le16(relocstart);
unsigned es = 0, ones = get_le16(relocs); const unsigned seg_high = get_le16(relocstart + 2);
const unsigned seghi = get_le16(relocs + 2); SPAN_S_VAR(const byte, p, relocstart + 4);
SPAN_S_VAR(const byte, p, relocs + 4); unsigned es = 0;
while (ones) { while (ones) {
unsigned di = get_le16(p); unsigned di = get_le16(p);
es += get_le16(p + 2); es += get_le16(p + 2);
bool dorel = true; bool dorel = true;
for (p += 4; ones && di < 0x10000; p++) { for (p += 4; ones && di < 0x10000; p++) {
if (dorel) { if (dorel) {
set_le16(wrkmem + (4 * relocn), di); set_le16(relocs + (4 * relocnum + 0), di);
set_le16(wrkmem + (2 + 4 * relocn++), es); set_le16(relocs + (4 * relocnum + 2), es);
NO_printf("%x\n", es * 16 + di); NO_printf("dos/exe unreloc %4d %6x\n", relocnum, es * 16 + di);
relocnum++;
} }
dorel = true; dorel = true;
if (*p == 0) { if (*p == 0) {
SPAN_S_VAR(const byte, q, obuf); SPAN_S_VAR(const byte, q, obuf + (es * 16 + di), obuf);
for (q = obuf + (es * 16 + di); !(*q == 0x9a && get_le16(q + 3) <= seghi); while (!(*q == 0x9a && get_le16(q + 3) <= seg_high))
q++) { q++;
} di = ptr_udiff_bytes(q, obuf + (es * 16)) + 3;
di = ptr_diff_bytes(q, obuf + (es * 16)) + 3;
} else if (*p == 1) { } else if (*p == 1) {
di += 254; di += 254;
if (di < 0x10000) if (di < 0x10000)
@ -657,16 +660,16 @@ void PackExe::unpack(OutputFile *fo) {
memset(&oh, 0, sizeof(oh)); memset(&oh, 0, sizeof(oh));
oh.ident = 'M' + 'Z' * 256; oh.ident = 'M' + 'Z' * 256;
if (relocn) { if (relocnum) {
oh.relocs = relocn; oh.relocs = relocnum;
while (relocn & 3) while (relocnum & 3) // paragraph align
set_le32(wrkmem + (4 * relocn++), 0); set_le32(relocs + (4 * relocnum++), 0);
} }
unsigned outputlen = ptr_udiff_bytes(relocs, obuf) + sizeof(oh) + relocn * 4; unsigned outputlen = sizeof(oh) + 4 * relocnum + ptr_udiff_bytes(relocstart, obuf);
oh.m512 = outputlen & 511; oh.m512 = outputlen & 511;
oh.p512 = (outputlen + 511) >> 9; oh.p512 = (outputlen + 511) >> 9;
oh.headsize16 = 2 + relocn / 4; oh.headsize16 = 2 + relocnum / 4;
oh.max = ih.max; oh.max = ih.max;
oh.min = ih.min; oh.min = ih.min;
@ -701,9 +704,9 @@ void PackExe::unpack(OutputFile *fo) {
// write header + relocations + uncompressed file // write header + relocations + uncompressed file
fo->write(&oh, sizeof(oh)); fo->write(&oh, sizeof(oh));
if (relocn) if (relocnum)
fo->write(wrkmem, relocn * 4); fo->write(relocs, 4 * relocnum);
fo->write(obuf, ptr_udiff_bytes(relocs, obuf)); fo->write(obuf, ptr_udiff_bytes(relocstart, obuf));
// copy the overlay // copy the overlay
copyOverlay(fo, ih_overlay, obuf); copyOverlay(fo, ih_overlay, obuf);

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; } virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_DOS_EXE; } virtual int getFormat() const override { return UPX_F_DOS_EXE; }
virtual const char *getName() const override { return "dos/exe"; } virtual const char *getName() const override { return "dos/exe"; }
virtual const char *getFullName(const options_t *) const override { return "i086-dos16.exe"; } virtual const char *getFullName(const Options *) const override { return "i086-dos16.exe"; }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override; virtual const int *getFilters() const override;
@ -90,18 +90,18 @@ protected:
exe_header_t ih, oh; exe_header_t ih, oh;
unsigned ih_exesize; unsigned ih_exesize = 0;
unsigned ih_imagesize; unsigned ih_imagesize = 0;
unsigned ih_overlay; unsigned ih_overlay = 0;
unsigned relocsize; unsigned relocsize = 0;
bool has_9a; bool has_9a = false;
bool device_driver; bool device_driver = false;
enum { NORELOC = 1, USEJUMP = 2, SS = 4, SP = 8, MINMEM = 16, MAXMEM = 32 }; enum { NORELOC = 1, USEJUMP = 2, SS = 4, SP = 8, MINMEM = 16, MAXMEM = 32 };
unsigned stack_for_lzma; // stack size required for lzma unsigned stack_for_lzma = 0; // stack size required for lzma
bool use_clear_dirty_stack; bool use_clear_dirty_stack = false;
}; };
#endif /* already included */ #endif /* already included */

View File

@ -45,7 +45,7 @@ public:
virtual int getVersion() const override { return 13; } virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_PS1_EXE; } virtual int getFormat() const override { return UPX_F_PS1_EXE; }
virtual const char *getName() const override { return "ps1/exe"; } virtual const char *getName() const override { return "ps1/exe"; }
virtual const char *getFullName(const options_t *) const override { return "mipsel.r3000-ps1"; } virtual const char *getFullName(const Options *) const override { return "mipsel.r3000-ps1"; }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override; virtual const int *getFilters() const override;

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; } virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_DOS_SYS; } virtual int getFormat() const override { return UPX_F_DOS_SYS; }
virtual const char *getName() const override { return "dos/sys"; } virtual const char *getName() const override { return "dos/sys"; }
virtual const char *getFullName(const options_t *) const override { return "i086-dos16.sys"; } virtual const char *getFullName(const Options *) const override { return "i086-dos16.sys"; }
virtual bool canPack() override; virtual bool canPack() override;

View File

@ -188,15 +188,18 @@ void PackTmt::pack(OutputFile *fo) {
checkOverlay(overlay); checkOverlay(overlay);
for (unsigned ic = 0; ic < relocnum; ic++) for (unsigned ic = 0; ic < relocnum; ic++)
set_le32(relocs + ic * 4, get_le32(relocs + ic * 4) - 4); set_le32(relocs + 4 * ic, get_le32(relocs + 4 * ic) - 4);
MemBuffer mb_orelocs(4 * relocnum + 8192); // relocations + extra_info MemBuffer mb_orelocs(4 * relocnum + 8192); // relocations + extra_info
SPAN_S_VAR(byte, orelocs, mb_orelocs); SPAN_S_VAR(byte, orelocs, mb_orelocs);
unsigned orelocsize = unsigned orelocsize =
optimizeReloc(relocnum, relocs, orelocs, ibuf, usize, 32, true, &big_relocs); optimizeReloc(relocnum, relocs, orelocs, ibuf, usize, 32, true, &big_relocs);
mb_relocs.dealloc(); // done mb_relocs.dealloc(); // done
#if 1
// write duplicate end marker; why is this here - historical oversight ???
orelocs[orelocsize++] = 0;
#endif
// extra_info // extra_info
orelocs[orelocsize++] = 0; // why is this needed - historical oversight ???
set_le32(orelocs + orelocsize, ih.entry); // save original entry point set_le32(orelocs + orelocsize, ih.entry); // save original entry point
orelocsize += 4; orelocsize += 4;
set_le32(orelocs + orelocsize, orelocsize + 4); // save orelocsize set_le32(orelocs + orelocsize, orelocsize + 4); // save orelocsize
@ -303,7 +306,7 @@ void PackTmt::unpack(OutputFile *fo) {
const unsigned relocnum = unoptimizeReloc(orelocs, mb_relocs, reloc_image, osize, 32, true); const unsigned relocnum = unoptimizeReloc(orelocs, mb_relocs, reloc_image, osize, 32, true);
SPAN_S_VAR(byte, relocs, mb_relocs); SPAN_S_VAR(byte, relocs, mb_relocs);
for (unsigned ic = 0; ic < relocnum; ic++) for (unsigned ic = 0; ic < relocnum; ic++)
set_le32(relocs + ic * 4, get_le32(relocs + ic * 4) + 4); set_le32(relocs + 4 * ic, get_le32(relocs + 4 * ic) + 4);
memcpy(&oh, &ih, sizeof(oh)); memcpy(&oh, &ih, sizeof(oh));
oh.imagesize = osize; oh.imagesize = osize;

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; } virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_TMT_ADAM; } virtual int getFormat() const override { return UPX_F_TMT_ADAM; }
virtual const char *getName() const override { return "tmt/adam"; } virtual const char *getName() const override { return "tmt/adam"; }
virtual const char *getFullName(const options_t *) const override { virtual const char *getFullName(const Options *) const override {
return "i386-dos32.tmt.adam"; return "i386-dos32.tmt.adam";
} }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;

View File

@ -223,11 +223,9 @@ void PackTos::buildLoader(const Filter *ft) {
#define F_FASTLOAD 0x01 // don't zero heap #define F_FASTLOAD 0x01 // don't zero heap
#define F_ALTLOAD 0x02 // OK to load in alternate ram #define F_ALTLOAD 0x02 // OK to load in alternate ram
#define F_ALTALLOC 0x04 // OK to malloc from alt. ram #define F_ALTALLOC 0x04 // OK to malloc from alt. ram
#define F_SMALLTPA \ #define F_SMALLTPA 0x08
0x08 // used in MagiC: TPA can be allocated // used in MagiC: TPA can be allocated as specified in the program header
// as specified in the program header // rather than the biggest free memory block
// rather than the biggest free memory
// block
#define F_MEMFLAGS 0xf0 // reserved for future use #define F_MEMFLAGS 0xf0 // reserved for future use
#define F_SHTEXT 0x800 // program's text may be shared #define F_SHTEXT 0x800 // program's text may be shared
@ -297,26 +295,26 @@ bool PackTos::checkFileHeader() {
// relocs // relocs
**************************************************************************/ **************************************************************************/
// Check relocation for errors to make sure our loader can handle it. // Check relocation for errors to make sure our loader can handle them
static int check_relocs(const byte *relocs, unsigned rsize, unsigned isize, unsigned *nrelocs, static int check_relocs(const byte *relocs, unsigned rsize, unsigned image_size, unsigned *relocnum,
unsigned *relocsize, unsigned *overlay) { unsigned *relocsize, unsigned *overlay) {
assert(rsize >= 4);
assert(image_size >= 4);
unsigned fixup = get_be32(relocs); unsigned fixup = get_be32(relocs);
assert(fixup > 0);
unsigned last_fixup = fixup; unsigned last_fixup = fixup;
unsigned i = 4; unsigned i = 4;
assert(isize >= 4); *relocnum = 1;
assert(fixup > 0);
*nrelocs = 1;
for (;;) { for (;;) {
if (fixup & 1) // must be word-aligned if (fixup & 1) // must be word-aligned
return -1; return -1;
if (fixup + 4 > isize) // too far if (fixup + 4 > image_size) // out of bounds
return -1; return -1;
if (i >= rsize) // premature EOF in relocs if (i >= rsize) // premature EOF in relocs
return -1; return -1;
unsigned c = relocs[i++]; unsigned c = relocs[i++];
if (c == 0) // end marker if (c == 0) // EOF end marker
break; break;
else if (c == 1) // increase fixup, no reloc else if (c == 1) // increase fixup, no reloc
fixup += 254; fixup += 254;
@ -328,7 +326,7 @@ static int check_relocs(const byte *relocs, unsigned rsize, unsigned isize, unsi
if (fixup - last_fixup < 4) // overlapping relocation if (fixup - last_fixup < 4) // overlapping relocation
return -1; return -1;
last_fixup = fixup; last_fixup = fixup;
*nrelocs += 1; *relocnum += 1;
} }
} }
@ -352,7 +350,7 @@ bool PackTos::canPack() {
if (!checkFileHeader()) if (!checkFileHeader())
throwCantPack("unsupported header flags"); throwCantPack("unsupported header flags");
if (file_size < 1024) if (file_size < 1024)
throwCantPack("program is too small"); throwCantPack("program is too small for atari/tos");
return true; return true;
} }
@ -370,7 +368,7 @@ void PackTos::fileInfo() {
void PackTos::pack(OutputFile *fo) { void PackTos::pack(OutputFile *fo) {
unsigned t; unsigned t;
unsigned nrelocs = 0; unsigned relocnum = 0;
unsigned relocsize = 0; unsigned relocsize = 0;
unsigned overlay = 0; unsigned overlay = 0;
@ -426,14 +424,14 @@ void PackTos::pack(OutputFile *fo) {
} else if (ih.fh_reloc != 0) } else if (ih.fh_reloc != 0)
relocsize = 0; relocsize = 0;
else { else {
int r = check_relocs(ibuf + t, overlay, t, &nrelocs, &relocsize, &overlay); int r = check_relocs(ibuf + t, overlay, t, &relocnum, &relocsize, &overlay);
if (r != 0) if (r != 0)
throwCantPack("bad relocation table"); throwCantPack("bad relocation table");
symbols.need_reloc = true; symbols.need_reloc = true;
} }
#if TESTING #if TESTING
printf("xx2: %d relocs: %d, overlay: %d, t: %d\n", nrelocs, relocsize, overlay, t); printf("xx2: %d relocs: %d, overlay: %d, t: %d\n", relocnum, relocsize, overlay, t);
#endif #endif
checkOverlay(overlay); checkOverlay(overlay);
@ -451,7 +449,7 @@ void PackTos::pack(OutputFile *fo) {
// Now the data in ibuf[0..t] looks like this: // Now the data in ibuf[0..t] looks like this:
// text + data + relocs + original file header // text + data + relocs + original file header
// After compression this will become the first part of the // After compression this will become the first part of the
// data segement. The second part will be the decompressor. // data segment. The second part will be the decompressor.
// alloc buffer (4096 is for decompressor and the various alignments) // alloc buffer (4096 is for decompressor and the various alignments)
obuf.allocForCompression(t, 4096); obuf.allocForCompression(t, 4096);

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; } virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_ATARI_TOS; } virtual int getFormat() const override { return UPX_F_ATARI_TOS; }
virtual const char *getName() const override { return "atari/tos"; } virtual const char *getName() const override { return "atari/tos"; }
virtual const char *getFullName(const options_t *) const override { return "m68k-atari.tos"; } virtual const char *getFullName(const Options *) const override { return "m68k-atari.tos"; }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override; virtual const int *getFilters() const override;

View File

@ -62,8 +62,8 @@ Linker *PackW32PeI386::newLinker() const { return new ElfLinkerX86; }
**************************************************************************/ **************************************************************************/
int PackW32PeI386::readFileHeader() { int PackW32PeI386::readFileHeader() {
if (fi->st_size() >= 0x206) { if (file_size >= 0x206) {
char buf[6]; byte buf[6];
fi->seek(0x200, SEEK_SET); fi->seek(0x200, SEEK_SET);
fi->readx(buf, 6); fi->readx(buf, 6);
isrtm = memcmp(buf, "32STUB", 6) == 0; isrtm = memcmp(buf, "32STUB", 6) == 0;

View File

@ -39,7 +39,7 @@ public:
virtual ~PackW32PeI386(); virtual ~PackW32PeI386();
virtual int getFormat() const override { return UPX_F_W32PE_I386; } virtual int getFormat() const override { return UPX_F_W32PE_I386; }
virtual const char *getName() const override { return isrtm ? "rtm32/pe" : "win32/pe"; } virtual const char *getName() const override { return isrtm ? "rtm32/pe" : "win32/pe"; }
virtual const char *getFullName(const options_t *) const override { return "i386-win32.pe"; } virtual const char *getFullName(const Options *) const override { return "i386-win32.pe"; }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override; virtual const int *getFilters() const override;

View File

@ -39,7 +39,7 @@ public:
virtual ~PackW64PeAmd64(); virtual ~PackW64PeAmd64();
virtual int getFormat() const override { return UPX_F_W64PE_AMD64; } virtual int getFormat() const override { return UPX_F_W64PE_AMD64; }
virtual const char *getName() const override { return "win64/pe"; } virtual const char *getName() const override { return "win64/pe"; }
virtual const char *getFullName(const options_t *) const override { return "amd64-win64.pe"; } virtual const char *getFullName(const Options *) const override { return "amd64-win64.pe"; }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override; virtual const int *getFilters() const override;

View File

@ -39,7 +39,7 @@ public:
virtual ~PackW64PeArm64() {} virtual ~PackW64PeArm64() {}
virtual int getFormat() const override { return UPX_F_W64PE_ARM64; } virtual int getFormat() const override { return UPX_F_W64PE_ARM64; }
virtual const char *getName() const override { return "win64/arm64"; } virtual const char *getName() const override { return "win64/arm64"; }
virtual const char *getFullName(const options_t *) const override { return "arm64-win64.pe"; } virtual const char *getFullName(const Options *) const override { return "arm64-win64.pe"; }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override; virtual const int *getFilters() const override;
@ -70,7 +70,7 @@ public:
PackW64PeArm64EC(InputFile *f) : super(f) {} PackW64PeArm64EC(InputFile *f) : super(f) {}
virtual int getFormat() const override { return UPX_F_W64PE_ARM64EC; } virtual int getFormat() const override { return UPX_F_W64PE_ARM64EC; }
virtual const char *getName() const override { return "win64/arm64ec"; } virtual const char *getName() const override { return "win64/arm64ec"; }
virtual const char *getFullName(const options_t *) const override { return "arm64ec-win64.pe"; } virtual const char *getFullName(const Options *) const override { return "arm64ec-win64.pe"; }
virtual bool canPack() override; virtual bool canPack() override;
}; };

View File

@ -39,7 +39,7 @@ public:
virtual int getVersion() const override { return 13; } virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_WATCOM_LE; } virtual int getFormat() const override { return UPX_F_WATCOM_LE; }
virtual const char *getName() const override { return "watcom/le"; } virtual const char *getName() const override { return "watcom/le"; }
virtual const char *getFullName(const options_t *) const override { virtual const char *getFullName(const Options *) const override {
return "i386-dos32.watcom.le"; return "i386-dos32.watcom.le";
} }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;

View File

@ -39,7 +39,7 @@ public:
virtual ~PackWinCeArm(); virtual ~PackWinCeArm();
virtual int getFormat() const override { return UPX_F_WINCE_ARM; } virtual int getFormat() const override { return UPX_F_WINCE_ARM; }
virtual const char *getName() const override { return "wince/arm"; } virtual const char *getName() const override { return "wince/arm"; }
virtual const char *getFullName(const options_t *) const override { return "arm-wince.pe"; } virtual const char *getFullName(const Options *) const override { return "arm-wince.pe"; }
virtual const int *getCompressionMethods(int method, int level) const override; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const override; virtual const int *getFilters() const override;
virtual void defineFilterSymbols(const Filter *) override {} virtual void defineFilterSymbols(const Filter *) override {}

View File

@ -46,7 +46,7 @@ Packer::Packer(InputFile *f)
mem_clear(&ph, sizeof(ph)); mem_clear(&ph, sizeof(ph));
} }
Packer::~Packer() { Packer::~Packer() noexcept {
delete uip; delete uip;
uip = nullptr; uip = nullptr;
delete linker; delete linker;
@ -834,27 +834,26 @@ static const char *getIdentstr(unsigned *size, int small) {
"\n"; "\n";
static char identtiny[] = UPX_VERSION_STRING4; static char identtiny[] = UPX_VERSION_STRING4;
static int done; static upx_std_once_flag init_done;
if (!done && (opt->debug.fake_stub_version[0] || opt->debug.fake_stub_year[0])) { upx_std_call_once(init_done, []() noexcept {
struct strinfo_t { if (opt->debug.fake_stub_version[0] || opt->debug.fake_stub_year[0]) {
char *s; struct Ident {
int size; char *s;
}; int len;
static const strinfo_t strlist[] = {{identbig, (int) sizeof(identbig)}, };
{identsmall, (int) sizeof(identsmall)}, static const Ident idents[] = {{identbig, (int) sizeof(identbig) - 1},
{identtiny, (int) sizeof(identtiny)}, {identsmall, (int) sizeof(identsmall) - 1},
{nullptr, 0}}; {identtiny, (int) sizeof(identtiny) - 1},
const strinfo_t *iter; {nullptr, 0}};
for (const Ident *iter = idents; iter->s; ++iter) {
for (iter = strlist; iter->s; ++iter) { if (opt->debug.fake_stub_version[0])
if (opt->debug.fake_stub_version[0]) mem_replace(iter->s, iter->len, UPX_VERSION_STRING4, 4,
mem_replace(iter->s, iter->size, UPX_VERSION_STRING4, 4, opt->debug.fake_stub_version);
opt->debug.fake_stub_version); if (opt->debug.fake_stub_year[0])
if (opt->debug.fake_stub_year[0]) mem_replace(iter->s, iter->len, UPX_VERSION_YEAR, 4, opt->debug.fake_stub_year);
mem_replace(iter->s, iter->size, UPX_VERSION_YEAR, 4, opt->debug.fake_stub_year); }
} }
done = 1; });
}
if (small < 0) if (small < 0)
small = opt->small; small = opt->small;

View File

@ -112,7 +112,7 @@ protected:
Packer(InputFile *f); Packer(InputFile *f);
public: public:
virtual ~Packer(); virtual ~Packer() noexcept;
virtual void assertPacker() const; virtual void assertPacker() const;
// getVersion() enables detecting forward incompatibility of unpack() // getVersion() enables detecting forward incompatibility of unpack()
@ -121,7 +121,7 @@ public:
// A unique integer ID for this executable format. See conf.h. // A unique integer ID for this executable format. See conf.h.
virtual int getFormat() const = 0; virtual int getFormat() const = 0;
virtual const char *getName() const = 0; virtual const char *getName() const = 0;
virtual const char *getFullName(const options_t *) const = 0; virtual const char *getFullName(const Options *) const = 0;
virtual const int *getCompressionMethods(int method, int level) const = 0; virtual const int *getCompressionMethods(int method, int level) const = 0;
virtual const int *getFilters() const = 0; virtual const int *getFilters() const = 0;
@ -187,7 +187,7 @@ protected:
unsigned overlap_range, upx_compress_config_t const *cconf, unsigned overlap_range, upx_compress_config_t const *cconf,
int filter_strategy, bool inhibit_compression_check = false); int filter_strategy, bool inhibit_compression_check = false);
// util for verifying overlapping decompresion // util for verifying overlapping decompression
// non-destructive test // non-destructive test
virtual bool testOverlappingDecompression(const byte *buf, const byte *tbuf, virtual bool testOverlappingDecompression(const byte *buf, const byte *tbuf,
unsigned overlap_overhead) const; unsigned overlap_overhead) const;
@ -299,9 +299,9 @@ protected:
int ph_version; int ph_version;
// compression buffers // compression buffers
MemBuffer ibuf; // input MemBuffer ibuf; // input
MemBuffer obuf; // output MemBuffer obuf; // output
unsigned ibufgood; // high-water mark in ibuf (pefile.cpp) unsigned ibufgood = 0; // high-water mark in ibuf (pefile.cpp)
// UI handler // UI handler
UiPacker *uip = nullptr; UiPacker *uip = nullptr;

View File

@ -30,7 +30,7 @@
/************************************************************************* /*************************************************************************
// sort and delta-compress relocations with optional bswap within image // sort and delta-compress relocations with optional bswap within image
// returns number of bytes written to |out| // returns number of bytes written to 'out'
**************************************************************************/ **************************************************************************/
unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(byte) out, unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(byte) out,
@ -38,6 +38,10 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
int *big) { int *big) {
assert(bits == 32 || bits == 64); assert(bits == 32 || bits == 64);
mem_size_assert(1, image_size); mem_size_assert(1, image_size);
#if WITH_XSPAN >= 2
ptr_check_no_overlap(relocs.data(), relocs.size_bytes(), image.data(image_size), image_size,
out.data(), out.size_bytes());
#endif
SPAN_P_VAR(byte, fix, out); SPAN_P_VAR(byte, fix, out);
*big = 0; *big = 0;
@ -69,7 +73,7 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
fix += 4; fix += 4;
} }
pc += delta; pc += delta;
if (pc + 4 >= image_size) if (pc + 4 > image_size)
throwCantPack("bad reloc[%#x] = %#x", i, pc); throwCantPack("bad reloc[%#x] = %#x", i, pc);
if (bswap) { if (bswap) {
if (bits == 32) if (bits == 32)
@ -84,14 +88,17 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
/************************************************************************* /*************************************************************************
// delta-decompress relocations // delta-decompress relocations
// advances |in| // advances 'in'
// allocates |out| and returns number of relocs written to |out| // allocates 'out' and returns number of relocs written to 'out'
**************************************************************************/ **************************************************************************/
unsigned Packer::unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P(byte) image, unsigned Packer::unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P(byte) image,
unsigned image_size, int bits, bool bswap) { unsigned image_size, int bits, bool bswap) {
assert(bits == 32 || bits == 64); assert(bits == 32 || bits == 64);
mem_size_assert(1, image_size); mem_size_assert(1, image_size);
#if WITH_XSPAN >= 2
ptr_check_no_overlap(in.data(), in.size_bytes(), image.data(image_size), image_size);
#endif
SPAN_S_VAR(const byte, fix, in); SPAN_S_VAR(const byte, fix, in);
// count // count
@ -125,7 +132,7 @@ unsigned Packer::unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P
if ((int) delta < 4) if ((int) delta < 4)
throwCantUnpack("overlapping fixups"); throwCantUnpack("overlapping fixups");
pc += delta; pc += delta;
if (pc + 4 >= image_size) if (pc + 4 > image_size)
throwCantUnpack("bad reloc[%#x] = %#x", i, pc); throwCantUnpack("bad reloc[%#x] = %#x", i, pc);
*relocs++ = pc; *relocs++ = pc;
if (bswap && image != nullptr) { if (bswap && image != nullptr) {

View File

@ -59,34 +59,37 @@
// //
**************************************************************************/ **************************************************************************/
PackMaster::PackMaster(InputFile *f, options_t *o) : fi(f), p(nullptr) { PackMaster::PackMaster(InputFile *f, Options *o) noexcept : fi(f) {
// replace global options with local options // replace global options with local options
saved_opt = o; if (o != nullptr) {
if (o) { #if WITH_THREADS
std::lock_guard<std::mutex> lock(opt_lock_mutex);
#endif
saved_opt = o;
memcpy(&this->local_options, o, sizeof(*o)); // struct copy memcpy(&this->local_options, o, sizeof(*o)); // struct copy
opt = &this->local_options; opt = &this->local_options;
} }
} }
PackMaster::~PackMaster() { PackMaster::~PackMaster() noexcept {
fi = nullptr; delete packer;
delete p; packer = nullptr;
p = nullptr;
// restore global options // restore global options
if (saved_opt) if (saved_opt != nullptr) {
#if WITH_THREADS
std::lock_guard<std::mutex> lock(opt_lock_mutex);
#endif
opt = saved_opt; opt = saved_opt;
saved_opt = nullptr; saved_opt = nullptr;
}
} }
/************************************************************************* /*************************************************************************
// //
**************************************************************************/ **************************************************************************/
static Packer *try_pack(Packer *p, void *user) { static Packer *try_can_pack(Packer *p, void *user) {
if (p == nullptr)
return nullptr;
InputFile *f = (InputFile *) user; InputFile *f = (InputFile *) user;
p->assertPacker();
try { try {
p->initPackHeader(); p->initPackHeader();
f->seek(0, SEEK_SET); f->seek(0, SEEK_SET);
@ -105,11 +108,8 @@ static Packer *try_pack(Packer *p, void *user) {
return nullptr; return nullptr;
} }
static Packer *try_unpack(Packer *p, void *user) { static Packer *try_can_unpack(Packer *p, void *user) {
if (p == nullptr)
return nullptr;
InputFile *f = (InputFile *) user; InputFile *f = (InputFile *) user;
p->assertPacker();
try { try {
p->initPackHeader(); p->initPackHeader();
f->seek(0, SEEK_SET); f->seek(0, SEEK_SET);
@ -123,6 +123,7 @@ static Packer *try_unpack(Packer *p, void *user) {
// see canUnpack() in packer.h // see canUnpack() in packer.h
} }
} catch (const IOException &) { } catch (const IOException &) {
// ignored
} catch (...) { } catch (...) {
delete p; delete p;
throw; throw;
@ -135,41 +136,40 @@ static Packer *try_unpack(Packer *p, void *user) {
// //
**************************************************************************/ **************************************************************************/
Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const options_t *o, /*static*/
void *user) { Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const Options *o, void *user) {
Packer *p = nullptr;
#define D(Klass) \ #define D(Klass) \
ACC_BLOCK_BEGIN \ ACC_BLOCK_BEGIN \
Klass *const kp = new Klass(f); \ COMPILE_TIME_ASSERT(std::is_nothrow_destructible_v<Klass>) \
Klass *kp = new Klass(f); \
kp->assertPacker(); \
if (o->debug.debug_level) \ if (o->debug.debug_level) \
fprintf(stderr, "visitAllPackers: (ver=%d, fmt=%3d) %s\n", kp->getVersion(), \ fprintf(stderr, "visitAllPackers: (ver=%d, fmt=%3d) %s\n", kp->getVersion(), \
kp->getFormat(), #Klass); \ kp->getFormat(), #Klass); \
if ((p = func(kp, user)) != nullptr) \ Packer *p = func(kp, user); \
if (p != nullptr) \
return p; \ return p; \
ACC_BLOCK_END ACC_BLOCK_END
// note: order of tries is important ! // NOTE: order of tries is important !!!
// //
// .exe // .exe
// //
if (!o->dos_exe.force_stub) { if (!o->dos_exe.force_stub) {
// dos32
D(PackDjgpp2); D(PackDjgpp2);
D(PackTmt); D(PackTmt);
D(PackWcle); D(PackWcle);
// Windows
// D(PackW64PeArm64EC); // NOT YET IMPLEMENTED // D(PackW64PeArm64EC); // NOT YET IMPLEMENTED
// D(PackW64PeArm64); // NOT YET IMPLEMENTED // D(PackW64PeArm64); // NOT YET IMPLEMENTED
D(PackW64PeAmd64); D(PackW64PeAmd64);
D(PackW32PeI386); D(PackW32PeI386);
D(PackWinCeArm);
} }
D(PackWinCeArm); D(PackExe); // dos/exe
D(PackExe);
//
// atari
//
D(PackTos);
// //
// linux kernel // linux kernel
@ -210,18 +210,7 @@ Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio
D(PackMachFat); // cafebabe conflict D(PackMachFat); // cafebabe conflict
D(PackLinuxI386); // cafebabe conflict D(PackLinuxI386); // cafebabe conflict
// // Mach (Darwin / macOS)
// psone
//
D(PackPs1);
//
// .sys and .com
//
D(PackSys);
D(PackCom);
// Mach (macOS)
D(PackDylibAMD64); D(PackDylibAMD64);
D(PackMachPPC32); // TODO: this works with upx 3.91..3.94 but got broken in 3.95; FIXME D(PackMachPPC32); // TODO: this works with upx 3.91..3.94 but got broken in 3.95; FIXME
D(PackMachI386); D(PackMachI386);
@ -235,24 +224,30 @@ Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio
// D(PackDylibI386); // D(PackDylibI386);
// D(PackDylibPPC32); // D(PackDylibPPC32);
//
// misc
//
D(PackTos); // atari/tos
D(PackPs1); // ps1/exe
D(PackSys); // dos/sys
D(PackCom); // dos/com
return nullptr; return nullptr;
#undef D #undef D
} }
Packer *PackMaster::getPacker(InputFile *f) { /*static*/ Packer *PackMaster::getPacker(InputFile *f) {
Packer *pp = visitAllPackers(try_pack, f, opt, f); Packer *p = visitAllPackers(try_can_pack, f, opt, f);
if (!pp) if (!p)
throwUnknownExecutableFormat(); throwUnknownExecutableFormat();
pp->assertPacker(); return p;
return pp;
} }
Packer *PackMaster::getUnpacker(InputFile *f) { /*static*/ Packer *PackMaster::getUnpacker(InputFile *f) {
Packer *pp = visitAllPackers(try_unpack, f, opt, f); Packer *p = visitAllPackers(try_can_unpack, f, opt, f);
if (!pp) if (!p)
throwNotPacked(); throwNotPacked();
pp->assertPacker(); return p;
return pp;
} }
/************************************************************************* /*************************************************************************
@ -260,39 +255,37 @@ Packer *PackMaster::getUnpacker(InputFile *f) {
**************************************************************************/ **************************************************************************/
void PackMaster::pack(OutputFile *fo) { void PackMaster::pack(OutputFile *fo) {
p = getPacker(fi); assert(packer == nullptr);
fi = nullptr; packer = getPacker(fi);
p->doPack(fo); packer->doPack(fo);
} }
void PackMaster::unpack(OutputFile *fo) { void PackMaster::unpack(OutputFile *fo) {
p = getUnpacker(fi); assert(packer == nullptr);
p->assertPacker(); packer = getUnpacker(fi);
fi = nullptr; packer->doUnpack(fo);
p->doUnpack(fo);
} }
void PackMaster::test() { void PackMaster::test() {
p = getUnpacker(fi); assert(packer == nullptr);
fi = nullptr; packer = getUnpacker(fi);
p->doTest(); packer->doTest();
} }
void PackMaster::list() { void PackMaster::list() {
p = getUnpacker(fi); assert(packer == nullptr);
fi = nullptr; packer = getUnpacker(fi);
p->doList(); packer->doList();
} }
void PackMaster::fileInfo() { void PackMaster::fileInfo() {
p = visitAllPackers(try_unpack, fi, opt, fi); assert(packer == nullptr);
if (!p) packer = visitAllPackers(try_can_unpack, fi, opt, fi);
p = visitAllPackers(try_pack, fi, opt, fi); if (!packer)
if (!p) packer = visitAllPackers(try_can_pack, fi, opt, fi);
if (!packer)
throwUnknownExecutableFormat(nullptr, 1); // make a warning here throwUnknownExecutableFormat(nullptr, 1); // make a warning here
p->assertPacker(); packer->doFileInfo();
fi = nullptr;
p->doFileInfo();
} }
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -32,13 +32,13 @@ class InputFile;
class OutputFile; class OutputFile;
/************************************************************************* /*************************************************************************
// interface for work.cpp // dispatch to a concrete subclass of class Packer; see work.cpp
**************************************************************************/ **************************************************************************/
class PackMaster final { class PackMaster final {
public: public:
PackMaster(InputFile *f, options_t *o = nullptr); PackMaster(InputFile *f, Options *o = nullptr) noexcept;
~PackMaster(); ~PackMaster() noexcept;
void pack(OutputFile *fo); void pack(OutputFile *fo);
void unpack(OutputFile *fo); void unpack(OutputFile *fo);
@ -47,18 +47,18 @@ public:
void fileInfo(); void fileInfo();
typedef Packer *(*visit_func_t)(Packer *p, void *user); typedef Packer *(*visit_func_t)(Packer *p, void *user);
static Packer *visitAllPackers(visit_func_t, InputFile *f, const options_t *, void *user); static Packer *visitAllPackers(visit_func_t, InputFile *f, const Options *, void *user);
private: private:
InputFile *fi = nullptr; Packer *packer = nullptr; // owner
Packer *p = nullptr; InputFile *fi = nullptr; // reference
static Packer *getPacker(InputFile *f); static Packer *getPacker(InputFile *f);
static Packer *getUnpacker(InputFile *f); static Packer *getUnpacker(InputFile *f);
// setup local options for each file // setup local options for each file
options_t local_options; Options local_options;
options_t *saved_opt = nullptr; Options *saved_opt = nullptr;
}; };
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -140,7 +140,7 @@ bool PeFile::testUnpackVersion(int version) const {
if (cpu >= IMAGE_FILE_MACHINE_I386 && cpu <= 0x150) // what is this 0x150 ??? if (cpu >= IMAGE_FILE_MACHINE_I386 && cpu <= 0x150) // what is this 0x150 ???
return UPX_F_W32PE_I386; return UPX_F_W32PE_I386;
// other or unkown (alpha, mips, etc.) // other or unknown (alpha, mips, etc.)
throwCantPack("pefile: unsupported machine %#x", cpu); throwCantPack("pefile: unsupported machine %#x", cpu);
return 0; // pacify msvc return 0; // pacify msvc
} }
@ -274,6 +274,19 @@ void PeFile::Interval::dump() const {
// relocation handling // relocation handling
**************************************************************************/ **************************************************************************/
namespace {
struct FixDeleter { // don't leak memory on exceptions
LE32 **fix;
size_t n;
~FixDeleter() noexcept {
for (size_t i = 0; i < n; i++) {
delete[] fix[i];
fix[i] = nullptr;
}
}
};
} // namespace
struct alignas(1) PeFile::Reloc::reloc { struct alignas(1) PeFile::Reloc::reloc {
LE32 pagestart; LE32 pagestart;
LE32 size; LE32 size;
@ -371,17 +384,21 @@ void PeFile32::processRelocs() // pass1
} }
mb_orelocs.alloc(1); mb_orelocs.alloc(1);
orelocs = mb_orelocs; // => orelocs now is a SPAN_S orelocs = mb_orelocs; // => orelocs now is a SPAN_S
orelocs[0] = 0; // clear
sorelocs = 0; sorelocs = 0;
return; return;
} }
for (ic = 15; ic > 3; ic--) for (ic = 4; ic < 16; ic++)
if (counts[ic]) if (counts[ic])
infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]); infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]);
LE32 *fix[4]; LE32 *fix[4];
for (; ic; ic--) FixDeleter fixdel{fix, 0}; // don't leak memory
for (ic = 0; ic < 4; ic++) {
fix[ic] = New(LE32, counts[ic]); fix[ic] = New(LE32, counts[ic]);
fixdel.n += 1;
}
unsigned xcounts[4]; unsigned xcounts[4];
memset(xcounts, 0, sizeof(xcounts)); memset(xcounts, 0, sizeof(xcounts));
@ -420,7 +437,6 @@ void PeFile32::processRelocs() // pass1
orelocs = mb_orelocs; // => orelocs now is a SPAN_S orelocs = mb_orelocs; // => orelocs now is a SPAN_S
sorelocs = optimizeReloc(xcounts[3], (byte *) fix[3], orelocs, ibuf + rvamin, ibufgood - rvamin, sorelocs = optimizeReloc(xcounts[3], (byte *) fix[3], orelocs, ibuf + rvamin, ibufgood - rvamin,
32, true, &big_relocs); 32, true, &big_relocs);
delete[] fix[3];
// Malware that hides behind UPX often has PE header info that is // Malware that hides behind UPX often has PE header info that is
// deliberately corrupt. Sometimes it is even tuned to cause us trouble! // deliberately corrupt. Sometimes it is even tuned to cause us trouble!
@ -433,7 +449,6 @@ void PeFile32::processRelocs() // pass1
for (ic = 2; ic; ic--) { for (ic = 2; ic; ic--) {
memcpy(orelocs + sorelocs, fix[ic], 4 * xcounts[ic]); memcpy(orelocs + sorelocs, fix[ic], 4 * xcounts[ic]);
sorelocs += 4 * xcounts[ic]; sorelocs += 4 * xcounts[ic];
delete[] fix[ic];
set_le32(orelocs + sorelocs, 0); set_le32(orelocs + sorelocs, 0);
if (xcounts[ic]) { if (xcounts[ic]) {
@ -471,13 +486,16 @@ void PeFile64::processRelocs() // pass1
return; return;
} }
for (ic = 15; ic; ic--) for (ic = 0; ic < 16; ic++)
if (ic != 10 && counts[ic]) if (ic != 10 && counts[ic])
infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]); infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]);
LE32 *fix[16]; LE32 *fix[16];
for (ic = 15; ic; ic--) FixDeleter fixdel{fix, 0}; // don't leak memory
for (ic = 0; ic < 16; ic++) {
fix[ic] = New(LE32, counts[ic]); fix[ic] = New(LE32, counts[ic]);
fixdel.n += 1;
}
unsigned xcounts[16]; unsigned xcounts[16];
memset(xcounts, 0, sizeof(xcounts)); memset(xcounts, 0, sizeof(xcounts));
@ -495,7 +513,7 @@ void PeFile64::processRelocs() // pass1
} }
// remove duplicated records // remove duplicated records
for (ic = 1; ic <= 15; ic++) { for (ic = 1; ic < 16; ic++) {
qsort(fix[ic], xcounts[ic], 4, le32_compare); qsort(fix[ic], xcounts[ic], 4, le32_compare);
unsigned prev = ~0u; unsigned prev = ~0u;
unsigned jc = 0; unsigned jc = 0;
@ -520,9 +538,6 @@ void PeFile64::processRelocs() // pass1
sorelocs = optimizeReloc(xcounts[10], (byte *) fix[10], orelocs, ibuf + rvamin, sorelocs = optimizeReloc(xcounts[10], (byte *) fix[10], orelocs, ibuf + rvamin,
ibufgood - rvamin, 64, true, &big_relocs); ibufgood - rvamin, 64, true, &big_relocs);
for (ic = 15; ic; ic--)
delete[] fix[ic];
#if 0 #if 0
// Malware that hides behind UPX often has PE header info that is // Malware that hides behind UPX often has PE header info that is
// deliberately corrupt. Sometimes it is even tuned to cause us trouble! // deliberately corrupt. Sometimes it is even tuned to cause us trouble!
@ -536,7 +551,6 @@ void PeFile64::processRelocs() // pass1
{ {
memcpy(orelocs + sorelocs,fix[ic],4 * xcounts[ic]); memcpy(orelocs + sorelocs,fix[ic],4 * xcounts[ic]);
sorelocs += 4 * xcounts[ic]; sorelocs += 4 * xcounts[ic];
delete [] fix[ic];
set_le32(orelocs + sorelocs,0); set_le32(orelocs + sorelocs,0);
if (xcounts[ic]) if (xcounts[ic])
@ -574,7 +588,7 @@ const LE32 &PeFile::IDADDR(unsigned x) const { return iddirs[x].vaddr; }
in the sorted order. in the sorted order.
*/ */
class PeFile::ImportLinker : public ElfLinkerAMD64 { class PeFile::ImportLinker final : public ElfLinkerAMD64 {
struct tstr : private ::noncopyable { struct tstr : private ::noncopyable {
char *s = nullptr; char *s = nullptr;
explicit tstr(char *str) : s(str) {} explicit tstr(char *str) : s(str) {}
@ -833,7 +847,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
import_desc *const im_save = im; import_desc *const im_save = im;
if (IDADDR(PEDIR_IMPORT)) { if (IDADDR(PEDIR_IMPORT)) {
for (;; ++dllnum, ++im) { for (;; ++dllnum, ++im) {
unsigned const skip2 = ptr_diff_bytes(im, ibuf); unsigned const skip2 = ptr_udiff_bytes(im, ibuf);
(void) ibuf.subref("bad import %#x", skip2, sizeof(*im)); (void) ibuf.subref("bad import %#x", skip2, sizeof(*im));
if (!im->dllname) if (!im->dllname)
break; break;
@ -853,25 +867,17 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
static int __acc_cdecl_qsort compare(const void *p1, const void *p2) { static int __acc_cdecl_qsort compare(const void *p1, const void *p2) {
const udll *u1 = *(const udll *const *) p1; const udll *u1 = *(const udll *const *) p1;
const udll *u2 = *(const udll *const *) p2; const udll *u2 = *(const udll *const *) p2;
if (u1->isk32) if (u1->isk32 != u2->isk32)
return -1; return u1->isk32 ? -1 : 1;
if (u2->isk32) if ((*u1->lookupt != 0) != (*u2->lookupt != 0))
return 1; return (*u1->lookupt != 0) ? -1 : 1;
if (!*u1->lookupt)
return 1;
if (!*u2->lookupt)
return -1;
int rc = strcasecmp(u1->name, u2->name); int rc = strcasecmp(u1->name, u2->name);
if (rc) if (rc)
return rc; return rc;
if (u1->ordinal) if ((u1->ordinal != 0) != (u2->ordinal != 0))
return -1; return (u1->ordinal != 0) ? -1 : 1;
if (u2->ordinal) if ((u1->shname != nullptr) != (u2->shname != nullptr))
return 1; return (u1->shname != nullptr) ? -1 : 1;
if (!u1->shname)
return 1;
if (!u2->shname)
return -1;
rc = (int) (upx_safe_strlen(u1->shname) - upx_safe_strlen(u2->shname)); rc = (int) (upx_safe_strlen(u1->shname) - upx_safe_strlen(u2->shname));
if (rc) if (rc)
return rc; return rc;
@ -904,8 +910,8 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
importbyordinal = true; importbyordinal = true;
soimport += 2; // ordinal num: 2 bytes soimport += 2; // ordinal num: 2 bytes
dlls[ic].ordinal = *tarr & 0xffff; dlls[ic].ordinal = *tarr & 0xffff;
} else // it's an import by name } else {
{ // it's an import by name
IPTR_VAR(const byte, const name, ibuf + *tarr + 2); IPTR_VAR(const byte, const name, ibuf + *tarr + 2);
unsigned len = strlen(name); unsigned len = strlen(name);
soimport += len + 1; soimport += len + 1;
@ -919,9 +925,12 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
mb_oimport.clear(); mb_oimport.clear();
oimport = mb_oimport; oimport = mb_oimport;
qsort(idlls, dllnum, sizeof(udll *), udll::compare); qsort(idlls, dllnum, sizeof(*idlls), udll::compare);
info("Processing imports: %d DLLs", dllnum); info("Processing imports: %d DLLs", dllnum);
for (ic = 0; ic < dllnum; ic++) {
info(" DLL %3d %s %s", ic, idlls[ic]->name, idlls[ic]->shname);
}
ilinker = new ImportLinker(sizeof(LEXX)); ilinker = new ImportLinker(sizeof(LEXX));
// create the new import table // create the new import table
@ -981,7 +990,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
} }
ppi++; ppi++;
unsigned esize = ptr_diff_bytes(tarr, idlls[ic]->lookupt); unsigned esize = ptr_udiff_bytes(tarr, idlls[ic]->lookupt);
lookups.add(idlls[ic]->lookupt, esize); lookups.add(idlls[ic]->lookupt, esize);
if (ptr_diff_bytes(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1), if (ptr_diff_bytes(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1),
(char *) idlls[ic]->lookupt) != 0) { (char *) idlls[ic]->lookupt) != 0) {
@ -1299,7 +1308,7 @@ void PeFile::processTls1(Interval *iv, typename tls_traits<LEXX>::cb_value_t ima
unsigned const take1 = sizeof(tls); unsigned const take1 = sizeof(tls);
unsigned const skip1 = IDADDR(PEDIR_TLS); unsigned const skip1 = IDADDR(PEDIR_TLS);
memcpy(otls, ibuf.subref("bad tls %#x", skip1, take1), take1); memcpy(otls, ibuf.subref("bad tls %#x", skip1, take1), take1);
// WARNING: this can acces data in BSS // WARNING: this can access data in BSS
unsigned const take3 = sotls - sizeof(tls); unsigned const take3 = sotls - sizeof(tls);
memcpy(otls + sizeof(tls), ibuf.subref("bad tls %#x", tlsdatastart, take3), take3); memcpy(otls + sizeof(tls), ibuf.subref("bad tls %#x", tlsdatastart, take3), take3);
tlsindex = tlsp->tlsindex - imagebase; tlsindex = tlsp->tlsindex - imagebase;
@ -1887,6 +1896,7 @@ void PeFile::processResources(Resource *res) {
soresources = ptr_diff_bytes(ores, oresources); soresources = ptr_diff_bytes(ores, oresources);
delete[] keep_icons; delete[] keep_icons;
keep_icons = nullptr;
if (!res->clear()) { if (!res->clear()) {
// The area occupied by the resource directory is not continuous // The area occupied by the resource directory is not continuous
// so to still support uncompression, I can't zero this area. // so to still support uncompression, I can't zero this area.
@ -2637,6 +2647,16 @@ void PeFile::rebuildTls() {
// this is an easy one : just do nothing ;-) // this is an easy one : just do nothing ;-)
} }
namespace {
template <class T>
struct VPtr {
static_assert(sizeof(T) == 1);
SPAN_S(T) ptr;
size_t vaddr;
auto operator+(size_t n) const { return ptr + mem_size(sizeof(T), n - vaddr); }
};
} // namespace
void PeFile::rebuildResources(SPAN_S(byte) & extra_info, unsigned lastvaddr) { void PeFile::rebuildResources(SPAN_S(byte) & extra_info, unsigned lastvaddr) {
if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0) if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0)
return; return;
@ -2646,12 +2666,13 @@ void PeFile::rebuildResources(SPAN_S(byte) & extra_info, unsigned lastvaddr) {
const unsigned vaddr = IDADDR(PEDIR_RESOURCE); const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
if (lastvaddr > vaddr || (vaddr - lastvaddr) > ibuf.getSize()) if (vaddr < lastvaddr || (vaddr - lastvaddr) > ibuf.getSize())
throwCantUnpack("corrupted PE header"); throwCantUnpack("corrupted PE header");
// TODO: introduce WildPtr for "virtual pointer" pointing before a buffer // INFO: use VPtr for "virtual pointer" pointing before a buffer
const byte *r = ibuf.raw_bytes(0) - lastvaddr; //// const byte *const r = ibuf.raw_bytes(0) - lastvaddr;
Resource res(r + vaddr, ibuf, ibuf + ibuf.getSize()); VPtr<const byte> const r{ibuf, lastvaddr};
Resource res(raw_bytes(r + vaddr, 0), ibuf, ibuf + ibuf.getSize());
while (res.next()) while (res.next())
if (res.offs() > vaddr) { if (res.offs() > vaddr) {
ICHECK(r + (res.offs() - 4), 4); ICHECK(r + (res.offs() - 4), 4);
@ -2702,8 +2723,9 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
} }
sdllnames = ALIGN_UP(sdllnames, 2u); sdllnames = ALIGN_UP(sdllnames, 2u);
// TODO: introduce WildPtr for "virtual pointer" pointing before a buffer // INFO: use VPtr for "virtual pointer" pointing before a buffer
byte *const Obuf = obuf.raw_bytes(0) - rvamin; //// byte *const Obuf = obuf.raw_bytes(0) - rvamin;
VPtr<byte> const Obuf{obuf, rvamin};
#if 0 #if 0
import_desc * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT)); import_desc * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT));
import_desc *im = im0; import_desc *im = im0;
@ -2711,9 +2733,10 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
byte *importednames = dllnames + sdllnames; byte *importednames = dllnames + sdllnames;
byte * const importednames_start = importednames; byte * const importednames_start = importednames;
#else #else
SPAN_S_VAR(import_desc, const im0, (import_desc *) (Obuf + ODADDR(PEDIR_IMPORT)), obuf); SPAN_S_VAR(import_desc, const im0, (import_desc *) raw_bytes(Obuf + ODADDR(PEDIR_IMPORT), 0),
obuf);
SPAN_S_VAR(import_desc, im, im0); SPAN_S_VAR(import_desc, im, im0);
SPAN_0_VAR(byte, dllnames, inamespos ? Obuf + inamespos : nullptr, obuf); SPAN_0_VAR(byte, dllnames, inamespos ? raw_bytes(Obuf + inamespos, 0) : nullptr, obuf);
SPAN_0_VAR(byte, importednames, inamespos ? dllnames + sdllnames : nullptr); SPAN_0_VAR(byte, importednames, inamespos ? dllnames + sdllnames : nullptr);
SPAN_0_VAR(byte, const importednames_start, importednames); SPAN_0_VAR(byte, const importednames_start, importednames);
#endif #endif
@ -2728,7 +2751,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
if (inamespos) { if (inamespos) {
// now I rebuild the dll names // now I rebuild the dll names
omemcpy(dllnames, dname, dlen + 1); omemcpy(dllnames, dname, dlen + 1);
im->dllname = ptr_udiff_bytes(dllnames, Obuf); im->dllname = ptr_udiff_bytes(dllnames, obuf) + rvamin;
//;;;printf("\ndll: %s:",dllnames); //;;;printf("\ndll: %s:",dllnames);
dllnames += dlen + 1; dllnames += dlen + 1;
} else { } else {
@ -2738,7 +2761,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
if (set_oft) if (set_oft)
im->oft = iatoffs; im->oft = iatoffs;
OPTR_VAR(LEXX, newiat, (LEXX *) (Obuf + iatoffs)); OPTR_VAR(LEXX, newiat, (LEXX *) raw_bytes(Obuf + iatoffs, 0));
// restore the imported names+ordinals // restore the imported names+ordinals
for (p += 8; *p; ++newiat) for (p += 8; *p; ++newiat)
@ -2749,7 +2772,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
importednames -= 1; importednames -= 1;
omemcpy(importednames + 2, p, ilen); omemcpy(importednames + 2, p, ilen);
//;;;printf(" %s",importednames+2); //;;;printf(" %s",importednames+2);
*newiat = ptr_udiff_bytes(importednames, Obuf); *newiat = ptr_udiff_bytes(importednames, obuf) + rvamin;
importednames += 2 + ilen; importednames += 2 + ilen;
} else { } else {
// Beware overlap! // Beware overlap!
@ -2986,7 +3009,7 @@ void PeFile32::readPeHeader() {
void PeFile32::pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase, void PeFile32::pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase,
bool last_section_rsrc_only) { bool last_section_rsrc_only) {
super::pack0<LE32>(fo, ih, oh, subsystem_mask, default_imagebase, last_section_rsrc_only); super::pack0<LE32>(fo, ih, oh, subsystem_mask, default_imagebase, last_section_rsrc_only);
infoWarning("End of PeFile32::pack0"); // infoWarning("End of PeFile32::pack0");
} }
void PeFile32::unpack(OutputFile *fo) { void PeFile32::unpack(OutputFile *fo) {

View File

@ -147,7 +147,7 @@ protected:
unsigned sotls; unsigned sotls;
unsigned tlsindex; unsigned tlsindex;
unsigned tlscb_ptr; unsigned tlscb_ptr;
unsigned tls_handler_offset; unsigned tls_handler_offset = 0;
bool use_tls_callbacks = false; bool use_tls_callbacks = false;
void processLoadConf(Reloc *, const Interval *, unsigned); void processLoadConf(Reloc *, const Interval *, unsigned);
@ -288,7 +288,7 @@ protected:
enum { enum {
IMAGE_SUBSYSTEM_UNKNOWN = 0, IMAGE_SUBSYSTEM_UNKNOWN = 0,
IMAGE_SUBSYSTEM_NATIVE = 1, IMAGE_SUBSYSTEM_NATIVE = 1,
IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, // Grapical IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, // Graphical
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, // Character-mode IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, // Character-mode
IMAGE_SUBSYSTEM_WINDOWS_OS2_CUI = 5, IMAGE_SUBSYSTEM_WINDOWS_OS2_CUI = 5,
IMAGE_SUBSYSTEM_WINDOWS_POSIX_CUI = 7, IMAGE_SUBSYSTEM_WINDOWS_POSIX_CUI = 7,

View File

@ -182,7 +182,7 @@ UiPacker::UiPacker(const Packer *p_) : ui_pass(0), ui_total_passes(0), p(p_), s(
s->mode = M_CB_SCREEN; s->mode = M_CB_SCREEN;
} }
UiPacker::~UiPacker() { UiPacker::~UiPacker() noexcept {
cb.reset(); cb.reset();
delete s; delete s;
s = nullptr; s = nullptr;

View File

@ -39,7 +39,7 @@ public:
UiPacker(const Packer *p_); UiPacker(const Packer *p_);
public: public:
virtual ~UiPacker(); virtual ~UiPacker() noexcept;
static void uiConfirmUpdate(); static void uiConfirmUpdate();
static void uiPackTotal(); static void uiPackTotal();

View File

@ -74,7 +74,7 @@ MemBuffer::MemBuffer(upx_uint64_t bytes) {
debug_set(debug.last_return_address_alloc, upx_return_address()); debug_set(debug.last_return_address_alloc, upx_return_address());
} }
MemBuffer::~MemBuffer() { this->dealloc(); } MemBuffer::~MemBuffer() noexcept { this->dealloc(); }
// similar to BoundedPtr, except checks only at creation // similar to BoundedPtr, except checks only at creation
// skip == offset, take == size_in_bytes // skip == offset, take == size_in_bytes
@ -215,19 +215,19 @@ void MemBuffer::alloc(upx_uint64_t bytes) {
set_ne32(p + size_in_bytes + 4, stats.global_alloc_counter); set_ne32(p + size_in_bytes + 4, stats.global_alloc_counter);
} }
ptr = (pointer) (void *) p; ptr = (pointer) (void *) p;
#if !defined(__SANITIZE_ADDRESS__) && 0 #if DEBUG
fill(0, size_in_bytes, (rand() & 0xff) | 1); // debug memset(ptr, 0xff, size_in_bytes);
(void) VALGRIND_MAKE_MEM_UNDEFINED(ptr, size_in_bytes); (void) VALGRIND_MAKE_MEM_UNDEFINED(ptr, size_in_bytes);
#endif #endif
stats.global_alloc_counter += 1; stats.global_alloc_counter += 1;
stats.global_total_bytes += size_in_bytes; stats.global_total_bytes += size_in_bytes;
stats.global_total_active_bytes += size_in_bytes; stats.global_total_active_bytes += size_in_bytes;
#if DEBUG #if DEBUG || 1
checkState(); checkState();
#endif #endif
} }
void MemBuffer::dealloc() { void MemBuffer::dealloc() noexcept {
if (ptr != nullptr) { if (ptr != nullptr) {
debug_set(debug.last_return_address_dealloc, upx_return_address()); debug_set(debug.last_return_address_dealloc, upx_return_address());
checkState(); checkState();

View File

@ -46,11 +46,12 @@ protected:
size_type size_in_bytes; size_type size_in_bytes;
public: public:
MemBufferBase() : ptr(nullptr), size_in_bytes(0) {} MemBufferBase() noexcept : ptr(nullptr), size_in_bytes(0) {}
inline ~MemBufferBase() noexcept {}
// NOTE: implicit conversion to underlying pointer // NOTE: implicit conversion to underlying pointer
// HINT: for fully bound-checked pointer use XSPAN_S from xspan.h // HINT: for fully bound-checked pointer use XSPAN_S from xspan.h
operator pointer() const { return ptr; } operator pointer() const noexcept { return ptr; }
// membuffer + n -> pointer // membuffer + n -> pointer
template <class U> template <class U>
@ -66,8 +67,8 @@ private:
DELETED_FUNCTION; DELETED_FUNCTION;
public: // raw access public: // raw access
pointer raw_ptr() const { return ptr; } pointer raw_ptr() const noexcept { return ptr; }
size_type raw_size_in_bytes() const { return size_in_bytes; } size_type raw_size_in_bytes() const noexcept { return size_in_bytes; }
pointer raw_bytes(size_t bytes) const { pointer raw_bytes(size_t bytes) const {
if (bytes > 0) { if (bytes > 0) {
@ -84,7 +85,7 @@ class MemBuffer final : public MemBufferBase<byte> {
public: public:
MemBuffer() : MemBufferBase<byte>() {} MemBuffer() : MemBufferBase<byte>() {}
explicit MemBuffer(upx_uint64_t bytes); explicit MemBuffer(upx_uint64_t bytes);
~MemBuffer(); ~MemBuffer() noexcept;
static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra = 0); static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra = 0);
static unsigned getSizeForDecompression(unsigned uncompressed_size, unsigned extra = 0); static unsigned getSizeForDecompression(unsigned uncompressed_size, unsigned extra = 0);
@ -93,7 +94,7 @@ public:
void allocForCompression(unsigned uncompressed_size, unsigned extra = 0); void allocForCompression(unsigned uncompressed_size, unsigned extra = 0);
void allocForDecompression(unsigned uncompressed_size, unsigned extra = 0); void allocForDecompression(unsigned uncompressed_size, unsigned extra = 0);
void dealloc(); void dealloc() noexcept;
void checkState() const; void checkState() const;
unsigned getSize() const { return size_in_bytes; } unsigned getSize() const { return size_in_bytes; }

View File

@ -35,9 +35,11 @@
// default: for any regular pointer, raw_bytes() is just the pointer itself // default: for any regular pointer, raw_bytes() is just the pointer itself
template <class T> template <class T>
inline inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_is_bounded_array<T>::value &&
typename std::enable_if<std::is_pointer<T>::value && !std_is_bounded_array<T>::value, T>::type (upx_is_integral<typename std::remove_pointer<T>::type>::value ||
raw_bytes(T ptr, size_t size_in_bytes) { std::is_void<typename std::remove_pointer<T>::type>::value),
T>::type
raw_bytes(T ptr, size_t size_in_bytes) {
if (size_in_bytes > 0) { if (size_in_bytes > 0) {
if very_unlikely (ptr == nullptr) if very_unlikely (ptr == nullptr)
throwCantPack("raw_bytes unexpected NULL ptr"); throwCantPack("raw_bytes unexpected NULL ptr");
@ -50,9 +52,10 @@ inline
// default: for any regular pointer, raw_index_bytes() is just "pointer + index" // default: for any regular pointer, raw_index_bytes() is just "pointer + index"
// NOTE: index == number of elements, *NOT* size in bytes! // NOTE: index == number of elements, *NOT* size in bytes!
template <class T> template <class T>
inline inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_is_bounded_array<T>::value &&
typename std::enable_if<std::is_pointer<T>::value && !std_is_bounded_array<T>::value, T>::type upx_is_integral<typename std::remove_pointer<T>::type>::value,
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) { T>::type
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
typedef typename std::remove_pointer<T>::type element_type; typedef typename std::remove_pointer<T>::type element_type;
if very_unlikely (ptr == nullptr) if very_unlikely (ptr == nullptr)
throwCantPack("raw_index_bytes unexpected NULL ptr"); throwCantPack("raw_index_bytes unexpected NULL ptr");

View File

@ -60,30 +60,30 @@ upx_rsize_t upx_safe_strlen(const char *);
#define vsnprintf upx_safe_vsnprintf #define vsnprintf upx_safe_vsnprintf
/************************************************************************* /*************************************************************************
// some unsigned char string support functions to avoid casts // some uchar string support functions to avoid casts
**************************************************************************/ **************************************************************************/
inline unsigned char *strcpy(unsigned char *s1, const unsigned char *s2) { forceinline uchar *strcpy(uchar *s1, const uchar *s2) {
return (unsigned char *) strcpy((char *) s1, (const char *) s2); return (uchar *) strcpy((char *) s1, (const char *) s2);
} }
inline int strcmp(const unsigned char *s1, const char *s2) { return strcmp((const char *) s1, s2); } forceinline int strcmp(const uchar *s1, const char *s2) { return strcmp((const char *) s1, s2); }
inline int strcmp(const char *s1, const unsigned char *s2) { return strcmp(s1, (const char *) s2); } forceinline int strcmp(const char *s1, const uchar *s2) { return strcmp(s1, (const char *) s2); }
inline int strcmp(const unsigned char *s1, const unsigned char *s2) { forceinline int strcmp(const uchar *s1, const uchar *s2) {
return strcmp((const char *) s1, (const char *) s2); return strcmp((const char *) s1, (const char *) s2);
} }
inline int strcasecmp(const unsigned char *s1, const char *s2) { forceinline int strcasecmp(const uchar *s1, const char *s2) {
return strcasecmp((const char *) s1, s2); return strcasecmp((const char *) s1, s2);
} }
inline int strcasecmp(const char *s1, const unsigned char *s2) { forceinline int strcasecmp(const char *s1, const uchar *s2) {
return strcasecmp(s1, (const char *) s2); return strcasecmp(s1, (const char *) s2);
} }
inline int strcasecmp(const unsigned char *s1, const unsigned char *s2) { forceinline int strcasecmp(const uchar *s1, const uchar *s2) {
return strcasecmp((const char *) s1, (const char *) s2); return strcasecmp((const char *) s1, (const char *) s2);
} }
inline upx_rsize_t upx_safe_strlen(const unsigned char *s) { forceinline upx_rsize_t upx_safe_strlen(const uchar *s) {
return upx_safe_strlen((const char *) s); return upx_safe_strlen((const char *) s);
} }

View File

@ -101,6 +101,10 @@ TEST_CASE("mem_size") {
CHECK_THROWS(mem_size(1, 0x30000000, 0x30000000, 0x30000000)); CHECK_THROWS(mem_size(1, 0x30000000, 0x30000000, 0x30000000));
} }
/*************************************************************************
// ptr util
**************************************************************************/
int ptr_diff_bytes(const void *a, const void *b) { int ptr_diff_bytes(const void *a, const void *b) {
if very_unlikely (a == nullptr) { if very_unlikely (a == nullptr) {
throwCantPack("ptr_diff_bytes null 1; take care"); throwCantPack("ptr_diff_bytes null 1; take care");
@ -108,13 +112,13 @@ int ptr_diff_bytes(const void *a, const void *b) {
if very_unlikely (b == nullptr) { if very_unlikely (b == nullptr) {
throwCantPack("ptr_diff_bytes null 2; take care"); throwCantPack("ptr_diff_bytes null 2; take care");
} }
ptrdiff_t d = (const char *) a - (const char *) b; ptrdiff_t d = (const charptr) a - (const charptr) b;
if (a >= b) { if (a >= b) {
if very_unlikely (!mem_size_valid_bytes(d)) if very_unlikely (!mem_size_valid_bytes(d))
throwCantPack("ptr_diff_bytes 1; take care"); throwCantPack("ptr_diff_bytes-1; take care");
} else { } else {
if very_unlikely (!mem_size_valid_bytes(-d)) if very_unlikely (!mem_size_valid_bytes(-d))
throwCantPack("ptr_diff_bytes 2; take care"); throwCantPack("ptr_diff_bytes-2; take care");
} }
return ACC_ICONV(int, d); return ACC_ICONV(int, d);
} }
@ -127,7 +131,7 @@ unsigned ptr_udiff_bytes(const void *a, const void *b) {
} }
TEST_CASE("ptr_diff") { TEST_CASE("ptr_diff") {
char buf[4] = {0, 1, 2, 3}; byte buf[4] = {0, 1, 2, 3};
CHECK_THROWS(ptr_diff_bytes(nullptr, buf)); CHECK_THROWS(ptr_diff_bytes(nullptr, buf));
CHECK_THROWS(ptr_diff_bytes(buf, nullptr)); CHECK_THROWS(ptr_diff_bytes(buf, nullptr));
CHECK(ptr_diff(buf, buf) == 0); CHECK(ptr_diff(buf, buf) == 0);
@ -138,6 +142,108 @@ TEST_CASE("ptr_diff") {
CHECK_THROWS(ptr_udiff(buf, buf + 1)); CHECK_THROWS(ptr_udiff(buf, buf + 1));
} }
// check that 2 buffers do not overlap; will throw on error
void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b, size_t b_size) {
if very_unlikely (a == 0 || b == 0)
throwCantPack("ptr_check_no_overlap-nullptr");
upx_uintptr_t a_end = a + mem_size(1, a_size);
upx_uintptr_t b_end = b + mem_size(1, b_size);
if very_unlikely (a_end < a || b_end < b) // wrap-around
throwCantPack("ptr_check_no_overlap-overflow");
// same as (!(a >= b_end || b >= a_end))
if (a < b_end && b < a_end)
throwCantPack("ptr_check_no_overlap-ab");
}
// check that 3 buffers do not overlap; will throw on error
void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b, size_t b_size,
upx_uintptr_t c, size_t c_size) {
if very_unlikely (a == 0 || b == 0 || c == 0)
throwCantPack("ptr_check_no_overlap-nullptr");
upx_uintptr_t a_end = a + mem_size(1, a_size);
upx_uintptr_t b_end = b + mem_size(1, b_size);
upx_uintptr_t c_end = c + mem_size(1, c_size);
if very_unlikely (a_end < a || b_end < b || c_end < c) // wrap-around
throwCantPack("ptr_check_no_overlap-overflow");
if (a < b_end && b < a_end)
throwCantPack("ptr_check_no_overlap-ab");
if (a < c_end && c < a_end)
throwCantPack("ptr_check_no_overlap-ac");
if (b < c_end && c < b_end)
throwCantPack("ptr_check_no_overlap-bc");
}
TEST_CASE("ptr_check_no_overlap 2") {
byte p[4] = {};
auto check_nothrow = [&p](int a, int as, int b, int bs) {
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + b, bs)); // ab
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + a, as)); // ba
};
auto check_throws_ = [&p](int a, int as, int b, int bs) {
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + b, bs)); // ab
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + a, as)); // ba
};
check_throws_(0, 1, 0, 1);
check_nothrow(0, 1, 1, 1);
check_throws_(0, 2, 1, 1);
check_nothrow(0, 2, 2, 1);
// empty buffers at edge
check_nothrow(0, 0, 0, 0);
check_nothrow(0, 0, 0, 1);
check_nothrow(0, 0, 1, 0);
// empty buffer
check_nothrow(0, 4, 0, 0);
check_throws_(0, 4, 1, 0);
check_throws_(0, 4, 2, 0);
check_throws_(0, 4, 3, 0);
check_nothrow(0, 4, 4, 0);
}
TEST_CASE("ptr_check_no_overlap 3") {
byte p[4] = {};
auto check_nothrow = [&p](int a, int as, int b, int bs, int c, int cs) {
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + b, bs, p + c, cs)); // abc
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + c, cs, p + b, bs)); // acb
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + a, as, p + c, cs)); // bac
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + c, cs, p + a, as)); // bca
CHECK_NOTHROW(ptr_check_no_overlap(p + c, cs, p + a, as, p + b, bs)); // cab
CHECK_NOTHROW(ptr_check_no_overlap(p + c, cs, p + b, bs, p + a, as)); // cba
};
auto check_throws_ = [&p](int a, int as, int b, int bs, int c, int cs) {
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + b, bs, p + c, cs)); // abc
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + c, cs, p + b, bs)); // acb
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + a, as, p + c, cs)); // bac
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + c, cs, p + a, as)); // bca
CHECK_THROWS(ptr_check_no_overlap(p + c, cs, p + a, as, p + b, bs)); // cab
CHECK_THROWS(ptr_check_no_overlap(p + c, cs, p + b, bs, p + a, as)); // cba
};
check_throws_(0, 1, 0, 1, 1, 1);
check_nothrow(0, 1, 1, 1, 2, 1);
check_throws_(0, 2, 1, 1, 2, 1);
check_nothrow(0, 2, 2, 1, 3, 1);
// empty buffers at edge
check_nothrow(0, 0, 0, 0, 0, 0);
check_nothrow(0, 0, 0, 0, 0, 1);
check_nothrow(0, 0, 0, 1, 1, 1);
check_nothrow(0, 0, 1, 0, 1, 1);
// empty buffer
check_nothrow(0, 4, 0, 0, 0, 0);
check_throws_(0, 4, 1, 0, 0, 0);
check_throws_(0, 4, 2, 0, 0, 0);
check_throws_(0, 4, 3, 0, 0, 0);
check_nothrow(0, 4, 4, 0, 0, 0);
// empty buffer
check_throws_(0, 4, 0, 0, 1, 0);
check_throws_(0, 4, 1, 0, 1, 0);
check_throws_(0, 4, 2, 0, 1, 0);
check_throws_(0, 4, 3, 0, 1, 0);
check_throws_(0, 4, 4, 0, 1, 0);
}
/************************************************************************* /*************************************************************************
// bele.h // bele.h
**************************************************************************/ **************************************************************************/
@ -152,6 +258,60 @@ const BEPolicy be_policy;
const LEPolicy le_policy; const LEPolicy le_policy;
} // namespace N_BELE_RTP } // namespace N_BELE_RTP
/*************************************************************************
// stdlib
**************************************************************************/
void *upx_calloc(size_t n, size_t element_size) {
size_t bytes = mem_size(element_size, n); // assert size
void *p = malloc(bytes);
if (p != nullptr)
memset(p, 0, bytes);
return p;
}
// extremely simple stable sort: Gnomesort
// WARNING: O(n**2) !!!!!
void upx_stable_sort(void *base, size_t n, size_t element_size,
int(__acc_cdecl_qsort *compare)(const void *, const void *)) {
(void) mem_size(element_size, n); // assert size
for (size_t i = 1; i < n;) {
char *a = (char *) base + element_size * i; // a = &array[i]
if (i == 0 || (compare(a - element_size, a) <= 0)) {
i += 1;
} else {
i -= 1;
// swap elements a[-1] <=> a[0]
// upx_memswap(a - element_size, a, element_size);
size_t j = element_size;
do {
char tmp = *(a - element_size);
*(a - element_size) = *a;
*a++ = tmp;
} while (--j != 0);
}
}
}
TEST_CASE("upx_stable_sort") {
// TODO C++20: use std::next_permutation() to test all permutations
{
unsigned a[] = {0, 1};
upx_stable_sort(a, 2, sizeof(*a), ne32_compare);
CHECK((a[0] == 0 && a[1] == 1));
}
{
unsigned a[] = {1, 0};
upx_stable_sort(a, 2, sizeof(*a), ne32_compare);
CHECK((a[0] == 0 && a[1] == 1));
}
{
unsigned a[] = {2, 1, 0};
upx_stable_sort(a, 3, sizeof(*a), ne32_compare);
CHECK((a[0] == 0 && a[1] == 1 && a[2] == 2));
}
}
/************************************************************************* /*************************************************************************
// qsort() util // qsort() util
**************************************************************************/ **************************************************************************/
@ -258,7 +418,7 @@ int __acc_cdecl_qsort le64_compare_signed(const void *e1, const void *e2) {
int find(const void *buf, int blen, const void *what, int wlen) { int find(const void *buf, int blen, const void *what, int wlen) {
// nullptr is explicitly allowed here // nullptr is explicitly allowed here
if (buf == nullptr || blen <= 0 || what == nullptr || wlen <= 0) if (buf == nullptr || blen < wlen || what == nullptr || wlen <= 0)
return -1; return -1;
const byte *b = (const byte *) buf; const byte *b = (const byte *) buf;
@ -367,7 +527,7 @@ static const char dir_sep[] = "/\\";
#define fn_is_drive(s) (s[0] && s[1] == ':') #define fn_is_drive(s) (s[0] && s[1] == ':')
#define fn_is_sep(c) (strchr(dir_sep, c) != nullptr) #define fn_is_sep(c) (strchr(dir_sep, c) != nullptr)
#define fn_skip_drive(s) (fn_is_drive(s) ? (s) + 2 : (s)) #define fn_skip_drive(s) (fn_is_drive(s) ? (s) + 2 : (s))
#define fn_tolower(c) (tolower(((unsigned char) (c)))) #define fn_tolower(c) (tolower(((uchar) (c))))
#else #else

View File

@ -40,9 +40,6 @@ inline bool mem_size_valid_bytes(upx_uint64_t bytes) noexcept { return bytes <=
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0, bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0,
upx_uint64_t extra2 = 0) noexcept; upx_uint64_t extra2 = 0) noexcept;
// "new" with asserted size; will throw on invalid size
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
// will throw on invalid size // will throw on invalid size
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1, upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
upx_uint64_t extra2 = 0); upx_uint64_t extra2 = 0);
@ -77,6 +74,27 @@ inline void mem_clear(void *p, size_t n) {
memset(p, 0, n); memset(p, 0, n);
} }
// "new" with asserted size; will throw on invalid size
#if DEBUG
template <class T>
T *NewArray(upx_uint64_t n) {
size_t bytes = mem_size(sizeof(T), n); // assert size
T *array = new T[size_t(n)];
if (array) {
memset(array, 0xff, bytes);
(void) VALGRIND_MAKE_MEM_UNDEFINED(array, bytes);
}
return array;
}
#define New(type, n) (NewArray<type>(n))
#else
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
#endif
/*************************************************************************
// ptr util
**************************************************************************/
// ptrdiff_t with nullptr checks and asserted size; will throw on failure // ptrdiff_t with nullptr checks and asserted size; will throw on failure
// NOTE: returns size_in_bytes, not number of elements! // NOTE: returns size_in_bytes, not number of elements!
int ptr_diff_bytes(const void *a, const void *b); int ptr_diff_bytes(const void *a, const void *b);
@ -94,6 +112,30 @@ ptr_udiff(const T *a, const U *b) {
return ptr_udiff_bytes(a, b); return ptr_udiff_bytes(a, b);
} }
// check that buffers do not overlap; will throw on error
noinline void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b,
size_t b_size);
noinline void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b,
size_t b_size, upx_uintptr_t c, size_t c_size);
forceinline void ptr_check_no_overlap(const void *a, size_t a_size, const void *b, size_t b_size) {
uintptr_check_no_overlap((upx_uintptr_t) a, a_size, (upx_uintptr_t) b, b_size);
}
forceinline void ptr_check_no_overlap(const void *a, size_t a_size, const void *b, size_t b_size,
const void *c, size_t c_size) {
uintptr_check_no_overlap((upx_uintptr_t) a, a_size, (upx_uintptr_t) b, b_size,
(upx_uintptr_t) c, c_size);
}
/*************************************************************************
// stdlib
**************************************************************************/
void *upx_calloc(size_t n, size_t element_size);
void upx_stable_sort(void *base, size_t n, size_t element_size,
int(__acc_cdecl_qsort *compare)(const void *, const void *));
/************************************************************************* /*************************************************************************
// misc. support functions // misc. support functions
**************************************************************************/ **************************************************************************/

View File

@ -44,28 +44,28 @@ struct XSpanStats {
static XSpanStats xspan_stats; static XSpanStats xspan_stats;
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience // HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
noinline void xspan_fail_nullptr() { void xspan_fail_nullptr() {
xspan_stats.fail_nullptr += 1; xspan_stats.fail_nullptr += 1;
throwCantPack("xspan unexpected NULL pointer; take care!"); throwCantPack("xspan unexpected NULL pointer; take care!");
} }
noinline void xspan_fail_nullbase() { void xspan_fail_nullbase() {
xspan_stats.fail_nullbase += 1; xspan_stats.fail_nullbase += 1;
throwCantPack("xspan unexpected NULL base; take care!"); throwCantPack("xspan unexpected NULL base; take care!");
} }
noinline void xspan_fail_not_same_base() { void xspan_fail_not_same_base() {
xspan_stats.fail_not_same_base += 1; xspan_stats.fail_not_same_base += 1;
throwCantPack("xspan unexpected base pointer; take care!"); throwCantPack("xspan unexpected base pointer; take care!");
} }
noinline void xspan_fail_range_nullptr() { void xspan_fail_range_nullptr() {
xspan_stats.fail_range_nullptr += 1; xspan_stats.fail_range_nullptr += 1;
throwCantPack("xspan_check_range: unexpected NULL pointer; take care!"); throwCantPack("xspan_check_range: unexpected NULL pointer; take care!");
} }
noinline void xspan_fail_range_nullbase() { void xspan_fail_range_nullbase() {
xspan_stats.fail_range_nullbase += 1; xspan_stats.fail_range_nullbase += 1;
throwCantPack("xspan_check_range: unexpected NULL base; take care!"); throwCantPack("xspan_check_range: unexpected NULL base; take care!");
} }
noinline void xspan_fail_range_range() { void xspan_fail_range_range() {
xspan_stats.fail_range_range += 1; xspan_stats.fail_range_range += 1;
throwCantPack("xspan_check_range: pointer out of range; take care!"); throwCantPack("xspan_check_range: pointer out of range; take care!");
} }
@ -75,7 +75,7 @@ void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes)
xspan_fail_range_nullptr(); xspan_fail_range_nullptr();
if very_unlikely (base == nullptr) if very_unlikely (base == nullptr)
xspan_fail_range_nullbase(); xspan_fail_range_nullbase();
ptrdiff_t off = (const char *) p - (const char *) base; ptrdiff_t off = (const charptr) p - (const charptr) base;
if very_unlikely (off < 0 || off > size_in_bytes) if very_unlikely (off < 0 || off > size_in_bytes)
xspan_fail_range_range(); xspan_fail_range_range();
xspan_stats.check_range_counter += 1; xspan_stats.check_range_counter += 1;

View File

@ -146,8 +146,11 @@ inline R *xspan_make_helper__(R * /*dummy*/, MemBuffer &first) {
#endif // WITH_XSPAN #endif // WITH_XSPAN
#if 1 /*************************************************************************
// nicer names // nicer names
**************************************************************************/
#if 1
#define SPAN_0 XSPAN_0 #define SPAN_0 XSPAN_0
#define SPAN_P XSPAN_P #define SPAN_P XSPAN_P
#define SPAN_S XSPAN_S #define SPAN_S XSPAN_S

View File

@ -52,11 +52,11 @@ void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes)
// help constructor to distinguish between number of elements and bytes // help constructor to distinguish between number of elements and bytes
struct XSpanCount { struct XSpanCount {
explicit XSpanCount(size_t n) : count(n) {} explicit XSpanCount(size_t n) noexcept : count(n) {}
size_t count; // public size_t count; // public
}; };
struct XSpanSizeInBytes { struct XSpanSizeInBytes {
explicit XSpanSizeInBytes(size_t bytes) : size_in_bytes(bytes) {} explicit XSpanSizeInBytes(size_t bytes) noexcept : size_in_bytes(bytes) {}
size_t size_in_bytes; // public size_t size_in_bytes; // public
}; };

View File

@ -28,165 +28,176 @@
// //
**************************************************************************/ **************************************************************************/
public: #if CLANG_FORMAT_DUMMY_CLASS
typedef T element_type; class CSelf {
typedef typename std::add_lvalue_reference<T>::type reference; #endif
typedef typename std::add_pointer<T>::type pointer;
typedef size_t size_type;
// befriend all public:
template <class> typedef T element_type;
friend struct PtrOrSpan; typedef typename std::add_lvalue_reference<T>::type reference;
template <class> typedef typename std::add_pointer<T>::type pointer;
friend struct PtrOrSpanOrNull; typedef size_t size_type;
template <class>
friend struct Span; // befriend all
template <class>
friend struct PtrOrSpan;
template <class>
friend struct PtrOrSpanOrNull;
template <class>
friend struct Span;
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION #if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION
operator pointer() const { return ptr; } public:
operator pointer() const noexcept { return ptr; }
#endif #endif
private: private:
pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr
pointer base; pointer base;
size_type size_in_bytes; size_type size_in_bytes;
// debug - internal sanity check; also serves as pseudo-documentation // debug - internal sanity check; also serves as pseudo-documentation
#if DEBUG #if DEBUG
noinline void assertInvariants() const { noinline void assertInvariants() const {
if __acc_cte (configRequirePtr) if __acc_cte (configRequirePtr)
assert(ptr != nullptr); assert(ptr != nullptr);
if __acc_cte (configRequireBase) if __acc_cte (configRequireBase)
assert(base != nullptr); assert(base != nullptr);
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr)) if __acc_cte ((configRequirePtr || ptr != nullptr) &&
xspan_check_range(ptr, base, size_in_bytes); (configRequireBase || base != nullptr))
} xspan_check_range(ptr, base, size_in_bytes);
}
#else #else
forceinline void assertInvariants() const {} inline void assertInvariants() const noexcept {}
#endif #endif
static forceinline pointer makeNotNull(pointer p) { static inline pointer makeNotNull(pointer p) {
if very_unlikely (p == nullptr) if very_unlikely (p == nullptr)
xspan_fail_nullptr(); xspan_fail_nullptr();
return p; return p;
} }
// enforce config invariants at constructor time - static functions // enforce config invariants at constructor time - static functions
static forceinline pointer makePtr(pointer p) { static inline pointer makePtr(pointer p) {
if __acc_cte (configRequirePtr && p == nullptr) if __acc_cte (configRequirePtr && p == nullptr)
xspan_fail_nullptr(); xspan_fail_nullptr();
return p; return p;
} }
static forceinline pointer makeBase(pointer b) { static inline pointer makeBase(pointer b) {
if __acc_cte (configRequireBase && b == nullptr) if __acc_cte (configRequireBase && b == nullptr)
xspan_fail_nullbase(); xspan_fail_nullbase();
return b; return b;
} }
// inverse logic for ensuring valid pointers from existing objets // inverse logic for ensuring valid pointers from existing objects
forceinline pointer ensurePtr() const { inline pointer ensurePtr() const {
if __acc_cte (!configRequirePtr && ptr == nullptr) if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr(); xspan_fail_nullptr();
return ptr; return ptr;
} }
forceinline pointer ensureBase() const { inline pointer ensureBase() const {
if __acc_cte (!configRequireBase && base == nullptr) if __acc_cte (!configRequireBase && base == nullptr)
xspan_fail_nullbase(); xspan_fail_nullbase();
return base; return base;
} }
public: public:
inline ~CSelf() {
#if DEBUG #if DEBUG
invalidate(); inline ~CSelf() { invalidate(); }
#else
inline ~CSelf() noexcept {}
#endif #endif
} noinline void invalidate() {
noinline void invalidate() { assertInvariants();
assertInvariants(); ptr = (pointer) (upx_uintptr_t) 16; // point to non-null invalid address
ptr = (pointer) (acc_uintptr_t) 16; // point to non-null invalid address // ptr = (pointer) (void *) &ptr; // point to self
// ptr = (pointer) (void *) &ptr; // point to self base = ptr;
base = ptr; size_in_bytes = 0;
size_in_bytes = 0; assertInvariants();
assertInvariants(); }
} // constructors from pointers
// constructors from pointers CSelf(pointer first, XSpanCount count)
CSelf(pointer first, XSpanCount count) : ptr(makePtr(first)), base(makeBase(first)),
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count.count)) { size_in_bytes(xspan_mem_size<T>(count.count)) {
assertInvariants(); assertInvariants();
} }
CSelf(pointer first, XSpanSizeInBytes bytes) CSelf(pointer first, XSpanSizeInBytes bytes)
: ptr(makePtr(first)), base(makeBase(first)), : ptr(makePtr(first)), base(makeBase(first)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) { size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
assertInvariants(); assertInvariants();
} }
// enable this constructor only if the underlying type is char or void // enable this constructor only if the underlying type is char or void
template <class U> template <class U>
CSelf(U *first, size_type count, XSPAN_REQUIRES_SIZE_1_A) CSelf(U *first, size_type count, XSPAN_REQUIRES_SIZE_1_A)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count)) { : ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count)) {
assertInvariants(); assertInvariants();
} }
CSelf(pointer first, XSpanCount count, pointer base_) CSelf(pointer first, XSpanCount count, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count.count)) { : ptr(makePtr(first)), base(makeBase(base_)),
// check invariants size_in_bytes(xspan_mem_size<T>(count.count)) {
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr)) // check invariants
xspan_check_range(ptr, base, size_in_bytes); if __acc_cte ((configRequirePtr || ptr != nullptr) &&
// double sanity check (configRequireBase || base != nullptr))
assertInvariants(); xspan_check_range(ptr, base, size_in_bytes);
} // double sanity check
CSelf(pointer first, XSpanSizeInBytes bytes, pointer base_) assertInvariants();
: ptr(makePtr(first)), base(makeBase(base_)), }
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) { CSelf(pointer first, XSpanSizeInBytes bytes, pointer base_)
// check invariants : ptr(makePtr(first)), base(makeBase(base_)),
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr)) size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
xspan_check_range(ptr, base, size_in_bytes); // check invariants
// double sanity check if __acc_cte ((configRequirePtr || ptr != nullptr) &&
assertInvariants(); (configRequireBase || base != nullptr))
} xspan_check_range(ptr, base, size_in_bytes);
// enable this constructor only if the underlying type is char or void // double sanity check
template <class U> assertInvariants();
CSelf(pointer first, size_type count, U *base_, XSPAN_REQUIRES_SIZE_1_A) }
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count)) { // enable this constructor only if the underlying type is char or void
// check invariants template <class U>
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr)) CSelf(pointer first, size_type count, U *base_, XSPAN_REQUIRES_SIZE_1_A)
xspan_check_range(ptr, base, size_in_bytes); : ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count)) {
// double sanity check // check invariants
assertInvariants(); if __acc_cte ((configRequirePtr || ptr != nullptr) &&
} (configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
#ifdef UPX_VERSION_HEX #ifdef UPX_VERSION_HEX
// constructors from MemBuffer // constructors from MemBuffer
CSelf(MemBuffer &mb) CSelf(MemBuffer &mb)
: CSelf(makeNotNull((pointer) membuffer_get_void_ptr(mb)), : CSelf(makeNotNull((pointer) membuffer_get_void_ptr(mb)),
XSpanSizeInBytes(membuffer_get_size(mb))) {} XSpanSizeInBytes(membuffer_get_size(mb))) {}
CSelf(pointer first, MemBuffer &mb) CSelf(pointer first, MemBuffer &mb)
: CSelf(first, XSpanSizeInBytes(membuffer_get_size(mb)), : CSelf(first, XSpanSizeInBytes(membuffer_get_size(mb)),
makeNotNull((pointer) membuffer_get_void_ptr(mb))) {} makeNotNull((pointer) membuffer_get_void_ptr(mb))) {}
CSelf(std::nullptr_t, MemBuffer &) XSPAN_DELETED_FUNCTION; CSelf(std::nullptr_t, MemBuffer &) XSPAN_DELETED_FUNCTION;
#endif #endif
// disable constructors from nullptr to catch compile-time misuse // disable constructors from nullptr to catch compile-time misuse
private: private:
CSelf(std::nullptr_t, XSpanCount) XSPAN_DELETED_FUNCTION; CSelf(std::nullptr_t, XSpanCount) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION; CSelf(std::nullptr_t, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION; CSelf(const void *, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanSizeInBytes) XSPAN_DELETED_FUNCTION; CSelf(std::nullptr_t, XSpanSizeInBytes) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION; CSelf(std::nullptr_t, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION; CSelf(const void *, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, size_type) XSPAN_DELETED_FUNCTION; CSelf(std::nullptr_t, size_type) XSPAN_DELETED_FUNCTION;
CSelf(std::nullptr_t, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION; CSelf(std::nullptr_t, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
CSelf(const void *, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION; CSelf(const void *, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
// unchecked constructor // unchecked constructor
protected: protected:
enum ModeUnchecked { Unchecked }; enum ModeUnchecked { Unchecked };
CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b) CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b)
: ptr(p), base(b), size_in_bytes(bytes) { : ptr(p), base(b), size_in_bytes(bytes) {
assertInvariants(); assertInvariants();
} }
// unchecked assignment // unchecked assignment
Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) { Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) {
ptr = p; ptr = p;
base = b; base = b;
size_in_bytes = bytes; size_in_bytes = bytes;
assertInvariants(); assertInvariants();
return *this; return *this;
} }
#if 0 #if 0
Self &assign(ModeUnchecked, const Self &other) { Self &assign(ModeUnchecked, const Self &other) {
ptr = other.ptr; ptr = other.ptr;
@ -198,230 +209,250 @@ Self &assign(ModeUnchecked, const Self &other) {
#endif #endif
public: public:
// assignment - here we can rely on invariants enforced at construction time by makePtr/makeBase // assignment - here we can rely on invariants enforced at construction time by makePtr/makeBase
// NOTE: *this remains unmodified in case of failure // NOTE: *this remains unmodified in case of failure
Self &assign(pointer other) { Self &assign(pointer other) {
assertInvariants(); assertInvariants();
other = makePtr(other); other = makePtr(other);
if __acc_cte ((configRequirePtr || other != nullptr) && (configRequireBase || base != nullptr)) if __acc_cte ((configRequirePtr || other != nullptr) &&
xspan_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))
xspan_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 very_unlikely (base != other.base)
xspan_fail_not_same_base();
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
(configRequireBase || base != nullptr)) (configRequireBase || base != nullptr))
xspan_check_range(other.ptr, base, size_in_bytes); xspan_check_range(other, base, size_in_bytes);
// ok // ok
ptr = other.ptr; 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))
xspan_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 very_unlikely (base != other.base)
xspan_fail_not_same_base();
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(other.ptr, base, size_in_bytes);
// ok
ptr = other.ptr;
}
assertInvariants();
return *this;
} }
assertInvariants();
return *this;
}
Self &operator=(pointer other) { return assign(other); } Self &operator=(pointer other) { return assign(other); }
Self &operator=(const Self &other) { return assign(other); } Self &operator=(const Self &other) { return assign(other); }
// FIXME: this is not called?? // FIXME: this is not called??
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(Self &) XSPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const CSelf<U> &other) { operator=(const CSelf<U> &other) {
// assert(0); // assert(0);
return assign(Self(other)); return assign(Self(other));
} }
#ifdef UPX_VERSION_HEX #ifdef UPX_VERSION_HEX
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); } Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
#endif #endif
Self subspan(ptrdiff_t offset, ptrdiff_t count) { Self subspan(ptrdiff_t offset, ptrdiff_t count) {
pointer begin = check_add(ptr, offset); pointer begin = check_add(ptr, offset);
pointer end = check_add(begin, count); pointer end = check_add(begin, count);
if (begin <= end) if (begin <= end)
return Self(Unchecked, begin, (end - begin) * sizeof(T), begin); return Self(Unchecked, begin, (end - begin) * sizeof(T), begin);
else else
return Self(Unchecked, end, (begin - end) * sizeof(T), end); return Self(Unchecked, end, (begin - end) * sizeof(T), end);
} }
bool operator==(pointer other) const { return ptr == other; } bool operator==(pointer other) const { return ptr == other; }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(U *other) const { operator==(U *other) const {
return ptr == other; return ptr == other;
} }
bool operator!=(pointer other) const { return ptr != other; } bool operator!=(pointer other) const { return ptr != other; }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(U *other) const { operator!=(U *other) const {
return ptr != other; return ptr != other;
} }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpan<U> &other) const { operator==(const PtrOrSpan<U> &other) const {
return ptr == other.ptr; return ptr == other.ptr;
} }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpanOrNull<U> &other) const { operator==(const PtrOrSpanOrNull<U> &other) const {
return ptr == other.ptr; return ptr == other.ptr;
} }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const Span<U> &other) const { operator==(const Span<U> &other) const {
return ptr == other.ptr; return ptr == other.ptr;
} }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpan<U> &other) const { operator!=(const PtrOrSpan<U> &other) const {
return !(*this == other); return !(*this == other);
} }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpanOrNull<U> &other) const { operator!=(const PtrOrSpanOrNull<U> &other) const {
return !(*this == other); return !(*this == other);
} }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const Span<U> &other) const { operator!=(const Span<U> &other) const {
return !(*this == other); return !(*this == other);
} }
// check for notNull here // check for notNull here
bool operator<(std::nullptr_t) const XSPAN_DELETED_FUNCTION; bool operator<(std::nullptr_t) const XSPAN_DELETED_FUNCTION;
bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); } bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpan<U> &other) const { operator<(const PtrOrSpan<U> &other) const {
return ensurePtr() < other.ensurePtr(); return ensurePtr() < other.ensurePtr();
} }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpanOrNull<U> &other) const { operator<(const PtrOrSpanOrNull<U> &other) const {
return ensurePtr() < other.ensurePtr(); return ensurePtr() < other.ensurePtr();
} }
template <class U> template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool) XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const Span<U> &other) const { operator<(const Span<U> &other) const {
return ensurePtr() < other.ensurePtr(); return ensurePtr() < other.ensurePtr();
} }
// dereference // dereference
reference operator*() const { return *check_deref(ptr); } reference operator*() const { return *check_deref(ptr); }
// array access // array access
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); } reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
// arrow operator // arrow operator
pointer operator->() const { return check_deref(ptr); } pointer operator->() const { return check_deref(ptr); }
Self &operator++() { Self &operator++() {
ptr = check_add(ptr, 1); ptr = check_add(ptr, 1);
return *this; return *this;
} }
Self operator++(int) { Self operator++(int) {
Self tmp = *this; Self tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
Self &operator--() { Self &operator--() {
ptr = check_add(ptr, -1); ptr = check_add(ptr, -1);
return *this; return *this;
} }
Self operator--(int) { Self operator--(int) {
Self tmp = *this; Self tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
Self &operator+=(ptrdiff_t n) { Self &operator+=(ptrdiff_t n) {
ptr = check_add(ptr, n); ptr = check_add(ptr, n);
return *this; return *this;
} }
Self &operator-=(ptrdiff_t n) { Self &operator-=(ptrdiff_t n) {
ptr = check_add(ptr, -n); ptr = check_add(ptr, -n);
return *this; return *this;
} }
Self operator+(ptrdiff_t n) const { Self operator+(ptrdiff_t n) const {
pointer first = check_add(ptr, n); pointer first = check_add(ptr, n);
return Self(Unchecked, first, size_in_bytes, base); return Self(Unchecked, first, size_in_bytes, base);
} }
Self operator-(ptrdiff_t n) const { Self operator-(ptrdiff_t n) const {
pointer first = check_add(ptr, -n); pointer first = check_add(ptr, -n);
return Self(Unchecked, first, size_in_bytes, base); return Self(Unchecked, first, size_in_bytes, base);
} }
private: private:
pointer check_deref(pointer p) const { pointer check_deref(pointer p) const {
if __acc_cte (!configRequirePtr && p == nullptr) if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr(); xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr) if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T)); xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants(); assertInvariants();
return p; return p;
} }
pointer check_deref(pointer p, ptrdiff_t n) const { pointer check_deref(pointer p, ptrdiff_t n) const {
if __acc_cte (!configRequirePtr && p == nullptr) if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr(); xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n); xspan_mem_size_assert_ptrdiff<T>(n);
p += n; p += n;
if __acc_cte (configRequireBase || base != nullptr) if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T)); xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants(); assertInvariants();
return p; return p;
} }
pointer check_add(pointer p, ptrdiff_t n) const { pointer check_add(pointer p, ptrdiff_t n) const {
if __acc_cte (!configRequirePtr && p == nullptr) if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr(); xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n); xspan_mem_size_assert_ptrdiff<T>(n);
p += n; p += n;
if __acc_cte (configRequireBase || base != nullptr) if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes); xspan_check_range(p, base, size_in_bytes);
assertInvariants(); assertInvariants();
return p; return p;
} }
// disable taking the address => force passing by reference // 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] // [I'm not too sure about this design decision, but we can always allow it if needed]
Self *operator&() const XSPAN_DELETED_FUNCTION; Self *operator&() const XSPAN_DELETED_FUNCTION;
public: // raw access public: // raw access
pointer raw_ptr() const { return ptr; } pointer raw_ptr() const noexcept { return ptr; }
pointer raw_base() const { return base; } pointer raw_base() const noexcept { return base; }
size_type raw_size_in_bytes() const { return size_in_bytes; } size_type raw_size_in_bytes() const noexcept { return size_in_bytes; }
pointer raw_bytes(size_t bytes) const { pointer raw_bytes(size_t bytes) const {
assertInvariants(); assertInvariants();
if (bytes > 0) { if (bytes > 0) {
if __acc_cte (!configRequirePtr && ptr == nullptr) if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr(); xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr) { if __acc_cte (configRequireBase || base != nullptr) {
xspan_check_range(ptr, base, size_in_bytes - bytes); xspan_check_range(ptr, base, size_in_bytes - bytes);
}
} }
return ptr;
} }
return ptr;
} // like C++ std::span
pointer data() const noexcept { return ptr; }
pointer data(size_t bytes) const { return raw_bytes(bytes); } // UPX extra
// size_type size() const { return size_bytes() / sizeof(element_type); } // NOT USED
size_type size_bytes() const {
assertInvariants();
if __acc_cte (!configRequirePtr && ptr == nullptr)
return 0;
if __acc_cte (!configRequireBase && base == nullptr)
return 0;
const charptr begin = (const charptr) ptr;
const charptr end = (const charptr) base + size_in_bytes;
return end - begin;
}
#if CLANG_FORMAT_DUMMY_CLASS
}; // class
#endif
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -51,25 +51,25 @@ private:
pointer ptr; pointer ptr;
// enforce config invariants at constructor time - static functions // enforce config invariants at constructor time - static functions
static forceinline pointer makePtr(pointer p) { return p; } static inline pointer makePtr(pointer p) { return p; }
// inverse logic for ensuring valid pointers from existing objets // inverse logic for ensuring valid pointers from existing objects
forceinline pointer ensurePtr() const { return ptr; } inline pointer ensurePtr() const { return ptr; }
// debug // debug
forceinline void assertInvariants() const {} inline void assertInvariants() const noexcept {}
public: public:
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1 #if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
operator pointer() const { return ptr; } operator pointer() const noexcept { return ptr; }
#endif #endif
inline ~CSelf() {
#if DEBUG #if DEBUG
invalidate(); inline ~CSelf() { invalidate(); }
#else
inline ~CSelf() noexcept {}
#endif #endif
}
noinline void invalidate() { noinline void invalidate() {
assertInvariants(); assertInvariants();
ptr = (pointer) (acc_uintptr_t) 16; // point to non-null invalid address ptr = (pointer) (upx_uintptr_t) 16; // point to non-null invalid address
// ptr = (pointer) (void *) &ptr; // point to self // ptr = (pointer) (void *) &ptr; // point to self
assertInvariants(); assertInvariants();
} }
@ -116,7 +116,7 @@ public:
return assign(Self(other)); return assign(Self(other));
} }
// comparision // comparison
bool operator==(pointer other) const { return ptr == other; } bool operator==(pointer other) const { return ptr == other; }
template <class U> template <class U>
@ -187,7 +187,7 @@ private:
forceinline pointer check_add(pointer p, ptrdiff_t n) const { return p + n; } forceinline pointer check_add(pointer p, ptrdiff_t n) const { return p + n; }
public: // raw access public: // raw access
pointer raw_ptr() const { return ptr; } pointer raw_ptr() const noexcept { return ptr; }
pointer raw_bytes(size_t bytes) const { pointer raw_bytes(size_t bytes) const {
assertInvariants(); assertInvariants();

View File

@ -26,7 +26,7 @@
*/ */
// This file implements the central loop, and it uses class PackMaster to // This file implements the central loop, and it uses class PackMaster to
// dispatch. PackMaster by itself will instatiate a concrete subclass // dispatch. PackMaster by itself will instantiate a concrete subclass
// of class Packer which then does the actual work. // of class Packer which then does the actual work.
// And see p_com.cpp for a simple executable format. // And see p_com.cpp for a simple executable format.
@ -141,7 +141,7 @@ void do_one_file(const char *iname, char *oname) {
else else
flags |= O_EXCL; flags |= O_EXCL;
int shmode = SH_DENYWR; int shmode = SH_DENYWR;
#if defined(__MINT__) #if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
flags |= O_TRUNC; flags |= O_TRUNC;
shmode = O_DENYRW; shmode = O_DENYRW;
#endif #endif
@ -266,7 +266,7 @@ static void unlink_ofile(char *oname) {
int do_files(int i, int argc, char *argv[]) { int do_files(int i, int argc, char *argv[]) {
upx_compiler_sanity_check(); upx_compiler_sanity_check();
if (opt->verbose >= 1) { if (opt->verbose >= 1) {
show_head(); show_header();
UiPacker::uiHeader(); UiPacker::uiHeader();
} }