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-windows-gnu }
env:
# 2023-02-19
ZIG_DIST_VERSION: 0.11.0-dev.1650+5e7b09ce9
# 2023-03-14
ZIG_DIST_VERSION: 0.11.0-dev.1970+962299157
# for zig-cc wrapper scripts (see below):
ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING
ZIG_FLAGS: ${{ matrix.zig_flags }}

View File

@ -27,7 +27,7 @@ jobs:
with:
operations-per-run: 300
exempt-all-milestones: true
exempt-issue-labels: 'blocker,enhancement,regression'
exempt-issue-labels: 'blocker,enhancement,help wanted,regression'
days-before-stale: 60
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.'

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
if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git")
@ -101,9 +101,13 @@ endif()
# 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
if(NOT UPX_CONFIG_DISABLE_THREADS)
find_package(Threads)
endif()
file(GLOB ucl_SOURCES "vendor/ucl/src/*.c")
list(SORT 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)
target_link_libraries(upx upx_vendor_zstd)
endif()
if(Threads_FOUND)
target_link_libraries(upx Threads::Threads)
endif()
#***********************************************************************
# compilation flags
@ -215,10 +222,11 @@ endif()
set(t upx_vendor_zlib)
upx_compile_target_debug_with_O2(${t})
upx_sanitize_target(${t})
target_compile_definitions(${t} PRIVATE HAVE_STDARG_H=1 HAVE_VSNPRINTF=1)
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()
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
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})
@ -228,7 +236,7 @@ if(NOT UPX_CONFIG_DISABLE_ZSTD)
set(t upx_vendor_zstd)
upx_compile_target_debug_with_O2(${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)
target_compile_options(${t} PRIVATE -J ${warn_WN} ${warn_WX})
else()
@ -245,6 +253,9 @@ if(GITREV_SHORT)
target_compile_definitions(${t} PRIVATE UPX_VERSION_GIT_DESCRIBE="${GIT_DESCRIBE}")
endif()
endif()
if(Threads_FOUND)
target_compile_definitions(${t} PRIVATE WITH_THREADS=1)
endif()
if(UPX_CONFIG_DISABLE_WSTRICT)
target_compile_definitions(${t} PRIVATE UPX_CONFIG_DISABLE_WSTRICT=1)
endif()
@ -263,9 +274,9 @@ else()
endif()
#***********************************************************************
# "ctest"
# "make test"
# "ninja test"
# ctest
# make test
# ninja test
#***********************************************************************
if(NOT UPX_CONFIG_CMAKE_DISABLE_TEST)
@ -302,9 +313,9 @@ endif()
endif() # UPX_CONFIG_CMAKE_DISABLE_TEST
#***********************************************************************
# "cmake --install ."
# "make install"
# "ninja install"
# cmake --install .
# make install
# ninja 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)
endif() # UPX_CONFIG_CMAKE_DISABLE_PRINT_INFO
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\"")
endif()
if(NOT UPX_CONFIG_CMAKE_DISABLE_PLATFORM_CHECK)
# 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},")
message(FATAL_ERROR "ERROR: CMAKE_C_PLATFORM_ID CMAKE_CXX_PLATFORM_ID mismatch")
endif()

View File

@ -44,8 +44,9 @@ all: build/debug build/release
debug: build/debug
release: build/release
.PHONY: PHONY
.NOTPARALLEL: # because the actual builds use "cmake --parallel"
.PHONY: PHONY
.SECONDEXPANSION:
.SUFFIXES:
# 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_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/release: PHONY; $(call run_config_and_build,$@,Release)
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 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/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 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/release: PHONY; $(call run_config_and_build,$@,Release)
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 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/release: PHONY; $(call run_config_and_build,$@,Release)
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
John S. Fine <johnfine@erols.com>
for the new version of the dos/exe decompressor
Kornel Pal
for the EFI support
Lukundoo <Lukundoo@softhome.net>
for beta testing
Michael Devore
for initial dos/exe device driver support
Oleg V. Volkov <rover@lglobus.ru>
for various FreeBSD specific informations
for various FreeBSD specific information
The Owl & G-RoM
for the --compress-icons fix
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><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]

View File

@ -153,7 +153,7 @@ OVERLAY HANDLING OPTIONS
UPX handles overlays like many other executable packers do: it simply
copies the overlay after the compressed image. This works with some
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]

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
copies the overlay after the compressed image. This works with some
files, but doesn't work with others, depending on how an application
actually accesses this overlayed data.
actually accesses this overlaid data.
.PP
.Vb 1
\& \-\-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
copies the overlay after the compressed image. This works with some
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]

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
# directly use the CMake build instead!
# NOTE: this Makefile is deprecated - please directly use the CMake build
# instead. And see the top-level Makefile for some pre-defined CMake
# build configurations.
MAKEFLAGS += -r
.SUFFIXES:
@ -21,6 +22,7 @@ endif
# redirect to top-level CMake build
#
# note that top-level Makefile .DEFAULT_GOAL is build/release
.DEFAULT_GOAL = build/debug
build/debug: $(top_srcdir)/build/debug/upx
@ -35,8 +37,10 @@ $(top_srcdir)/build/debug/upx: PHONY
$(top_srcdir)/build/release/upx: PHONY
$(MAKE) -C $(top_srcdir) build/release
.NOTPARALLEL: # because the actual builds use "cmake --parallel"
.PHONY: PHONY
.NOTPARALLEL:
.SECONDEXPANSION:
.SUFFIXES:
#
# "make run-testsuite"
@ -79,9 +83,8 @@ endif
# automatically format some C++ source code files
ifeq ($(shell uname),Linux)
# 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 += packer_c.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 := $(filter-out $(CLANG_FORMAT_EXCLUDE_FILES),$(CLANG_FORMAT_FILES))

View File

@ -38,35 +38,35 @@
// 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_memcpy_inline(&v, p, sizeof(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_memcpy_inline(&v, p, sizeof(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_memcpy_inline(&v, p, sizeof(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_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_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_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)
// unfortunately *not* constexpr with MSVC
static forceinline unsigned bswap16(unsigned v) { return (unsigned) _byteswap_ulong(v << 16); }
static forceinline unsigned bswap32(unsigned v) { return (unsigned) _byteswap_ulong(v); }
static forceinline upx_uint64_t bswap64(upx_uint64_t v) { return _byteswap_uint64(v); }
// unfortunately *not* constexpr with current MSVC
static forceinline unsigned bswap16(unsigned v) noexcept {
return (unsigned) _byteswap_ulong(v << 16);
}
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
static forceinline constexpr unsigned bswap16(unsigned v) {
static forceinline constexpr unsigned bswap16(unsigned v) noexcept {
// return __builtin_bswap16((upx_uint16_t) (v & 0xffff));
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48);
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 __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
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
}
static forceinline constexpr unsigned no_bswap32(unsigned v) { return v; }
static forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t 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) noexcept { return v; }
#if (ACC_ABI_BIG_ENDIAN)
#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) {
// preserve the top 6 bits
#if 0
set_le32(p, (get_le32(p) & 0xfc000000) | (v & 0x03ffffff));
#else
// set_le32(p, (get_le32(p) & 0xfc000000) | (v & 0x03ffffff));
// optimized version, saving a runtime bswap32
set_ne32(p, (get_ne32(p) & ne32_to_le32(0xfc000000)) |
(ne32_to_le32(v) & ne32_to_le32(0x03ffffff)));
#endif
}
/*************************************************************************
// 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);
v &= sign_bit | (sign_bit - 1);
v |= 0 - (v & sign_bit);
v |= 0u - (v & sign_bit);
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);
v &= sign_bit | (sign_bit - 1);
v |= 0 - (v & sign_bit);
v |= 0ull - (v & sign_bit);
return ACC_ICAST(upx_int64_t, v);
}
@ -252,359 +253,348 @@ struct alignas(1) BE16 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[2];
BE16 &operator=(unsigned v) {
BE16 &operator=(unsigned v) noexcept {
set_be16(d, v);
return *this;
}
BE16 &operator+=(unsigned v) {
BE16 &operator+=(unsigned v) noexcept {
set_be16(d, get_be16(d) + v);
return *this;
}
BE16 &operator-=(unsigned v) {
BE16 &operator-=(unsigned v) noexcept {
set_be16(d, get_be16(d) - v);
return *this;
}
BE16 &operator*=(unsigned v) {
BE16 &operator*=(unsigned v) noexcept {
set_be16(d, get_be16(d) * v);
return *this;
}
BE16 &operator/=(unsigned v) {
BE16 &operator/=(unsigned v) noexcept {
set_be16(d, get_be16(d) / v);
return *this;
}
BE16 &operator&=(unsigned v) {
BE16 &operator&=(unsigned v) noexcept {
set_be16(d, get_be16(d) & v);
return *this;
}
BE16 &operator|=(unsigned v) {
BE16 &operator|=(unsigned v) noexcept {
set_be16(d, get_be16(d) | v);
return *this;
}
BE16 &operator^=(unsigned v) {
BE16 &operator^=(unsigned v) noexcept {
set_be16(d, get_be16(d) ^ v);
return *this;
}
BE16 &operator<<=(unsigned v) {
BE16 &operator<<=(unsigned v) noexcept {
set_be16(d, get_be16(d) << v);
return *this;
}
BE16 &operator>>=(unsigned v) {
BE16 &operator>>=(unsigned v) noexcept {
set_be16(d, get_be16(d) >> v);
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 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[4];
BE32 &operator=(unsigned v) {
BE32 &operator=(unsigned v) noexcept {
set_be32(d, v);
return *this;
}
BE32 &operator+=(unsigned v) {
BE32 &operator+=(unsigned v) noexcept {
set_be32(d, get_be32(d) + v);
return *this;
}
BE32 &operator-=(unsigned v) {
BE32 &operator-=(unsigned v) noexcept {
set_be32(d, get_be32(d) - v);
return *this;
}
BE32 &operator*=(unsigned v) {
BE32 &operator*=(unsigned v) noexcept {
set_be32(d, get_be32(d) * v);
return *this;
}
BE32 &operator/=(unsigned v) {
BE32 &operator/=(unsigned v) noexcept {
set_be32(d, get_be32(d) / v);
return *this;
}
BE32 &operator&=(unsigned v) {
BE32 &operator&=(unsigned v) noexcept {
set_be32(d, get_be32(d) & v);
return *this;
}
BE32 &operator|=(unsigned v) {
BE32 &operator|=(unsigned v) noexcept {
set_be32(d, get_be32(d) | v);
return *this;
}
BE32 &operator^=(unsigned v) {
BE32 &operator^=(unsigned v) noexcept {
set_be32(d, get_be32(d) ^ v);
return *this;
}
BE32 &operator<<=(unsigned v) {
BE32 &operator<<=(unsigned v) noexcept {
set_be32(d, get_be32(d) << v);
return *this;
}
BE32 &operator>>=(unsigned v) {
BE32 &operator>>=(unsigned v) noexcept {
set_be32(d, get_be32(d) >> v);
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 {
typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t
byte d[8];
BE64 &operator=(upx_uint64_t v) {
BE64 &operator=(upx_uint64_t v) noexcept {
set_be64(d, v);
return *this;
}
BE64 &operator+=(upx_uint64_t v) {
BE64 &operator+=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) + v);
return *this;
}
BE64 &operator-=(upx_uint64_t v) {
BE64 &operator-=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) - v);
return *this;
}
BE64 &operator*=(upx_uint64_t v) {
BE64 &operator*=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) * v);
return *this;
}
BE64 &operator/=(upx_uint64_t v) {
BE64 &operator/=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) / v);
return *this;
}
BE64 &operator&=(upx_uint64_t v) {
BE64 &operator&=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) & v);
return *this;
}
BE64 &operator|=(upx_uint64_t v) {
BE64 &operator|=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) | v);
return *this;
}
BE64 &operator^=(upx_uint64_t v) {
BE64 &operator^=(upx_uint64_t v) noexcept {
set_be64(d, get_be64(d) ^ v);
return *this;
}
BE64 &operator<<=(unsigned v) {
BE64 &operator<<=(unsigned v) noexcept {
set_be64(d, get_be64(d) << v);
return *this;
}
BE64 &operator>>=(unsigned v) {
BE64 &operator>>=(unsigned v) noexcept {
set_be64(d, get_be64(d) >> v);
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 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[2];
LE16 &operator=(unsigned v) {
LE16 &operator=(unsigned v) noexcept {
set_le16(d, v);
return *this;
}
LE16 &operator+=(unsigned v) {
LE16 &operator+=(unsigned v) noexcept {
set_le16(d, get_le16(d) + v);
return *this;
}
LE16 &operator-=(unsigned v) {
LE16 &operator-=(unsigned v) noexcept {
set_le16(d, get_le16(d) - v);
return *this;
}
LE16 &operator*=(unsigned v) {
LE16 &operator*=(unsigned v) noexcept {
set_le16(d, get_le16(d) * v);
return *this;
}
LE16 &operator/=(unsigned v) {
LE16 &operator/=(unsigned v) noexcept {
set_le16(d, get_le16(d) / v);
return *this;
}
LE16 &operator&=(unsigned v) {
LE16 &operator&=(unsigned v) noexcept {
set_le16(d, get_le16(d) & v);
return *this;
}
LE16 &operator|=(unsigned v) {
LE16 &operator|=(unsigned v) noexcept {
set_le16(d, get_le16(d) | v);
return *this;
}
LE16 &operator^=(unsigned v) {
LE16 &operator^=(unsigned v) noexcept {
set_le16(d, get_le16(d) ^ v);
return *this;
}
LE16 &operator<<=(unsigned v) {
LE16 &operator<<=(unsigned v) noexcept {
set_le16(d, get_le16(d) << v);
return *this;
}
LE16 &operator>>=(unsigned v) {
LE16 &operator>>=(unsigned v) noexcept {
set_le16(d, get_le16(d) >> v);
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 {
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
byte d[4];
LE32 &operator=(unsigned v) {
LE32 &operator=(unsigned v) noexcept {
set_le32(d, v);
return *this;
}
LE32 &operator+=(unsigned v) {
LE32 &operator+=(unsigned v) noexcept {
set_le32(d, get_le32(d) + v);
return *this;
}
LE32 &operator-=(unsigned v) {
LE32 &operator-=(unsigned v) noexcept {
set_le32(d, get_le32(d) - v);
return *this;
}
LE32 &operator*=(unsigned v) {
LE32 &operator*=(unsigned v) noexcept {
set_le32(d, get_le32(d) * v);
return *this;
}
LE32 &operator/=(unsigned v) {
LE32 &operator/=(unsigned v) noexcept {
set_le32(d, get_le32(d) / v);
return *this;
}
LE32 &operator&=(unsigned v) {
LE32 &operator&=(unsigned v) noexcept {
set_le32(d, get_le32(d) & v);
return *this;
}
LE32 &operator|=(unsigned v) {
LE32 &operator|=(unsigned v) noexcept {
set_le32(d, get_le32(d) | v);
return *this;
}
LE32 &operator^=(unsigned v) {
LE32 &operator^=(unsigned v) noexcept {
set_le32(d, get_le32(d) ^ v);
return *this;
}
LE32 &operator<<=(unsigned v) {
LE32 &operator<<=(unsigned v) noexcept {
set_le32(d, get_le32(d) << v);
return *this;
}
LE32 &operator>>=(unsigned v) {
LE32 &operator>>=(unsigned v) noexcept {
set_le32(d, get_le32(d) >> v);
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 {
typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t
byte d[8];
LE64 &operator=(upx_uint64_t v) {
LE64 &operator=(upx_uint64_t v) noexcept {
set_le64(d, v);
return *this;
}
LE64 &operator+=(upx_uint64_t v) {
LE64 &operator+=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) + v);
return *this;
}
LE64 &operator-=(upx_uint64_t v) {
LE64 &operator-=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) - v);
return *this;
}
LE64 &operator*=(upx_uint64_t v) {
LE64 &operator*=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) * v);
return *this;
}
LE64 &operator/=(upx_uint64_t v) {
LE64 &operator/=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) / v);
return *this;
}
LE64 &operator&=(upx_uint64_t v) {
LE64 &operator&=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) & v);
return *this;
}
LE64 &operator|=(upx_uint64_t v) {
LE64 &operator|=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) | v);
return *this;
}
LE64 &operator^=(upx_uint64_t v) {
LE64 &operator^=(upx_uint64_t v) noexcept {
set_le64(d, get_le64(d) ^ v);
return *this;
}
LE64 &operator<<=(unsigned v) {
LE64 &operator<<=(unsigned v) noexcept {
set_le64(d, get_le64(d) << v);
return *this;
}
LE64 &operator>>=(unsigned v) {
LE64 &operator>>=(unsigned v) noexcept {
set_le64(d, get_le64(d) >> v);
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)
**************************************************************************/
template <class T>
inline T *operator+(T *ptr, const BE16 &v) {
inline T *operator+(T *ptr, const BE16 &v) noexcept {
return ptr + unsigned(v);
}
template <class T>
inline T *operator-(T *ptr, const BE16 &v) {
inline T *operator-(T *ptr, const BE16 &v) noexcept {
return ptr - unsigned(v);
}
template <class T>
inline T *operator+(T *ptr, const BE32 &v) {
inline T *operator+(T *ptr, const BE32 &v) noexcept {
return ptr + unsigned(v);
}
template <class T>
inline T *operator-(T *ptr, const BE32 &v) {
inline T *operator-(T *ptr, const BE32 &v) noexcept {
return ptr - unsigned(v);
}
template <class T>
inline T *operator+(T *ptr, const LE16 &v) {
inline T *operator+(T *ptr, const LE16 &v) noexcept {
return ptr + unsigned(v);
}
template <class T>
inline T *operator-(T *ptr, const LE16 &v) {
inline T *operator-(T *ptr, const LE16 &v) noexcept {
return ptr - unsigned(v);
}
template <class T>
inline T *operator+(T *ptr, const LE32 &v) {
inline T *operator+(T *ptr, const LE32 &v) noexcept {
return ptr + unsigned(v);
}
template <class T>
inline T *operator-(T *ptr, const LE32 &v) {
inline T *operator-(T *ptr, const LE32 &v) noexcept {
return ptr - unsigned(v);
}
// these are not implemented on purpose and will cause errors
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>
T *operator-(T *ptr, const BE64 &v) DELETED_FUNCTION;
T *operator-(T *ptr, const BE64 &v) noexcept DELETED_FUNCTION;
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>
T *operator-(T *ptr, const LE64 &v) DELETED_FUNCTION;
T *operator-(T *ptr, const LE64 &v) noexcept DELETED_FUNCTION;
/*************************************************************************
// global overloads
@ -644,6 +634,19 @@ inline unsigned UPX_MIN(const LE32 &a, unsigned b) { return UPX_MIN(unsigned(a),
// 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()
extern "C" {
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 *);
} // 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.
//

View File

@ -37,20 +37,20 @@
// CTP - Compile-Time Polymorphism (templates)
#define V static inline
#define S static int __acc_cdecl_qsort
#define C /*empty*/
#define C noexcept
#elif defined(BELE_RTP)
// RTP - Run-Time Polymorphism (virtual functions)
#define V virtual
#define S virtual int
#define C const
#define C const noexcept
#else
#error
#endif
#if defined(BELE_RTP)
struct AbstractPolicy {
inline AbstractPolicy() {}
virtual inline ~AbstractPolicy() {}
inline AbstractPolicy() noexcept {}
virtual inline ~AbstractPolicy() noexcept {}
V bool isBE() C = 0;
V bool isLE() C = 0;
@ -91,7 +91,7 @@ private:
#if defined(BELE_RTP)
#undef C
#define C const override
#define C const noexcept override
#endif
struct BEPolicy
@ -99,7 +99,7 @@ struct BEPolicy
final : public AbstractPolicy
#endif
{
inline BEPolicy() {}
inline BEPolicy() noexcept {}
#if defined(BELE_CTP)
typedef N_BELE_RTP::BEPolicy RTP_Policy;
#elif defined(BELE_RTP)
@ -160,7 +160,7 @@ struct LEPolicy
final : public AbstractPolicy
#endif
{
inline LEPolicy() {}
inline LEPolicy() noexcept {}
#if defined(BELE_CTP)
typedef N_BELE_RTP::LEPolicy RTP_Policy;
#elif defined(BELE_RTP)
@ -225,24 +225,6 @@ typedef LEPolicy HostPolicy;
#error "ACC_ABI_ENDIAN"
#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 S
#undef C

View File

@ -39,7 +39,7 @@ int upx_doctest_check(int argc, char **argv) {
const char *e = getenv("UPX_DEBUG_DOCTEST_DISABLE");
if (e && e[0] && strcmp(e, "0") != 0)
return 0;
bool minimal = true; // only show failing tests
bool minimal = true; // don't show summary
bool duration = false; // show timings
bool success = false; // show all tests
#if DEBUG
@ -47,12 +47,13 @@ int upx_doctest_check(int argc, char **argv) {
#endif
e = getenv("UPX_DEBUG_DOCTEST_VERBOSE");
if (e && e[0]) {
minimal = false;
if (strcmp(e, "0") == 0) {
minimal = true;
} else if (strcmp(e, "2") == 0) {
minimal = false;
duration = true;
} else if (strcmp(e, "3") == 0) {
minimal = false;
duration = 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("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("a", ""))
@ -145,15 +147,18 @@ namespace {
template <class T>
struct TestBELE {
__acc_static_noinline bool test(void) {
static noinline bool test(void) {
// POD checks
{
COMPILE_TIME_ASSERT(std::is_standard_layout<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_trivially_copyable<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
{
@ -177,8 +182,7 @@ struct TestBELE {
UNUSED(t1);
UNUSED(t2);
}
#if 1
// arithmetic checks
// arithmetic checks (modern compilers will optimize this away)
{
T allbits;
allbits = 0;
@ -187,6 +191,7 @@ struct TestBELE {
T v1;
v1 = 1;
v1 *= 2;
v1 /= 1;
v1 -= 1;
T v2;
v2 = 1;
@ -217,14 +222,13 @@ struct TestBELE {
if ((v1 ^ v2) != 1)
return false;
}
#endif
return true;
}
};
template <class A, class B>
struct TestNoAliasingStruct {
__acc_static_noinline bool test(A *a, B *b) {
static noinline bool test(A *a, B *b) {
*a = 0;
*b = 0;
*b -= 3;
@ -232,7 +236,7 @@ struct TestNoAliasingStruct {
}
};
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);
}
template <class T>
@ -274,6 +278,10 @@ void upx_compiler_sanity_check(void) {
COMPILE_TIME_ASSERT_ALIGNED1(LE32)
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)
assert(strlen(UPX_VERSION_STRING4) == 4);
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);
#if 1
#if DEBUG || 1
assert(TestBELE<LE16>::test());
assert(TestBELE<LE32>::test());
assert(TestBELE<LE64>::test());
@ -354,9 +362,9 @@ void upx_compiler_sanity_check(void) {
assert(dd == ne32_to_le32(0xf7020304));
}
{
upx_uint16_t a;
upx_uint32_t b;
upx_uint64_t c;
upx_uint16_t a = 0;
upx_uint32_t b = 0;
upx_uint64_t c = 0;
set_ne16(&a, 0x04030201); // ignore upper bits
set_ne32(&b, 0x04030201);
set_ne64(&c, 0x0807060504030201ull);
@ -454,7 +462,7 @@ TEST_CASE("working -fno-strict-overflow") {
}
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];
long long ll = acc_vget_int(-1, 0);
unsigned long long llu = (unsigned long long) ll;

View File

@ -29,23 +29,30 @@
**************************************************************************/
#define DOCTEST_CONFIG_IMPLEMENT
#if !defined(UPX_DOCTEST_CONFIG_MULTITHREADING)
#define DOCTEST_CONFIG_NO_MULTITHREADING
#endif
#define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
#if !defined(DOCTEST_CONFIG_DISABLE)
#if defined(__i386__) && defined(__MSDOS__) && defined(__DJGPP__) && defined(__GNUC__)
#define DOCTEST_CONFIG_NO_MULTITHREADING
#define DOCTEST_CONFIG_NO_POSIX_SIGNALS
#elif defined(__m68k__) && defined(__atarist__) && defined(__GNUC__)
#define DOCTEST_CONFIG_COLORS_NONE
#define DOCTEST_CONFIG_NO_MULTITHREADING
#define DOCTEST_CONFIG_NO_POSIX_SIGNALS
#pragma GCC diagnostic ignored "-Wshadow"
#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)
// warning: comparison with NaN always evaluates to false in fast floating point modes
#pragma clang diagnostic ignored "-Wtautological-constant-compare"
#endif
#include <doctest/doctest/parts/doctest.cpp>
#endif
#endif // DOCTEST_CONFIG_DISABLE
/* 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_THROWS(raw_bytes(a0, 1));
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_index_bytes(c0, 1, 3) == buf + 1);
CHECK(raw_bytes(cp, 4) == buf);
@ -136,6 +147,17 @@ TEST_CASE("basic xspan usage") {
CHECK_NOTHROW(raw_bytes(a0, 0));
CHECK_THROWS(raw_bytes(a0, 1));
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_index_bytes(c0, 1, 3) == buf + 1);
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
assert(*dst_len != 0);
#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));
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;
}
#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
// need about 6 MiB of stack during runtime decompression.
res->lit_pos_bits = 4;
@ -524,13 +524,12 @@ const char *upx_lzma_version_string(void) { return "4.43"; }
**************************************************************************/
TEST_CASE("upx_lzma_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[16];
const byte *c_data;
byte d_buf[16];
unsigned d_len;
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;
r = upx_lzma_decompress(c_data, 9, d_buf, &d_len, M_LZMA, nullptr);
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_size = 0;
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];
} else {
throwInternalError("unknown compression method");
return UPX_E_ERROR;
}
// optimize compression parms
// optimize compression params
if (level <= 3 && cconf.max_offset == UCL_UINT_MAX)
cconf.max_offset = 8 * 1024 - 1;
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" {
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); }
}
} // extern "C"
int upx_ucl_init(void) {
if (ucl_init() != UCL_E_OK)
@ -327,13 +327,12 @@ TEST_CASE("compress_ucl") {
#endif // DEBUG
TEST_CASE("upx_ucl_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[16];
const byte *c_data;
byte d_buf[16];
unsigned d_len;
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;
r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr);
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);
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;
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr);
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);
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;
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2E_8, nullptr);
CHECK((r == 0 && d_len == 16));

View File

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

View File

@ -207,13 +207,12 @@ TEST_CASE("compress_zstd") {
#endif // DEBUG
TEST_CASE("upx_zstd_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[32];
const byte *c_data;
byte d_buf[32];
unsigned d_len;
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;
r = upx_zstd_decompress(c_data, 16, d_buf, &d_len, M_ZSTD, nullptr);
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)
#endif
#endif // !UPX_CONFIG_DISABLE_WSTRICT && !UPX_CONFIG_DISABLE_WERROR
// disable some warnings
#if (ACC_CC_MSC)
# pragma warning(disable: 4244) // -Wconversion
@ -124,22 +125,30 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
#include <new>
#include <type_traits>
#include <typeinfo>
#if __STDC_NO_ATOMICS__ || 1
// UPX currently does not use multithreading
#define upx_std_atomic(Type) Type
//#define upx_std_atomic(Type) typename std::add_volatile<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(); }
}
#else
// multithreading (UPX currently does not use multithreading)
#ifndef WITH_THREADS
# define WITH_THREADS 0
#endif
#if __STDC_NO_ATOMICS__
# undef WITH_THREADS
#endif
#if (WITH_THREADS)
#define upx_thread_local thread_local
#include <atomic>
#define upx_std_atomic(Type) std::atomic<Type>
#include <mutex>
#define upx_std_once_flag std::once_flag
#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
#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
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>
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
**************************************************************************/
// 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_uint8_t upx_uint8_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_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;
#define upx_byte byte
#define upx_bytep byte *
// 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 (1024 * 1024)
typedef unsigned char uchar;
// use "charptr" when dealing with pointer arithmetics
#define charptr upx_charptr_unit_type *
// upx_charptr_unit_type is some opaque type with sizeof(type) == 1
struct alignas(1) upx_charptr_unit_type { char dummy; };
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(upx_charptr_unit_type) == 1)
// using the system off_t was a bad idea even back in 199x...
typedef upx_int64_t upx_off_t;
@ -244,8 +277,8 @@ typedef upx_int64_t upx_off_t;
#endif
#if (ACC_OS_DOS32) && defined(__DJGPP__)
# undef sopen
# undef __unix__
# undef __unix
# undef __unix__
#endif
#ifndef STDIN_FILENO
@ -304,7 +337,7 @@ typedef upx_int64_t upx_off_t;
# endif
#endif
// avoid warnings about shadowing global functions
// avoid warnings about shadowing global symbols
#undef _base
#undef basename
#undef index
@ -391,14 +424,6 @@ inline void NO_fprintf(FILE *, const char *, ...) {}
#define __packed_struct(s) struct alignas(1) s {
#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) { \
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; }; \
@ -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>
inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; }
template <size_t TypeSize>
struct USizeOfTypeImpl {
static forceinline constexpr unsigned value() {
COMPILE_TIME_ASSERT(TypeSize >= 1 && TypeSize <= 64 * 1024) // arbitrary limit
return ACC_ICONV(unsigned, TypeSize);
}
template <size_t Size>
struct UnsignedSizeOf {
static_assert(Size >= 1 && Size <= UPX_RSIZE_MAX_MEM);
static constexpr unsigned value = unsigned(Size);
};
#define usizeof(type) (USizeOfTypeImpl<sizeof(type)>::value())
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == 4)
#define usizeof(expr) (UnsignedSizeOf<sizeof(expr)>::value)
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == sizeof(int))
// An Array allocates memory on the heap, and automatically
// 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)); \
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
{
protected:
inline noncopyable() {}
inline ~noncopyable() {}
inline noncopyable() noexcept {}
inline ~noncopyable() noexcept {}
private:
noncopyable(const noncopyable &) DELETED_FUNCTION; // copy constuctor
noncopyable(const noncopyable &) DELETED_FUNCTION; // copy constructor
noncopyable& operator=(const noncopyable &) DELETED_FUNCTION; // copy assignment
noncopyable(noncopyable &&) DELETED_FUNCTION; // move constructor
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));
}
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) {
return !string_eq(a, b);
@ -644,7 +667,7 @@ struct upx_callback_t
upx_progress_func_t nprogress;
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);
}
OptVar() : v(default_value), is_set(false) { }
OptVar() noexcept : v(default_value), is_set(false) { }
OptVar& operator= (const T &other) {
assertValue(other);
v = other;
@ -678,8 +701,8 @@ struct OptVar
return *this;
}
void reset() { v = default_value; is_set = false; }
operator T () const { return v; }
void reset() noexcept { v = default_value; is_set = false; }
operator T () const noexcept { return v; }
T v;
bool is_set;
@ -818,26 +841,16 @@ struct upx_compress_result_t
// 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
class ElfLinker;
typedef ElfLinker Linker;
class Throwable;
// util/membuffer.h
class MemBuffer;
void *membuffer_get_void_ptr(MemBuffer &mb);
unsigned membuffer_get_size(MemBuffer &mb);
// xspan
#include "util/raw_bytes.h"
#include "util/xspan.h"
// util/dt_check.cpp
void upx_compiler_sanity_check();
int upx_doctest_check();
@ -870,7 +883,7 @@ int do_files(int i, int argc, char *argv[]);
// help.cpp
extern const char gitrev[];
void show_head();
void show_header();
void show_help(int verbose=0);
void show_license();
void show_usage();
@ -898,6 +911,17 @@ int upx_test_overlap ( const upx_bytep buf,
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 defined(INVALID_HANDLE_VALUE) || defined(MAKEWORD) || defined(RT_CURSOR)
# 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)
throwIOException("write error", errno);
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 {

View File

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

View File

@ -28,7 +28,7 @@
#include "conf.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) {
if (size < *capacity)
@ -67,7 +67,7 @@ ElfLinker::Section::Section(const char *n, const void *i, unsigned s, unsigned a
((char *) input)[s] = 0;
}
ElfLinker::Section::~Section() {
ElfLinker::Section::~Section() noexcept {
free(name);
free(input);
}
@ -83,7 +83,7 @@ ElfLinker::Symbol::Symbol(const char *n, Section *s, upx_uint64_t o)
assert(section != nullptr);
}
ElfLinker::Symbol::~Symbol() { free(name); }
ElfLinker::Symbol::~Symbol() noexcept { free(name); }
/*************************************************************************
// Relocation
@ -105,7 +105,7 @@ ElfLinker::ElfLinker()
nsections_capacity(0), nsymbols(0), nsymbols_capacity(0), nrelocations(0),
nrelocations_capacity(0), reloc_done(false) {}
ElfLinker::~ElfLinker() {
ElfLinker::~ElfLinker() noexcept {
delete[] input;
delete[] output;
@ -548,7 +548,7 @@ upx_uint64_t ElfLinker::getSymbolOffset(const char *name) const {
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);
outputlen += len;
}
@ -559,7 +559,7 @@ void ElfLinker::relocate1(const Relocation *rel, byte *, upx_uint64_t, const cha
/*************************************************************************
// 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
**************************************************************************/
@ -802,12 +802,12 @@ void ElfLinkerPpc32::relocate1(const Relocation *rel, byte *location, upx_uint64
if (strcmp(type, "24") == 0) {
if (3 & value)
internal_error("unaligned word diplacement");
// FIXME: displacment overflow?
// FIXME: displacement overflow?
set_be32(location, (0xfc000003 & get_be32(location)) + (0x03fffffc & value));
} else if (strcmp(type, "14") == 0) {
if (3 & value)
internal_error("unaligned word diplacement");
// FIXME: displacment overflow?
// FIXME: displacement overflow?
set_be32(location, (0xffff0003 & get_be32(location)) + (0x0000fffc & value));
} else
super::relocate1(rel, location, value, type);

View File

@ -77,7 +77,7 @@ protected:
public:
ElfLinker();
virtual ~ElfLinker();
virtual ~ElfLinker() noexcept;
void init(const void *pdata, int plen, unsigned pxtra = 0);
// virtual void setLoaderAlignOffset(int phase);
@ -98,7 +98,7 @@ public:
void dumpSymbol(const Symbol *, unsigned flags, FILE *fp) 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 alignData(unsigned len) { alignWithByte(len, 0); }
@ -133,7 +133,7 @@ struct ElfLinker::Section : private noncopyable {
Section *next = nullptr;
Section(const char *n, const void *i, unsigned s, unsigned a = 0);
~Section();
~Section() noexcept;
};
struct ElfLinker::Symbol : private noncopyable {
@ -142,7 +142,7 @@ struct ElfLinker::Symbol : private noncopyable {
upx_uint64_t offset = 0;
Symbol(const char *n, Section *s, upx_uint64_t o);
~Symbol();
~Symbol() noexcept;
};
struct ElfLinker::Relocation : private noncopyable {
@ -153,6 +153,7 @@ struct ElfLinker::Relocation : private noncopyable {
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() noexcept {}
};
/*************************************************************************

View File

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

View File

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

View File

@ -29,6 +29,14 @@
#ifndef UPX_OPTIONS_H__
#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
**************************************************************************/
@ -46,7 +54,7 @@ enum {
CMD_VERSION,
};
struct options_t final {
struct Options final {
int cmd;
// compression options
@ -164,8 +172,6 @@ struct options_t final {
void reset();
};
extern struct options_t *opt;
#endif /* already included */
/* vim:set ts=4 sw=4 et: */

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_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 *getFilters() const override;

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 14; }
virtual int getFormat() const override { return UPX_F_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";
}
virtual const int *getCompressionMethods(int method, int level) const override;

View File

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

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_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 *getFilters() const override;
@ -90,18 +90,18 @@ protected:
exe_header_t ih, oh;
unsigned ih_exesize;
unsigned ih_imagesize;
unsigned ih_overlay;
unsigned relocsize;
unsigned ih_exesize = 0;
unsigned ih_imagesize = 0;
unsigned ih_overlay = 0;
unsigned relocsize = 0;
bool has_9a;
bool device_driver;
bool has_9a = false;
bool device_driver = false;
enum { NORELOC = 1, USEJUMP = 2, SS = 4, SP = 8, MINMEM = 16, MAXMEM = 32 };
unsigned stack_for_lzma; // stack size required for lzma
bool use_clear_dirty_stack;
unsigned stack_for_lzma = 0; // stack size required for lzma
bool use_clear_dirty_stack = false;
};
#endif /* already included */

View File

@ -45,7 +45,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_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 *getFilters() const override;

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_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;

View File

@ -188,15 +188,18 @@ void PackTmt::pack(OutputFile *fo) {
checkOverlay(overlay);
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
SPAN_S_VAR(byte, orelocs, mb_orelocs);
unsigned orelocsize =
optimizeReloc(relocnum, relocs, orelocs, ibuf, usize, 32, true, &big_relocs);
mb_relocs.dealloc(); // done
#if 1
// write duplicate end marker; why is this here - historical oversight ???
orelocs[orelocsize++] = 0;
#endif
// extra_info
orelocs[orelocsize++] = 0; // why is this needed - historical oversight ???
set_le32(orelocs + orelocsize, ih.entry); // save original entry point
orelocsize += 4;
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);
SPAN_S_VAR(byte, relocs, mb_relocs);
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));
oh.imagesize = osize;

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_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";
}
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_ALTLOAD 0x02 // OK to load in alternate ram
#define F_ALTALLOC 0x04 // OK to malloc from alt. ram
#define F_SMALLTPA \
0x08 // used in MagiC: TPA can be allocated
// as specified in the program header
// rather than the biggest free memory
// block
#define F_SMALLTPA 0x08
// used in MagiC: TPA can be allocated as specified in the program header
// rather than the biggest free memory block
#define F_MEMFLAGS 0xf0 // reserved for future use
#define F_SHTEXT 0x800 // program's text may be shared
@ -297,26 +295,26 @@ bool PackTos::checkFileHeader() {
// relocs
**************************************************************************/
// Check relocation for errors to make sure our loader can handle it.
static int check_relocs(const byte *relocs, unsigned rsize, unsigned isize, unsigned *nrelocs,
// Check relocation for errors to make sure our loader can handle them
static int check_relocs(const byte *relocs, unsigned rsize, unsigned image_size, unsigned *relocnum,
unsigned *relocsize, unsigned *overlay) {
assert(rsize >= 4);
assert(image_size >= 4);
unsigned fixup = get_be32(relocs);
assert(fixup > 0);
unsigned last_fixup = fixup;
unsigned i = 4;
assert(isize >= 4);
assert(fixup > 0);
*nrelocs = 1;
*relocnum = 1;
for (;;) {
if (fixup & 1) // must be word-aligned
return -1;
if (fixup + 4 > isize) // too far
if (fixup + 4 > image_size) // out of bounds
return -1;
if (i >= rsize) // premature EOF in relocs
return -1;
unsigned c = relocs[i++];
if (c == 0) // end marker
if (c == 0) // EOF end marker
break;
else if (c == 1) // increase fixup, no reloc
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
return -1;
last_fixup = fixup;
*nrelocs += 1;
*relocnum += 1;
}
}
@ -352,7 +350,7 @@ bool PackTos::canPack() {
if (!checkFileHeader())
throwCantPack("unsupported header flags");
if (file_size < 1024)
throwCantPack("program is too small");
throwCantPack("program is too small for atari/tos");
return true;
}
@ -370,7 +368,7 @@ void PackTos::fileInfo() {
void PackTos::pack(OutputFile *fo) {
unsigned t;
unsigned nrelocs = 0;
unsigned relocnum = 0;
unsigned relocsize = 0;
unsigned overlay = 0;
@ -426,14 +424,14 @@ void PackTos::pack(OutputFile *fo) {
} else if (ih.fh_reloc != 0)
relocsize = 0;
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)
throwCantPack("bad relocation table");
symbols.need_reloc = true;
}
#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
checkOverlay(overlay);
@ -451,7 +449,7 @@ void PackTos::pack(OutputFile *fo) {
// Now the data in ibuf[0..t] looks like this:
// text + data + relocs + original file header
// 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)
obuf.allocForCompression(t, 4096);

View File

@ -41,7 +41,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_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 *getFilters() const override;

View File

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

View File

@ -39,7 +39,7 @@ public:
virtual ~PackW32PeI386();
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 *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 *getFilters() const override;

View File

@ -39,7 +39,7 @@ public:
virtual ~PackW64PeAmd64();
virtual int getFormat() const override { return UPX_F_W64PE_AMD64; }
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 *getFilters() const override;

View File

@ -39,7 +39,7 @@ public:
virtual ~PackW64PeArm64() {}
virtual int getFormat() const override { return UPX_F_W64PE_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 *getFilters() const override;
@ -70,7 +70,7 @@ public:
PackW64PeArm64EC(InputFile *f) : super(f) {}
virtual int getFormat() const override { return UPX_F_W64PE_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;
};

View File

@ -39,7 +39,7 @@ public:
virtual int getVersion() const override { return 13; }
virtual int getFormat() const override { return UPX_F_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";
}
virtual const int *getCompressionMethods(int method, int level) const override;

View File

@ -39,7 +39,7 @@ public:
virtual ~PackWinCeArm();
virtual int getFormat() const override { return UPX_F_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 *getFilters() const override;
virtual void defineFilterSymbols(const Filter *) override {}

View File

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

View File

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

View File

@ -30,7 +30,7 @@
/*************************************************************************
// 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,
@ -38,6 +38,10 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
int *big) {
assert(bits == 32 || bits == 64);
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);
*big = 0;
@ -69,7 +73,7 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
fix += 4;
}
pc += delta;
if (pc + 4 >= image_size)
if (pc + 4 > image_size)
throwCantPack("bad reloc[%#x] = %#x", i, pc);
if (bswap) {
if (bits == 32)
@ -84,14 +88,17 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
/*************************************************************************
// delta-decompress relocations
// advances |in|
// allocates |out| and returns number of relocs written to |out|
// advances 'in'
// 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 image_size, int bits, bool bswap) {
assert(bits == 32 || bits == 64);
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);
// count
@ -125,7 +132,7 @@ unsigned Packer::unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P
if ((int) delta < 4)
throwCantUnpack("overlapping fixups");
pc += delta;
if (pc + 4 >= image_size)
if (pc + 4 > image_size)
throwCantUnpack("bad reloc[%#x] = %#x", i, pc);
*relocs++ = pc;
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
if (o != nullptr) {
#if WITH_THREADS
std::lock_guard<std::mutex> lock(opt_lock_mutex);
#endif
saved_opt = o;
if (o) {
memcpy(&this->local_options, o, sizeof(*o)); // struct copy
opt = &this->local_options;
}
}
PackMaster::~PackMaster() {
fi = nullptr;
delete p;
p = nullptr;
PackMaster::~PackMaster() noexcept {
delete packer;
packer = nullptr;
// 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;
saved_opt = nullptr;
}
}
/*************************************************************************
//
**************************************************************************/
static Packer *try_pack(Packer *p, void *user) {
if (p == nullptr)
return nullptr;
static Packer *try_can_pack(Packer *p, void *user) {
InputFile *f = (InputFile *) user;
p->assertPacker();
try {
p->initPackHeader();
f->seek(0, SEEK_SET);
@ -105,11 +108,8 @@ static Packer *try_pack(Packer *p, void *user) {
return nullptr;
}
static Packer *try_unpack(Packer *p, void *user) {
if (p == nullptr)
return nullptr;
static Packer *try_can_unpack(Packer *p, void *user) {
InputFile *f = (InputFile *) user;
p->assertPacker();
try {
p->initPackHeader();
f->seek(0, SEEK_SET);
@ -123,6 +123,7 @@ static Packer *try_unpack(Packer *p, void *user) {
// see canUnpack() in packer.h
}
} catch (const IOException &) {
// ignored
} catch (...) {
delete p;
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,
void *user) {
Packer *p = nullptr;
/*static*/
Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const Options *o, void *user) {
#define D(Klass) \
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) \
fprintf(stderr, "visitAllPackers: (ver=%d, fmt=%3d) %s\n", kp->getVersion(), \
kp->getFormat(), #Klass); \
if ((p = func(kp, user)) != nullptr) \
Packer *p = func(kp, user); \
if (p != nullptr) \
return p; \
ACC_BLOCK_END
// note: order of tries is important !
// NOTE: order of tries is important !!!
//
// .exe
//
if (!o->dos_exe.force_stub) {
// dos32
D(PackDjgpp2);
D(PackTmt);
D(PackWcle);
// Windows
// D(PackW64PeArm64EC); // NOT YET IMPLEMENTED
// D(PackW64PeArm64); // NOT YET IMPLEMENTED
D(PackW64PeAmd64);
D(PackW32PeI386);
}
D(PackWinCeArm);
D(PackExe);
//
// atari
//
D(PackTos);
}
D(PackExe); // dos/exe
//
// linux kernel
@ -210,18 +210,7 @@ Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio
D(PackMachFat); // cafebabe conflict
D(PackLinuxI386); // cafebabe conflict
//
// psone
//
D(PackPs1);
//
// .sys and .com
//
D(PackSys);
D(PackCom);
// Mach (macOS)
// Mach (Darwin / macOS)
D(PackDylibAMD64);
D(PackMachPPC32); // TODO: this works with upx 3.91..3.94 but got broken in 3.95; FIXME
D(PackMachI386);
@ -235,24 +224,30 @@ Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio
// D(PackDylibI386);
// D(PackDylibPPC32);
//
// misc
//
D(PackTos); // atari/tos
D(PackPs1); // ps1/exe
D(PackSys); // dos/sys
D(PackCom); // dos/com
return nullptr;
#undef D
}
Packer *PackMaster::getPacker(InputFile *f) {
Packer *pp = visitAllPackers(try_pack, f, opt, f);
if (!pp)
/*static*/ Packer *PackMaster::getPacker(InputFile *f) {
Packer *p = visitAllPackers(try_can_pack, f, opt, f);
if (!p)
throwUnknownExecutableFormat();
pp->assertPacker();
return pp;
return p;
}
Packer *PackMaster::getUnpacker(InputFile *f) {
Packer *pp = visitAllPackers(try_unpack, f, opt, f);
if (!pp)
/*static*/ Packer *PackMaster::getUnpacker(InputFile *f) {
Packer *p = visitAllPackers(try_can_unpack, f, opt, f);
if (!p)
throwNotPacked();
pp->assertPacker();
return pp;
return p;
}
/*************************************************************************
@ -260,39 +255,37 @@ Packer *PackMaster::getUnpacker(InputFile *f) {
**************************************************************************/
void PackMaster::pack(OutputFile *fo) {
p = getPacker(fi);
fi = nullptr;
p->doPack(fo);
assert(packer == nullptr);
packer = getPacker(fi);
packer->doPack(fo);
}
void PackMaster::unpack(OutputFile *fo) {
p = getUnpacker(fi);
p->assertPacker();
fi = nullptr;
p->doUnpack(fo);
assert(packer == nullptr);
packer = getUnpacker(fi);
packer->doUnpack(fo);
}
void PackMaster::test() {
p = getUnpacker(fi);
fi = nullptr;
p->doTest();
assert(packer == nullptr);
packer = getUnpacker(fi);
packer->doTest();
}
void PackMaster::list() {
p = getUnpacker(fi);
fi = nullptr;
p->doList();
assert(packer == nullptr);
packer = getUnpacker(fi);
packer->doList();
}
void PackMaster::fileInfo() {
p = visitAllPackers(try_unpack, fi, opt, fi);
if (!p)
p = visitAllPackers(try_pack, fi, opt, fi);
if (!p)
assert(packer == nullptr);
packer = visitAllPackers(try_can_unpack, fi, opt, fi);
if (!packer)
packer = visitAllPackers(try_can_pack, fi, opt, fi);
if (!packer)
throwUnknownExecutableFormat(nullptr, 1); // make a warning here
p->assertPacker();
fi = nullptr;
p->doFileInfo();
packer->doFileInfo();
}
/* vim:set ts=4 sw=4 et: */

View File

@ -32,13 +32,13 @@ class InputFile;
class OutputFile;
/*************************************************************************
// interface for work.cpp
// dispatch to a concrete subclass of class Packer; see work.cpp
**************************************************************************/
class PackMaster final {
public:
PackMaster(InputFile *f, options_t *o = nullptr);
~PackMaster();
PackMaster(InputFile *f, Options *o = nullptr) noexcept;
~PackMaster() noexcept;
void pack(OutputFile *fo);
void unpack(OutputFile *fo);
@ -47,18 +47,18 @@ public:
void fileInfo();
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:
InputFile *fi = nullptr;
Packer *p = nullptr;
Packer *packer = nullptr; // owner
InputFile *fi = nullptr; // reference
static Packer *getPacker(InputFile *f);
static Packer *getUnpacker(InputFile *f);
// setup local options for each file
options_t local_options;
options_t *saved_opt = nullptr;
Options local_options;
Options *saved_opt = nullptr;
};
/* 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 ???
return UPX_F_W32PE_I386;
// other or unkown (alpha, mips, etc.)
// other or unknown (alpha, mips, etc.)
throwCantPack("pefile: unsupported machine %#x", cpu);
return 0; // pacify msvc
}
@ -274,6 +274,19 @@ void PeFile::Interval::dump() const {
// 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 {
LE32 pagestart;
LE32 size;
@ -371,17 +384,21 @@ void PeFile32::processRelocs() // pass1
}
mb_orelocs.alloc(1);
orelocs = mb_orelocs; // => orelocs now is a SPAN_S
orelocs[0] = 0; // clear
sorelocs = 0;
return;
}
for (ic = 15; ic > 3; ic--)
for (ic = 4; ic < 16; ic++)
if (counts[ic])
infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]);
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]);
fixdel.n += 1;
}
unsigned xcounts[4];
memset(xcounts, 0, sizeof(xcounts));
@ -420,7 +437,6 @@ void PeFile32::processRelocs() // pass1
orelocs = mb_orelocs; // => orelocs now is a SPAN_S
sorelocs = optimizeReloc(xcounts[3], (byte *) fix[3], orelocs, ibuf + rvamin, ibufgood - rvamin,
32, true, &big_relocs);
delete[] fix[3];
// Malware that hides behind UPX often has PE header info that is
// deliberately corrupt. Sometimes it is even tuned to cause us trouble!
@ -433,7 +449,6 @@ void PeFile32::processRelocs() // pass1
for (ic = 2; ic; ic--) {
memcpy(orelocs + sorelocs, fix[ic], 4 * xcounts[ic]);
sorelocs += 4 * xcounts[ic];
delete[] fix[ic];
set_le32(orelocs + sorelocs, 0);
if (xcounts[ic]) {
@ -471,13 +486,16 @@ void PeFile64::processRelocs() // pass1
return;
}
for (ic = 15; ic; ic--)
for (ic = 0; ic < 16; ic++)
if (ic != 10 && counts[ic])
infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]);
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]);
fixdel.n += 1;
}
unsigned xcounts[16];
memset(xcounts, 0, sizeof(xcounts));
@ -495,7 +513,7 @@ void PeFile64::processRelocs() // pass1
}
// remove duplicated records
for (ic = 1; ic <= 15; ic++) {
for (ic = 1; ic < 16; ic++) {
qsort(fix[ic], xcounts[ic], 4, le32_compare);
unsigned prev = ~0u;
unsigned jc = 0;
@ -520,9 +538,6 @@ void PeFile64::processRelocs() // pass1
sorelocs = optimizeReloc(xcounts[10], (byte *) fix[10], orelocs, ibuf + rvamin,
ibufgood - rvamin, 64, true, &big_relocs);
for (ic = 15; ic; ic--)
delete[] fix[ic];
#if 0
// Malware that hides behind UPX often has PE header info that is
// 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]);
sorelocs += 4 * xcounts[ic];
delete [] fix[ic];
set_le32(orelocs + sorelocs,0);
if (xcounts[ic])
@ -574,7 +588,7 @@ const LE32 &PeFile::IDADDR(unsigned x) const { return iddirs[x].vaddr; }
in the sorted order.
*/
class PeFile::ImportLinker : public ElfLinkerAMD64 {
class PeFile::ImportLinker final : public ElfLinkerAMD64 {
struct tstr : private ::noncopyable {
char *s = nullptr;
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;
if (IDADDR(PEDIR_IMPORT)) {
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));
if (!im->dllname)
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) {
const udll *u1 = *(const udll *const *) p1;
const udll *u2 = *(const udll *const *) p2;
if (u1->isk32)
return -1;
if (u2->isk32)
return 1;
if (!*u1->lookupt)
return 1;
if (!*u2->lookupt)
return -1;
if (u1->isk32 != u2->isk32)
return u1->isk32 ? -1 : 1;
if ((*u1->lookupt != 0) != (*u2->lookupt != 0))
return (*u1->lookupt != 0) ? -1 : 1;
int rc = strcasecmp(u1->name, u2->name);
if (rc)
return rc;
if (u1->ordinal)
return -1;
if (u2->ordinal)
return 1;
if (!u1->shname)
return 1;
if (!u2->shname)
return -1;
if ((u1->ordinal != 0) != (u2->ordinal != 0))
return (u1->ordinal != 0) ? -1 : 1;
if ((u1->shname != nullptr) != (u2->shname != nullptr))
return (u1->shname != nullptr) ? -1 : 1;
rc = (int) (upx_safe_strlen(u1->shname) - upx_safe_strlen(u2->shname));
if (rc)
return rc;
@ -904,8 +910,8 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
importbyordinal = true;
soimport += 2; // ordinal num: 2 bytes
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);
unsigned len = strlen(name);
soimport += len + 1;
@ -919,9 +925,12 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
mb_oimport.clear();
oimport = mb_oimport;
qsort(idlls, dllnum, sizeof(udll *), udll::compare);
qsort(idlls, dllnum, sizeof(*idlls), udll::compare);
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));
// create the new import table
@ -981,7 +990,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
}
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);
if (ptr_diff_bytes(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1),
(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 skip1 = IDADDR(PEDIR_TLS);
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);
memcpy(otls + sizeof(tls), ibuf.subref("bad tls %#x", tlsdatastart, take3), take3);
tlsindex = tlsp->tlsindex - imagebase;
@ -1887,6 +1896,7 @@ void PeFile::processResources(Resource *res) {
soresources = ptr_diff_bytes(ores, oresources);
delete[] keep_icons;
keep_icons = nullptr;
if (!res->clear()) {
// The area occupied by the resource directory is not continuous
// 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 ;-)
}
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) {
if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0)
return;
@ -2646,12 +2666,13 @@ void PeFile::rebuildResources(SPAN_S(byte) & extra_info, unsigned lastvaddr) {
const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
if (lastvaddr > vaddr || (vaddr - lastvaddr) > ibuf.getSize())
if (vaddr < lastvaddr || (vaddr - lastvaddr) > ibuf.getSize())
throwCantUnpack("corrupted PE header");
// TODO: introduce WildPtr for "virtual pointer" pointing before a buffer
const byte *r = ibuf.raw_bytes(0) - lastvaddr;
Resource res(r + vaddr, ibuf, ibuf + ibuf.getSize());
// INFO: use VPtr for "virtual pointer" pointing before a buffer
//// const byte *const r = ibuf.raw_bytes(0) - lastvaddr;
VPtr<const byte> const r{ibuf, lastvaddr};
Resource res(raw_bytes(r + vaddr, 0), ibuf, ibuf + ibuf.getSize());
while (res.next())
if (res.offs() > vaddr) {
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);
// TODO: introduce WildPtr for "virtual pointer" pointing before a buffer
byte *const Obuf = obuf.raw_bytes(0) - rvamin;
// INFO: use VPtr for "virtual pointer" pointing before a buffer
//// byte *const Obuf = obuf.raw_bytes(0) - rvamin;
VPtr<byte> const Obuf{obuf, rvamin};
#if 0
import_desc * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT));
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 * const importednames_start = importednames;
#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_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, const importednames_start, importednames);
#endif
@ -2728,7 +2751,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
if (inamespos) {
// now I rebuild the dll names
omemcpy(dllnames, dname, dlen + 1);
im->dllname = ptr_udiff_bytes(dllnames, Obuf);
im->dllname = ptr_udiff_bytes(dllnames, obuf) + rvamin;
//;;;printf("\ndll: %s:",dllnames);
dllnames += dlen + 1;
} else {
@ -2738,7 +2761,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
if (set_oft)
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
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;
omemcpy(importednames + 2, p, ilen);
//;;;printf(" %s",importednames+2);
*newiat = ptr_udiff_bytes(importednames, Obuf);
*newiat = ptr_udiff_bytes(importednames, obuf) + rvamin;
importednames += 2 + ilen;
} else {
// Beware overlap!
@ -2986,7 +3009,7 @@ void PeFile32::readPeHeader() {
void PeFile32::pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase,
bool 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) {

View File

@ -147,7 +147,7 @@ protected:
unsigned sotls;
unsigned tlsindex;
unsigned tlscb_ptr;
unsigned tls_handler_offset;
unsigned tls_handler_offset = 0;
bool use_tls_callbacks = false;
void processLoadConf(Reloc *, const Interval *, unsigned);
@ -288,7 +288,7 @@ protected:
enum {
IMAGE_SUBSYSTEM_UNKNOWN = 0,
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_OS2_CUI = 5,
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;
}
UiPacker::~UiPacker() {
UiPacker::~UiPacker() noexcept {
cb.reset();
delete s;
s = nullptr;

View File

@ -39,7 +39,7 @@ public:
UiPacker(const Packer *p_);
public:
virtual ~UiPacker();
virtual ~UiPacker() noexcept;
static void uiConfirmUpdate();
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());
}
MemBuffer::~MemBuffer() { this->dealloc(); }
MemBuffer::~MemBuffer() noexcept { this->dealloc(); }
// similar to BoundedPtr, except checks only at creation
// 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);
}
ptr = (pointer) (void *) p;
#if !defined(__SANITIZE_ADDRESS__) && 0
fill(0, size_in_bytes, (rand() & 0xff) | 1); // debug
#if DEBUG
memset(ptr, 0xff, size_in_bytes);
(void) VALGRIND_MAKE_MEM_UNDEFINED(ptr, size_in_bytes);
#endif
stats.global_alloc_counter += 1;
stats.global_total_bytes += size_in_bytes;
stats.global_total_active_bytes += size_in_bytes;
#if DEBUG
#if DEBUG || 1
checkState();
#endif
}
void MemBuffer::dealloc() {
void MemBuffer::dealloc() noexcept {
if (ptr != nullptr) {
debug_set(debug.last_return_address_dealloc, upx_return_address());
checkState();

View File

@ -46,11 +46,12 @@ protected:
size_type size_in_bytes;
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
// 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
template <class U>
@ -66,8 +67,8 @@ private:
DELETED_FUNCTION;
public: // raw access
pointer raw_ptr() const { return ptr; }
size_type raw_size_in_bytes() const { return size_in_bytes; }
pointer raw_ptr() const noexcept { return ptr; }
size_type raw_size_in_bytes() const noexcept { return size_in_bytes; }
pointer raw_bytes(size_t bytes) const {
if (bytes > 0) {
@ -84,7 +85,7 @@ class MemBuffer final : public MemBufferBase<byte> {
public:
MemBuffer() : MemBufferBase<byte>() {}
explicit MemBuffer(upx_uint64_t bytes);
~MemBuffer();
~MemBuffer() noexcept;
static unsigned getSizeForCompression(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 allocForDecompression(unsigned uncompressed_size, unsigned extra = 0);
void dealloc();
void dealloc() noexcept;
void checkState() const;
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
template <class T>
inline
typename std::enable_if<std::is_pointer<T>::value && !std_is_bounded_array<T>::value, T>::type
raw_bytes(T ptr, size_t size_in_bytes) {
inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_is_bounded_array<T>::value &&
(upx_is_integral<typename std::remove_pointer<T>::type>::value ||
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 very_unlikely (ptr == nullptr)
throwCantPack("raw_bytes unexpected NULL ptr");
@ -50,9 +52,10 @@ inline
// default: for any regular pointer, raw_index_bytes() is just "pointer + index"
// NOTE: index == number of elements, *NOT* size in bytes!
template <class T>
inline
typename std::enable_if<std::is_pointer<T>::value && !std_is_bounded_array<T>::value, T>::type
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_is_bounded_array<T>::value &&
upx_is_integral<typename std::remove_pointer<T>::type>::value,
T>::type
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
typedef typename std::remove_pointer<T>::type element_type;
if very_unlikely (ptr == nullptr)
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
/*************************************************************************
// 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) {
return (unsigned char *) strcpy((char *) s1, (const char *) s2);
forceinline uchar *strcpy(uchar *s1, const uchar *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); }
inline int strcmp(const char *s1, const unsigned char *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 char *s2) { return strcmp((const char *) s1, s2); }
forceinline int strcmp(const char *s1, const uchar *s2) { return strcmp(s1, (const char *) s2); }
forceinline int strcmp(const uchar *s1, const uchar *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);
}
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);
}
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);
}
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);
}

View File

@ -101,6 +101,10 @@ TEST_CASE("mem_size") {
CHECK_THROWS(mem_size(1, 0x30000000, 0x30000000, 0x30000000));
}
/*************************************************************************
// ptr util
**************************************************************************/
int ptr_diff_bytes(const void *a, const void *b) {
if very_unlikely (a == nullptr) {
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) {
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 very_unlikely (!mem_size_valid_bytes(d))
throwCantPack("ptr_diff_bytes 1; take care");
throwCantPack("ptr_diff_bytes-1; take care");
} else {
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);
}
@ -127,7 +131,7 @@ unsigned ptr_udiff_bytes(const void *a, const void *b) {
}
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(buf, nullptr));
CHECK(ptr_diff(buf, buf) == 0);
@ -138,6 +142,108 @@ TEST_CASE("ptr_diff") {
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
**************************************************************************/
@ -152,6 +258,60 @@ const BEPolicy be_policy;
const LEPolicy le_policy;
} // 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
**************************************************************************/
@ -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) {
// 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;
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_sep(c) (strchr(dir_sep, c) != nullptr)
#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

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,
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
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
upx_uint64_t extra2 = 0);
@ -77,6 +74,27 @@ inline void mem_clear(void *p, size_t 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
// NOTE: returns size_in_bytes, not number of elements!
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);
}
// 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
**************************************************************************/

View File

@ -44,28 +44,28 @@ struct XSpanStats {
static XSpanStats xspan_stats;
// 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;
throwCantPack("xspan unexpected NULL pointer; take care!");
}
noinline void xspan_fail_nullbase() {
void xspan_fail_nullbase() {
xspan_stats.fail_nullbase += 1;
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;
throwCantPack("xspan unexpected base pointer; take care!");
}
noinline void xspan_fail_range_nullptr() {
void xspan_fail_range_nullptr() {
xspan_stats.fail_range_nullptr += 1;
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;
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;
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();
if very_unlikely (base == nullptr)
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)
xspan_fail_range_range();
xspan_stats.check_range_counter += 1;

View File

@ -146,8 +146,11 @@ inline R *xspan_make_helper__(R * /*dummy*/, MemBuffer &first) {
#endif // WITH_XSPAN
#if 1
/*************************************************************************
// nicer names
**************************************************************************/
#if 1
#define SPAN_0 XSPAN_0
#define SPAN_P XSPAN_P
#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
struct XSpanCount {
explicit XSpanCount(size_t n) : count(n) {}
explicit XSpanCount(size_t n) noexcept : count(n) {}
size_t count; // public
};
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
};

View File

@ -28,165 +28,176 @@
//
**************************************************************************/
public:
typedef T element_type;
typedef typename std::add_lvalue_reference<T>::type reference;
typedef typename std::add_pointer<T>::type pointer;
typedef size_t size_type;
#if CLANG_FORMAT_DUMMY_CLASS
class CSelf {
#endif
// befriend all
template <class>
friend struct PtrOrSpan;
template <class>
friend struct PtrOrSpanOrNull;
template <class>
friend struct Span;
public:
typedef T element_type;
typedef typename std::add_lvalue_reference<T>::type reference;
typedef typename std::add_pointer<T>::type pointer;
typedef size_t size_type;
// befriend all
template <class>
friend struct PtrOrSpan;
template <class>
friend struct PtrOrSpanOrNull;
template <class>
friend struct Span;
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION
operator pointer() const { return ptr; }
public:
operator pointer() const noexcept { return ptr; }
#endif
private:
pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr
pointer base;
size_type size_in_bytes;
pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr
pointer base;
size_type size_in_bytes;
// debug - internal sanity check; also serves as pseudo-documentation
#if DEBUG
noinline void assertInvariants() const {
noinline void assertInvariants() const {
if __acc_cte (configRequirePtr)
assert(ptr != nullptr);
if __acc_cte (configRequireBase)
assert(base != nullptr);
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
}
}
#else
forceinline void assertInvariants() const {}
inline void assertInvariants() const noexcept {}
#endif
static forceinline pointer makeNotNull(pointer p) {
static inline pointer makeNotNull(pointer p) {
if very_unlikely (p == nullptr)
xspan_fail_nullptr();
return p;
}
// enforce config invariants at constructor time - static functions
static forceinline pointer makePtr(pointer p) {
}
// enforce config invariants at constructor time - static functions
static inline pointer makePtr(pointer p) {
if __acc_cte (configRequirePtr && p == nullptr)
xspan_fail_nullptr();
return p;
}
static forceinline pointer makeBase(pointer b) {
}
static inline pointer makeBase(pointer b) {
if __acc_cte (configRequireBase && b == nullptr)
xspan_fail_nullbase();
return b;
}
// inverse logic for ensuring valid pointers from existing objets
forceinline pointer ensurePtr() const {
}
// inverse logic for ensuring valid pointers from existing objects
inline pointer ensurePtr() const {
if __acc_cte (!configRequirePtr && ptr == nullptr)
xspan_fail_nullptr();
return ptr;
}
forceinline pointer ensureBase() const {
}
inline pointer ensureBase() const {
if __acc_cte (!configRequireBase && base == nullptr)
xspan_fail_nullbase();
return base;
}
}
public:
inline ~CSelf() {
#if DEBUG
invalidate();
inline ~CSelf() { invalidate(); }
#else
inline ~CSelf() noexcept {}
#endif
}
noinline void invalidate() {
noinline void invalidate() {
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
base = ptr;
size_in_bytes = 0;
assertInvariants();
}
// constructors from pointers
CSelf(pointer first, XSpanCount count)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count.count)) {
}
// constructors from pointers
CSelf(pointer first, XSpanCount count)
: ptr(makePtr(first)), base(makeBase(first)),
size_in_bytes(xspan_mem_size<T>(count.count)) {
assertInvariants();
}
CSelf(pointer first, XSpanSizeInBytes bytes)
}
CSelf(pointer first, XSpanSizeInBytes bytes)
: ptr(makePtr(first)), base(makeBase(first)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(U *first, size_type count, XSPAN_REQUIRES_SIZE_1_A)
}
// enable this constructor only if the underlying type is char or void
template <class U>
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)) {
assertInvariants();
}
CSelf(pointer first, XSpanCount count, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count.count)) {
}
CSelf(pointer first, XSpanCount count, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)),
size_in_bytes(xspan_mem_size<T>(count.count)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
CSelf(pointer first, XSpanSizeInBytes bytes, pointer base_)
}
CSelf(pointer first, XSpanSizeInBytes bytes, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)),
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(ptr, base, size_in_bytes);
// double sanity check
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(pointer first, size_type count, U *base_, XSPAN_REQUIRES_SIZE_1_A)
}
// enable this constructor only if the underlying type is char or void
template <class U>
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)) {
// check invariants
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
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
// constructors from MemBuffer
CSelf(MemBuffer &mb)
// constructors from MemBuffer
CSelf(MemBuffer &mb)
: CSelf(makeNotNull((pointer) membuffer_get_void_ptr(mb)),
XSpanSizeInBytes(membuffer_get_size(mb))) {}
CSelf(pointer first, MemBuffer &mb)
CSelf(pointer first, MemBuffer &mb)
: CSelf(first, XSpanSizeInBytes(membuffer_get_size(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
// disable constructors from nullptr to catch compile-time misuse
// disable constructors from nullptr to catch compile-time misuse
private:
CSelf(std::nullptr_t, XSpanCount) 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(std::nullptr_t, XSpanSizeInBytes) 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(std::nullptr_t, size_type) 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(std::nullptr_t, XSpanCount) 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(std::nullptr_t, XSpanSizeInBytes) 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(std::nullptr_t, size_type) 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;
// unchecked constructor
// unchecked constructor
protected:
enum ModeUnchecked { Unchecked };
CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b)
enum ModeUnchecked { Unchecked };
CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b)
: ptr(p), base(b), size_in_bytes(bytes) {
assertInvariants();
}
// unchecked assignment
Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) {
}
// unchecked assignment
Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) {
ptr = p;
base = b;
size_in_bytes = bytes;
assertInvariants();
return *this;
}
}
#if 0
Self &assign(ModeUnchecked, const Self &other) {
ptr = other.ptr;
@ -198,19 +209,20 @@ Self &assign(ModeUnchecked, const Self &other) {
#endif
public:
// assignment - here we can rely on invariants enforced at construction time by makePtr/makeBase
// NOTE: *this remains unmodified in case of failure
Self &assign(pointer other) {
// assignment - here we can rely on invariants enforced at construction time by makePtr/makeBase
// NOTE: *this remains unmodified in case of failure
Self &assign(pointer other) {
assertInvariants();
other = makePtr(other);
if __acc_cte ((configRequirePtr || other != nullptr) && (configRequireBase || base != nullptr))
if __acc_cte ((configRequirePtr || other != nullptr) &&
(configRequireBase || base != nullptr))
xspan_check_range(other, base, size_in_bytes);
// ok
ptr = other;
assertInvariants();
return *this;
}
Self &assign(const Self &other) {
}
Self &assign(const Self &other) {
assertInvariants();
other.assertInvariants();
if __acc_cte (!configRequireBase && base == nullptr) {
@ -235,154 +247,154 @@ Self &assign(const Self &other) {
}
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??
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const CSelf<U> &other) {
// FIXME: this is not called??
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const CSelf<U> &other) {
// assert(0);
return assign(Self(other));
}
}
#ifdef UPX_VERSION_HEX
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
#endif
Self subspan(ptrdiff_t offset, ptrdiff_t count) {
Self subspan(ptrdiff_t offset, ptrdiff_t count) {
pointer begin = check_add(ptr, offset);
pointer end = check_add(begin, count);
if (begin <= end)
return Self(Unchecked, begin, (end - begin) * sizeof(T), begin);
else
return Self(Unchecked, end, (begin - end) * sizeof(T), end);
}
}
bool operator==(pointer other) const { return ptr == other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(U *other) const {
bool operator==(pointer other) const { return ptr == other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(U *other) const {
return ptr == other;
}
bool operator!=(pointer other) const { return ptr != other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(U *other) const {
}
bool operator!=(pointer other) const { return ptr != other; }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(U *other) const {
return ptr != other;
}
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpan<U> &other) const {
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpan<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpanOrNull<U> &other) const {
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpanOrNull<U> &other) const {
return ptr == other.ptr;
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const Span<U> &other) const {
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const Span<U> &other) const {
return ptr == other.ptr;
}
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpan<U> &other) const {
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpan<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpanOrNull<U> &other) const {
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpanOrNull<U> &other) const {
return !(*this == other);
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const Span<U> &other) const {
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const Span<U> &other) const {
return !(*this == other);
}
}
// check for notNull here
bool operator<(std::nullptr_t) const XSPAN_DELETED_FUNCTION;
bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); }
// check for notNull here
bool operator<(std::nullptr_t) const XSPAN_DELETED_FUNCTION;
bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); }
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpan<U> &other) const {
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpan<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpanOrNull<U> &other) const {
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpanOrNull<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const Span<U> &other) const {
}
template <class U>
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const Span<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
}
// dereference
reference operator*() const { return *check_deref(ptr); }
// dereference
reference operator*() const { return *check_deref(ptr); }
// array access
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
// array access
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
// arrow operator
pointer operator->() const { return check_deref(ptr); }
// arrow operator
pointer operator->() const { return check_deref(ptr); }
Self &operator++() {
Self &operator++() {
ptr = check_add(ptr, 1);
return *this;
}
Self operator++(int) {
}
Self operator++(int) {
Self tmp = *this;
++*this;
return tmp;
}
Self &operator--() {
}
Self &operator--() {
ptr = check_add(ptr, -1);
return *this;
}
Self operator--(int) {
}
Self operator--(int) {
Self tmp = *this;
--*this;
return tmp;
}
}
Self &operator+=(ptrdiff_t n) {
Self &operator+=(ptrdiff_t n) {
ptr = check_add(ptr, n);
return *this;
}
Self &operator-=(ptrdiff_t n) {
}
Self &operator-=(ptrdiff_t n) {
ptr = check_add(ptr, -n);
return *this;
}
}
Self operator+(ptrdiff_t n) const {
Self operator+(ptrdiff_t n) const {
pointer first = check_add(ptr, n);
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);
return Self(Unchecked, first, size_in_bytes, base);
}
}
private:
pointer check_deref(pointer p) const {
pointer check_deref(pointer p) const {
if __acc_cte (!configRequirePtr && p == nullptr)
xspan_fail_nullptr();
if __acc_cte (configRequireBase || base != nullptr)
xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants();
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)
xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n);
@ -391,8 +403,8 @@ pointer check_deref(pointer p, ptrdiff_t n) const {
xspan_check_range(p, base, size_in_bytes - sizeof(T));
assertInvariants();
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)
xspan_fail_nullptr();
xspan_mem_size_assert_ptrdiff<T>(n);
@ -401,18 +413,18 @@ pointer check_add(pointer p, ptrdiff_t n) const {
xspan_check_range(p, base, size_in_bytes);
assertInvariants();
return p;
}
}
// 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]
Self *operator&() const XSPAN_DELETED_FUNCTION;
// 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]
Self *operator&() const XSPAN_DELETED_FUNCTION;
public: // raw access
pointer raw_ptr() const { return ptr; }
pointer raw_base() const { return base; }
size_type raw_size_in_bytes() const { return size_in_bytes; }
pointer raw_ptr() const noexcept { return ptr; }
pointer raw_base() const noexcept { return base; }
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();
if (bytes > 0) {
if __acc_cte (!configRequirePtr && ptr == nullptr)
@ -422,6 +434,25 @@ pointer raw_bytes(size_t bytes) const {
}
}
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: */

View File

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

View File

@ -26,7 +26,7 @@
*/
// 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.
// And see p_com.cpp for a simple executable format.
@ -141,7 +141,7 @@ void do_one_file(const char *iname, char *oname) {
else
flags |= O_EXCL;
int shmode = SH_DENYWR;
#if defined(__MINT__)
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
flags |= O_TRUNC;
shmode = O_DENYRW;
#endif
@ -266,7 +266,7 @@ static void unlink_ofile(char *oname) {
int do_files(int i, int argc, char *argv[]) {
upx_compiler_sanity_check();
if (opt->verbose >= 1) {
show_head();
show_header();
UiPacker::uiHeader();
}