From c75d7a685dd73da33abc08e16cbdb984d02b16f1 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Sun, 11 Sep 2022 16:03:56 +0200 Subject: [PATCH] src: major cleanups, introduce new eXtended Span class - initial minimally invasive eXtended Span implementation - rename ptr_diff to ptr_diff_bytes - move some files to util subdir - lots of cleanups - start using the new checked pointers - this needs some real-world testing --- .github/workflows/ci.yml | 6 +- CMakeLists.txt | 6 +- src/Makefile | 11 +- src/bele.h | 81 ++-- src/bele_policy.h | 2 +- src/bptr.h | 106 ---- src/compress.cpp | 2 +- src/compress_lzma.cpp | 2 +- src/compress_ucl.cpp | 2 +- src/compress_zlib.cpp | 2 +- src/conf.h | 57 ++- src/except.h | 51 +- src/file.cpp | 334 ++++--------- src/file.h | 161 ++----- src/lefile.cpp | 30 +- src/lefile.h | 8 +- src/main.cpp | 2 +- src/mem.h | 88 ---- src/options.h | 5 +- src/p_djgpp2.h | 32 +- src/p_exe.cpp | 21 +- src/p_lx_elf.cpp | 4 +- src/p_mach.cpp | 4 +- src/p_ps1.h | 38 +- src/p_tmt.cpp | 19 +- src/p_tmt.h | 30 +- src/p_tos.cpp | 4 +- src/p_wcle.cpp | 79 +-- src/packer.cpp | 107 +++-- src/packer.h | 72 +-- src/packhead.cpp | 10 +- src/pefile.cpp | 224 +++++---- src/pefile.h | 56 +-- src/stub/tools/macho-snip/macho-snip.c | 2 +- src/ui.h | 1 + src/util/bptr.h | 142 ++++++ src/{ => util}/dt_check.cpp | 40 +- src/{ => util}/dt_impl.cpp | 0 src/{mem.cpp => util/membuffer.cpp} | 228 ++++----- src/util/membuffer.h | 127 +++++ src/{ => util}/snprintf.cpp | 2 +- src/{ => util}/snprintf.h | 16 +- src/{ => util}/util.cpp | 91 ++-- src/{ => util}/util.h | 76 ++- src/util/xspan.cpp | 637 +++++++++++++++++++++++++ src/util/xspan.h | 144 ++++++ src/util/xspan_fwd.h | 293 ++++++++++++ src/util/xspan_impl.h | 240 ++++++++++ src/util/xspan_impl_common.h | 417 ++++++++++++++++ src/util/xspan_impl_ptr.h | 209 ++++++++ src/util/xspan_impl_ptr_or_null.h | 108 +++++ src/util/xspan_impl_ptr_or_span.h | 133 ++++++ src/util/xspan_impl_span.h | 135 ++++++ src/work.cpp | 20 +- 54 files changed, 3521 insertions(+), 1196 deletions(-) delete mode 100644 src/bptr.h delete mode 100644 src/mem.h create mode 100644 src/util/bptr.h rename src/{ => util}/dt_check.cpp (90%) rename src/{ => util}/dt_impl.cpp (100%) rename src/{mem.cpp => util/membuffer.cpp} (51%) create mode 100644 src/util/membuffer.h rename src/{ => util}/snprintf.cpp (99%) rename src/{ => util}/snprintf.h (87%) rename src/{ => util}/util.cpp (87%) rename src/{ => util}/util.h (58%) create mode 100644 src/util/xspan.cpp create mode 100644 src/util/xspan.h create mode 100644 src/util/xspan_fwd.h create mode 100644 src/util/xspan_impl.h create mode 100644 src/util/xspan_impl_common.h create mode 100644 src/util/xspan_impl_ptr.h create mode 100644 src/util/xspan_impl_ptr_or_null.h create mode 100644 src/util/xspan_impl_ptr_or_span.h create mode 100644 src/util/xspan_impl_span.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17120fa5..db32a82c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -311,18 +311,18 @@ jobs: @REM build UCL cd %BDIR%\ucl set s=%H%\upx\vendor\ucl - cl -MT -O2 -W4 %DEFS% -I%s%\include -I%s% -c %s%\src\*.c + cl -MT -J -O2 -W4 %DEFS% -I%s%\include -I%s% -c %s%\src\*.c link -lib -out:ucl.lib *.obj @REM build zlib cd %BDIR%\zlib - cl -MT -O2 -W3 %DEFS% -c %H%\upx\vendor\zlib\*.c + cl -MT -J -O2 -W3 %DEFS% -c %H%\upx\vendor\zlib\*.c link -lib -out:zlib.lib *.obj @REM build UPX cd %BDIR%\upx set s=%H%\upx\src cat .GITREV.txt set /p GITREV=<.GITREV.txt - cl -MT -EHsc -J -O2 -W4 -WX -DUPX_VERSION_GITREV="""%GITREV%""" %DEFS% -I%H%\upx\vendor\doctest -I%H%\upx\vendor\lzma-sdk -I%H%\upx\vendor\ucl\include -I%H%\upx\vendor\zlib -Feupx.exe %s%\*.cpp %BDIR%\ucl\ucl.lib %BDIR%\zlib\zlib.lib /link setargv.obj + cl -MT -EHsc -J -O2 -W4 -WX -DUPX_VERSION_GITREV="""%GITREV%""" %DEFS% -I%H%\upx\vendor\doctest -I%H%\upx\vendor\lzma-sdk -I%H%\upx\vendor\ucl\include -I%H%\upx\vendor\zlib -Feupx.exe %s%\*.cpp %s%\util\*.cpp %BDIR%\ucl\ucl.lib %BDIR%\zlib\zlib.lib /link setargv.obj - name: 'Basic tests' shell: cmd diff --git a/CMakeLists.txt b/CMakeLists.txt index a7e8c22d..07ffbb8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,7 @@ list(SORT zlib_SOURCES) add_library(upx_vendor_zlib STATIC ${zlib_SOURCES}) set_property(TARGET upx_vendor_zlib PROPERTY C_STANDARD 11) -file(GLOB upx_SOURCES "src/*.cpp") +file(GLOB upx_SOURCES "src/*.cpp" "src/util/*.cpp") list(SORT upx_SOURCES) add_executable(upx ${upx_SOURCES}) set_property(TARGET upx PROPERTY CXX_STANDARD 14) @@ -124,14 +124,14 @@ endif() set(t upx_vendor_ucl) target_include_directories(${t} PRIVATE vendor/ucl/include vendor/ucl) if(MSVC) - target_compile_options(${t} PRIVATE -W4 ${warn_WX}) + target_compile_options(${t} PRIVATE -J -W4 ${warn_WX}) else() target_compile_options(${t} PRIVATE -Wall -Wextra -Wvla ${warn_Werror}) endif() set(t upx_vendor_zlib) if(MSVC) - target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_VSNPRINTF -W3 ${warn_WX}) + target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_VSNPRINTF -J -W3 ${warn_WX}) else() target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_UNISTD_H -DHAVE_VSNPRINTF) target_compile_options(${t} PRIVATE -Wall -Wextra -Wvla ${warn_Werror}) diff --git a/src/Makefile b/src/Makefile index b36a99ea..d340a4de 100644 --- a/src/Makefile +++ b/src/Makefile @@ -55,7 +55,7 @@ ALL_LDFLAGS = $(strip $(call all_flags,LDFLAGS)) ALL_LDADD = $(strip $(call all_flags,LDADD)) ALL_LIBS = $(strip $(call all_flags,LIBS)) -upx_SOURCES := $(sort $(wildcard $(srcdir)/*.cpp)) +upx_SOURCES := $(sort $(wildcard $(srcdir)/*.cpp $(srcdir)/util/*.cpp)) upx_OBJECTS := $(notdir $(upx_SOURCES:.cpp=$(objext))) ifneq ($(wildcard $(top_srcdir)/.git/.),) @@ -131,6 +131,8 @@ upx$(exeext): $(upx_OBJECTS) $(upx_DEPENDENCIES) %.o : %.cpp | ./.depend $(strip $(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -o $@ -c $<) +%.o : util/%.cpp | ./.depend + $(strip $(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -o $@ -c $<) %.cpp.ii : %.cpp $(strip $(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -o $@ -E $<) @@ -207,13 +209,14 @@ endif # automatically format some C++ source code files ifeq ($(shell uname),Linux) CLANG_FORMAT_FILES += bele.h bele_policy.h -CLANG_FORMAT_FILES += dt_check.cpp dt_impl.cpp except.cpp except.h +CLANG_FORMAT_FILES += except.cpp except.h +CLANG_FORMAT_FILES += file.cpp file.h CLANG_FORMAT_FILES += linker.cpp linker.h packhead.cpp packmast.cpp packmast.h CLANG_FORMAT_FILES += main.cpp options.cpp options.h packer.cpp packer.h CLANG_FORMAT_FILES += p_tos.cpp p_tos.h CLANG_FORMAT_FILES += s_djgpp2.cpp s_object.cpp s_vcsa.cpp s_win32.cpp screen.h -CLANG_FORMAT_FILES += snprintf.cpp -CLANG_FORMAT_FILES += ui.cpp ui.h util.cpp util.h work.cpp +CLANG_FORMAT_FILES += ui.cpp ui.h work.cpp +CLANG_FORMAT_FILES += $(wildcard util/[a-ln-z]*.[ch]* util/mem*.[ch]*) clang-format: $(top_srcdir)/misc/scripts/upx-clang-format -i $(addprefix $(top_srcdir)/src/,$(sort $(CLANG_FORMAT_FILES))) .PHONY: clang-format diff --git a/src/bele.h b/src/bele.h index 4a3d5527..71b03b15 100644 --- a/src/bele.h +++ b/src/bele.h @@ -25,8 +25,9 @@ */ -#ifndef __UPX_BELE_H -#define __UPX_BELE_H 1 +#pragma once +#ifndef UPX_BELE_H__ +#define UPX_BELE_H__ 1 // BE - Big Endian // LE - Little Endian @@ -294,6 +295,8 @@ struct alignas(1) BE16 { } operator unsigned() const { return get_be16(d); } + + bool operator<(const BE16 &v) const { return unsigned(*this) < unsigned(v); } }; struct alignas(1) BE32 { @@ -341,6 +344,8 @@ struct alignas(1) BE32 { } operator unsigned() const { return get_be32(d); } + + bool operator<(const BE32 &v) const { return unsigned(*this) < unsigned(v); } }; struct alignas(1) BE64 { @@ -388,6 +393,8 @@ struct alignas(1) BE64 { } operator upx_uint64_t() const { return get_be64(d); } + + bool operator<(const BE64 &v) const { return upx_uint64_t(*this) < upx_uint64_t(v); } }; struct alignas(1) LE16 { @@ -435,6 +442,8 @@ struct alignas(1) LE16 { } operator unsigned() const { return get_le16(d); } + + bool operator<(const LE16 &v) const { return unsigned(*this) < unsigned(v); } }; struct alignas(1) LE32 { @@ -482,6 +491,8 @@ struct alignas(1) LE32 { } operator unsigned() const { return get_le32(d); } + + bool operator<(const LE32 &v) const { return unsigned(*this) < unsigned(v); } }; struct alignas(1) LE64 { @@ -529,6 +540,8 @@ struct alignas(1) LE64 { } operator upx_uint64_t() const { return get_le64(d); } + + bool operator<(const LE64 &v) const { return upx_uint64_t(*this) < upx_uint64_t(v); } }; // native types @@ -548,20 +561,20 @@ typedef LE64 NE64; template inline T *operator+(T *ptr, const BE16 &v) { - return ptr + (unsigned) v; + return ptr + unsigned(v); } template inline T *operator-(T *ptr, const BE16 &v) { - return ptr - (unsigned) v; + return ptr - unsigned(v); } template inline T *operator+(T *ptr, const BE32 &v) { - return ptr + (unsigned) v; + return ptr + unsigned(v); } template inline T *operator-(T *ptr, const BE32 &v) { - return ptr - (unsigned) v; + return ptr - unsigned(v); } // these are not implemented on purpose and will cause link-time errors @@ -572,20 +585,20 @@ T *operator-(T *ptr, const BE64 &v); template inline T *operator+(T *ptr, const LE16 &v) { - return ptr + (unsigned) v; + return ptr + unsigned(v); } template inline T *operator-(T *ptr, const LE16 &v) { - return ptr - (unsigned) v; + return ptr - unsigned(v); } template inline T *operator+(T *ptr, const LE32 &v) { - return ptr + (unsigned) v; + return ptr + unsigned(v); } template inline T *operator-(T *ptr, const LE32 &v) { - return ptr - (unsigned) v; + return ptr - unsigned(v); } // these are not implemented on purpose and will cause link-time errors @@ -598,35 +611,35 @@ T *operator-(T *ptr, const LE64 &v); // global overloads **************************************************************************/ -inline unsigned ALIGN_DOWN(unsigned a, const BE32 &b) { return ALIGN_DOWN(a, (unsigned) b); } -inline unsigned ALIGN_DOWN(const BE32 &a, unsigned b) { return ALIGN_DOWN((unsigned) a, b); } -inline unsigned ALIGN_UP(unsigned a, const BE32 &b) { return ALIGN_UP(a, (unsigned) b); } -inline unsigned ALIGN_UP(const BE32 &a, unsigned b) { return ALIGN_UP((unsigned) a, b); } +inline unsigned ALIGN_DOWN(unsigned a, const BE32 &b) { return ALIGN_DOWN(a, unsigned(b)); } +inline unsigned ALIGN_DOWN(const BE32 &a, unsigned b) { return ALIGN_DOWN(unsigned(a), b); } +inline unsigned ALIGN_UP(unsigned a, const BE32 &b) { return ALIGN_UP(a, unsigned(b)); } +inline unsigned ALIGN_UP(const BE32 &a, unsigned b) { return ALIGN_UP(unsigned(a), b); } -inline unsigned ALIGN_DOWN(unsigned a, const LE32 &b) { return ALIGN_DOWN(a, (unsigned) b); } -inline unsigned ALIGN_DOWN(const LE32 &a, unsigned b) { return ALIGN_DOWN((unsigned) a, b); } -inline unsigned ALIGN_UP(unsigned a, const LE32 &b) { return ALIGN_UP(a, (unsigned) b); } -inline unsigned ALIGN_UP(const LE32 &a, unsigned b) { return ALIGN_UP((unsigned) a, b); } +inline unsigned ALIGN_DOWN(unsigned a, const LE32 &b) { return ALIGN_DOWN(a, unsigned(b)); } +inline unsigned ALIGN_DOWN(const LE32 &a, unsigned b) { return ALIGN_DOWN(unsigned(a), b); } +inline unsigned ALIGN_UP(unsigned a, const LE32 &b) { return ALIGN_UP(a, unsigned(b)); } +inline unsigned ALIGN_UP(const LE32 &a, unsigned b) { return ALIGN_UP(unsigned(a), b); } -inline unsigned UPX_MAX(unsigned a, const BE16 &b) { return UPX_MAX(a, (unsigned) b); } -inline unsigned UPX_MAX(const BE16 &a, unsigned b) { return UPX_MAX((unsigned) a, b); } -inline unsigned UPX_MIN(unsigned a, const BE16 &b) { return UPX_MIN(a, (unsigned) b); } -inline unsigned UPX_MIN(const BE16 &a, unsigned b) { return UPX_MIN((unsigned) a, b); } +inline unsigned UPX_MAX(unsigned a, const BE16 &b) { return UPX_MAX(a, unsigned(b)); } +inline unsigned UPX_MAX(const BE16 &a, unsigned b) { return UPX_MAX(unsigned(a), b); } +inline unsigned UPX_MIN(unsigned a, const BE16 &b) { return UPX_MIN(a, unsigned(b)); } +inline unsigned UPX_MIN(const BE16 &a, unsigned b) { return UPX_MIN(unsigned(a), b); } -inline unsigned UPX_MAX(unsigned a, const BE32 &b) { return UPX_MAX(a, (unsigned) b); } -inline unsigned UPX_MAX(const BE32 &a, unsigned b) { return UPX_MAX((unsigned) a, b); } -inline unsigned UPX_MIN(unsigned a, const BE32 &b) { return UPX_MIN(a, (unsigned) b); } -inline unsigned UPX_MIN(const BE32 &a, unsigned b) { return UPX_MIN((unsigned) a, b); } +inline unsigned UPX_MAX(unsigned a, const BE32 &b) { return UPX_MAX(a, unsigned(b)); } +inline unsigned UPX_MAX(const BE32 &a, unsigned b) { return UPX_MAX(unsigned(a), b); } +inline unsigned UPX_MIN(unsigned a, const BE32 &b) { return UPX_MIN(a, unsigned(b)); } +inline unsigned UPX_MIN(const BE32 &a, unsigned b) { return UPX_MIN(unsigned(a), b); } -inline unsigned UPX_MAX(unsigned a, const LE16 &b) { return UPX_MAX(a, (unsigned) b); } -inline unsigned UPX_MAX(const LE16 &a, unsigned b) { return UPX_MAX((unsigned) a, b); } -inline unsigned UPX_MIN(unsigned a, const LE16 &b) { return UPX_MIN(a, (unsigned) b); } -inline unsigned UPX_MIN(const LE16 &a, unsigned b) { return UPX_MIN((unsigned) a, b); } +inline unsigned UPX_MAX(unsigned a, const LE16 &b) { return UPX_MAX(a, unsigned(b)); } +inline unsigned UPX_MAX(const LE16 &a, unsigned b) { return UPX_MAX(unsigned(a), b); } +inline unsigned UPX_MIN(unsigned a, const LE16 &b) { return UPX_MIN(a, unsigned(b)); } +inline unsigned UPX_MIN(const LE16 &a, unsigned b) { return UPX_MIN(unsigned(a), b); } -inline unsigned UPX_MAX(unsigned a, const LE32 &b) { return UPX_MAX(a, (unsigned) b); } -inline unsigned UPX_MAX(const LE32 &a, unsigned b) { return UPX_MAX((unsigned) a, b); } -inline unsigned UPX_MIN(unsigned a, const LE32 &b) { return UPX_MIN(a, (unsigned) b); } -inline unsigned UPX_MIN(const LE32 &a, unsigned b) { return UPX_MIN((unsigned) a, b); } +inline unsigned UPX_MAX(unsigned a, const LE32 &b) { return UPX_MAX(a, unsigned(b)); } +inline unsigned UPX_MAX(const LE32 &a, unsigned b) { return UPX_MAX(unsigned(a), b); } +inline unsigned UPX_MIN(unsigned a, const LE32 &b) { return UPX_MIN(a, unsigned(b)); } +inline unsigned UPX_MIN(const LE32 &a, unsigned b) { return UPX_MIN(unsigned(a), b); } /************************************************************************* // misc support diff --git a/src/bele_policy.h b/src/bele_policy.h index 1b7eb5c5..91a09c56 100644 --- a/src/bele_policy.h +++ b/src/bele_policy.h @@ -25,7 +25,7 @@ */ -#ifndef __UPX_BELE_H +#ifndef UPX_BELE_H__ #error "this is an internal include file" #endif diff --git a/src/bptr.h b/src/bptr.h deleted file mode 100644 index 74628077..00000000 --- a/src/bptr.h +++ /dev/null @@ -1,106 +0,0 @@ -/* bptr.h -- - - This file is part of the UPX executable compressor. - - Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996-2022 Laszlo Molnar - All Rights Reserved. - - UPX and the UCL library are free software; you can redistribute them - and/or modify them under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - Markus F.X.J. Oberhumer Laszlo Molnar - - */ - - -#ifndef __UPX_BPTR_H -#define __UPX_BPTR_H 1 - - -/************************************************************************* -// BoundedPtr -**************************************************************************/ - -template -class BoundedPtr -{ -public: - //typedef T* StoredType; - //typedef T* PointerType; - //typedef T& ReferenceType; - - ~BoundedPtr() { } - - BoundedPtr(void* base, size_t size_in_bytes, T* ptr=nullptr) - : ptr_(ptr), base_(base), size_in_bytes_(0) - { - assert(base_ != nullptr); - size_in_bytes_ = mem_size(1, size_in_bytes); - check(); - } - - // assignment - BoundedPtr& operator= (const BoundedPtr& other) { - assert(base_ == other.base_); - assert(size_in_bytes_ == other.size_in_bytes_); - ptr_ = other.ptr_; check(); return *this; - } - BoundedPtr& operator= (T* other) { - ptr_ = other; check(); return *this; - } - - operator T* () { return ptr_; } - operator const T* () const { return ptr_; } - - BoundedPtr& operator += (size_t n) { - checkNULL(); ptr_ += n; checkRange(); return *this; - } - BoundedPtr& operator -= (size_t n) { - checkNULL(); ptr_ -= n; checkRange(); return *this; - } - BoundedPtr& operator ++ (void) { - checkNULL(); ptr_ += 1; checkRange(); return *this; - } - -private: - void checkNULL() const { - if __acc_very_unlikely(!ptr_) - throwCantUnpack("unexpected NULL pointer; take care!"); - } - void checkRange() const { - size_t off = (const char *) ptr_ - (const char *) base_; - if __acc_very_unlikely(off > size_in_bytes_) - throwCantUnpack("pointer out of range; take care!"); - } - void check() const { // check ptr_ invariant: either NULL or valid checkRange() - if (ptr_ != nullptr) - checkRange(); - } - - T* ptr_; - void* base_; - size_t size_in_bytes_; - - // disable copy - BoundedPtr(const BoundedPtr&) = delete; - // disable dynamic allocation - ACC_CXX_DISABLE_NEW_DELETE -}; - - -#endif /* already included */ - -/* vim:set ts=4 sw=4 et: */ diff --git a/src/compress.cpp b/src/compress.cpp index 29fc5f62..92f481a8 100644 --- a/src/compress.cpp +++ b/src/compress.cpp @@ -28,7 +28,7 @@ #include "conf.h" #include "compress.h" -#include "mem.h" +#include "util/membuffer.h" /************************************************************************* diff --git a/src/compress_lzma.cpp b/src/compress_lzma.cpp index 675ef06b..1a1f5f7e 100644 --- a/src/compress_lzma.cpp +++ b/src/compress_lzma.cpp @@ -28,7 +28,7 @@ #include "conf.h" #include "compress.h" -#include "mem.h" +#include "util/membuffer.h" #if (ACC_CC_CLANG) # pragma clang diagnostic ignored "-Wshadow" diff --git a/src/compress_ucl.cpp b/src/compress_ucl.cpp index 56e38c66..b95d390d 100644 --- a/src/compress_ucl.cpp +++ b/src/compress_ucl.cpp @@ -291,7 +291,7 @@ unsigned upx_ucl_crc32(const void *buf, unsigned len, unsigned crc) #if DEBUG && 1 -#include "mem.h" +#include "util/membuffer.h" static bool check_ucl(const int method, const unsigned expected_c_len) { const unsigned u_len = 16384; diff --git a/src/compress_zlib.cpp b/src/compress_zlib.cpp index 6b438ce0..63d29941 100644 --- a/src/compress_zlib.cpp +++ b/src/compress_zlib.cpp @@ -28,7 +28,7 @@ #include "conf.h" #include "compress.h" -#include "mem.h" +#include "util/membuffer.h" #include diff --git a/src/conf.h b/src/conf.h index 44ac0a2e..13834224 100644 --- a/src/conf.h +++ b/src/conf.h @@ -25,9 +25,9 @@ */ - -#ifndef __UPX_CONF_H -#define __UPX_CONF_H 1 +#pragma once +#ifndef UPX_CONF_H__ +#define UPX_CONF_H__ 1 #if defined(__cplusplus) # if (__cplusplus >= 201402L) @@ -356,7 +356,7 @@ template inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; } -// An Array allocates memory on the heap, but automatically +// An Array allocates memory on the heap, and automatically // gets destructed when leaving scope or on exceptions. #define Array(type, var, size) \ MemBuffer var ## _membuf(mem_size(sizeof(type), size)); \ @@ -397,6 +397,23 @@ constexpr bool string_ge(const char *a, const char *b) { } } +/************************************************************************* +// raw_bytes() - get underlying memory from checked buffers/pointers. +// This is overloaded by various utility classes like BoundedPtr, +// MemBuffer and Span. +// +// Note that the pointer type is retained, the "_bytes" hints size_in_bytes +**************************************************************************/ + +// default: for any regular pointer, raw_bytes() is just the pointer itself +template +inline T *raw_bytes(T *ptr, size_t size_in_bytes) { + if (size_in_bytes > 0) { + assert(ptr != nullptr); + } + return ptr; +} + /************************************************************************* // constants **************************************************************************/ @@ -712,7 +729,7 @@ struct upx_compress_result_t // globals **************************************************************************/ -#include "snprintf.h" // must get included first! +#include "util/snprintf.h" // must get included first! #include #include @@ -722,19 +739,27 @@ struct upx_compress_result_t #include "options.h" #include "except.h" #include "bele.h" -#include "util.h" #include "console.h" - -//#define DOCTEST_CONFIG_DISABLE -#include +#include "util/util.h" // classes class ElfLinker; typedef ElfLinker Linker; -// dt_check.cpp -void upx_compiler_sanity_check(void); -bool upx_doctest_check(void); +// util/membuffer.h +class MemBuffer; +void *membuffer_get_void_ptr(MemBuffer &mb); +unsigned membuffer_get_size(MemBuffer &mb); + +#include "util/xspan.h" + +//#define DOCTEST_CONFIG_DISABLE +#include + +// util/dt_check.cpp +void upx_compiler_sanity_check(); +bool upx_doctest_check(); +bool upx_doctest_check(int argc, char **argv); // main.cpp extern const char *progname; @@ -754,7 +779,7 @@ void printWarn(const char *iname, const char *format, ...) attribute_format(2, 3 void infoWarning(const char *format, ...) attribute_format(1, 2); void infoHeader(const char *format, ...) attribute_format(1, 2); void info(const char *format, ...) attribute_format(1, 2); -void infoHeader(void); +void infoHeader(); void infoWriting(const char *what, long size); // work.cpp @@ -763,10 +788,10 @@ int do_files(int i, int argc, char *argv[]); // help.cpp extern const char gitrev[]; -void show_head(void); +void show_head(); void show_help(int verbose=0); -void show_license(void); -void show_usage(void); +void show_license(); +void show_usage(); void show_version(int); // compress.cpp diff --git a/src/except.h b/src/except.h index a1c6d9cd..c20f8671 100644 --- a/src/except.h +++ b/src/except.h @@ -25,8 +25,9 @@ */ -#ifndef __UPX_EXCEPT_H -#define __UPX_EXCEPT_H 1 +#pragma once +#ifndef UPX_EXCEPT_H__ +#define UPX_EXCEPT_H__ 1 #ifdef __cplusplus @@ -50,16 +51,16 @@ public: bool isWarning() const noexcept { return is_warning; } private: - char *msg; - int err; + char *msg = nullptr; + int err = 0; protected: - bool is_warning; // can be set by subclasses + bool is_warning = false; // can be set by subclasses private: // disable assignment - Throwable &operator=(const Throwable &); - // disable dynamic allocation + Throwable &operator=(const Throwable &) = delete; + // disable dynamic allocation => force throwing by value ACC_CXX_DISABLE_NEW_DELETE private: @@ -192,27 +193,27 @@ public: #undef NORET #if 1 && defined(__GNUC__) -#define NORET __attribute__((__noreturn__)) +#define NORET __attribute__((__noreturn__)) __acc_noinline #else -#define NORET /*empty*/ +#define NORET __acc_noinline #endif -void throwCantPack(const char *msg) NORET; -void throwCantPackExact() NORET; -void throwUnknownExecutableFormat(const char *msg = nullptr, bool warn = false) NORET; -void throwNotCompressible(const char *msg = nullptr) NORET; -void throwAlreadyPacked(const char *msg = nullptr) NORET; -void throwAlreadyPackedByUPX(const char *msg = nullptr) NORET; -void throwCantUnpack(const char *msg) NORET; -void throwNotPacked(const char *msg = nullptr) NORET; -void throwFilterException() NORET; -void throwBadLoader() NORET; -void throwChecksumError() NORET; -void throwCompressedDataViolation() NORET; -void throwInternalError(const char *msg) NORET; -void throwOutOfMemoryException(const char *msg = nullptr) NORET; -void throwIOException(const char *msg = nullptr, int e = 0) NORET; -void throwEOFException(const char *msg = nullptr, int e = 0) NORET; +NORET void throwCantPack(const char *msg); +NORET void throwCantPackExact(); +NORET void throwUnknownExecutableFormat(const char *msg = nullptr, bool warn = false); +NORET void throwNotCompressible(const char *msg = nullptr); +NORET void throwAlreadyPacked(const char *msg = nullptr); +NORET void throwAlreadyPackedByUPX(const char *msg = nullptr); +NORET void throwCantUnpack(const char *msg); +NORET void throwNotPacked(const char *msg = nullptr); +NORET void throwFilterException(); +NORET void throwBadLoader(); +NORET void throwChecksumError(); +NORET void throwCompressedDataViolation(); +NORET void throwInternalError(const char *msg); +NORET void throwOutOfMemoryException(const char *msg = nullptr); +NORET void throwIOException(const char *msg = nullptr, int e = 0); +NORET void throwEOFException(const char *msg = nullptr, int e = 0); #undef NORET diff --git a/src/file.cpp b/src/file.cpp index d636d4f5..5cae7755 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -25,59 +25,48 @@ */ - #include "conf.h" #include "file.h" -#include "mem.h" - /************************************************************************* -// +// static functions **************************************************************************/ -void File::chmod(const char *name, int mode) -{ +void FileBase::chmod(const char *name, int mode) { #if (HAVE_CHMOD) - if (::chmod(name,mode) != 0) - throwIOException(name,errno); + if (::chmod(name, mode) != 0) + throwIOException(name, errno); #else - UNUSED(name); UNUSED(mode); + UNUSED(name); + UNUSED(mode); #endif } - -void File::rename(const char *old_, const char *new_) -{ +void FileBase::rename(const char *old_, const char *new_) { #if (ACC_OS_DOS32) && defined(__DJGPP__) - if (::_rename(old_,new_) != 0) + if (::_rename(old_, new_) != 0) #else - if (::rename(old_,new_) != 0) + if (::rename(old_, new_) != 0) #endif - throwIOException("rename error",errno); + throwIOException("rename error", errno); } - -void File::unlink(const char *name) -{ +void FileBase::unlink(const char *name) { if (::unlink(name) != 0) - throwIOException(name,errno); + throwIOException(name, errno); } - /************************************************************************* // **************************************************************************/ -FileBase::FileBase() : - _fd(-1), _flags(0), _shflags(0), _mode(0), _name(nullptr), _offset(0), _length(0) -{ - memset(&st,0,sizeof(st)); +FileBase::FileBase() + : _fd(-1), _flags(0), _shflags(0), _mode(0), _name(nullptr), _offset(0), _length(0) { + memset(&st, 0, sizeof(st)); } - -FileBase::~FileBase() -{ -#if 0 && defined(__GNUC__) // debug +FileBase::~FileBase() { +#if 0 && defined(__GNUC__) // debug if (isOpen()) fprintf(stderr,"%s: %s\n", _name, __PRETTY_FUNCTION__); #endif @@ -87,17 +76,14 @@ FileBase::~FileBase() closex(); } - -bool FileBase::do_sopen() -{ +bool FileBase::do_sopen() { if (_shflags < 0) _fd = ::open(_name, _flags, _mode); - else - { + else { #if (ACC_OS_DOS32) && defined(__DJGPP__) - _fd = ::open(_name,_flags | _shflags, _mode); + _fd = ::open(_name, _flags | _shflags, _mode); #elif defined(__MINT__) - _fd = ::open(_name,_flags | (_shflags & O_SHMODE), _mode); + _fd = ::open(_name, _flags | (_shflags & O_SHMODE), _mode); #elif defined(SH_DENYRW) _fd = ::sopen(_name, _flags, _shflags, _mode); #else @@ -112,9 +98,7 @@ bool FileBase::do_sopen() return true; } - -bool FileBase::close() -{ +bool FileBase::close() { bool ok = true; if (isOpen() && _fd != STDIN_FILENO && _fd != STDOUT_FILENO && _fd != STDERR_FILENO) if (::close(_fd) == -1) @@ -128,53 +112,15 @@ bool FileBase::close() return ok; } - -void FileBase::closex() -{ +void FileBase::closex() { if (!close()) - throwIOException("close failed",errno); + throwIOException("close failed", errno); } - -int FileBase::read(void *buf, int len) -{ - if (!isOpen() || len < 0) - throwIOException("bad read"); - mem_size_assert(1, len); // sanity check - errno = 0; - long l = acc_safe_hread(_fd, buf, len); - if (errno) - throwIOException("read error",errno); - return (int) l; -} - - -int FileBase::readx(void *buf, int len) -{ - int l = this->read(buf, len); - if (l != len) - throwEOFException(); - return l; -} - - -void FileBase::write(const void *buf, int len) -{ - if (!isOpen() || len < 0) - throwIOException("bad write"); - mem_size_assert(1, len); // sanity check - errno = 0; - long l = acc_safe_hwrite(_fd, buf, len); - if (l != len) - throwIOException("write error",errno); -} - - -upx_off_t FileBase::seek(upx_off_t off, int whence) -{ - mem_size_assert(1, off >= 0 ? off : -off); // sanity check +upx_off_t FileBase::seek(upx_off_t off, int whence) { if (!isOpen()) throwIOException("bad seek 1"); + mem_size_assert(1, off >= 0 ? off : -off); // sanity check if (whence == SEEK_SET) { if (off < 0) throwIOException("bad seek 2"); @@ -186,51 +132,34 @@ upx_off_t FileBase::seek(upx_off_t off, int whence) off += _offset + _length; whence = SEEK_SET; } - if (::lseek(_fd,off,whence) < 0) - throwIOException("seek error",errno); + if (::lseek(_fd, off, whence) < 0) + throwIOException("seek error", errno); return off - _offset; } - -upx_off_t FileBase::tell() const -{ +upx_off_t FileBase::tell() const { if (!isOpen()) throwIOException("bad tell"); upx_off_t l = ::lseek(_fd, 0, SEEK_CUR); if (l < 0) - throwIOException("tell error",errno); + throwIOException("tell error", errno); return l - _offset; } - -void FileBase::set_extent(upx_off_t offset, upx_off_t length) -{ +void FileBase::set_extent(upx_off_t offset, upx_off_t length) { _offset = offset; _length = length; } -upx_off_t FileBase::st_size() const -{ - return _length; -} - +upx_off_t FileBase::st_size() const { return _length; } /************************************************************************* // **************************************************************************/ -InputFile::InputFile() -{ -} +InputFile::InputFile() {} - -InputFile::~InputFile() -{ -} - - -void InputFile::sopen(const char *name, int flags, int shflags) -{ +void InputFile::sopen(const char *name, int flags, int shflags) { close(); _name = name; _flags = flags; @@ -238,8 +167,7 @@ void InputFile::sopen(const char *name, int flags, int shflags) _mode = 0; _offset = 0; _length = 0; - if (!FileBase::do_sopen()) - { + if (!super::do_sopen()) { if (errno == ENOENT) throw FileNotFoundException(_name, errno); else if (errno == EEXIST) @@ -250,80 +178,40 @@ void InputFile::sopen(const char *name, int flags, int shflags) _length_orig = _length; } - -int InputFile::read(void *buf, int len) -{ - return super::read(buf, len); +int InputFile::read(SPAN_P(void) buf, int len) { + if (!isOpen() || len < 0) + throwIOException("bad read"); + mem_size_assert(1, len); // sanity check + errno = 0; + long l = acc_safe_hread(_fd, raw_bytes(buf, len), len); + if (errno) + throwIOException("read error", errno); + return (int) l; } -int InputFile::readx(void *buf, int len) -{ - return super::readx(buf, len); +int InputFile::readx(SPAN_P(void) buf, int len) { + int l = this->read(buf, len); + if (l != len) + throwEOFException(); + return l; } - -int InputFile::read(MemBuffer *buf, int len) -{ - buf->checkState(); - assert((unsigned)len <= buf->getSize()); - return read(buf->getVoidPtr(), len); -} - -int InputFile::readx(MemBuffer *buf, int len) -{ - buf->checkState(); - assert((unsigned)len <= buf->getSize()); - return read(buf->getVoidPtr(), len); -} - - -int InputFile::read(MemBuffer &buf, int len) -{ - return read(&buf, len); -} - -int InputFile::readx(MemBuffer &buf, int len) -{ - return readx(&buf, len); -} - - -upx_off_t InputFile::seek(upx_off_t off, int whence) -{ +upx_off_t InputFile::seek(upx_off_t off, int whence) { upx_off_t pos = super::seek(off, whence); if (_length < pos) throwIOException("bad seek 4"); return pos; } - -upx_off_t InputFile::tell() const -{ - return super::tell(); -} - -upx_off_t InputFile::st_size_orig() const -{ - return _length_orig; -} +upx_off_t InputFile::st_size_orig() const { return _length_orig; } /************************************************************************* // **************************************************************************/ -OutputFile::OutputFile() : - bytes_written(0) -{ -} +OutputFile::OutputFile() : bytes_written(0) {} - -OutputFile::~OutputFile() -{ -} - - -void OutputFile::sopen(const char *name, int flags, int shflags, int mode) -{ +void OutputFile::sopen(const char *name, int flags, int shflags, int mode) { close(); _name = name; _flags = flags; @@ -331,8 +219,7 @@ void OutputFile::sopen(const char *name, int flags, int shflags, int mode) _mode = mode; _offset = 0; _length = 0; - if (!FileBase::do_sopen()) - { + if (!super::do_sopen()) { #if 0 // don't throw FileNotFound here -- this is confusing if (errno == ENOENT) @@ -340,15 +227,13 @@ void OutputFile::sopen(const char *name, int flags, int shflags, int mode) else #endif if (errno == EEXIST) - throw FileAlreadyExistsException(_name,errno); + throw FileAlreadyExistsException(_name, errno); else - throwIOException(_name,errno); + throwIOException(_name, errno); } } - -bool OutputFile::openStdout(int flags, bool force) -{ +bool OutputFile::openStdout(int flags, bool force) { close(); int fd = STDOUT_FILENO; if (!force && acc_isatty(fd)) @@ -365,17 +250,27 @@ bool OutputFile::openStdout(int flags, bool force) return true; } - -void OutputFile::write(const void *buf, int len) -{ - super::write(buf, len); +void OutputFile::write(SPAN_0(const void) buf, int len) { + if (!isOpen() || len < 0) + throwIOException("bad write"); + // allow nullptr if len == 0 + if (len == 0) + return; + mem_size_assert(1, len); // sanity check + errno = 0; +#if 0 + fprintf(stderr, "write %p %zd (%p) %d\n", buf.raw_ptr(), buf.raw_size_in_bytes(), + buf.raw_base(), len); +#endif + long l = acc_safe_hwrite(_fd, raw_bytes(buf, len), len); + if (l != len) + throwIOException("write error", errno); bytes_written += len; } -upx_off_t OutputFile::st_size() const -{ - if (opt->to_stdout) { // might be a pipe ==> .st_size is invalid - return bytes_written; // too big if seek()+write() instead of rewrite() +upx_off_t OutputFile::st_size() const { + if (opt->to_stdout) { // might be a pipe ==> .st_size is invalid + return bytes_written; // too big if seek()+write() instead of rewrite() } struct stat my_st; my_st.st_size = 0; @@ -384,34 +279,13 @@ upx_off_t OutputFile::st_size() const return my_st.st_size; } - -void OutputFile::write(const MemBuffer *buf, int len) -{ - buf->checkState(); - assert((unsigned)len <= buf->getSize()); - write(buf->getVoidPtr(), len); -} - - -void OutputFile::write(const MemBuffer &buf, int len) -{ - write(&buf, len); -} - -void OutputFile::rewrite(const void *buf, int len) -{ +void OutputFile::rewrite(SPAN_P(const void) buf, int len) { assert(!opt->to_stdout); write(buf, len); - bytes_written -= len; // restore + bytes_written -= len; // restore } -upx_off_t OutputFile::tell() const -{ - return super::tell(); -} - -upx_off_t OutputFile::seek(upx_off_t off, int whence) -{ +upx_off_t OutputFile::seek(upx_off_t off, int whence) { mem_size_assert(1, off >= 0 ? off : -off); // sanity check assert(!opt->to_stdout); switch (whence) { @@ -419,18 +293,18 @@ upx_off_t OutputFile::seek(upx_off_t off, int whence) if (bytes_written < off) { bytes_written = off; } - _length = bytes_written; // cheap, lazy update; needed? + _length = bytes_written; // cheap, lazy update; needed? } break; case SEEK_END: { - _length = bytes_written; // necessary + _length = bytes_written; // necessary } break; } - return super::seek(off,whence); + return super::seek(off, whence); } // WARNING: fsync() does not exist in some Windows environments. // This trick works only on UNIX-like systems. -//int OutputFile::read(void *buf, int len) +// int OutputFile::read(void *buf, int len) //{ // fsync(_fd); // InputFile infile; @@ -439,19 +313,17 @@ upx_off_t OutputFile::seek(upx_off_t off, int whence) // return infile.read(buf, len); //} -void OutputFile::set_extent(upx_off_t offset, upx_off_t length) -{ +void OutputFile::set_extent(upx_off_t offset, upx_off_t length) { super::set_extent(offset, length); bytes_written = 0; - if (0==offset && (upx_off_t)~0u==length) { + if (0 == offset && (upx_off_t) ~0u == length) { if (::fstat(_fd, &st) != 0) throwIOException(_name, errno); _length = st.st_size - offset; } } -upx_off_t OutputFile::unset_extent() -{ +upx_off_t OutputFile::unset_extent() { upx_off_t l = ::lseek(_fd, 0, SEEK_END); if (l < 0) throwIOException("lseek error", errno); @@ -461,44 +333,14 @@ upx_off_t OutputFile::unset_extent() return _length; } -void OutputFile::dump(const char *name, const void *buf, int len, int flags) -{ +void OutputFile::dump(const char *name, SPAN_P(const void) buf, int len, int flags) { if (flags < 0) - flags = O_CREAT | O_TRUNC; + flags = O_CREAT | O_TRUNC; flags |= O_WRONLY | O_BINARY; OutputFile f; f.open(name, flags, 0600); - f.write(buf, len); + f.write(raw_bytes(buf, len), len); f.closex(); } - -/************************************************************************* -// -**************************************************************************/ - -#if 0 - -MemoryOutputFile::MemoryOutputFile() : - b(nullptr), b_size(0), b_pos(0), bytes_written(0) -{ -} - - -void MemoryOutputFile::write(const void *buf, int len) -{ - if (!isOpen() || len < 0) - throwIOException("bad write"); - if (len == 0) - return; - if (b_pos + len > b_size) - throwIOException("write error",ENOSPC); - memcpy(b + b_pos, buf, len); - b_pos += len; - bytes_written += len; -} - - -#endif /* if 0 */ - /* vim:set ts=4 sw=4 et: */ diff --git a/src/file.h b/src/file.h index 8fb5dc30..1f6809c3 100644 --- a/src/file.h +++ b/src/file.h @@ -25,165 +25,110 @@ */ - -#ifndef __UPX_FILE_H -#define __UPX_FILE_H 1 - -class MemBuffer; - +#pragma once +#ifndef UPX_FILE_H__ +#define UPX_FILE_H__ 1 /************************************************************************* // **************************************************************************/ -class File -{ -protected: - File() { } - virtual ~File() { } -public: - static void chmod(const char *name, int mode); - static void rename(const char *old_, const char *new_); - static void unlink(const char *name); -}; - - -class FileBase : public File -{ +class FileBase { protected: FileBase(); virtual ~FileBase(); + public: - virtual bool close(); - virtual void closex(); - virtual bool isOpen() const { return _fd >= 0; } + bool close(); + void closex(); + bool isOpen() const { return _fd >= 0; } int getFd() const { return _fd; } const char *getName() const { return _name; } - virtual upx_off_t st_size() const; // { return _length; } + + virtual upx_off_t seek(upx_off_t off, int whence); + upx_off_t tell() const; + virtual upx_off_t st_size() const; // { return _length; } virtual void set_extent(upx_off_t offset, upx_off_t length); +public: + // static file-related util functions + static void chmod(const char *name, int mode); + static void rename(const char *old_, const char *new_); + static void unlink(const char *name); + protected: bool do_sopen(); - virtual int read(void *buf, int len); - virtual int readx(void *buf, int len); - virtual void write(const void *buf, int len); - virtual upx_off_t seek(upx_off_t off, int whence); - virtual upx_off_t tell() const; + int _fd = -1; + int _flags = 0; + int _shflags = 0; + int _mode = 0; + const char *_name = nullptr; + upx_off_t _offset = 0; + upx_off_t _length = 0; - int _fd; - int _flags; - int _shflags; - int _mode; - const char *_name; - upx_off_t _offset; - upx_off_t _length; public: - struct stat st; + struct stat st = {}; }; - /************************************************************************* // **************************************************************************/ -class InputFile final : public FileBase -{ +class InputFile final : public FileBase { typedef FileBase super; + public: InputFile(); - virtual ~InputFile(); + virtual ~InputFile() {} - virtual void sopen(const char *name, int flags, int shflags); - virtual void open(const char *name, int flags) - { - sopen(name, flags, -1); - } + void sopen(const char *name, int flags, int shflags); + void open(const char *name, int flags) { sopen(name, flags, -1); } - virtual int read(void *buf, int len) override; - virtual int readx(void *buf, int len) override; - virtual int read(MemBuffer *buf, int len); - virtual int readx(MemBuffer *buf, int len); - virtual int read(MemBuffer &buf, int len); - virtual int readx(MemBuffer &buf, int len); + int read(SPAN_P(void) buf, int len); + int readx(SPAN_P(void) buf, int len); virtual upx_off_t seek(upx_off_t off, int whence) override; - virtual upx_off_t tell() const override; - virtual upx_off_t st_size_orig() const; -protected: - upx_off_t _length_orig; -}; + upx_off_t st_size_orig() const; +protected: + upx_off_t _length_orig = 0; +}; /************************************************************************* // **************************************************************************/ -class OutputFile final : public FileBase -{ +class OutputFile final : public FileBase { typedef FileBase super; + public: OutputFile(); - virtual ~OutputFile(); + virtual ~OutputFile() {} - virtual void sopen(const char *name, int flags, int shflags, int mode); - virtual void open(const char *name, int flags, int mode) - { - sopen(name, flags, -1, mode); - } - virtual bool openStdout(int flags=0, bool force=false); + void sopen(const char *name, int flags, int shflags, int mode); + void open(const char *name, int flags, int mode) { sopen(name, flags, -1, mode); } + bool openStdout(int flags = 0, bool force = false); - virtual void write(const void *buf, int len) override; - virtual void write(const MemBuffer *buf, int len); - virtual void write(const MemBuffer &buf, int len); + // info: allow nullptr if len == 0 + void write(SPAN_0(const void) buf, int len); + + virtual upx_off_t seek(upx_off_t off, int whence) override; + virtual upx_off_t st_size() const override; // { return _length; } virtual void set_extent(upx_off_t offset, upx_off_t length) override; - virtual upx_off_t unset_extent(); // returns actual length + upx_off_t unset_extent(); // returns actual length upx_off_t getBytesWritten() const { return bytes_written; } - virtual upx_off_t st_size() const override; // { return _length; } // FIXME - these won't work when using the '--stdout' option - virtual upx_off_t seek(upx_off_t off, int whence) override; - virtual upx_off_t tell() const override; - virtual void rewrite(const void *buf, int len); + void rewrite(SPAN_P(const void) buf, int len); // util - static void dump(const char *name, const void *buf, int len, int flags=-1); + static void dump(const char *name, SPAN_P(const void) buf, int len, int flags = -1); protected: - upx_off_t bytes_written; + upx_off_t bytes_written = 0; }; - -/************************************************************************* -// -**************************************************************************/ - -#if 0 /* NOT USED */ -class MemoryOutputFile : public FileBase -{ - typedef FileBase super; -public: - MemoryOutputFile(); - virtual ~MemoryOutputFile() { b = nullptr; } - - virtual bool close() { b = nullptr; return true; } - virtual bool isOpen() const { return b != nullptr; } - virtual void open(void *buf, unsigned size) - { b = (upx_bytep) buf; b_size = size; } - - virtual void write(const void *buf, int len); - - upx_off_t getBytesWritten() const { return bytes_written; } - -protected: - upx_bytep b; - unsigned b_size; - unsigned b_pos; - upx_off_t bytes_written; -}; -#endif /* if 0 */ - - -#endif /* already included */ +#endif /* vim:set ts=4 sw=4 et: */ diff --git a/src/lefile.cpp b/src/lefile.cpp index 49e11f58..d18face9 100644 --- a/src/lefile.cpp +++ b/src/lefile.cpp @@ -28,7 +28,7 @@ #include "conf.h" #include "file.h" -#include "mem.h" +#include "util/membuffer.h" #include "lefile.h" @@ -77,7 +77,8 @@ LeFile::~LeFile() void LeFile::readObjectTable() { - iobject_table = new le_object_table_entry_t[soobject_table = objects]; + soobject_table = objects; + iobject_table = New(le_object_table_entry_t, soobject_table); fif->seek(le_offset + ih.object_table_offset,SEEK_SET); fif->readx(iobject_table,sizeof(*iobject_table)*objects); } @@ -92,7 +93,8 @@ void LeFile::writeObjectTable() void LeFile::readPageMap() { - ipm_entries = new le_pagemap_entry_t[sopm_entries = pages]; + sopm_entries = pages; + ipm_entries = New(le_pagemap_entry_t, sopm_entries); fif->seek(le_offset + ih.object_pagemap_offset,SEEK_SET); fif->readx(ipm_entries,sizeof(*ipm_entries)*pages); @@ -112,7 +114,7 @@ void LeFile::writePageMap() void LeFile::readResidentNames() { sores_names = ih.entry_table_offset - ih.resident_names_offset; - ires_names = new upx_byte[sores_names]; + ires_names = New(upx_byte, sores_names); fif->seek(le_offset+ih.resident_names_offset,SEEK_SET); fif->readx(ires_names,sores_names); } @@ -129,7 +131,7 @@ void LeFile::readEntryTable() { soentries = ih.fixup_page_table_offset - ih.entry_table_offset; fif->seek(le_offset + ih.entry_table_offset,SEEK_SET); - ientries = new upx_byte[soentries]; + ientries = New(upx_byte, soentries); fif->readx(ientries,soentries); } @@ -143,7 +145,8 @@ void LeFile::writeEntryTable() void LeFile::readFixupPageTable() { - ifpage_table = new unsigned[sofpage_table = 1+pages]; + sofpage_table = 1+pages; + ifpage_table = New(unsigned, sofpage_table); fif->seek(le_offset + ih.fixup_page_table_offset,SEEK_SET); fif->readx(ifpage_table,4*sofpage_table); } @@ -159,7 +162,7 @@ void LeFile::writeFixupPageTable() void LeFile::readFixups() { sofixups = get_le32(ifpage_table+pages)-get_le32(ifpage_table); - ifixups = new upx_byte[sofixups]; + ifixups = New(upx_byte, sofixups); fif->seek(le_offset + ih.fixup_record_table_offset,SEEK_SET); fif->readx(ifixups,sofixups); } @@ -187,8 +190,9 @@ unsigned LeFile::getImageSize() const void LeFile::readImage() { soimage = pages*mps; - iimage.alloc(soimage); - memset(iimage,0,soimage); + mb_iimage.alloc(soimage); + mb_iimage.clear(); + iimage = mb_iimage; unsigned ic,jc; for (ic = jc = 0; ic < pages; ic++) @@ -197,7 +201,8 @@ void LeFile::readImage() { fif->seek(ih.data_pages_offset + exe_offset + (ipm_entries[ic].m*0x100 + ipm_entries[ic].l-1) * mps,SEEK_SET); - fif->readx(iimage+jc,ic != pages-1 ? mps : ih.bytes_on_last_page); + auto bytes = ic != pages-1 ? mps : ih.bytes_on_last_page; + fif->readx(raw_bytes(iimage+jc, bytes), bytes); } jc += mps; } @@ -207,7 +212,7 @@ void LeFile::readImage() void LeFile::writeImage() { if (fof && oimage != nullptr) - fof->write(oimage, soimage); + fof->write(raw_bytes(oimage, soimage), soimage); } @@ -215,7 +220,8 @@ void LeFile::readNonResidentNames() { if (ih.non_resident_name_table_length) { - inonres_names = new upx_byte[sononres_names = ih.non_resident_name_table_length]; + sononres_names = ih.non_resident_name_table_length; + inonres_names = New(upx_byte, sononres_names); fif->seek(exe_offset+ih.non_resident_name_table_offset,SEEK_SET); fif->readx(inonres_names,sononres_names); } diff --git a/src/lefile.h b/src/lefile.h index 8ba62c4a..957f9dbf 100644 --- a/src/lefile.h +++ b/src/lefile.h @@ -39,7 +39,7 @@ class OutputFile; class LeFile { -public: +protected: LeFile(InputFile *); virtual ~LeFile(); @@ -198,8 +198,10 @@ protected: upx_byte *ofixups; upx_byte *inonres_names; upx_byte *ononres_names; - MemBuffer iimage; - MemBuffer oimage; + MemBuffer mb_iimage; + SPAN_0(upx_byte) iimage = nullptr; + MemBuffer mb_oimage; + SPAN_0(upx_byte) oimage = nullptr; upx_byte *ientries; upx_byte *oentries; diff --git a/src/main.cpp b/src/main.cpp index ae2da383..40520e7e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1122,7 +1122,7 @@ int upx_main(int argc, char *argv[]) { argv0 = argv[0]; upx_compiler_sanity_check(); - if (!upx_doctest_check()) { + if (!upx_doctest_check(argc, argv)) { fprintf(stderr, "%s: internal error: doctest failed\n", argv0); e_exit(EXIT_INIT); } diff --git a/src/mem.h b/src/mem.h deleted file mode 100644 index 6307cb57..00000000 --- a/src/mem.h +++ /dev/null @@ -1,88 +0,0 @@ -/* mem.h -- - - This file is part of the UPX executable compressor. - - Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996-2022 Laszlo Molnar - All Rights Reserved. - - UPX and the UCL library are free software; you can redistribute them - and/or modify them under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. - If not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - Markus F.X.J. Oberhumer Laszlo Molnar - - */ - - -#ifndef __UPX_MEM_H -#define __UPX_MEM_H 1 - - -/************************************************************************* -// -**************************************************************************/ - -class MemBuffer -{ -public: - MemBuffer() : b(nullptr), b_size(0) { } - explicit MemBuffer(upx_uint64_t size); - ~MemBuffer(); - - static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra=0); - static unsigned getSizeForUncompression(unsigned uncompressed_size, unsigned extra=0); - - void alloc(upx_uint64_t size); - void allocForCompression(unsigned uncompressed_size, unsigned extra=0); - void allocForUncompression(unsigned uncompressed_size, unsigned extra=0); - - void dealloc(); - - void checkState() const; - - unsigned getSize() const { return b_size; } - - operator unsigned char * () { return b; } - operator const unsigned char * () const { return b; } - - void *getVoidPtr() { return (void *) b; } - const void *getVoidPtr() const { return (const void *) b; } - - void fill(unsigned off, unsigned len, int value); - void clear(unsigned off, unsigned len) { fill(off, len, 0); } - void clear() { fill(0, b_size, 0); } - - // If the entire range [skip, take+skip) is inside the buffer, - // then return &b[skip]; else throwCantPack(sprintf(errfmt, skip, take)). - // This is similar to BoundedPtr, except only checks once. - unsigned char *subref(char const *errfmt, unsigned skip, unsigned take); - -private: - unsigned char *b; - unsigned b_size; - - static unsigned global_alloc_counter; - - // disable copy, assignment and move assignment - MemBuffer(const MemBuffer &) = delete; - MemBuffer& operator= (const MemBuffer &) = delete; - MemBuffer& operator= (MemBuffer &&) = delete; - // disable dynamic allocation - ACC_CXX_DISABLE_NEW_DELETE -}; - -#endif /* already included */ - -/* vim:set ts=4 sw=4 et: */ diff --git a/src/options.h b/src/options.h index d4021502..6d497716 100644 --- a/src/options.h +++ b/src/options.h @@ -25,8 +25,9 @@ */ -#ifndef __UPX_OPTIONS_H -#define __UPX_OPTIONS_H 1 +#pragma once +#ifndef UPX_OPTIONS_H__ +#define UPX_OPTIONS_H__ 1 /************************************************************************* // globals diff --git a/src/p_djgpp2.h b/src/p_djgpp2.h index b684ede0..ab673063 100644 --- a/src/p_djgpp2.h +++ b/src/p_djgpp2.h @@ -34,35 +34,35 @@ // djgpp2/coff **************************************************************************/ -class PackDjgpp2 : public Packer +class PackDjgpp2 final : public Packer { typedef Packer super; public: PackDjgpp2(InputFile *f); - virtual int getVersion() const { return 14; } - virtual int getFormat() const { return UPX_F_DJGPP2_COFF; } - virtual const char *getName() const { return "djgpp2/coff"; } - virtual const char *getFullName(const options_t *) const { return "i386-dos32.djgpp2.coff"; } - virtual const int *getCompressionMethods(int method, int level) const; - virtual const int *getFilters() const; + 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 { return "i386-dos32.djgpp2.coff"; } + virtual const int *getCompressionMethods(int method, int level) const override; + virtual const int *getFilters() const override; - virtual void pack(OutputFile *fo); - virtual void unpack(OutputFile *fo); + virtual void pack(OutputFile *fo) override; + virtual void unpack(OutputFile *fo) override; - virtual bool canPack(); - virtual int canUnpack(); + virtual bool canPack() override; + virtual int canUnpack() override; protected: - virtual void handleStub(OutputFile *fo); - virtual int readFileHeader(); + void handleStub(OutputFile *fo); + int readFileHeader(); virtual unsigned findOverlapOverhead(const upx_bytep buf, const upx_bytep tbuf, unsigned range = 0, - unsigned upper_limit = ~0u) const; - virtual void buildLoader(const Filter *ft); - virtual Linker* newLinker() const; + unsigned upper_limit = ~0u) const override; + virtual void buildLoader(const Filter *ft) override; + virtual Linker* newLinker() const override; unsigned coff_offset; diff --git a/src/p_exe.cpp b/src/p_exe.cpp index fe45707c..9b85dd41 100644 --- a/src/p_exe.cpp +++ b/src/p_exe.cpp @@ -607,8 +607,8 @@ void PackExe::pack(OutputFile *fo) } // g++ 3.1 does not like the following line... -// oh.relocoffs = offsetof(exe_header_t, firstreloc); - oh.relocoffs = ptr_diff(&oh.firstreloc, &oh); + 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); @@ -658,7 +658,7 @@ void PackExe::pack(OutputFile *fo) verifyOverlappingDecompression(); // copy the overlay - copyOverlay(fo, ih_overlay, &obuf); + copyOverlay(fo, ih_overlay, obuf); //fprintf (stderr,"%x %x\n",relocsize,ph.u_len); // finally check the compression ratio @@ -710,7 +710,7 @@ void PackExe::unpack(OutputFile *fo) const unsigned char flag = ibuf[imagesize]; unsigned relocn = 0; - upx_byte *relocs = obuf + ph.u_len; + SPAN_S_VAR(upx_byte, relocs, obuf + ph.u_len, obuf); MemBuffer wrkmem; if (!(flag & NORELOC)) @@ -721,7 +721,7 @@ void PackExe::unpack(OutputFile *fo) wrkmem.alloc(4*MAXRELOCS); unsigned es = 0, ones = get_le16(relocs); const unsigned seghi = get_le16(relocs+2); - const upx_byte *p = relocs + 4; + SPAN_S_VAR(const upx_byte, p, relocs + 4); while (ones) { @@ -739,10 +739,11 @@ void PackExe::unpack(OutputFile *fo) dorel = true; if (*p == 0) { - const upx_byte *q; + SPAN_S_VAR(const upx_byte, q, obuf); + for (q = obuf+es*16+di; !(*q == 0x9a && get_le16(q+3) <= seghi); q++) ; - di = ptr_diff(q, obuf+es*16) + 3; + di = ptr_diff_bytes(q, obuf+es*16) + 3; } else if (*p == 1) { @@ -768,7 +769,7 @@ void PackExe::unpack(OutputFile *fo) set_le32(wrkmem+4*relocn++,0); } - unsigned outputlen = ptr_diff(relocs, obuf) + sizeof(oh) + relocn*4; + unsigned outputlen = ptr_udiff_bytes(relocs, obuf) + sizeof(oh) + relocn*4; oh.m512 = outputlen & 511; oh.p512 = (outputlen + 511) >> 9; oh.headsize16 = 2+relocn/4; @@ -800,10 +801,10 @@ void PackExe::unpack(OutputFile *fo) fo->write(&oh,sizeof(oh)); if (relocn) fo->write(wrkmem,relocn*4); - fo->write(obuf, ptr_diff(relocs, obuf)); + fo->write(obuf, ptr_diff_bytes(relocs, obuf)); // copy the overlay - copyOverlay(fo, ih_overlay, &obuf); + copyOverlay(fo, ih_overlay, obuf); } diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 899ce131..3bc12678 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -1456,8 +1456,6 @@ static const static const #include "stub/armeb.v4a-linux.elf-fold.h" -#include "mem.h" - void PackLinuxElf32armBe::buildLoader(Filter const *ft) { @@ -4611,7 +4609,7 @@ void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft) unsigned tmp = sz_pack2 + get_te32(&elfout.phdr[C_TEXT].p_vaddr); tmp |= (Elf32_Ehdr::EM_ARM==e_machine); // THUMB mode set_te32(&tmp, tmp); - fo->seek(ptr_udiff(&jni_onload_sym->st_value, file_image), SEEK_SET); + fo->seek(ptr_udiff_bytes(&jni_onload_sym->st_value, file_image), SEEK_SET); fo->rewrite(&tmp, sizeof(tmp)); } } diff --git a/src/p_mach.cpp b/src/p_mach.cpp index 8158a946..380b58d3 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -1529,7 +1529,7 @@ void PackMachBase::unpack(OutputFile *fo) if (is_bad_linker_command( ((Mach_command const *)ptr)->cmd, cmdsize, headway, lc_seg, sizeof(Addr))) { char msg[50]; snprintf(msg, sizeof(msg), - "bad packed Mach load_command @%#x", ptr_udiff(ptr, mhdr)); + "bad packed Mach load_command @%#x", ptr_udiff_bytes(ptr, mhdr)); throwCantUnpack(msg); } memcpy(&msegcmd[j], ptr, umin(sizeof(Mach_segment_command), cmdsize)); @@ -1905,7 +1905,7 @@ template upx_uint64_t PackMachBase::get_mod_init_func(Mach_segment_command const *segptr) { for (Mach_section_command const *secptr = (Mach_section_command const *)(1+ segptr); - ptr_udiff(secptr, segptr) < segptr->cmdsize; + ptr_udiff_bytes(secptr, segptr) < segptr->cmdsize; ++secptr ) { if (sizeof(Addr) == secptr->size diff --git a/src/p_ps1.h b/src/p_ps1.h index d58ac832..10488327 100644 --- a/src/p_ps1.h +++ b/src/p_ps1.h @@ -38,34 +38,34 @@ // ps1/exe **************************************************************************/ -class PackPs1 : public Packer +class PackPs1 final : public Packer { typedef Packer super; public: PackPs1(InputFile *f); - virtual int getVersion() const { return 13; } - virtual int getFormat() const { return UPX_F_PS1_EXE; } - virtual const char *getName() const { return "ps1/exe"; } - virtual const char *getFullName(const options_t *) const { return "mipsel.r3000-ps1"; } - virtual const int *getCompressionMethods(int method, int level) const; - virtual const int *getFilters() const; + 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 int *getCompressionMethods(int method, int level) const override; + virtual const int *getFilters() const override; - virtual void pack(OutputFile *fo); - virtual void unpack(OutputFile *fo); + virtual void pack(OutputFile *fo) override; + virtual void unpack(OutputFile *fo) override; - virtual bool canPack(); - virtual int canUnpack(); + virtual bool canPack() override; + virtual int canUnpack() override; protected: - virtual void putBkupHeader(const unsigned char *src, unsigned char *dst, unsigned *len); - virtual bool getBkupHeader(unsigned char *src, unsigned char * dst); - virtual bool readBkupHeader(); - virtual void buildLoader(const Filter *ft); - virtual bool findBssSection(); - virtual Linker* newLinker() const; + void putBkupHeader(const unsigned char *src, unsigned char *dst, unsigned *len); + bool getBkupHeader(unsigned char *src, unsigned char * dst); + bool readBkupHeader(); + virtual void buildLoader(const Filter *ft) override; + bool findBssSection(); + virtual Linker* newLinker() const override; - virtual int readFileHeader(); - virtual bool checkFileHeader(); + int readFileHeader(); + bool checkFileHeader(); __packed_struct(ps1_exe_t) // ident string diff --git a/src/p_tmt.cpp b/src/p_tmt.cpp index c01d2ff6..0559bddf 100644 --- a/src/p_tmt.cpp +++ b/src/p_tmt.cpp @@ -235,9 +235,7 @@ void PackTmt::pack(OutputFile *fo) { for (unsigned ic=4; ic<=rsize; ic+=4) set_le32(wrkmem+ic,get_le32(wrkmem+ic)-4); - relocsize = ptr_diff( - optimizeReloc32(wrkmem+4,rsize/4,wrkmem,ibuf,file_size,1,&big_relocs), - wrkmem); + relocsize = optimizeReloc32(wrkmem+4,rsize/4,wrkmem,ibuf,file_size,1,&big_relocs); } wrkmem[relocsize++] = 0; @@ -300,7 +298,7 @@ void PackTmt::pack(OutputFile *fo) verifyOverlappingDecompression(); // copy the overlay - copyOverlay(fo, overlay, &obuf); + copyOverlay(fo, overlay, obuf); // finally check the compression ratio if (!checkFinalCompressionRatio(fo)) @@ -332,7 +330,7 @@ void PackTmt::unpack(OutputFile *fo) // decode relocations const unsigned osize = ph.u_len - get_le32(obuf+ph.u_len-4); - upx_byte *relocs = obuf + osize; + SPAN_P_VAR(upx_byte, relocs, obuf + osize); const unsigned origstart = get_le32(obuf+ph.u_len-8); // unfilter @@ -343,12 +341,13 @@ void PackTmt::unpack(OutputFile *fo) ft.cto = (unsigned char) ph.filter_cto; if (ph.version < 11) ft.cto = (unsigned char) (get_le32(obuf+ph.u_len-12) >> 24); - ft.unfilter(obuf, ptr_diff(relocs, obuf)); + ft.unfilter(obuf, ptr_udiff_bytes(relocs, obuf)); } // decode relocations - MemBuffer wrkmem; - unsigned relocn = unoptimizeReloc32(&relocs,obuf,&wrkmem,1); + MemBuffer mb_wrkmem; + unsigned relocn = unoptimizeReloc32(relocs, obuf, mb_wrkmem, true); + SPAN_S_VAR(upx_byte, wrkmem, mb_wrkmem); for (unsigned ic = 0; ic < relocn; ic++) set_le32(wrkmem+ic*4,get_le32(wrkmem+ic*4)+4); @@ -366,11 +365,11 @@ void PackTmt::unpack(OutputFile *fo) { fo->write(&oh,sizeof(oh)); fo->write(obuf,osize); - fo->write(wrkmem,relocn*4); + fo->write(raw_bytes(wrkmem,relocn*4), relocn*4); } // copy the overlay - copyOverlay(fo, overlay, &obuf); + copyOverlay(fo, overlay, obuf); } /* vim:set ts=4 sw=4 et: */ diff --git a/src/p_tmt.h b/src/p_tmt.h index b25aabe4..09bed17f 100644 --- a/src/p_tmt.h +++ b/src/p_tmt.h @@ -34,33 +34,33 @@ // tmt/adam **************************************************************************/ -class PackTmt : public Packer +class PackTmt final : public Packer { typedef Packer super; public: PackTmt(InputFile *f); - virtual int getVersion() const { return 13; } - virtual int getFormat() const { return UPX_F_TMT_ADAM; } - virtual const char *getName() const { return "tmt/adam"; } - virtual const char *getFullName(const options_t *) const { return "i386-dos32.tmt.adam"; } - virtual const int *getCompressionMethods(int method, int level) const; - virtual const int *getFilters() const; + 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 { return "i386-dos32.tmt.adam"; } + virtual const int *getCompressionMethods(int method, int level) const override; + virtual const int *getFilters() const override; - virtual void pack(OutputFile *fo); - virtual void unpack(OutputFile *fo); + virtual void pack(OutputFile *fo) override; + virtual void unpack(OutputFile *fo) override; - virtual bool canPack(); - virtual int canUnpack(); + virtual bool canPack() override; + virtual int canUnpack() override; protected: - virtual int readFileHeader(); + int readFileHeader(); virtual unsigned findOverlapOverhead(const upx_bytep buf, const upx_bytep tbuf, unsigned range = 0, - unsigned upper_limit = ~0u) const; - virtual void buildLoader(const Filter *ft); - virtual Linker* newLinker() const; + unsigned upper_limit = ~0u) const override; + virtual void buildLoader(const Filter *ft) override; + virtual Linker* newLinker() const override; unsigned adam_offset; int big_relocs; diff --git a/src/p_tos.cpp b/src/p_tos.cpp index 169f6ef5..978f973c 100644 --- a/src/p_tos.cpp +++ b/src/p_tos.cpp @@ -662,7 +662,7 @@ void PackTos::pack(OutputFile *fo) { verifyOverlappingDecompression(); // copy the overlay - copyOverlay(fo, overlay, &obuf); + copyOverlay(fo, overlay, obuf); // finally check the compression ratio if (!checkFinalCompressionRatio(fo)) @@ -713,7 +713,7 @@ void PackTos::unpack(OutputFile *fo) { fo->write(obuf, ph.u_len - FH_SIZE); // orig. text+data+relocs // copy any overlay - copyOverlay(fo, overlay, &obuf); + copyOverlay(fo, overlay, obuf); } } diff --git a/src/p_wcle.cpp b/src/p_wcle.cpp index 4974c475..0f174534 100644 --- a/src/p_wcle.cpp +++ b/src/p_wcle.cpp @@ -176,7 +176,7 @@ void PackWcle::encodeEntryTable() //if (Opt_debug) printf("%d entries encoded.\n",n); UNUSED(n); - soentries = ptr_diff(p, ientries) + 1; + soentries = ptr_udiff_bytes(p, ientries) + 1; oentries = ientries; ientries = nullptr; } @@ -290,12 +290,13 @@ void PackWcle::preprocessFixups() throwCantPack("files without relocations are not supported"); } - ByteArray(rl, jc); + MemBuffer rl_membuf(jc); ByteArray(srf, counts[objects+0]+1); ByteArray(slf, counts[objects+1]+1); - upx_byte *selector_fixups = srf; - upx_byte *selfrel_fixups = slf; + SPAN_S_VAR(upx_byte, rl, rl_membuf); + SPAN_S_VAR(upx_byte, selector_fixups, srf_membuf); + SPAN_S_VAR(upx_byte, selfrel_fixups, slf_membuf); unsigned rc = 0; upx_byte *fix = ifixups; @@ -399,20 +400,20 @@ void PackWcle::preprocessFixups() delete[] ifixups; ifixups = new upx_byte[1000]; } - fix = optimizeReloc32 (rl,rc,ifixups,iimage,file_size,1,&big_relocs); - has_extra_code = srf != selector_fixups; + fix = ifixups + optimizeReloc32 (rl,rc,ifixups,iimage,file_size,1,&big_relocs); + has_extra_code = ptr_udiff_bytes(selector_fixups, srf) != 0; // FIXME: this could be removed if has_extra_code = false // but then we'll need a flag *selector_fixups++ = 0xC3; // ret - memcpy(fix,srf,selector_fixups-srf); // copy selector fixup code - fix += selector_fixups-srf; + memcpy(fix,srf,ptr_udiff_bytes(selector_fixups, srf)); // copy selector fixup code + fix += ptr_udiff_bytes(selector_fixups, srf); - memcpy(fix,slf,selfrel_fixups-slf); // copy self-relative fixup positions - fix += selfrel_fixups-slf; + memcpy(fix,slf,ptr_udiff_bytes(selfrel_fixups,slf)); // copy self-relative fixup positions + fix += ptr_udiff_bytes(selfrel_fixups, slf); set_le32(fix,0xFFFFFFFFUL); fix += 4; - sofixups = ptr_diff(fix, ifixups); + sofixups = ptr_udiff(fix, ifixups); } @@ -427,7 +428,8 @@ void PackWcle::encodeImage(Filter *ft) delete[] ifixups; ifixups = nullptr; - oimage.allocForCompression(isize, RESERVED+512); + mb_oimage.allocForCompression(isize, RESERVED+512); + oimage = mb_oimage; // prepare packheader ph.u_len = isize; // prepare filter [already done] @@ -435,7 +437,7 @@ void PackWcle::encodeImage(Filter *ft) upx_compress_config_t cconf; cconf.reset(); cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack compressWithFilters(ibuf, isize, - oimage + RESERVED, + raw_bytes(oimage + RESERVED, mb_oimage.getSize() - RESERVED), ibuf + ft->addvalue, ft->buf_len, nullptr, 0, ft, 512, &cconf, 0); @@ -473,7 +475,7 @@ void PackWcle::pack(OutputFile *fo) readNonResidentNames(); // if (find_le32(iimage,20,get_le32("UPX ")) >= 0) - if (find_le32(iimage,UPX_MIN(soimage,256u),UPX_MAGIC_LE32) >= 0) + if (find_le32(raw_bytes(iimage, soimage) ,UPX_MIN(soimage,256u),UPX_MAGIC_LE32) >= 0) throwAlreadyPacked(); if (ih.init_ss_object != objects) @@ -556,14 +558,14 @@ void PackWcle::pack(OutputFile *fo) writeFile(fo, opt->watcom_le.le); // verify - verifyOverlappingDecompression(oimage + e_len, oimage.getSize() - e_len); + verifyOverlappingDecompression(mb_oimage + e_len, mb_oimage.getSize() - e_len); // copy the overlay const unsigned overlaystart = ih.data_pages_offset + exe_offset + getImageSize(); const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length; checkOverlay(overlay); - copyOverlay(fo, overlay, &oimage); + copyOverlay(fo, overlay, mb_oimage); // finally check the compression ratio if (!checkFinalCompressionRatio(fo)) @@ -577,12 +579,14 @@ void PackWcle::pack(OutputFile *fo) void PackWcle::decodeFixups() { - upx_byte *p = oimage + soimage; + SPAN_P_VAR(upx_byte, p, oimage + soimage); +// assert(p.raw_size_in_bytes() == mb_oimage.getSize()); // Span sanity check - iimage.dealloc(); + mb_iimage.dealloc(); + iimage = nullptr; MemBuffer tmpbuf; - unsigned const fixupn = unoptimizeReloc32(&p,oimage,&tmpbuf,1); + unsigned const fixupn = unoptimizeReloc32(p,oimage,tmpbuf,true); MemBuffer wrkmem(8*fixupn+8); unsigned ic,jc,o,r; @@ -600,10 +604,10 @@ void PackWcle::decodeFixups() tmpbuf.dealloc(); // selector fixups then self-relative fixups - const upx_byte *selector_fixups = p; + SPAN_P_VAR(const upx_byte, selector_fixups, p); // Find selfrel_fixups by skipping over selector_fixups. - const upx_byte *q = selector_fixups; + SPAN_P_VAR(const upx_byte, q, selector_fixups); // The code is a subroutine that ends in RET (0xC3). while (*q != 0xC3) { // Defend against tampered selector_fixups; see PackWcle::preprocessFixups(). @@ -622,20 +626,21 @@ void PackWcle::decodeFixups() } // Guard against run-away. static unsigned char const blank[9] = {0}; - if (q > (oimage + ph.u_len - sizeof(blank)) // catastrophic worst case + if (ptr_diff_bytes(oimage + ph.u_len - sizeof(blank), raw_bytes(q,0)) < 0 // catastrophic worst case || !memcmp(blank, q, sizeof(blank)) // no-good early warning ) { char msg[50]; snprintf(msg, sizeof(msg), - "bad selector_fixups +%#zx", q - selector_fixups); + "bad selector_fixups %d", ptr_diff_bytes(q, selector_fixups)); throwCantPack(msg); } q += 9; } - unsigned selectlen = ptr_diff(q, selector_fixups)/9; - const upx_byte *selfrel_fixups = 1+ q; // Skip the 0xC3 + unsigned selectlen = ptr_udiff_bytes(q, selector_fixups)/9; + SPAN_P_VAR(const upx_byte, selfrel_fixups, q + 1); // Skip the 0xC3 - ofixups = New(upx_byte, fixupn*9+1000+selectlen*5); - upx_bytep fp = ofixups; + const unsigned fbytes = fixupn*9+1000+selectlen*5; + ofixups = New(upx_byte, fbytes); + SPAN_S_VAR(upx_byte, fp, ofixups, fbytes, ofixups); for (ic = 1, jc = 0; ic <= opages; ic++) { @@ -698,11 +703,11 @@ void PackWcle::decodeFixups() fp += fp[1] ? 9 : 7; jc += 2; } - set_le32(ofpage_table+ic,ptr_diff(fp,ofixups)); + set_le32(ofpage_table+ic,ptr_udiff_bytes(fp,ofixups)); } for (ic=0; ic < FIXUP_EXTRA; ic++) *fp++ = 0; - sofixups = ptr_diff(fp, ofixups); + sofixups = ptr_udiff_bytes(fp, ofixups); } @@ -751,7 +756,8 @@ void PackWcle::decodeObjectTable() void PackWcle::decodeImage() { - oimage.allocForUncompression(ph.u_len); + mb_oimage.allocForUncompression(ph.u_len); + oimage = mb_oimage; decompress(iimage + ph.buf_offset + ph.getPackHeaderSize(),oimage); soimage = get_le32(oimage + ph.u_len - 5); @@ -762,11 +768,13 @@ void PackWcle::decodeImage() void PackWcle::decodeEntryTable() { - unsigned count,object,r; - upx_byte *p = ientries; + unsigned count,object,n,r; + SPAN_S_VAR(upx_byte, p, ientries, soentries); + n = 0; while (*p) { count = *p; + n += count; if (p[1] == 0) // unused bundle p += 2; else if (p[1] == 3) // 32-bit offset bundle @@ -787,8 +795,9 @@ void PackWcle::decodeEntryTable() } //if (Opt_debug) printf("\n%d entries decoded.\n",n); + UNUSED(n); - soentries = ptr_diff(p, ientries) + 1; + soentries = ptr_udiff_bytes(p, ientries) + 1; oentries = ientries; ientries = nullptr; } @@ -852,7 +861,7 @@ void PackWcle::unpack(OutputFile *fo) ft.cto = (unsigned char) ph.filter_cto; if (ph.version < 11) ft.cto = (unsigned char) (get_le32(oimage+ph.u_len-9) >> 24); - ft.unfilter(oimage+text_vaddr, text_size); + ft.unfilter(raw_bytes(oimage+text_vaddr, text_size), text_size); } decodeFixupPageTable(); @@ -878,7 +887,7 @@ void PackWcle::unpack(OutputFile *fo) + getImageSize(); const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length; checkOverlay(overlay); - copyOverlay(fo, overlay, &oimage); + copyOverlay(fo, overlay, mb_oimage); } /* vim:set ts=4 sw=4 et: */ diff --git a/src/packer.cpp b/src/packer.cpp index 4d085ac2..78571929 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -180,7 +180,7 @@ int forced_method(int method) // extract the forced method // compress - wrap call to low-level upx_compress() **************************************************************************/ -bool Packer::compress(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr, +bool Packer::compress(SPAN_P(upx_byte) i_ptr, unsigned i_len, SPAN_P(upx_byte) o_ptr, const upx_compress_config_t *cconf_parm) { ph.u_len = i_len; ph.c_len = 0; @@ -194,7 +194,7 @@ bool Packer::compress(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr, ph.saved_u_adler = ph.u_adler; ph.saved_c_adler = ph.c_adler; // update checksum of uncompressed data - ph.u_adler = upx_adler32(i_ptr, ph.u_len, ph.u_adler); + ph.u_adler = upx_adler32(raw_bytes(i_ptr, ph.u_len), ph.u_len, ph.u_adler); // set compression parameters upx_compress_config_t cconf; @@ -241,8 +241,8 @@ bool Packer::compress(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr, // OutputFile::dump("data.raw", in, ph.u_len); // compress - int r = upx_compress(i_ptr, ph.u_len, o_ptr, &ph.c_len, uip->getCallback(), method, ph.level, - &cconf, &ph.compress_result); + int r = upx_compress(raw_bytes(i_ptr, ph.u_len), ph.u_len, raw_bytes(o_ptr, 0), &ph.c_len, + uip->getCallback(), method, ph.level, &cconf, &ph.compress_result); // uip->finalCallback(ph.u_len, ph.c_len); uip->endCallback(); @@ -277,12 +277,13 @@ bool Packer::compress(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr, return false; // update checksum of compressed data - ph.c_adler = upx_adler32(o_ptr, ph.c_len, ph.c_adler); + ph.c_adler = upx_adler32(raw_bytes(o_ptr, ph.c_len), ph.c_len, ph.c_adler); // Decompress and verify. Skip this when using the fastest level. if (!ph_skipVerify(ph)) { // decompress unsigned new_len = ph.u_len; - r = upx_decompress(o_ptr, ph.c_len, i_ptr, &new_len, method, &ph.compress_result); + r = upx_decompress(raw_bytes(o_ptr, ph.c_len), ph.c_len, raw_bytes(i_ptr, ph.u_len), + &new_len, method, &ph.compress_result); if (r == UPX_E_OUT_OF_MEMORY) throwOutOfMemoryException(); // printf("%d %d: %d %d %d\n", method, r, ph.c_len, ph.u_len, new_len); @@ -292,7 +293,7 @@ bool Packer::compress(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr, throwInternalError("decompression failed (size error)"); // verify decompression - if (ph.u_adler != upx_adler32(i_ptr, ph.u_len, ph.saved_u_adler)) + if (ph.u_adler != upx_adler32(raw_bytes(i_ptr, ph.u_len), ph.u_len, ph.saved_u_adler)) throwInternalError("decompression failed (checksum error)"); } return true; @@ -340,13 +341,13 @@ bool Packer::checkFinalCompressionRatio(const OutputFile *fo) const { // decompress **************************************************************************/ -void ph_decompress(PackHeader &ph, const upx_bytep in, upx_bytep out, bool verify_checksum, - Filter *ft) { +void ph_decompress(PackHeader &ph, SPAN_P(const upx_byte) in, SPAN_P(upx_byte) out, + bool verify_checksum, Filter *ft) { unsigned adler; // verify checksum of compressed data if (verify_checksum) { - adler = upx_adler32(in, ph.c_len, ph.saved_c_adler); + adler = upx_adler32(raw_bytes(in, ph.c_len), ph.c_len, ph.saved_c_adler); if (adler != ph.c_adler) throwChecksumError(); } @@ -356,8 +357,8 @@ void ph_decompress(PackHeader &ph, const upx_bytep in, upx_bytep out, bool verif throwCantUnpack("header corrupted"); } unsigned new_len = ph.u_len; - int r = - upx_decompress(in, ph.c_len, out, &new_len, forced_method(ph.method), &ph.compress_result); + int r = upx_decompress(raw_bytes(in, ph.c_len), ph.c_len, raw_bytes(out, ph.u_len), &new_len, + forced_method(ph.method), &ph.compress_result); if (r == UPX_E_OUT_OF_MEMORY) throwOutOfMemoryException(); if (r != UPX_E_OK || new_len != ph.u_len) @@ -366,14 +367,15 @@ void ph_decompress(PackHeader &ph, const upx_bytep in, upx_bytep out, bool verif // verify checksum of decompressed data if (verify_checksum) { if (ft) - ft->unfilter(out, ph.u_len); - adler = upx_adler32(out, ph.u_len, ph.saved_u_adler); + ft->unfilter(raw_bytes(out, ph.u_len), ph.u_len); + adler = upx_adler32(raw_bytes(out, ph.u_len), ph.u_len, ph.saved_u_adler); if (adler != ph.u_adler) throwChecksumError(); } } -void Packer::decompress(const upx_bytep in, upx_bytep out, bool verify_checksum, Filter *ft) { +void Packer::decompress(SPAN_P(const upx_byte) in, SPAN_P(upx_byte) out, bool verify_checksum, + Filter *ft) { ph_decompress(ph, in, out, verify_checksum, ft); } @@ -535,10 +537,10 @@ void Packer::checkOverlay(unsigned overlay) { throw OverlayException("file has overlay -- skipped; try '--overlay=copy'"); } -void Packer::copyOverlay(OutputFile *fo, unsigned overlay, MemBuffer *buf, bool do_seek) { +void Packer::copyOverlay(OutputFile *fo, unsigned overlay, MemBuffer &buf, bool do_seek) { assert((int) overlay >= 0); assert(overlay < file_size_u); - buf->checkState(); + buf.checkState(); if (!fo || overlay == 0) return; if (opt->overlay != opt->COPY_OVERLAY) { @@ -551,7 +553,7 @@ void Packer::copyOverlay(OutputFile *fo, unsigned overlay, MemBuffer *buf, bool fi->seek(-(upx_off_t) overlay, SEEK_END); // get buffer size, align to improve i/o speed - unsigned buf_size = buf->getSize(); + unsigned buf_size = buf.getSize(); if (buf_size > 65536) buf_size = ALIGN_DOWN(buf_size, 4096u); assert((int) buf_size > 0); @@ -562,7 +564,7 @@ void Packer::copyOverlay(OutputFile *fo, unsigned overlay, MemBuffer *buf, bool fo->write(buf, len); overlay -= len; } while (overlay > 0); - buf->checkState(); + buf.checkState(); } // Create a pseudo-unique program id. @@ -643,14 +645,15 @@ int Packer::patchPackHeader(void *b, int blen) { int boff = find_le32(b, blen, UPX_MAGIC_LE32); checkPatch(b, blen, boff, size); - unsigned char *p = (unsigned char *) b + boff; - ph.putPackHeader(p); + auto bb = (upx_byte *) b; + ph.putPackHeader(SPAN_S_MAKE(upx_byte, bb + boff, blen, bb)); return boff; } -bool Packer::getPackHeader(void const *b, int blen, bool allow_incompressible) { - if (!ph.fillPackHeader((unsigned char const *) b, blen)) +bool Packer::getPackHeader(const void *b, int blen, bool allow_incompressible) { + auto bb = (const upx_byte *) b; + if (!ph.fillPackHeader(SPAN_S_MAKE(const upx_byte, bb, blen), blen)) return false; if (ph.version > getVersion()) @@ -825,18 +828,19 @@ int Packer::patch_le32(void *b, int blen, const void *old, unsigned new_) { // relocation util **************************************************************************/ -upx_byte *Packer::optimizeReloc(upx_byte *in, unsigned relocnum, upx_byte *out, upx_byte *image, - unsigned headway, int bswap, int *big, int bits) { +unsigned Packer::optimizeReloc(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out, + SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big, + int bits) { if (opt->exact) throwCantPackExact(); *big = 0; if (relocnum == 0) - return out; - qsort(in, relocnum, 4, le32_compare); + return 0; + qsort(raw_bytes(in, 4 * relocnum), relocnum, 4, le32_compare); unsigned jc, pc, oc; - upx_byte *fix = out; + SPAN_P_VAR(upx_byte, fix, out); pc = (unsigned) -4; for (jc = 0; jc < relocnum; jc++) { @@ -875,36 +879,35 @@ upx_byte *Packer::optimizeReloc(upx_byte *in, unsigned relocnum, upx_byte *out, } } *fix++ = 0; - return fix; + return ptr_udiff_bytes(fix, out); } -upx_byte *Packer::optimizeReloc32(upx_byte *in, unsigned relocnum, upx_byte *out, upx_byte *image, - unsigned headway, int bswap, int *big) { +unsigned Packer::optimizeReloc32(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out, + SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big) { return optimizeReloc(in, relocnum, out, image, headway, bswap, big, 32); } -upx_byte *Packer::optimizeReloc64(upx_byte *in, unsigned relocnum, upx_byte *out, upx_byte *image, - unsigned headway, int bswap, int *big) { +unsigned Packer::optimizeReloc64(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out, + SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big) { return optimizeReloc(in, relocnum, out, image, headway, bswap, big, 64); } -unsigned Packer::unoptimizeReloc(upx_byte **in, upx_byte *image, MemBuffer *out, int bswap, - int bits) { - upx_byte *p; +unsigned Packer::unoptimizeReloc(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out, + bool bswap, int bits) { + SPAN_P_VAR(upx_byte, p, in); unsigned relocn = 0; - for (p = *in; *p; p++, relocn++) + for (; *p; p++, relocn++) if (*p >= 0xF0) { if (*p == 0xF0 && get_le16(p + 1) == 0) p += 4; p += 2; } - upx_byte const *in_end = p; + SPAN_P_VAR(upx_byte, const in_end, p); // fprintf(stderr,"relocnum=%x\n",relocn); - out->alloc(4 * relocn + 4); // one extra data - LE32 *const outp = (LE32 *) (unsigned char *) *out; - LE32 *relocs = outp; + out.alloc(4 * (relocn + 1)); // one extra entry + SPAN_S_VAR(LE32, relocs, out); unsigned jc = (unsigned) -4; - for (p = *in; p < in_end; p++) { + for (p = in; p < in_end; p++) { if (*p < 0xF0) jc += *p; else { @@ -920,32 +923,34 @@ unsigned Packer::unoptimizeReloc(upx_byte **in, upx_byte *image, MemBuffer *out, if (!relocn--) { break; } - if (bswap && image) { + if (bswap && image != nullptr) { if (bits == 32) { set_be32(image + jc, get_le32(image + jc)); - if ((size_t)(p - (image + jc)) < 4) { + if ((unsigned) ptr_diff_bytes(p, image + jc) < 4) { // data must not overlap control - p = (4 - 1) + image + jc; // -1: 'for' also increments + p = image + jc + (4 - 1); // -1: 'for' also increments } } else if (bits == 64) { set_be64(image + jc, get_le64(image + jc)); - if ((size_t)(p - (image + jc)) < 8) { + if ((unsigned) ptr_diff_bytes(p, image + jc) < 8) { // data must not overlap control - p = (8 - 1) + image + jc; // -1: 'for' also increments + p = image + jc + (8 - 1); // -1: 'for' also increments } } else throwInternalError("unoptimizeReloc problem"); } } - *in = p + 1; - return (unsigned) (relocs - outp); + in = p + 1; + return ptr_udiff_bytes(relocs, out); } -unsigned Packer::unoptimizeReloc32(upx_byte **in, upx_byte *image, MemBuffer *out, int bswap) { +unsigned Packer::unoptimizeReloc32(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out, + bool bswap) { return unoptimizeReloc(in, image, out, bswap, 32); } -unsigned Packer::unoptimizeReloc64(upx_byte **in, upx_byte *image, MemBuffer *out, int bswap) { +unsigned Packer::unoptimizeReloc64(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out, + bool bswap) { return unoptimizeReloc(in, image, out, bswap, 64); } diff --git a/src/packer.h b/src/packer.h index 39ee07d6..fa1a1af0 100644 --- a/src/packer.h +++ b/src/packer.h @@ -25,10 +25,11 @@ */ -#ifndef __UPX_PACKER_H -#define __UPX_PACKER_H 1 +#pragma once +#ifndef UPX_PACKER_H__ +#define UPX_PACKER_H__ 1 -#include "mem.h" +#include "util/membuffer.h" class InputFile; class OutputFile; @@ -42,15 +43,14 @@ class Filter; **************************************************************************/ // see stub/src/include/header.S -class PackHeader { +class PackHeader final { friend class Packer; -private: - // these are strictly private to Packer and not accessible in subclasses + // these are strictly private to friend Packer PackHeader(); - void putPackHeader(upx_bytep p); - bool fillPackHeader(const upx_bytep b, int blen); + void putPackHeader(SPAN_S(upx_byte) p); + bool fillPackHeader(SPAN_S(const upx_byte) b, int blen); public: int getPackHeaderSize() const; @@ -95,9 +95,9 @@ public: }; bool ph_skipVerify(const PackHeader &ph); -void ph_decompress(PackHeader &ph, const upx_bytep in, upx_bytep out, bool verify_checksum, - Filter *ft); -bool ph_testOverlappingDecompression(const PackHeader &ph, const upx_bytep buf, +void ph_decompress(PackHeader &ph, SPAN_P(const upx_byte) in, SPAN_P(upx_byte) out, + bool verify_checksum, Filter *ft); +bool ph_testOverlappingDecompression(const PackHeader &ph, SPAN_P(const upx_byte) buf, unsigned overlap_overhead); /************************************************************************* @@ -107,7 +107,6 @@ bool ph_testOverlappingDecompression(const PackHeader &ph, const upx_bytep buf, **************************************************************************/ class Packer { - // friend class PackMaster; friend class UiPacker; protected: @@ -163,10 +162,10 @@ public: protected: // main compression drivers - virtual bool compress(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr, - const upx_compress_config_t *cconf = nullptr); - virtual void decompress(const upx_bytep in, upx_bytep out, bool verify_checksum = true, - Filter *ft = nullptr); + bool compress(SPAN_P(upx_byte) i_ptr, unsigned i_len, SPAN_P(upx_byte) o_ptr, + const upx_compress_config_t *cconf = nullptr); + void decompress(SPAN_P(const upx_byte) in, SPAN_P(upx_byte) out, bool verify_checksum = true, + Filter *ft = nullptr); virtual bool checkDefaultCompressionRatio(unsigned u_len, unsigned c_len) const; virtual bool checkCompressionRatio(unsigned u_len, unsigned c_len) const; virtual bool checkFinalCompressionRatio(const OutputFile *fo) const; @@ -202,7 +201,7 @@ protected: // packheader handling virtual int patchPackHeader(void *b, int blen); - virtual bool getPackHeader(void const *b, int blen, bool allow_incompressible = false); + virtual bool getPackHeader(const void *b, int blen, bool allow_incompressible = false); virtual bool readPackHeader(int len, bool allow_incompressible = false); virtual void checkAlreadyPacked(const void *b, int blen); @@ -256,7 +255,7 @@ protected: // stub and overlay util static void handleStub(InputFile *fi, OutputFile *fo, unsigned size); virtual void checkOverlay(unsigned overlay); - virtual void copyOverlay(OutputFile *fo, unsigned overlay, MemBuffer *buf, bool do_seek = true); + virtual void copyOverlay(OutputFile *fo, unsigned overlay, MemBuffer &buf, bool do_seek = true); // misc util virtual unsigned getRandomId() const; @@ -273,34 +272,37 @@ protected: void checkPatch(void *b, int blen, int boff, int size); // relocation util - static upx_byte *optimizeReloc(upx_byte *in, unsigned relocnum, upx_byte *out, upx_byte *image, - unsigned headway, int bs, int *big, int bits); - static unsigned unoptimizeReloc(upx_byte **in, upx_byte *image, MemBuffer *out, int bs, - int bits); + static unsigned optimizeReloc(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out, + SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big, + int bits); + static unsigned unoptimizeReloc(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out, + bool bswap, int bits); - static upx_byte *optimizeReloc32(upx_byte *in, unsigned relocnum, upx_byte *out, - upx_byte *image, unsigned headway, int bs, int *big); - static unsigned unoptimizeReloc32(upx_byte **in, upx_byte *image, MemBuffer *out, int bs); + static unsigned optimizeReloc32(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out, + SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big); + static unsigned unoptimizeReloc32(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out, + bool bswap); - static upx_byte *optimizeReloc64(upx_byte *in, unsigned relocnum, upx_byte *out, - upx_byte *image, unsigned headway, int bs, int *big); - static unsigned unoptimizeReloc64(upx_byte **in, upx_byte *image, MemBuffer *out, int bs); + static unsigned optimizeReloc64(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out, + SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big); + static unsigned unoptimizeReloc64(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out, + bool bswap); - // target endianness abstraction + // Target Endianness abstraction unsigned get_te16(const void *p) const { return bele->get16(p); } unsigned get_te32(const void *p) const { return bele->get32(p); } upx_uint64_t get_te64(const void *p) const { return bele->get64(p); } - void set_te16(void *p, unsigned v) const { bele->set16(p, v); } - void set_te32(void *p, unsigned v) const { bele->set32(p, v); } - void set_te64(void *p, upx_uint64_t v) const { bele->set64(p, v); } + void set_te16(void *p, unsigned v) { bele->set16(p, v); } + void set_te32(void *p, unsigned v) { bele->set32(p, v); } + void set_te64(void *p, upx_uint64_t v) { bele->set64(p, v); } protected: const N_BELE_RTP::AbstractPolicy *bele = nullptr; // target endianness InputFile *fi = nullptr; - union { // unnamed union - upx_int64_t file_size; // will get set by constructor - upx_uint64_t file_size_u; // explicitly unsigned + union { // unnamed union + upx_int64_t file_size = 0; // will get set by constructor + upx_uint64_t file_size_u; // explicitly unsigned }; PackHeader ph; // must be filled by canUnpack() diff --git a/src/packhead.cpp b/src/packhead.cpp index 48085431..58e52ac9 100644 --- a/src/packhead.cpp +++ b/src/packhead.cpp @@ -41,7 +41,7 @@ PackHeader::PackHeader() : version(-1), format(-1) {} // simple checksum for the header itself (since version 10) **************************************************************************/ -static unsigned char get_packheader_checksum(const upx_bytep buf, int len) { +static unsigned char get_packheader_checksum(SPAN_S(const upx_byte) buf, int len) { assert(len >= 4); assert(get_le32(buf) == UPX_MAGIC_LE32); // printf("1 %d\n", len); @@ -92,7 +92,7 @@ int PackHeader::getPackHeaderSize() const { // see stub/header.ash **************************************************************************/ -void PackHeader::putPackHeader(upx_bytep p) { +void PackHeader::putPackHeader(SPAN_S(upx_byte) p) { // NOTE: It is the caller's responsbility to ensure the buffer p has // sufficient space for the header. assert(get_le32(p) == UPX_MAGIC_LE32); @@ -170,12 +170,12 @@ void PackHeader::putPackHeader(upx_bytep p) { // **************************************************************************/ -bool PackHeader::fillPackHeader(const upx_bytep buf, int blen) { - int boff = find_le32(buf, blen, UPX_MAGIC_LE32); +bool PackHeader::fillPackHeader(SPAN_S(const upx_byte) buf, int blen) { + int boff = find_le32(raw_bytes(buf, blen), blen, UPX_MAGIC_LE32); if (boff < 0) return false; - const upx_bytep const p = buf + boff; + SPAN_S_VAR(const upx_byte, p, buf + boff); unsigned const headway = blen - boff; // bytes remaining in buf if (headway < (1 + 7)) diff --git a/src/pefile.cpp b/src/pefile.cpp index 84baf04d..1ae8c7aa 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -39,42 +39,51 @@ // **************************************************************************/ -#include "bptr.h" -#define IPTR(type, var) BoundedPtr var(ibuf, ibuf.getSize()) -#define OPTR(type, var) BoundedPtr var(obuf, obuf.getSize()) -#define IPTR_I_D(type, var, disp) \ - BoundedPtr var(ibuf + (disp), ibuf.getSize() - (disp), ibuf + (disp)) -#define IPTR_I(type, var, v) BoundedPtr var(ibuf, ibuf.getSize(), v) -#define OPTR_I(type, var, v) BoundedPtr var(obuf, obuf.getSize(), v) -#define IPTR_C(type, var, v) const BoundedPtr var(ibuf, ibuf.getSize(), v) -#define OPTR_C(type, var, v) const BoundedPtr var(obuf, obuf.getSize(), v) +#include "util/bptr.h" +#if (WITH_SPAN >= 2) && 1 +//#define IPTR(type, var) Span var(ibuf, ibuf.getSize(), ibuf) +//#define OPTR(type, var) Span var(obuf, obuf.getSize(), obuf) +#define IPTR_I_D(type, var, disp) Span var(ibuf + (disp), ibuf.getSize() - (disp), ibuf + (disp)) +#define IPTR_I(type, var, first) Span var(first, ibuf) +#define OPTR_I(type, var, first) Span var(first, obuf) +#define IPTR_C(type, var, first) const Span var(first, ibuf) +#define OPTR_C(type, var, first) const Span var(first, obuf) +#else +//#define IPTR(type, var) BoundedPtr var(ibuf, ibuf.getSize()) +//#define OPTR(type, var) BoundedPtr var(obuf, obuf.getSize()) +#define IPTR_I_D(type, var, disp) BoundedPtr var(ibuf + (disp), ibuf.getSize() - (disp), ibuf + (disp)) +#define IPTR_I(type, var, first) BoundedPtr var(ibuf, ibuf.getSize(), first) +#define OPTR_I(type, var, first) BoundedPtr var(obuf, obuf.getSize(), first) +#define IPTR_C(type, var, first) const BoundedPtr var(ibuf, ibuf.getSize(), first) +#define OPTR_C(type, var, first) const BoundedPtr var(obuf, obuf.getSize(), first) +#endif static void xcheck(const void *p) { if (!p) - throwCantUnpack("unexpected nullptr pointer; take care!"); + throwCantUnpack("xcheck unexpected nullptr pointer; take care!"); } static void xcheck(const void *p, size_t plen, const void *b, size_t blen) { const char *pp = (const char *) p; const char *bb = (const char *) b; if (pp < bb || pp > bb + blen || pp + plen > bb + blen) - throwCantUnpack("pointer out of range; take care!"); + throwCantUnpack("xcheck pointer out of range; take care!"); } #if 0 static void xcheck(size_t poff, size_t plen, const void *b, size_t blen) { ACC_UNUSED(b); if (poff > blen || poff + plen > blen) - throwCantUnpack("pointer out of range; take care!"); + throwCantUnpack("xcheck pointer out of range; take care!"); } #endif -#define ICHECK(x, size) xcheck(x, size, ibuf, ibuf.getSize()) -#define OCHECK(x, size) xcheck(x, size, obuf, obuf.getSize()) +#define ICHECK(x, size) xcheck(raw_bytes(x, 0), size, ibuf, ibuf.getSize()) +#define OCHECK(x, size) xcheck(raw_bytes(x, 0), size, obuf, obuf.getSize()) -#define imemset(a,b,c) ICHECK(a,c), memset(a,b,c) -#define omemset(a,b,c) OCHECK(a,c), memset(a,b,c) -#define imemcpy(a,b,c) ICHECK(a,c), memcpy(a,b,c) +//#define imemset(a,b,c) ICHECK(a,c), memset(a,b,c) +//#define omemset(a,b,c) OCHECK(a,c), memset(a,b,c) +//#define imemcpy(a,b,c) ICHECK(a,c), memcpy(a,b,c) #define omemcpy(a,b,c) OCHECK(a,c), memcpy(a,b,c) #define omemmove(a,b,c) OCHECK(a,c), memmove(a,b,c) @@ -211,12 +220,12 @@ PeFile::Interval::~Interval() void PeFile::Interval::add(const void *start,unsigned len) { - add(ptr_diff(start,base),len); + add(ptr_diff_bytes(start,base),len); } void PeFile::Interval::add(const void *start,const void *end) { - add(ptr_diff(start,base),ptr_diff(end,start)); + add(ptr_diff_bytes(start,base),ptr_diff_bytes(end,start)); } int __acc_cdecl_qsort PeFile::Interval::compare(const void *p1,const void *p2) @@ -306,7 +315,7 @@ PeFile::Reloc::Reloc(upx_byte *s,unsigned si) : PeFile::Reloc::Reloc(unsigned rnum) : start(nullptr), size(0), rel(nullptr), rel1(nullptr) { - start = new upx_byte[mem_size(4, rnum, 8192)]; + start = new upx_byte[mem_size(4, rnum, 8192)]; // => oxrelocs counts[0] = 0; } @@ -314,7 +323,7 @@ bool PeFile::Reloc::next(unsigned &pos,unsigned &type) { if (!rel) newRelocPos(start); - if (ptr_diff(rel, start) >= (int) size) { + if (ptr_diff_bytes(rel, start) >= (int) size) { rel = nullptr; // rewind return false; } @@ -322,7 +331,7 @@ bool PeFile::Reloc::next(unsigned &pos,unsigned &type) pos = rel->pagestart + (*rel1 & 0xfff); type = *rel1++ >> 12; //printf("%x %d\n",pos,type); - if (ptr_diff(rel1,rel) >= (int) rel->size) + if (ptr_diff_bytes(rel1,rel) >= (int) rel->size) newRelocPos(rel1); return type == 0 ? next(pos,type) : true; } @@ -347,14 +356,14 @@ void PeFile::Reloc::finish(upx_byte *&p,unsigned &siz) { prev = pos; *rel1 = 0; - rel->size = ALIGN_UP(ptr_diff(rel1,rel), 4); + rel->size = ALIGN_UP(ptr_diff_bytes(rel1,rel), 4); newRelocPos((char *)rel + rel->size); rel->pagestart = (pos >> 4) &~ 0xfff; } *rel1++ = (pos << 12) + ((pos >> 4) & 0xfff); } p = start; - siz = ptr_diff(rel1,start) &~ 3; + siz = ptr_udiff_bytes(rel1,start) &~ 3; siz -= 8; // siz can be 0 in 64-bit mode // assert(siz > 0); start = nullptr; // safety @@ -389,7 +398,7 @@ void PeFile32::processRelocs() // pass1 ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects); } mb_orelocs.alloc(1); - orelocs = (upx_byte *)mb_orelocs.getVoidPtr(); + orelocs = mb_orelocs; sorelocs = 0; return; } @@ -439,10 +448,9 @@ void PeFile32::processRelocs() // pass1 ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); mb_orelocs.alloc(mem_size(4, rnum, 1024)); // 1024 - safety - orelocs = (upx_byte *)mb_orelocs.getVoidPtr(); - sorelocs = ptr_diff(optimizeReloc32((upx_byte*) fix[3], xcounts[3], - orelocs, ibuf + rvamin, ibufgood - rvamin, 1, &big_relocs), - orelocs); + orelocs = mb_orelocs; + sorelocs = optimizeReloc32((upx_byte*) fix[3], xcounts[3], + orelocs, ibuf + rvamin, ibufgood - rvamin, true, &big_relocs); delete [] fix[3]; // Malware that hides behind UPX often has PE header info that is @@ -492,7 +500,7 @@ void PeFile64::processRelocs() // pass1 ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects); } mb_orelocs.alloc(1); - orelocs = (upx_byte *)mb_orelocs.getVoidPtr(); + orelocs = mb_orelocs; sorelocs = 0; return; } @@ -545,10 +553,9 @@ void PeFile64::processRelocs() // pass1 ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); mb_orelocs.alloc(mem_size(4, rnum, 1024)); // 1024 - safety - orelocs = (upx_byte *)mb_orelocs.getVoidPtr(); - sorelocs = ptr_diff(optimizeReloc64((upx_byte*) fix[10], xcounts[10], - orelocs, ibuf + rvamin, ibufgood - rvamin, 1, &big_relocs), - orelocs); + orelocs = mb_orelocs; + sorelocs = optimizeReloc64((upx_byte*) fix[10], xcounts[10], + orelocs, ibuf + rvamin, ibufgood - rvamin, true, &big_relocs); for (ic = 15; ic; ic--) delete [] fix[ic]; @@ -896,7 +903,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 if (IDADDR(PEDIR_IMPORT)) { for (;; ++dllnum, ++im) { - unsigned const skip2 = ptr_diff(im, ibuf); + unsigned const skip2 = ptr_diff_bytes(im, ibuf); (void)ibuf.subref("bad import %#x", skip2, sizeof(*im)); if (!im->dllname) break; @@ -975,8 +982,8 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 } } mb_oimport.alloc(soimport); - oimport = (upx_byte *)mb_oimport.getVoidPtr(); - memset(oimport,0,soimport); + mb_oimport.clear(); + oimport = mb_oimport; qsort(idlls,dllnum,sizeof (udll*),udll::compare); @@ -1017,7 +1024,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 Interval names(ibuf),iats(ibuf),lookups(ibuf); // create the preprocessed data - upx_byte *ppi = oimport; // preprocessed imports + SPAN_P_VAR(upx_byte, ppi, oimport); // preprocessed imports for (ic = 0; ic < dllnum; ic++) { LEXX *tarr = idlls[ic]->lookupt; @@ -1052,7 +1059,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 } ppi++; - unsigned esize = ptr_diff((char *)tarr, (char *)idlls[ic]->lookupt); + unsigned esize = ptr_diff_bytes(tarr, idlls[ic]->lookupt); lookups.add(idlls[ic]->lookupt,esize); if (ptr_diff(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1), (char *)idlls[ic]->lookupt)) { @@ -1063,7 +1070,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 } ppi += 4; assert(ppi < oimport+soimport); - soimport = ptr_diff(ppi,oimport); + soimport = ptr_diff_bytes(ppi,oimport); if (soimport == 4) soimport = 0; @@ -1088,7 +1095,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 for (ic = 0; ic < dllnum; ic++, im++) { memset(im,FILLVAL,sizeof(*im)); - im->dllname = ptr_diff(dlls[idlls[ic]->original_position].name,ibuf); + im->dllname = ptr_diff_bytes(dlls[idlls[ic]->original_position].name,ibuf); } } else @@ -1250,14 +1257,14 @@ void PeFile::processExports(Export *xport) // pass1 xport->convert(IDADDR(PEDIR_EXPORT),IDSIZE(PEDIR_EXPORT)); soexport = ALIGN_UP(xport->getsize(), 4u); mb_oexport.alloc(soexport); - oexport = (upx_byte *)mb_oexport.getVoidPtr(); - memset(oexport, 0, soexport); + mb_oexport.clear(); + oexport = mb_oexport; } void PeFile::processExports(Export *xport,unsigned newoffs) // pass2 { if (soexport) - xport->build((char*) oexport,newoffs); + xport->build((char *) raw_bytes(oexport, 0), newoffs); } @@ -1382,8 +1389,8 @@ void PeFile::processTls1(Interval *iv, // the PE loader wants this stuff uncompressed mb_otls.alloc(sotls); - otls = (upx_byte *)mb_otls.getVoidPtr(); - memset(otls,0,sotls); + mb_otls.clear(); + otls = mb_otls; // => SPAN_S unsigned const take1 = sizeof(tls); unsigned const skip1 = IDADDR(PEDIR_TLS); memcpy(otls,ibuf.subref("bad tls %#x", skip1, take1), take1); @@ -1422,16 +1429,17 @@ void PeFile::processTls2(Reloc *rel,const Interval *iv,unsigned newaddr, for (ic = 0; ic < (use_tls_callbacks ? 4 * cb_size : 3 * cb_size); ic += cb_size) rel->add(newaddr + ic, reloc_type); - tls * const tlsp = (tls*) otls; + SPAN_S_VAR(tls, const tlsp, mb_otls); // now the relocation entries in the tls data area for (ic = 0; ic < iv->ivnum; ic += 4) { - void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - imagebase) + sizeof(tls); - cb_value_t kc = *(LEXX*)(p); + SPAN_S_VAR(upx_byte, pp, otls + (iv->ivarr[ic].start - (tlsp->datastart - imagebase) + sizeof(tls))); + LEXX * const p = (LEXX *) raw_bytes(pp, sizeof(LEXX)); + cb_value_t kc = *p; if (kc < tlsp->dataend && kc >= tlsp->datastart) { kc += newaddr + sizeof(tls) - tlsp->datastart; - *(LEXX*)(p) = kc + imagebase; + *p = kc + imagebase; rel->add(kc,iv->ivarr[ic].len); } else @@ -1442,16 +1450,19 @@ void PeFile::processTls2(Reloc *rel,const Interval *iv,unsigned newaddr, tlsp->datastart = newaddr + sizeof(tls) + imagebase; tlsp->dataend = tlsp->datastart + tls_data_size; - //NEW: if we have TLS callbacks to handle, we create a pointer to the new callback chain - Stefan Widmann + // NEW: if we have TLS callbacks to handle, we create a pointer to the new callback chain - Stefan Widmann tlsp->callbacks = (use_tls_callbacks ? newaddr + sotls + imagebase - 2 * cb_size : 0); if (use_tls_callbacks) { - //set handler offset - *(LEXX*)(otls + sotls - 2 * cb_size) = tls_handler_offset + imagebase; - *(LEXX*)(otls + sotls - 1 * cb_size) = 0; // end of one-item list - //add relocation for TLS handler offset - rel->add(newaddr + sotls - 2 * cb_size, reloc_type); + // set handler offset + SPAN_S_VAR(upx_byte, pp, otls); + pp = otls + (sotls - 2 * cb_size); + * (LEXX *) raw_bytes(pp, sizeof(LEXX)) = tls_handler_offset + imagebase; + pp = otls + (sotls - 1 * cb_size); + * (LEXX *) raw_bytes(pp, sizeof(LEXX)) = 0; // end of one-item list + // add relocation for TLS handler offset + rel->add(newaddr + sotls - 2 * cb_size, reloc_type); } } @@ -1947,8 +1958,9 @@ void PeFile::processResources(Resource *res) for (soresources = res->dirsize(); res->next(); soresources += 4 + res->size()) ; mb_oresources.alloc(soresources); - oresources = (upx_byte *)mb_oresources.getVoidPtr(); - upx_byte *ores = oresources + res->dirsize(); + mb_oresources.clear(); + oresources = mb_oresources; // => SPAN_S + SPAN_S_VAR(upx_byte, ores, oresources + res->dirsize()); char *keep_icons = nullptr; // icon ids in the first icon group unsigned iconsin1stdir = 0; @@ -2026,14 +2038,14 @@ void PeFile::processResources(Resource *res) ICHECK(ibuf + res->offs(), take); memcpy(ores, ibuf.subref("bad resoff %#x", res->offs(), take), take); ibuf.fill(res->offs(), take, FILLVAL); - res->newoffs() = ptr_diff(ores,oresources); + res->newoffs() = ptr_diff_bytes(ores,oresources); if (rtype == RT_ICON && opt->win32_pe.compress_icons == 1) compress_icon = true; else if (rtype == RT_GROUP_ICON) { if (opt->win32_pe.compress_icons == 1) { - icondir_offset = 4 + ptr_diff(ores,oresources); + icondir_offset = 4 + ptr_diff_bytes(ores,oresources); icondir_count = get_le16(oresources + icondir_offset); set_le16(oresources + icondir_offset,1); } @@ -2041,7 +2053,7 @@ void PeFile::processResources(Resource *res) } ores += res->size(); } - soresources = ptr_diff(ores,oresources); + soresources = ptr_diff_bytes(ores,oresources); delete[] keep_icons; if (!res->clear()) @@ -2446,7 +2458,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, s += 2; } // end of extra data - set_le32(p1 + s,ptr_diff(p1,ibuf) - rvamin); + set_le32(p1 + s,ptr_diff_bytes(p1,ibuf) - rvamin); s += 4; ph.u_len += s; obuf.allocForCompression(ph.u_len); @@ -2710,16 +2722,16 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, OutputFile::dump(opt->debug.dump_stub_loader, loader, codesize); if ((ic = fo->getBytesWritten() & (sizeof(LEXX) - 1)) != 0) fo->write(ibuf, sizeof(LEXX) - ic); - fo->write(otls, aligned_sotls); + fo->write(raw_bytes(otls, aligned_sotls), aligned_sotls); fo->write(oloadconf, soloadconf); if ((ic = fo->getBytesWritten() & fam1) != 0) fo->write(ibuf,oh.filealign - ic); if (!last_section_rsrc_only) - fo->write(oresources,soresources); + fo->write(raw_bytes(oresources, soresources) ,soresources); else fo->write(oxrelocs,soxrelocs); fo->write(oimpdlls,soimpdlls); - fo->write(oexport,soexport); + fo->write(raw_bytes(oexport, soexport), soexport); if (!last_section_rsrc_only) fo->write(oxrelocs,soxrelocs); @@ -2728,7 +2740,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, if (last_section_rsrc_only) { - fo->write(oresources,soresources); + fo->write(raw_bytes(oresources, soresources) ,soresources); if ((ic = fo->getBytesWritten() & fam1) != 0) fo->write(ibuf,oh.filealign - ic); } @@ -2752,7 +2764,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, verifyOverlappingDecompression(); // copy the overlay - copyOverlay(fo, overlay, &obuf); + copyOverlay(fo, overlay, obuf); // finally check the compression ratio if (!checkFinalCompressionRatio(fo)) @@ -2763,7 +2775,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, // unpack **************************************************************************/ -void PeFile::rebuildRelocs(upx_byte *& extrainfo, unsigned bits, +void PeFile::rebuildRelocs(SPAN_S(upx_byte) & extrainfo, unsigned bits, unsigned flags, upx_uint64_t imagebase) { assert(bits == 32 || bits == 64); @@ -2776,18 +2788,17 @@ void PeFile::rebuildRelocs(upx_byte *& extrainfo, unsigned bits, return; } - upx_byte *rdata = obuf + get_le32(extrainfo); + SPAN_P_VAR(upx_byte, rdata, obuf); + rdata += get_le32(extrainfo); const upx_byte big = extrainfo[4]; extrainfo += 5; -// upx_byte *p = rdata; - OPTR_I(upx_byte, p, rdata); - MemBuffer wrkmem; - unsigned relocn = unoptimizeReloc(&rdata,obuf,&wrkmem,1,bits); + MemBuffer mb_wrkmem; + unsigned relocn = unoptimizeReloc(rdata,obuf,mb_wrkmem,true,bits); unsigned r16 = 0; if (big & 6) // 16 bit relocations { - const LE32 *q = (LE32*) rdata; + SPAN_S_VAR(const LE32, q, (const LE32 *) raw_bytes(rdata, 0), obuf); while (*q++) r16++; if ((big & 6) == 6) @@ -2798,31 +2809,30 @@ void PeFile::rebuildRelocs(upx_byte *& extrainfo, unsigned bits, if (big & 6) { - LE32 *q = (LE32*) rdata; + SPAN_S_VAR(LE32, q, (LE32 *) raw_bytes(rdata, 0), obuf); while (*q) rel.add(*q++ + rvamin,(big & 4) ? 2 : 1); if ((big & 6) == 6) while (*++q) rel.add(*q + rvamin,1); - rdata = (upx_byte*) q; + // rdata = (upx_byte *) raw_bytes(q, 0); // ??? } - //memset(p,0,rdata - p); - + SPAN_S_VAR(upx_byte, const wrkmem, mb_wrkmem); for (unsigned ic = 0; ic < relocn; ic++) { - p = obuf + get_le32(wrkmem + 4 * ic); + OPTR_I(upx_byte, p, obuf + get_le32(wrkmem + 4 * ic)); if (bits == 32) - set_le32(p, get_le32((unsigned char *)p) + imagebase + rvamin); + set_le32(p, get_le32(p) + imagebase + rvamin); else - set_le64(p, get_le64((unsigned char *)p) + imagebase + rvamin); + set_le64(p, get_le64(p) + imagebase + rvamin); rel.add(rvamin + get_le32(wrkmem + 4 * ic), bits == 32 ? 3 : 10); } rel.finish (oxrelocs,soxrelocs); omemcpy(obuf + ODADDR(PEDIR_RELOC) - rvamin,oxrelocs,soxrelocs); delete [] oxrelocs; oxrelocs = nullptr; - wrkmem.dealloc(); + mb_wrkmem.dealloc(); ODSIZE(PEDIR_RELOC) = soxrelocs; } @@ -2836,7 +2846,7 @@ void PeFile::rebuildExports() Export xport((char*)(unsigned char*) ibuf - isection[2].vaddr); processExports(&xport); processExports(&xport,ODADDR(PEDIR_EXPORT)); - omemcpy(obuf + ODADDR(PEDIR_EXPORT) - rvamin,oexport,soexport); + omemcpy(obuf + ODADDR(PEDIR_EXPORT) - rvamin, oexport, soexport); } void PeFile::rebuildTls() @@ -2844,7 +2854,7 @@ void PeFile::rebuildTls() // this is an easy one : just do nothing ;-) } -void PeFile::rebuildResources(upx_byte *& extrainfo, unsigned lastvaddr) +void PeFile::rebuildResources(SPAN_S(upx_byte) & extrainfo, unsigned lastvaddr) { if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0) return; @@ -2857,7 +2867,8 @@ void PeFile::rebuildResources(upx_byte *& extrainfo, unsigned lastvaddr) if (lastvaddr > vaddr || (vaddr - lastvaddr) > ibuf.getSize()) throwCantUnpack("corrupted PE header"); - const upx_byte *r = ibuf - lastvaddr; + // TODO: introduce WildPtr for "virtual pointer" pointing before a buffer + const upx_byte *r = ibuf.raw_bytes(0) - lastvaddr; Resource res(r + vaddr, ibuf, ibuf + ibuf.getSize()); while (res.next()) if (res.offs() > vaddr) @@ -2882,29 +2893,25 @@ void PeFile::rebuildResources(upx_byte *& extrainfo, unsigned lastvaddr) } template -void PeFile::rebuildImports(upx_byte *& extrainfo, +void PeFile::rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, bool set_oft) { if (ODADDR(PEDIR_IMPORT) == 0 || ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc)) return; -// const upx_byte * const idata = obuf + get_le32(extrainfo); OPTR_C(const upx_byte, idata, obuf + get_le32(extrainfo)); const unsigned inamespos = get_le32(extrainfo + 4); extrainfo += 8; unsigned sdllnames = 0; -// const upx_byte *import = ibuf + IDADDR(PEDIR_IMPORT) - isection[2].vaddr; -// const upx_byte *p; IPTR_I_D(const upx_byte, import, IDADDR(PEDIR_IMPORT) - isection[2].vaddr); - OPTR(const upx_byte, p); + OPTR_I(const upx_byte, p, raw_bytes(idata, 4)); - for (p = idata; get_le32(p) != 0; ++p) + for ( ; get_le32(p) != 0; ++p) { - const upx_byte *dname = get_le32(p) + import; - ICHECK(dname, 1); + const upx_byte *dname = raw_bytes(import + get_le32(p), 1); const unsigned dlen = strlen(dname); ICHECK(dname, dlen + 1); @@ -2919,18 +2926,26 @@ void PeFile::rebuildImports(upx_byte *& extrainfo, } sdllnames = ALIGN_UP(sdllnames, 2u); - upx_byte * const Obuf = obuf - rvamin; + // TODO: introduce WildPtr for "virtual pointer" pointing before a buffer + upx_byte * const Obuf = obuf.raw_bytes(0) - rvamin; +#if 0 import_desc * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT)); import_desc *im = im0; upx_byte *dllnames = Obuf + inamespos; upx_byte *importednames = dllnames + sdllnames; upx_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, im, im0); + SPAN_0_VAR(upx_byte, dllnames, inamespos ? Obuf + inamespos : nullptr, obuf); + SPAN_0_VAR(upx_byte, importednames, inamespos ? dllnames + sdllnames : nullptr); + SPAN_0_VAR(upx_byte, const importednames_start, importednames); +#endif for (p = idata; get_le32(p) != 0; ++p) { // restore the name of the dll - const upx_byte *dname = get_le32(p) + import; - ICHECK(dname, 1); + const upx_byte *dname = raw_bytes(import + get_le32(p), 1); const unsigned dlen = strlen(dname); ICHECK(dname, dlen + 1); @@ -2939,7 +2954,7 @@ void PeFile::rebuildImports(upx_byte *& extrainfo, { // now I rebuild the dll names omemcpy(dllnames, dname, dlen + 1); - im->dllname = ptr_diff(dllnames,Obuf); + im->dllname = ptr_diff_bytes(dllnames,Obuf); //;;;printf("\ndll: %s:",dllnames); dllnames += dlen + 1; } @@ -2960,11 +2975,11 @@ void PeFile::rebuildImports(upx_byte *& extrainfo, const unsigned ilen = strlen(++p) + 1; if (inamespos) { - if (ptr_diff(importednames, importednames_start) & 1) + if (ptr_diff_bytes(importednames, importednames_start) & 1) importednames -= 1; omemcpy(importednames + 2, p, ilen); //;;;printf(" %s",importednames+2); - *newiat = ptr_diff(importednames, Obuf); + *newiat = ptr_diff_bytes(importednames, Obuf); importednames += 2 + ilen; } else @@ -2982,7 +2997,7 @@ void PeFile::rebuildImports(upx_byte *& extrainfo, } else { - *newiat = *(const LEXX*)(get_le32(p + 1) + import); + *newiat = * (const LEXX*) raw_bytes(import + get_le32(p + 1), sizeof(LEXX)); assert(*newiat & ord_mask); p += 5; } @@ -3017,8 +3032,9 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, decompress(ibuf,obuf); unsigned skip = get_le32(obuf + ph.u_len - 4); unsigned take = sizeof(oh); - upx_byte *extrainfo = obuf.subref("bad extrainfo offset %#x", skip, take); - //upx_byte * const eistart = extrainfo; + SPAN_S_VAR(upx_byte, extrainfo, obuf); + extrainfo = obuf.subref("bad extrainfo offset %#x", skip, take); + //upx_byte * const eistart = raw_bytes(extrainfo, 0); memcpy(&oh, extrainfo, take); extrainfo += take; @@ -3080,7 +3096,7 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, //FIXME: this does bad things if the relocation section got removed // during compression ... - //memset(eistart,0,extrainfo - eistart + 4); + //memset(eistart, 0, ptr_udiff_bytes(extrainfo, eistart) + 4); // fill the data directory ODADDR(PEDIR_DEBUG) = 0; @@ -3112,7 +3128,7 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, for (ic = 0; ic < objs; ic++) if (osection[ic].rawdataptr) fo->write(obuf + osection[ic].vaddr - rvamin,ALIGN_UP(osection[ic].size,oh.filealign)); - copyOverlay(fo, overlay, &obuf); + copyOverlay(fo, overlay, obuf); } ibuf.dealloc(); } diff --git a/src/pefile.h b/src/pefile.h index 5e25211e..adc923a0 100644 --- a/src/pefile.h +++ b/src/pefile.h @@ -29,7 +29,7 @@ #ifndef __UPX_PEFILE_H #define __UPX_PEFILE_H 1 -#include "mem.h" +#include "util/membuffer.h" /************************************************************************* @@ -40,7 +40,7 @@ class PeFile : public Packer { typedef Packer super; public: - virtual int getVersion() const { return 13; } + virtual int getVersion() const override { return 13; } protected: class Interval; class Reloc; @@ -84,7 +84,7 @@ protected: ord_mask_t ord_mask, bool set_oft); // unpacker capabilities - virtual bool canUnpackVersion(int version) const + virtual bool canUnpackVersion(int version) const override { return (version >= 12 && version <= 13); } int canUnpack0(unsigned max_sections, LE16 &ih_objects, @@ -92,7 +92,7 @@ protected: protected: virtual int readFileHeader(); - virtual bool testUnpackVersion(int version) const; + virtual bool testUnpackVersion(int version) const override; virtual void readPeHeader() = 0; unsigned pe_offset; @@ -101,12 +101,12 @@ protected: unsigned processImports0(ord_mask_t ord_mask); template - void rebuildImports(upx_byte *& extrainfo, + void rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, bool set_oft); virtual unsigned processImports() = 0; virtual void processImports2(unsigned, unsigned); MemBuffer mb_oimport; - upx_byte *oimport; + SPAN_0(upx_byte) oimport = nullptr; unsigned soimport; upx_byte *oimpdlls; unsigned soimpdlls; @@ -118,26 +118,26 @@ protected: virtual void processRelocs() = 0; void processRelocs(Reloc *); - void rebuildRelocs(upx_byte *&, unsigned bits, + void rebuildRelocs(SPAN_S(upx_byte) &, unsigned bits, unsigned flags, upx_uint64_t imagebase); MemBuffer mb_orelocs; - upx_byte *orelocs; + SPAN_0(upx_byte) orelocs = nullptr; unsigned sorelocs; - upx_byte *oxrelocs; + upx_byte *oxrelocs = nullptr; unsigned soxrelocs; void processExports(Export *); void processExports(Export *,unsigned); void rebuildExports(); MemBuffer mb_oexport; - upx_byte *oexport; + SPAN_0(upx_byte) oexport = nullptr; unsigned soexport; void processResources(Resource *); void processResources(Resource *, unsigned); - void rebuildResources(upx_byte *&, unsigned); + void rebuildResources(SPAN_S(upx_byte) &, unsigned); MemBuffer mb_oresources; - upx_byte *oresources; + SPAN_0(upx_byte) oresources = nullptr; unsigned soresources; template @@ -154,7 +154,7 @@ protected: void rebuildTls(); MemBuffer mb_otls; - upx_byte *otls; + SPAN_0(upx_byte) otls = nullptr; unsigned sotls; unsigned tlsindex; unsigned tlscb_ptr; @@ -357,7 +357,7 @@ protected: const unsigned *getcounts() const { return counts; } // void add(unsigned pos,unsigned type); - void finish(upx_byte *&p,unsigned &size); + void finish(upx_byte* &p,unsigned &size); }; class Resource : private noncopyable @@ -460,15 +460,15 @@ protected: virtual ~PeFile32(); void pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase, bool last_section_rsrc_only); - virtual void unpack(OutputFile *fo); - virtual int canUnpack(); + virtual void unpack(OutputFile *fo) override; + virtual int canUnpack() override; - virtual void readPeHeader(); + virtual void readPeHeader() override; - virtual unsigned processImports(); - virtual void processRelocs(); - virtual void processTls(Interval *); - virtual void processTls(Reloc *, const Interval *, unsigned); + virtual unsigned processImports() override; + virtual void processRelocs() override; + virtual void processTls(Interval *) override; + virtual void processTls(Reloc *, const Interval *, unsigned) override; __packed_struct(pe_header_t) // 0x0 @@ -522,15 +522,15 @@ protected: void pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase); - virtual void unpack(OutputFile *fo); - virtual int canUnpack(); + virtual void unpack(OutputFile *fo) override; + virtual int canUnpack() override; - virtual void readPeHeader(); + virtual void readPeHeader() override; - virtual unsigned processImports(); - virtual void processRelocs(); - virtual void processTls(Interval *); - virtual void processTls(Reloc *, const Interval *, unsigned); + virtual unsigned processImports() override; + virtual void processRelocs() override; + virtual void processTls(Interval *) override; + virtual void processTls(Reloc *, const Interval *, unsigned) override; __packed_struct(pe_header_t) // 0x0 diff --git a/src/stub/tools/macho-snip/macho-snip.c b/src/stub/tools/macho-snip/macho-snip.c index 0afcd6fb..169cf67b 100644 --- a/src/stub/tools/macho-snip/macho-snip.c +++ b/src/stub/tools/macho-snip/macho-snip.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +// SPDX-License-Identifier: GPL-2.0-or-later // Copyright 2022 BitWagon Software LLC. All rights reserved. #include diff --git a/src/ui.h b/src/ui.h index e8221578..59c20137 100644 --- a/src/ui.h +++ b/src/ui.h @@ -25,6 +25,7 @@ */ +#pragma once #ifndef __UPX_UI_H #define __UPX_UI_H 1 diff --git a/src/util/bptr.h b/src/util/bptr.h new file mode 100644 index 00000000..64646c8f --- /dev/null +++ b/src/util/bptr.h @@ -0,0 +1,142 @@ +/* bptr.h -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2022 Laszlo Molnar + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer Laszlo Molnar + + */ + +#pragma once +#ifndef UPX_BPTR_H__ +#define UPX_BPTR_H__ 1 + +/************************************************************************* +// BoundedPtr +**************************************************************************/ + +template +class BoundedPtr { +public: + ~BoundedPtr() {} + + BoundedPtr(void *base, size_t size_in_bytes, T *ptr = nullptr) + : ptr_(ptr), base_(base), size_in_bytes_(0) { + assert(base_ != nullptr); + size_in_bytes_ = mem_size(1, size_in_bytes); + check(); + } + + // assignment + BoundedPtr &operator=(const BoundedPtr &other) { + assert(base_ == other.base_); + assert(size_in_bytes_ == other.size_in_bytes_); + ptr_ = other.ptr_; + check(); + return *this; + } + BoundedPtr &operator=(T *other) { + ptr_ = other; + check(); + return *this; + } + + // dereference + T &operator*() { + checkNULL(); + checkRange(ptr_ + 1); + return *ptr_; + } + const T &operator*() const { + checkNULL(); + checkRange(ptr_ + 1); + return *ptr_; + } + + operator T *() { return ptr_; } + operator const T *() const { return ptr_; } + + BoundedPtr &operator+=(size_t n) { + checkNULL(); + ptr_ += n; + checkRange(); + return *this; + } + BoundedPtr &operator-=(size_t n) { + checkNULL(); + ptr_ -= n; + checkRange(); + return *this; + } + BoundedPtr &operator++(void) { + checkNULL(); + ptr_ += 1; + checkRange(); + return *this; + } + + T *raw_bytes(size_t bytes) const { + checkNULL(); + if (bytes > 0) + checkRange((const char *) (const void *) ptr_ + bytes); + return ptr_; + } + +private: + void checkNULL() const { + if __acc_very_unlikely (!ptr_) + throwCantUnpack("unexpected NULL pointer; take care!"); + } + __acc_forceinline void checkRange() const { checkRange(ptr_, base_, size_in_bytes_); } + __acc_forceinline void checkRange(const void *p) const { checkRange(p, base_, size_in_bytes_); } + static void checkRange(const void *ptr, const void *base, size_t size_in_bytes) { + size_t off = (const char *) ptr - (const char *) base; + if __acc_very_unlikely (off > size_in_bytes) + throwCantUnpack("pointer out of range; take care!"); + } + void check() const { // check ptr_ invariant: either NULL or valid checkRange() + if (ptr_ != nullptr) + checkRange(); + } + + T *ptr_; + void *base_; + size_t size_in_bytes_; + + // disable copy + BoundedPtr(const BoundedPtr &) = delete; + // disable dynamic allocation + ACC_CXX_DISABLE_NEW_DELETE + + // disable taking the address => force passing by reference + // [I'm not too sure about this design decision, but we can always allow it if needed] + BoundedPtr *operator&() const = delete; +}; + +// raw_bytes overload +template +inline T *raw_bytes(const BoundedPtr &a, size_t size_in_bytes) { + return a.raw_bytes(size_in_bytes); +} + +#endif /* already included */ + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/dt_check.cpp b/src/util/dt_check.cpp similarity index 90% rename from src/dt_check.cpp rename to src/util/dt_check.cpp index abeb81ee..53ad11f6 100644 --- a/src/dt_check.cpp +++ b/src/util/dt_check.cpp @@ -25,36 +25,52 @@ */ -#include "conf.h" +#include "../conf.h" /************************************************************************* // upx_doctest_check() **************************************************************************/ -bool upx_doctest_check(void) { +bool upx_doctest_check(int argc, char **argv) { bool minimal = true; // only show failing tests bool duration = false; // show timings + bool success = false; // show all tests const char *e = getenv("UPX_DEBUG_DOCTEST_VERBOSE"); if (e && e[0] && strcmp(e, "0") != 0) { minimal = false; if (strcmp(e, "2") == 0) duration = true; + if (strcmp(e, "3") == 0) { + duration = true; + success = true; + } } #if DEBUG minimal = false; // duration = true; #endif doctest::Context context; +#if 0 + if (argc > 0 && argv != nullptr) + context.applyCommandLine(argc, argv); +#else + UNUSED(argc); + UNUSED(argv); +#endif if (minimal) context.setOption("dt-minimal", true); if (duration) context.setOption("dt-duration", true); + if (success) + context.setOption("dt-success", true); int r = context.run(); if (context.shouldExit() || r != 0) return false; return true; } +bool upx_doctest_check() { return upx_doctest_check(0, nullptr); } + /************************************************************************* // compile-time checks **************************************************************************/ @@ -194,13 +210,13 @@ struct TestIntegerWrap { #define ACC_WANT_ACC_CHK_CH 1 #undef ACCCHK_ASSERT -#include "miniacc.h" +#include "../miniacc.h" void upx_compiler_sanity_check(void) { #define ACC_WANT_ACC_CHK_CH 1 #undef ACCCHK_ASSERT #define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT(expr) -#include "miniacc.h" +#include "../miniacc.h" #undef ACCCHK_ASSERT COMPILE_TIME_ASSERT(sizeof(char) == 1) @@ -390,11 +406,21 @@ TEST_CASE("working -fno-strict-overflow") { TEST_CASE("libc snprintf") { // runtime check that Win32/MinGW works as expected + char buf[64]; long long ll = acc_vget_int(-1, 0); unsigned long long llu = (unsigned long long) ll; - char buf[64]; - snprintf(buf, sizeof(buf), ".%d.%ld.%lld.%u.%lu.%llu", -3, -2L, ll, 3U, 2LU, llu); - CHECK_EQ(strcmp(buf, ".-3.-2.-1.3.2.18446744073709551615"), 0); + snprintf(buf, sizeof(buf), "%d.%ld.%lld.%u.%lu.%llu", -3, -2L, ll, 3U, 2LU, llu); + CHECK_EQ(strcmp(buf, "-3.-2.-1.3.2.18446744073709551615"), 0); + intmax_t im = ll; + uintmax_t um = llu; + snprintf(buf, sizeof(buf), "%d.%d.%d.%d.%d.%d.%d.%d.%d.%jd", -4, 0, 0, 0, 0, 0, 0, 0, 4, im); + CHECK_EQ(strcmp(buf, "-4.0.0.0.0.0.0.0.4.-1"), 0); + snprintf(buf, sizeof(buf), "%d.%d.%d.%d.%d.%d.%d.%d.%d.%ju", -5, 0, 0, 0, 0, 0, 0, 0, 5, um); + CHECK_EQ(strcmp(buf, "-5.0.0.0.0.0.0.0.5.18446744073709551615"), 0); + snprintf(buf, sizeof(buf), "%d.%d.%d.%d.%d.%d.%d.%d.%d.%jx", -6, 0, 0, 0, 0, 0, 0, 0, 6, um); + CHECK_EQ(strcmp(buf, "-6.0.0.0.0.0.0.0.6.ffffffffffffffff"), 0); + snprintf(buf, sizeof(buf), "%d.%d.%d.%d.%d.%d.%d.%d.%d.%#jx", -7, 0, 0, 0, 0, 0, 0, 0, 7, um); + CHECK_EQ(strcmp(buf, "-7.0.0.0.0.0.0.0.7.0xffffffffffffffff"), 0); } /* vim:set ts=4 sw=4 et: */ diff --git a/src/dt_impl.cpp b/src/util/dt_impl.cpp similarity index 100% rename from src/dt_impl.cpp rename to src/util/dt_impl.cpp diff --git a/src/mem.cpp b/src/util/membuffer.cpp similarity index 51% rename from src/mem.cpp rename to src/util/membuffer.cpp index ae453771..52e49d3a 100644 --- a/src/mem.cpp +++ b/src/util/membuffer.cpp @@ -1,4 +1,4 @@ -/* mem.cpp -- +/* membuffer.cpp -- This file is part of the UPX executable compressor. @@ -25,10 +25,12 @@ */ +#include "../conf.h" +#include "membuffer.h" -#include "conf.h" -#include "mem.h" - +// extra functions to reduce dependency on membuffer.h +void *membuffer_get_void_ptr(MemBuffer &mb) { return mb.getVoidPtr(); } +unsigned membuffer_get_size(MemBuffer &mb) { return mb.getSize(); } /************************************************************************* // bool use_simple_mcheck() @@ -38,17 +40,15 @@ __acc_static_forceinline constexpr bool use_simple_mcheck() { return false; } #elif (WITH_VALGRIND) && defined(RUNNING_ON_VALGRIND) static int use_simple_mcheck_flag = -1; -__acc_static_noinline void use_simple_mcheck_init() -{ +__acc_static_noinline void use_simple_mcheck_init() { use_simple_mcheck_flag = 1; if (RUNNING_ON_VALGRIND) { use_simple_mcheck_flag = 0; - //fprintf(stderr, "upx: detected RUNNING_ON_VALGRIND\n"); + // fprintf(stderr, "upx: detected RUNNING_ON_VALGRIND\n"); } } -__acc_static_forceinline bool use_simple_mcheck() -{ - if __acc_unlikely(use_simple_mcheck_flag < 0) +__acc_static_forceinline bool use_simple_mcheck() { + if __acc_unlikely (use_simple_mcheck_flag < 0) use_simple_mcheck_init(); return (bool) use_simple_mcheck_flag; } @@ -56,182 +56,166 @@ __acc_static_forceinline bool use_simple_mcheck() __acc_static_forceinline constexpr bool use_simple_mcheck() { return true; } #endif - /************************************************************************* // **************************************************************************/ -MemBuffer::MemBuffer(upx_uint64_t size) : - b(nullptr), b_size(0) -{ - alloc(size); -} +MemBuffer::MemBuffer(upx_uint64_t size_in_bytes) { alloc(size_in_bytes); } - -MemBuffer::~MemBuffer() -{ - this->dealloc(); -} +MemBuffer::~MemBuffer() { this->dealloc(); } // similar to BoundedPtr, except checks only at creation -unsigned char *MemBuffer::subref(char const *errfmt, unsigned skip, unsigned take) -{ - if ((take + skip) < take // wrap-around - || (take + skip) > b_size // overrun - ) { - char buf[100]; snprintf(buf, sizeof(buf), errfmt, skip, take); +// skip == offset, take == size_in_bytes +void *MemBuffer::subref_impl(const char *errfmt, size_t skip, size_t take) { + // check overrun and wrap-around + if (skip + take > b_size_in_bytes || skip + take < skip) { + char buf[100]; + // printf is using unsigned formatting + if (!errfmt || !errfmt[0]) + errfmt = "bad subref %#x %#x"; + snprintf(buf, sizeof(buf), errfmt, (unsigned) skip, (unsigned) take); throwCantPack(buf); } return &b[skip]; } -void MemBuffer::dealloc() -{ - if (b != nullptr) - { - checkState(); - if (use_simple_mcheck()) - { - // remove magic constants - set_be32(b - 8, 0); - set_be32(b - 4, 0); - set_be32(b + b_size, 0); - set_be32(b + b_size + 4, 0); - // - ::free(b - 16); - } - else - ::free(b); - b = nullptr; - b_size = 0; - } - else - assert(b_size == 0); -} - - -static unsigned width(unsigned x) -{ +static unsigned width(unsigned x) { unsigned w = 0; - if ((~0u << 16) & x) { w += 16; x >>= 16; } - if ((~0u << 8) & x) { w += 8; x >>= 8; } - if ((~0u << 4) & x) { w += 4; x >>= 4; } - if ((~0u << 2) & x) { w += 2; x >>= 2; } - if ((~0u << 1) & x) { w += 1; x >>= 1; } - return 1+ w; + if ((~0u << 16) & x) { + w += 16; + x >>= 16; + } + if ((~0u << 8) & x) { + w += 8; + x >>= 8; + } + if ((~0u << 4) & x) { + w += 4; + x >>= 4; + } + if ((~0u << 2) & x) { + w += 2; + x >>= 2; + } + if ((~0u << 1) & x) { + w += 1; + // x >>= 1; + } + return 1 + w; } -static unsigned umax(unsigned a, unsigned b) -{ - return (a >= b) ? a : b; -} +static inline unsigned umax(unsigned a, unsigned b) { return (a >= b) ? a : b; } -unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned extra) -{ - size_t const z = uncompressed_size; // fewer keystrokes and display columns - size_t bytes = mem_size(1, z, extra); - size_t const w = umax(8, width(z -1)); // ignore tiny offsets - bytes = 256 + // safety? - umax(bytes + z/8, // All literal: 1 bit overhead per literal byte - // Worst matching: All match at max_offset, which implies 3==min_match - // NRV2B: 1 byte plus 2 bits per width exceeding 8 ("ss11") - umax((z/3 * (8+ 2*(w - 8)/1))/8, - // NRV2E: 1 byte plus 3 bits per pair of width exceeding 7 ("ss12") - (z/3 * (8+ 3*(w - 7)/2))/8 ) ); +unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned extra) { + size_t const z = uncompressed_size; // fewer keystrokes and display columns + size_t const w = umax(8, width(z - 1)); // ignore tiny offsets + size_t bytes = mem_size(1, z); + // Worst matching: All match at max_offset, which implies 3==min_match + // All literal: 1 bit overhead per literal byte + bytes = umax(bytes, bytes + z / 8); + // NRV2B: 1 byte plus 2 bits per width exceeding 8 ("ss11") + bytes = umax(bytes, (z / 3 * (8 + 2 * (w - 8) / 1)) / 8); + // NRV2E: 1 byte plus 3 bits per pair of width exceeding 7 ("ss12") + bytes = umax(bytes, (z / 3 * (8 + 3 * (w - 7) / 2)) / 8); + // extra + 256 safety for rounding + bytes = mem_size(1, bytes, extra, 256); return ACC_ICONV(unsigned, bytes); } -unsigned MemBuffer::getSizeForUncompression(unsigned uncompressed_size, unsigned extra) -{ +unsigned MemBuffer::getSizeForUncompression(unsigned uncompressed_size, unsigned extra) { size_t bytes = mem_size(1, uncompressed_size, extra); - // INFO: 3 bytes are the allowed overrun for the i386 asm_fast decompressors -#if (ACC_ARCH_I386) - bytes += 3; -#endif return ACC_ICONV(unsigned, bytes); } - -void MemBuffer::allocForCompression(unsigned uncompressed_size, unsigned extra) -{ +void MemBuffer::allocForCompression(unsigned uncompressed_size, unsigned extra) { unsigned size = getSizeForCompression(uncompressed_size, extra); alloc(size); } - -void MemBuffer::allocForUncompression(unsigned uncompressed_size, unsigned extra) -{ +void MemBuffer::allocForUncompression(unsigned uncompressed_size, unsigned extra) { unsigned size = getSizeForUncompression(uncompressed_size, extra); alloc(size); } - -void MemBuffer::fill(unsigned off, unsigned len, int value) -{ +void MemBuffer::fill(unsigned off, unsigned len, int value) { checkState(); - assert((int)off >= 0); - assert((int)len >= 0); - assert(off <= b_size); - assert(len <= b_size); - assert(off + len <= b_size); + assert((int) off >= 0); + assert((int) len >= 0); + assert(off <= b_size_in_bytes); + assert(len <= b_size_in_bytes); + assert(off + len <= b_size_in_bytes); if (len > 0) memset(b + off, value, len); } - /************************************************************************* // **************************************************************************/ -#define PTR(p) ((unsigned) ((upx_uintptr_t)(p) & 0xffffffff)) -#define MAGIC1(p) (PTR(p) ^ 0xfefdbeeb) -#define MAGIC2(p) (PTR(p) ^ 0xfefdbeeb ^ 0x80024001) +#define PTR(p) ((unsigned) ((upx_uintptr_t)(p) &0xffffffff)) +#define MAGIC1(p) (PTR(p) ^ 0xfefdbeeb) +#define MAGIC2(p) (PTR(p) ^ 0xfefdbeeb ^ 0x80024001) unsigned MemBuffer::global_alloc_counter = 0; - -void MemBuffer::checkState() const -{ +void MemBuffer::checkState() const { if (!b) throwInternalError("block not allocated"); - if (use_simple_mcheck()) - { + if (use_simple_mcheck()) { if (get_be32(b - 4) != MAGIC1(b)) throwInternalError("memory clobbered before allocated block 1"); - if (get_be32(b - 8) != b_size) + if (get_be32(b - 8) != b_size_in_bytes) throwInternalError("memory clobbered before allocated block 2"); - if (get_be32(b + b_size) != MAGIC2(b)) + if (get_be32(b + b_size_in_bytes) != MAGIC2(b)) throwInternalError("memory clobbered past end of allocated block"); } - assert((int)b_size > 0); } - -void MemBuffer::alloc(upx_uint64_t size) -{ +void MemBuffer::alloc(upx_uint64_t size) { // NOTE: we don't automatically free a used buffer assert(b == nullptr); - assert(b_size == 0); + assert(b_size_in_bytes == 0); // assert(size > 0); size_t bytes = mem_size(1, size, use_simple_mcheck() ? 32 : 0); unsigned char *p = (unsigned char *) malloc(bytes); if (!p) throwOutOfMemoryException(); - b_size = ACC_ICONV(unsigned, size); - if (use_simple_mcheck()) - { + b_size_in_bytes = ACC_ICONV(unsigned, size); + if (use_simple_mcheck()) { b = p + 16; // store magic constants to detect buffer overruns - set_be32(b - 8, b_size); + set_be32(b - 8, b_size_in_bytes); set_be32(b - 4, MAGIC1(b)); - set_be32(b + b_size, MAGIC2(b)); - set_be32(b + b_size + 4, global_alloc_counter++); - } - else - b = p ; + set_be32(b + b_size_in_bytes, MAGIC2(b)); + set_be32(b + b_size_in_bytes + 4, global_alloc_counter++); + } else + b = p; - //fill(0, b_size, (rand() & 0xff) | 1); // debug +#if defined(__SANITIZE_ADDRESS__) || DEBUG + fill(0, b_size_in_bytes, (rand() & 0xff) | 1); // debug + (void) VALGRIND_MAKE_MEM_UNDEFINED(b, b_size_in_bytes); +#endif +} + +void MemBuffer::dealloc() { + if (b != nullptr) { + checkState(); + if (use_simple_mcheck()) { + // clear magic constants + set_be32(b - 8, 0); + set_be32(b - 4, 0); + set_be32(b + b_size_in_bytes, 0); + set_be32(b + b_size_in_bytes + 4, 0); + // + ::free(b - 16); + } else + ::free(b); + b = nullptr; + b_size_in_bytes = 0; + } else { + assert(b_size_in_bytes == 0); + } } /* vim:set ts=4 sw=4 et: */ diff --git a/src/util/membuffer.h b/src/util/membuffer.h new file mode 100644 index 00000000..7aa31677 --- /dev/null +++ b/src/util/membuffer.h @@ -0,0 +1,127 @@ +/* membuffer.h -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2022 Laszlo Molnar + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer Laszlo Molnar + + */ + +#pragma once + +/************************************************************************* +// A MemBuffer allocates memory on the heap, and automatically +// gets destructed when leaving scope or on exceptions. +**************************************************************************/ + +// provides some base functionality for treating a MemBuffer as a pointer +template +class MemBufferBase { +public: + typedef T element_type; + typedef T *pointer; + +protected: + pointer b = nullptr; + unsigned b_size_in_bytes = 0; + +public: + // NOTE: implicit conversion to underlying pointer + // NOTE: for fully bound-checked pointer use SPAN_S from xspan.h + operator pointer() const { return b; } + + template ::value, U>::type> + pointer operator+(V n) const { + size_t bytes = mem_size(sizeof(T), n); // check + return raw_bytes(bytes) + n; + } + + // NOT allowed; use raw_bytes() instead + template ::value, U>::type> + pointer operator-(V n) const = delete; + + pointer raw_bytes(size_t bytes) const { + if (bytes > 0) { + assert(b != nullptr); + assert(bytes <= b_size_in_bytes); + } + return b; + } +}; + +class MemBuffer : public MemBufferBase { +public: + MemBuffer() = default; + explicit MemBuffer(upx_uint64_t size_in_bytes); + ~MemBuffer(); + + static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra = 0); + static unsigned getSizeForUncompression(unsigned uncompressed_size, unsigned extra = 0); + + void alloc(upx_uint64_t size); + void allocForCompression(unsigned uncompressed_size, unsigned extra = 0); + void allocForUncompression(unsigned uncompressed_size, unsigned extra = 0); + + void dealloc(); + void checkState() const; + unsigned getSize() const { return b_size_in_bytes; } + + // explicit converstion + void *getVoidPtr() { return (void *) b; } + const void *getVoidPtr() const { return (const void *) b; } + + // util + void fill(unsigned off, unsigned len, int value); + void clear(unsigned off, unsigned len) { fill(off, len, 0); } + void clear() { fill(0, b_size_in_bytes, 0); } + + // If the entire range [skip, skip+take) is inside the buffer, + // then return &b[skip]; else throwCantPack(sprintf(errfmt, skip, take)). + // This is similar to BoundedPtr, except only checks once. + // skip == offset, take == size_in_bytes + pointer subref(const char *errfmt, size_t skip, size_t take) { + return (pointer) subref_impl(errfmt, skip, take); + } + +private: + void *subref_impl(const char *errfmt, size_t skip, size_t take); + + static unsigned global_alloc_counter; + + // disable copy, assignment and move assignment + MemBuffer(const MemBuffer &) = delete; + MemBuffer &operator=(const MemBuffer &) = delete; + MemBuffer &operator=(MemBuffer &&) = delete; + // disable dynamic allocation + ACC_CXX_DISABLE_NEW_DELETE + + // disable taking the address => force passing by reference + // [I'm not too sure about this design decision, but we can always allow it if needed] + MemBuffer *operator&() const = delete; +}; + +// raw_bytes overload +template +inline T *raw_bytes(const MemBufferBase &a, size_t size_in_bytes) { + return a.raw_bytes(size_in_bytes); +} + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/snprintf.cpp b/src/util/snprintf.cpp similarity index 99% rename from src/snprintf.cpp rename to src/util/snprintf.cpp index 693b4e8c..f1c42110 100644 --- a/src/snprintf.cpp +++ b/src/util/snprintf.cpp @@ -25,7 +25,7 @@ */ -#include "conf.h" +#include "../conf.h" /************************************************************************* // UPX version of string functions, with assertions and sane limits diff --git a/src/snprintf.h b/src/util/snprintf.h similarity index 87% rename from src/snprintf.h rename to src/util/snprintf.h index cd634afd..5a615547 100644 --- a/src/snprintf.h +++ b/src/util/snprintf.h @@ -25,8 +25,9 @@ */ -#ifndef __UPX_SNPRINTF_H -#define __UPX_SNPRINTF_H 1 +#pragma once +#ifndef UPX_SNPRINTF_H__ +#define UPX_SNPRINTF_H__ 1 /************************************************************************* // UPX version of string functions, with assertions and sane limits @@ -35,11 +36,12 @@ // info: snprintf() returns length and NOT size, but max_size is indeed size (incl NUL) int upx_safe_vsnprintf(char *str, upx_rsize_t max_size, const char *format, va_list ap); -int upx_safe_snprintf (char *str, upx_rsize_t max_size, const char *format, ...) attribute_format(3, 4); +int upx_safe_snprintf(char *str, upx_rsize_t max_size, const char *format, ...) + attribute_format(3, 4); // malloc's *ptr int upx_safe_vasprintf(char **ptr, const char *format, va_list ap); -int upx_safe_asprintf (char **ptr, const char *format, ...) attribute_format(2, 3); +int upx_safe_asprintf(char **ptr, const char *format, ...) attribute_format(2, 3); // returns a malloc'd pointer char *upx_safe_xprintf(const char *format, ...) attribute_format(1, 2); @@ -50,12 +52,12 @@ upx_rsize_t upx_safe_strlen(const char *); #undef snprintf #undef sprintf #undef vsnprintf -#define snprintf upx_safe_snprintf -#define sprintf ERROR_sprintf_IS_DANGEROUS_USE_snprintf +#define snprintf upx_safe_snprintf +#define sprintf ERROR_sprintf_IS_DANGEROUS_USE_snprintf #define vsnprintf upx_safe_vsnprintf #undef strlen -#define strlen upx_safe_strlen +#define strlen upx_safe_strlen /************************************************************************* // some unsigned char string support functions diff --git a/src/util.cpp b/src/util/util.cpp similarity index 87% rename from src/util.cpp rename to src/util/util.cpp index bc414adc..bb200f52 100644 --- a/src/util.cpp +++ b/src/util/util.cpp @@ -25,18 +25,18 @@ */ -#include "conf.h" +#include "../conf.h" #include "util.h" #define ACC_WANT_ACC_INCI_H 1 -#include "miniacc.h" +#include "../miniacc.h" #define ACC_WANT_ACCLIB_GETOPT 1 #define ACC_WANT_ACCLIB_HSREAD 1 #define ACC_WANT_ACCLIB_MISC 1 #define ACC_WANT_ACCLIB_VGET 1 #define ACC_WANT_ACCLIB_WILDARGV 1 #undef HAVE_MKDIR -#include "miniacc.h" +#include "../miniacc.h" /************************************************************************* // assert sane memory buffer sizes to protect against integer overflows @@ -51,44 +51,33 @@ ACC_COMPILE_TIME_ASSERT_HEADER(2ull * UPX_RSIZE_MAX * 9 / 8 + 16 * 1024 * 1024 < upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1, upx_uint64_t extra2) { assert(element_size > 0); - if (element_size > UPX_RSIZE_MAX) + if __acc_very_unlikely (element_size > UPX_RSIZE_MAX) throwCantPack("mem_size 1; take care"); - if (n > UPX_RSIZE_MAX) + if __acc_very_unlikely (n > UPX_RSIZE_MAX) throwCantPack("mem_size 2; take care"); - if (extra1 > UPX_RSIZE_MAX) + if __acc_very_unlikely (extra1 > UPX_RSIZE_MAX) throwCantPack("mem_size 3; take care"); - if (extra2 > UPX_RSIZE_MAX) + if __acc_very_unlikely (extra2 > UPX_RSIZE_MAX) throwCantPack("mem_size 4; take care"); upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow - if (bytes > UPX_RSIZE_MAX) + if __acc_very_unlikely (bytes > UPX_RSIZE_MAX) throwCantPack("mem_size 5; take care"); return ACC_ICONV(upx_rsize_t, bytes); } -upx_rsize_t mem_size_get_n(upx_uint64_t element_size, upx_uint64_t n) { - mem_size_assert(element_size, n); - return ACC_ICONV(upx_rsize_t, n); // return n -} - bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1, - upx_uint64_t extra2) { + upx_uint64_t extra2) noexcept { assert(element_size > 0); - if (element_size > UPX_RSIZE_MAX) + if __acc_very_unlikely (element_size > UPX_RSIZE_MAX) return false; - if (n > UPX_RSIZE_MAX) + if __acc_very_unlikely (n > UPX_RSIZE_MAX) return false; - if (extra1 > UPX_RSIZE_MAX) + if __acc_very_unlikely (extra1 > UPX_RSIZE_MAX) return false; - if (extra2 > UPX_RSIZE_MAX) + if __acc_very_unlikely (extra2 > UPX_RSIZE_MAX) return false; upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow - if (bytes > UPX_RSIZE_MAX) - return false; - return true; -} - -bool mem_size_valid_bytes(upx_uint64_t bytes) { - if (bytes > UPX_RSIZE_MAX) + if __acc_very_unlikely (bytes > UPX_RSIZE_MAX) return false; return true; } @@ -100,28 +89,49 @@ TEST_CASE("mem_size") { CHECK(!mem_size_valid(1, 0x30000000, 1)); CHECK(!mem_size_valid(1, 0x30000000, 0, 1)); CHECK(!mem_size_valid(1, 0x30000000, 0x30000000, 0x30000000)); + CHECK_NOTHROW(mem_size(1, 0)); + CHECK_NOTHROW(mem_size(1, 0x30000000)); + CHECK_THROWS(mem_size(1, 0x30000000 + 1)); + CHECK_THROWS(mem_size(1, 0x30000000, 1)); + CHECK_THROWS(mem_size(1, 0x30000000, 0, 1)); + CHECK_THROWS(mem_size(1, 0x30000000, 0x30000000, 0x30000000)); } -int ptr_diff(const void *p1, const void *p2) { - assert(p1 != nullptr); - assert(p2 != nullptr); - ptrdiff_t d = (const char *) p1 - (const char *) p2; - if (p1 >= p2) - assert(mem_size_valid_bytes(d)); - else - assert(mem_size_valid_bytes(-d)); +int ptr_diff_bytes(const void *a, const void *b) { + if __acc_very_unlikely (a == nullptr) { + throwCantPack("ptr_diff_bytes null 1; take care"); + } + if __acc_very_unlikely (b == nullptr) { + throwCantPack("ptr_diff_bytes null 2; take care"); + } + ptrdiff_t d = (const char *) a - (const char *) b; + if (a >= b) { + if __acc_very_unlikely (!mem_size_valid_bytes(d)) + throwCantPack("ptr_diff_bytes 1; take care"); + } else { + if __acc_very_unlikely (!mem_size_valid_bytes(-d)) + throwCantPack("ptr_diff_bytes 2; take care"); + } return ACC_ICONV(int, d); } -unsigned ptr_udiff(const void *p1, const void *p2) { - int d = ptr_diff(p1, p2); - assert(d >= 0); +unsigned ptr_udiff_bytes(const void *a, const void *b) { + int d = ptr_diff_bytes(a, b); + if __acc_very_unlikely (d < 0) + throwCantPack("ptr_udiff_bytes; take care"); return ACC_ICONV(unsigned, d); } -void mem_clear(void *p, size_t n) { - mem_size_assert(1, n); - memset(p, 0, n); +TEST_CASE("ptr_diff") { + char 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); + CHECK(ptr_diff(buf + 1, buf) == 1); + CHECK(ptr_diff(buf, buf + 1) == -1); + CHECK(ptr_udiff(buf, buf) == 0); + CHECK(ptr_udiff(buf + 1, buf) == 1); + CHECK_THROWS(ptr_udiff(buf, buf + 1)); } /************************************************************************* @@ -560,6 +570,9 @@ TEST_CASE("get_ratio") { CHECK(get_ratio(1, 11) == 9999999); CHECK(get_ratio(100000, 100000) == 1000050); CHECK(get_ratio(100000, 200000) == 2000050); + CHECK(get_ratio(UPX_RSIZE_MAX, UPX_RSIZE_MAX) == 1000050); + CHECK(get_ratio(2 * UPX_RSIZE_MAX, 2 * UPX_RSIZE_MAX) == 1000050); + CHECK(get_ratio(2 * UPX_RSIZE_MAX, 1024ull * UPX_RSIZE_MAX) == 9999999); } /* vim:set ts=4 sw=4 et: */ diff --git a/src/util.h b/src/util/util.h similarity index 58% rename from src/util.h rename to src/util/util.h index 5bef2294..e4329222 100644 --- a/src/util.h +++ b/src/util/util.h @@ -25,32 +25,72 @@ */ -#ifndef __UPX_UTIL_H -#define __UPX_UTIL_H 1 +#pragma once +#ifndef UPX_UTIL_H__ +#define UPX_UTIL_H__ 1 /************************************************************************* -// protect against integer overflows and malicious header fields +// assert sane memory buffer sizes to protect against integer overflows +// and malicious header fields +// see C 11 standard, Annex K **************************************************************************/ -#define New(type, n) new type[mem_size_get_n(sizeof(type), n)] - -upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0, - upx_uint64_t extra2 = 0); -upx_rsize_t mem_size_get_n(upx_uint64_t element_size, upx_uint64_t n); - -inline void mem_size_assert(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0, - upx_uint64_t extra2 = 0) { - (void) mem_size(element_size, n, extra1, extra2); // sanity check -} +inline bool mem_size_valid_bytes(upx_uint64_t bytes) noexcept { return bytes <= UPX_RSIZE_MAX; } bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0, - upx_uint64_t extra2 = 0); -bool mem_size_valid_bytes(upx_uint64_t bytes); + upx_uint64_t extra2 = 0) noexcept; -int ptr_diff(const void *p1, const void *p2); -unsigned ptr_udiff(const void *p1, const void *p2); // asserts p1 >= p2 +// new with asserted size; will throw on failure +#define New(type, n) new type[mem_size_get_n(sizeof(type), n)] -void mem_clear(void *p, size_t 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); + +// inline fast paths: + +// will throw on invalid size +inline upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n) { + upx_uint64_t bytes = element_size * n; + if __acc_very_unlikely (element_size == 0 || element_size > UPX_RSIZE_MAX || + n > UPX_RSIZE_MAX || bytes > UPX_RSIZE_MAX) + return mem_size(element_size, n, 0, 0); // this will throw + return ACC_ICONV(upx_rsize_t, bytes); +} + +// will throw on invalid size +inline upx_rsize_t mem_size_get_n(upx_uint64_t element_size, upx_uint64_t n) { + (void) mem_size(element_size, n); // assert size + return ACC_ICONV(upx_rsize_t, n); // and return n +} + +// will throw on invalid size +inline void mem_size_assert(upx_uint64_t element_size, upx_uint64_t n) { + (void) mem_size(element_size, n); // assert size +} + +// will throw on invalid size +inline void mem_clear(void *p, size_t n) { + (void) mem_size(1, n); // assert size + memset(p, 0, n); +} + +// ptrdiff_t with nullptr check and asserted size; will throw on failure +// WARNING: returns size_in_bytes, not number of elements! +int ptr_diff_bytes(const void *a, const void *b); +unsigned ptr_udiff_bytes(const void *a, const void *b); // asserts a >= b + +// short names "ptr_diff" and "ptr_udiff" for types with sizeof(X) == 1 +template +inline typename std::enable_if::type ptr_diff(const T *a, + const U *b) { + return ptr_diff_bytes(a, b); +} +template +inline typename std::enable_if::type +ptr_udiff(const T *a, const U *b) { + return ptr_udiff_bytes(a, b); +} /************************************************************************* // misc. support functions diff --git a/src/util/xspan.cpp b/src/util/xspan.cpp new file mode 100644 index 00000000..1f62723e --- /dev/null +++ b/src/util/xspan.cpp @@ -0,0 +1,637 @@ +/* xspan -- a minimally invasive checked memory smart pointer + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + +#include "../conf.h" + +#if WITH_SPAN + +SPAN_NAMESPACE_BEGIN + +unsigned long long span_check_stats_check_range; + +__acc_noinline void span_fail_nullptr() { + throwCantUnpack("span unexpected NULL pointer; take care!"); +} + +__acc_noinline void span_fail_not_same_base() { + throwInternalError("span unexpected base pointer; take care!"); +} + +__acc_noinline void span_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes) { + if __acc_very_unlikely (p == nullptr) + throwCantUnpack("span_check_range: unexpected NULL pointer; take care!"); + if __acc_very_unlikely (base == nullptr) + throwCantUnpack("span_check_range: unexpected NULL base; take care!"); + ptrdiff_t off = (const char *) p - (const char *) base; + if __acc_very_unlikely (off < 0 || off > size_in_bytes) + throwCantUnpack("span_check_range: pointer out of range; take care!"); + span_check_stats_check_range += 1; + // fprintf(stderr, "span_check_range done\n"); +} + +SPAN_NAMESPACE_END + +#endif // WITH_SPAN +#if WITH_SPAN >= 2 + +// lots of tests (and probably quite a number of redundant tests) + +/************************************************************************* +// +**************************************************************************/ + +TEST_CASE("PtrOrSpanOrNull") { + char real_buf[2 + 6 + 2] = {126, 127, 0, 1, 2, 3, 4, 5, 124, 125}; + char *base_buf = real_buf + 2; + char *const my_null = nullptr; + typedef PtrOrSpanOrNull Span0; + + // basic nullptr + CHECK_NOTHROW(Span0(base_buf, 4, base_buf) = my_null); + CHECK_NOTHROW(Span0(base_buf, 4, base_buf).assign(my_null)); + // basic range checking + CHECK_NOTHROW(Span0(base_buf, 4, base_buf)); + CHECK_NOTHROW(Span0(base_buf, 0, base_buf)); + CHECK_NOTHROW(Span0(base_buf, 0, base_buf) - 0); + CHECK_THROWS(Span0(base_buf, 0, base_buf) + 1); + CHECK_THROWS(Span0(base_buf, 0, base_buf) - 1); + CHECK_NOTHROW(Span0(base_buf, 4, base_buf) + 4); + CHECK_THROWS(Span0(base_buf, 4, base_buf) + 5); + CHECK_THROWS(Span0(base_buf - 1, 4, base_buf)); + CHECK_THROWS(Span0(base_buf + 1, 0, base_buf)); + // basic same base + CHECK_NOTHROW(Span0(base_buf, 4, base_buf) = Span0(base_buf + 1, 3, base_buf)); + CHECK_NOTHROW(Span0(base_buf, 4, base_buf) = Span0(base_buf + 1, 1, base_buf)); + CHECK_NOTHROW(Span0(base_buf, 4, base_buf) = Span0(base_buf + 1, 5, base_buf)); + CHECK_THROWS(Span0(base_buf, 4, base_buf) = Span0(base_buf + 1, 3, base_buf + 1)); + + Span0 a1(nullptr); + assert(a1 == nullptr); + assert(a1.raw_ptr() == nullptr); + assert(a1.raw_base() == nullptr); + assert(a1.raw_size_in_bytes() == 0u); + CHECK_THROWS(*a1); + CHECK_THROWS(a1[0]); + + Span0 a2 = nullptr; + assert(a2 == nullptr); + assert(a2.raw_ptr() == nullptr); + assert(a2.raw_base() == nullptr); + assert(a2.raw_size_in_bytes() == 0u); + CHECK_THROWS(*a2); + CHECK_THROWS(a2[0]); + + Span0 base0(nullptr, 4, base_buf); + assert(base0.raw_ptr() == nullptr); + assert(base0.raw_base() == base_buf); + assert(base0.raw_size_in_bytes() == 4u); + CHECK_THROWS(*base0); // nullptr + CHECK_THROWS(base0[0]); // nullptr + CHECK_THROWS(base0 + 1); // nullptr + + Span0 base4(base_buf, 4); + assert(base4.raw_ptr() == base_buf); + assert(base4.raw_base() == base_buf); + assert(base4.raw_size_in_bytes() == 4u); + + a1 = base_buf; + a1 = base0; + assert(a1 == nullptr); + assert(a1.raw_ptr() == nullptr); + assert(a1.raw_base() == base_buf); + assert(a1.raw_size_in_bytes() == 4u); + a1 = base4; + assert(a1 == base_buf); + assert(a1.raw_ptr() == base_buf); + assert(a1.raw_base() == base_buf); + assert(a1.raw_size_in_bytes() == 4u); + + a1 = base_buf; + assert(a1 != nullptr); + a1 = base_buf + 1; + CHECK(*a1++ == 1); + CHECK(*++a1 == 3); + CHECK(*a1 == 3); + a1 = base_buf + 4; // at the end of buffer + CHECK_THROWS(*a1); + CHECK_THROWS(a1 = base_buf + 5); // range error + assert(a1 == base_buf + 4); + CHECK(a1[-4] == 0); + CHECK_THROWS(a1[-5]); // range error + a1 = base_buf; + CHECK(*a1 == 0); + + Span0 new_base4(base_buf + 2, 4); + CHECK_THROWS(a1 = new_base4); // not same base + a2 = new_base4; + CHECK_THROWS(a2 = base4); // not same base + + Span0 s0_no_base(nullptr); + Span0 s0_with_base(nullptr, 4, base_buf); + s0_no_base = nullptr; + s0_with_base = nullptr; + s0_with_base = s0_no_base; + assert(s0_no_base.raw_base() == nullptr); + assert(s0_with_base.raw_base() == base_buf); + s0_no_base = s0_with_base; + assert(s0_no_base.raw_base() == base_buf); + assert(s0_no_base.raw_ptr() == nullptr); + assert(s0_with_base.raw_ptr() == nullptr); + s0_no_base = my_null; + s0_with_base = my_null; +} + +/************************************************************************* +// +**************************************************************************/ + +TEST_CASE("PtrOrSpan") { + char real_buf[2 + 6 + 2] = {126, 127, 0, 1, 2, 3, 4, 5, 124, 125}; + char *base_buf = real_buf + 2; + char *const my_null = nullptr; + typedef PtrOrSpan SpanP; + + // basic nullptr + CHECK_THROWS(SpanP(base_buf, 4, base_buf) = my_null); + CHECK_THROWS(SpanP(base_buf, 4, base_buf).assign(my_null)); + // basic range checking + CHECK_NOTHROW(SpanP(base_buf, 4, base_buf)); + CHECK_NOTHROW(SpanP(base_buf, 0, base_buf)); + CHECK_NOTHROW(SpanP(base_buf, 0, base_buf) - 0); + CHECK_THROWS(SpanP(base_buf, 0, base_buf) + 1); + CHECK_THROWS(SpanP(base_buf, 0, base_buf) - 1); + CHECK_NOTHROW(SpanP(base_buf, 4, base_buf) + 4); + CHECK_THROWS(SpanP(base_buf, 4, base_buf) + 5); + CHECK_THROWS(SpanP(base_buf - 1, 4, base_buf)); + CHECK_THROWS(SpanP(base_buf + 1, 0, base_buf)); + // basic same base + CHECK_NOTHROW(SpanP(base_buf, 4, base_buf) = SpanP(base_buf + 1, 3, base_buf)); + CHECK_NOTHROW(SpanP(base_buf, 4, base_buf) = SpanP(base_buf + 1, 1, base_buf)); + CHECK_NOTHROW(SpanP(base_buf, 4, base_buf) = SpanP(base_buf + 1, 5, base_buf)); + CHECK_THROWS(SpanP(base_buf, 4, base_buf) = SpanP(base_buf + 1, 3, base_buf + 1)); + + SpanP x1(base_buf, 0); + assert(x1 != nullptr); + assert(x1.raw_ptr() == base_buf); + assert(x1.raw_base() == base_buf); + assert(x1.raw_size_in_bytes() == 0u); + CHECK_THROWS(*x1); + CHECK_THROWS(x1[0]); + + SpanP a2 = base_buf; + assert(a2 != nullptr); + assert(a2.raw_ptr() == base_buf); + assert(a2.raw_base() == nullptr); + assert(a2.raw_size_in_bytes() == 0u); + CHECK(*a2 == 0); + CHECK(a2[1] == 1); + + SpanP base0(base_buf, 4, base_buf); + assert(base0.raw_ptr() == base_buf); + assert(base0.raw_base() == base_buf); + assert(base0.raw_size_in_bytes() == 4u); + + SpanP base4(base_buf, 4); + assert(base4.raw_ptr() == base_buf); + assert(base4.raw_base() == base_buf); + assert(base4.raw_size_in_bytes() == 4u); + + SpanP a1(base_buf, 4); + a1 = base_buf; + a1 = base0; + assert(a1 == base0); + assert(a1 != nullptr); + assert(a1.raw_ptr() == base0.raw_ptr()); + assert(a1.raw_base() == base_buf); + assert(a1.raw_size_in_bytes() == 4u); + a1 = base4; + assert(a1 == base_buf); + assert(a1.raw_ptr() == base_buf); + assert(a1.raw_base() == base_buf); + assert(a1.raw_size_in_bytes() == 4u); + + a1 = base_buf; + a1 = base_buf + 1; + CHECK(*a1++ == 1); + CHECK(*++a1 == 3); + CHECK(*a1 == 3); + a1 = base_buf + 4; // at the end of buffer + CHECK_THROWS(*a1); + CHECK_THROWS(a1 = base_buf + 5); // range error + assert(a1 == base_buf + 4); + CHECK(a1[-4] == 0); + CHECK_THROWS(a1[-5]); // range error + a1 = base_buf; + CHECK(*a1 == 0); + + SpanP new_base4(base_buf + 2, 4); + CHECK_THROWS(a1 = new_base4); // not same base + a2 = new_base4; + CHECK_THROWS(a2 = base4); // not same base + + SpanP sp_no_base(base_buf); + SpanP sp_with_base(base_buf, 4, base_buf); + assert(sp_no_base.raw_base() == nullptr); + assert(sp_with_base.raw_base() == base_buf); + CHECK_THROWS(sp_no_base = my_null); // nullptr assignment + CHECK_THROWS(sp_with_base = my_null); // nullptr assignment +#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION + typedef PtrOrSpanOrNull Span0; + Span0 s0_no_base(nullptr); + Span0 s0_with_base(nullptr, 4, base_buf); + CHECK_THROWS(sp_no_base = s0_no_base); // nullptr assignment + CHECK_THROWS(sp_no_base = s0_with_base); // nullptr assignment + CHECK_THROWS(sp_with_base = s0_no_base); // nullptr assignment + CHECK_THROWS(sp_with_base = s0_with_base); // nullptr assignment +#endif +} + +/************************************************************************* +// +**************************************************************************/ + +TEST_CASE("Span") { + char real_buf[2 + 6 + 2] = {126, 127, 0, 1, 2, 3, 4, 5, 124, 125}; + char *base_buf = real_buf + 2; + char *const my_null = nullptr; + typedef Span SpanS; + + // basic nullptr + CHECK_THROWS(SpanS(base_buf, 4, base_buf) = my_null); + CHECK_THROWS(SpanS(base_buf, 4, base_buf).assign(my_null)); + // basic range checking + CHECK_NOTHROW(SpanS(base_buf, 4, base_buf)); + CHECK_NOTHROW(SpanS(base_buf, 0, base_buf)); + CHECK_NOTHROW(SpanS(base_buf, 0, base_buf) - 0); + CHECK_THROWS(SpanS(base_buf, 0, base_buf) + 1); + CHECK_THROWS(SpanS(base_buf, 0, base_buf) - 1); + CHECK_NOTHROW(SpanS(base_buf, 4, base_buf) + 4); + CHECK_THROWS(SpanS(base_buf, 4, base_buf) + 5); + CHECK_THROWS(SpanS(base_buf - 1, 4, base_buf)); + CHECK_THROWS(SpanS(base_buf + 1, 0, base_buf)); + // basic same base + CHECK_NOTHROW(SpanS(base_buf, 4, base_buf) = SpanS(base_buf + 1, 3, base_buf)); + CHECK_NOTHROW(SpanS(base_buf, 4, base_buf) = SpanS(base_buf + 1, 1, base_buf)); + CHECK_NOTHROW(SpanS(base_buf, 4, base_buf) = SpanS(base_buf + 1, 5, base_buf)); + CHECK_THROWS(SpanS(base_buf, 4, base_buf) = SpanS(base_buf + 1, 3, base_buf + 1)); + + SpanS x1(base_buf, 0); + assert(x1 != nullptr); + assert(x1.raw_ptr() == base_buf); + assert(x1.raw_base() == base_buf); + assert(x1.raw_size_in_bytes() == 0u); + CHECK_THROWS(*x1); + CHECK_THROWS(x1[0]); + + SpanS a2(base_buf, 4); + assert(a2 != nullptr); + assert(a2.raw_ptr() == base_buf); + assert(a2.raw_base() == base_buf); + assert(a2.raw_size_in_bytes() == 4u); + CHECK(*a2 == 0); + CHECK(a2[1] == 1); + + SpanS base0(base_buf, 4, base_buf); + assert(base0.raw_ptr() == base_buf); + assert(base0.raw_base() == base_buf); + assert(base0.raw_size_in_bytes() == 4u); + + SpanS base4(base_buf, 4); + assert(base4.raw_ptr() == base_buf); + assert(base4.raw_base() == base_buf); + assert(base4.raw_size_in_bytes() == 4u); + + SpanS a1(base_buf, 4); + a1 = base_buf; + a1 = base0; + assert(a1 == base0); + assert(a1 != nullptr); + assert(a1.raw_ptr() == base0.raw_ptr()); + assert(a1.raw_base() == base_buf); + assert(a1.raw_size_in_bytes() == 4u); + a1 = base4; + assert(a1 == base_buf); + assert(a1.raw_ptr() == base_buf); + assert(a1.raw_base() == base_buf); + assert(a1.raw_size_in_bytes() == 4u); + + a1 = base_buf; + a1 = base_buf + 1; + CHECK(*a1++ == 1); + CHECK(*++a1 == 3); + CHECK(*a1 == 3); + a1 = base_buf + 4; // at the end of buffer + CHECK_THROWS(*a1); + CHECK_THROWS(a1 = base_buf + 5); // range error + assert(a1 == base_buf + 4); + CHECK(a1[-4] == 0); + CHECK_THROWS(a1[-5]); // range error + a1 = base_buf; + CHECK(*a1 == 0); + + SpanS new_base4(base_buf + 2, 4); + CHECK_THROWS(a1 = new_base4); // not same base + CHECK_THROWS(a2 = new_base4); // not same base + + SpanS ss_with_base(base_buf, 4, base_buf); + assert(ss_with_base.raw_base() == base_buf); + CHECK_THROWS(ss_with_base = my_null); // nullptr assignment +#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION + typedef PtrOrSpanOrNull Span0; + Span0 s0_no_base(nullptr); + Span0 s0_with_base(nullptr, 4, base_buf); + CHECK_THROWS(ss_with_base = s0_no_base); // nullptr assignment + CHECK_THROWS(ss_with_base = s0_with_base); // nullptr assignment + typedef PtrOrSpanOrNull SpanP; + SpanP sp_1(base_buf + 1, 3, base_buf); + SpanP sp_2(base_buf + 2, 2, base_buf); + // SpanP sp_4(base_buf + 4, 0, base_buf); + SpanP sp_x(base_buf + 1, 3, base_buf + 1); + assert(ss_with_base.raw_base() == base_buf); +#if 0 + ss_with_base = sp_1; + assert(ss_with_base.raw_ptr() == base_buf + 1); + CHECK(*ss_with_base == 1); + ss_with_base = sp_2; + assert(ss_with_base.raw_ptr() == base_buf + 2); + CHECK_THROWS(ss_with_base = sp_x); // not same base + assert(ss_with_base.raw_base() == base_buf); +#endif +#endif +} + +/************************************************************************* +// +**************************************************************************/ + +TEST_CASE("Span void ptr") { + static char a[4] = {0, 1, 2, 3}; + SPAN_0(void) a0(a, 4); + SPAN_P(void) ap(a, 4); + SPAN_S(void) as(a, 4); + SPAN_0(const void) c0(a, 4); + SPAN_P(const void) cp(a, 4); + SPAN_S(const void) cs(a, 4); + static const char b[4] = {0, 1, 2, 3}; + SPAN_0(const void) b0(b, 4); + SPAN_P(const void) bp(b, 4); + SPAN_S(const void) bs(b, 4); +} + +TEST_CASE("Span deref/array/arrow") { + static char real_a[2 + 4 + 2] = {126, 127, 0, 1, 2, 3, 124, 125}; + static char *a = real_a + 2; + SPAN_0(char) a0(a, 4); + SPAN_P(char) ap(a, 4); + SPAN_S(char) as(a, 4); + CHECK_THROWS(a0[4]); + CHECK_THROWS(a0[-1]); + CHECK_THROWS(a0[-2]); + a0 += 2; + CHECK(*a0 == 2); + CHECK(a0[-1] == 1); + CHECK(a0[0] == 2); + CHECK(a0[1] == 3); + ap += 2; + CHECK(*ap == 2); + CHECK(ap[-1] == 1); + CHECK(ap[0] == 2); + CHECK(ap[1] == 3); + as += 2; + CHECK(*as == 2); + CHECK(as[-1] == 1); + CHECK(as[0] == 2); + CHECK(as[1] == 3); +} + +TEST_CASE("Span subspan") { + static char buf[4] = {0, 1, 2, 3}; + SPAN_S(char) as(buf, 4); + CHECK(as.subspan(1, 1)[0] == 1); + CHECK((as + 1).subspan(1, 1)[0] == 2); + CHECK((as + 2).subspan(0, -2)[0] == 0); + CHECK_THROWS(as.subspan(1, 0)[0]); + CHECK_THROWS(as.subspan(1, 1)[-1]); +} + +TEST_CASE("Span constness") { + static char buf[4] = {0, 1, 2, 3}; + + SPAN_0(char) b0(buf, 4); + SPAN_P(char) bp(buf, 4); + SPAN_S(char) bs(buf, 4); + + SPAN_0(char) s0(b0); + SPAN_P(char) sp(bp); + SPAN_S(char) ss(bs); + + SPAN_0(const char) b0c(buf, 4); + SPAN_P(const char) bpc(buf, 4); + SPAN_S(const char) bsc(buf, 4); + + SPAN_0(const char) s0c(b0c); + SPAN_P(const char) spc(bpc); + SPAN_S(const char) ssc(bsc); + + SPAN_0(const char) x0c(b0); + SPAN_P(const char) xpc(bp); + SPAN_S(const char) xsc(bs); + + CHECK(ptr_diff_bytes(b0, buf) == 0); + CHECK(ptr_diff_bytes(bp, buf) == 0); + CHECK(ptr_diff_bytes(bs, buf) == 0); + CHECK(ptr_diff_bytes(s0, buf) == 0); + CHECK(ptr_diff_bytes(sp, buf) == 0); + CHECK(ptr_diff_bytes(bs, buf) == 0); + // + CHECK(ptr_diff_bytes(s0, bp) == 0); + CHECK(ptr_diff_bytes(s0, sp) == 0); + CHECK(ptr_diff_bytes(s0, ss) == 0); + // + CHECK(ptr_diff_bytes(s0c, b0c) == 0); + CHECK(ptr_diff_bytes(spc, bpc) == 0); + CHECK(ptr_diff_bytes(ssc, bsc) == 0); +} + +/************************************************************************* +// +**************************************************************************/ + +namespace { +int my_memcmp_v1(SPAN_P(const void) a, SPAN_0(const void) b, size_t n) { + if (b == nullptr) + return -2; + SPAN_0(const void) x(a); + return memcmp(x, b, n); +} +int my_memcmp_v2(SPAN_P(const char) a, SPAN_0(const char) b, size_t n) { + if (a == b) + return 0; + if (b == nullptr) + return -2; + a += 1; + b -= 1; + SPAN_0(const char) x(a); + SPAN_0(const char) y = b; + return memcmp(x, y, n); +} +} // namespace + +TEST_CASE("PtrOrSpan") { + static const char buf[4] = {0, 1, 2, 3}; + CHECK(my_memcmp_v1(buf, nullptr, 4) == -2); + CHECK(my_memcmp_v2(buf + 4, buf + 4, 999) == 0); + CHECK(my_memcmp_v2(buf, buf + 2, 3) == 0); +} + +/************************************************************************* +// +**************************************************************************/ + +TEST_CASE("PtrOrSpan char") { + char real_buf[2 + 8 + 2] = {126, 127, 0, 1, 2, 3, 4, 5, 6, 7, 124, 125}; + char *buf = real_buf + 2; + SPAN_P(char) a(buf, SpanSizeInBytes(8)); + SPAN_P(char) b = a.subspan(0, 7); + SPAN_P(char) c = (b + 1).subspan(0, 6); + a += 1; + CHECK(*a == 1); + *a++ += 1; + *b++ = 1; + CHECK(a == buf + 2); + CHECK(b == buf + 1); + CHECK(c == buf + 1); + CHECK(*b == 2); + CHECK(*c == 2); + CHECK(a.raw_size_in_bytes() == 8u); + CHECK(b.raw_size_in_bytes() == 7u); + CHECK(c.raw_size_in_bytes() == 6u); + CHECK(a.raw_base() == buf); + CHECK(b.raw_base() == buf); + CHECK(c.raw_base() == buf + 1); +#ifdef UPX_VERSION_HEX + CHECK(get_le32(a) != 0); +#endif + ++c; + c++; +#ifdef UPX_VERSION_HEX + CHECK(get_le32(c) != 0); +#endif + ++c; +#ifdef UPX_VERSION_HEX + CHECK_THROWS(get_le32(c)); +#endif + ++b; + b++; + b += 4; + CHECK(b.raw_ptr() == buf + 7); + CHECK_THROWS(*b); + CHECK(a.raw_size_in_bytes() == 8u); + a = b; + CHECK(a.raw_size_in_bytes() == 8u); + CHECK(a.raw_ptr() == buf + 7); + a++; + CHECK_THROWS(*a); + CHECK_THROWS(raw_bytes(a, 1)); + a = b; + CHECK_THROWS(a = c); + *a = 0; + a = buf; +#ifdef UPX_VERSION_HEX + CHECK(upx_safe_strlen(a) == 7u); +#endif +} + +TEST_CASE("PtrOrSpan int") { + int buf[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + SPAN_P(int) a(buf, SpanCount(8)); + CHECK(a.raw_size_in_bytes() == 8 * sizeof(int)); + SPAN_P(int) b = a.subspan(0, 7); + CHECK(b.raw_size_in_bytes() == 7 * sizeof(int)); + SPAN_P(int) c = (b + 1).subspan(0, 6); + CHECK(c.raw_size_in_bytes() == 6 * sizeof(int)); + a += 1; + CHECK(*a == 1); + CHECK(*a++ == 1); + CHECK(*++a == 3); + CHECK(--*a == 2); + CHECK(*a-- == 2); + CHECK(*b == 0); + CHECK(*c == 1); + a = buf + 7; +#ifdef UPX_VERSION_HEX + CHECK(get_le32(a) == ne32_to_le32(7)); +#endif + a++; +#ifdef UPX_VERSION_HEX + CHECK_THROWS(get_le32(a)); +#endif + CHECK_THROWS(raw_bytes(a, 1)); +} + +/************************************************************************* +// codegen +**************************************************************************/ + +namespace { +template +__acc_static_noinline int foo(T p) { + unsigned r = 0; + r += *p++; + r += *++p; + p += 3; + r += *p; + return r; +} + +template +SPAN_0(T) +make_span_0(T *ptr, size_t count) { + return PtrOrSpanOrNull(ptr, count); +} +template +SPAN_P(T) +make_span_p(T *ptr, size_t count) { + return PtrOrSpan(ptr, count); +} +template +SPAN_S(T) +make_span_s(T *ptr, size_t count) { + return Span(ptr, count); +} +} // namespace + +TEST_CASE("Span codegen") { + char buf[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + CHECK(foo(buf) == 0 + 2 + 5); + CHECK(foo(make_span_0(buf, 8)) == 0 + 2 + 5); + CHECK(foo(make_span_p(buf, 8)) == 0 + 2 + 5); + CHECK(foo(make_span_s(buf, 8)) == 0 + 2 + 5); +} + +#endif // WITH_SPAN >= 2 + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/util/xspan.h b/src/util/xspan.h new file mode 100644 index 00000000..791a82b3 --- /dev/null +++ b/src/util/xspan.h @@ -0,0 +1,144 @@ +/* xspan -- a minimally invasive checked memory smart pointer + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + +#pragma once + +/************************************************************************* +// config and implementation +**************************************************************************/ + +#ifndef WITH_SPAN +#define WITH_SPAN 2 +#endif + +#if WITH_SPAN + +// automatic conversion to underlying pointer; do NOT enable this config as this +// defeats the main purpose of a checked pointer => use raw_bytes() as needed; +// and see xspan_fwd.h how to make this more convenient +#ifndef SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION +#define SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION 0 +#endif +// allow automatic conversion PtrOrSpanOrNull => PtrOrSpan => Span (with runtime checks) +// choose between compile-time safety vs. possible run-time errors +#ifndef SPAN_CONFIG_ENABLE_SPAN_CONVERSION +#define SPAN_CONFIG_ENABLE_SPAN_CONVERSION 1 +#endif + +#include "xspan_impl.h" + +#ifdef SPAN_NAMESPACE_NAME +// help constructor to distinguish between number of elements and bytes +using SPAN_NAMESPACE_NAME::SpanCount; +using SPAN_NAMESPACE_NAME::SpanSizeInBytes; +// actual classes +using SPAN_NAMESPACE_NAME::Ptr; +using SPAN_NAMESPACE_NAME::PtrOrSpan; +using SPAN_NAMESPACE_NAME::PtrOrSpanOrNull; +using SPAN_NAMESPACE_NAME::Span; +// util +using SPAN_NAMESPACE_NAME::raw_bytes; // overloaded for all classes +#endif + +#endif // WITH_SPAN + +/************************************************************************* +// usage +// +// PtrOrSpanOrNull invariants: ptr is checked if ptr != null && base != null +// PtrOrSpan invariants: ptr is checked if base != null; ptr != null +// Span invariants: ptr is checked; ptr != null; base != null +// +// Ptr invariants: none; this is just a no-op pointer wrapper +**************************************************************************/ + +#if WITH_SPAN >= 2 + +// fully checked + +#define SPAN_0(type) PtrOrSpanOrNull +#define SPAN_P(type) PtrOrSpan +#define SPAN_S(type) Span + +// define a new variable +#define SPAN_0_VAR(type, var, first, ...) SPAN_0(type) var(first, ##__VA_ARGS__) +#define SPAN_P_VAR(type, var, first, ...) SPAN_P(type) var(first, ##__VA_ARGS__) +#define SPAN_S_VAR(type, var, first, ...) SPAN_S(type) var(first, ##__VA_ARGS__) + +// create a value +#define SPAN_0_MAKE(type, first, ...) (SPAN_0(type)(first, ##__VA_ARGS__)) +#define SPAN_P_MAKE(type, first, ...) (SPAN_P(type)(first, ##__VA_ARGS__)) +#define SPAN_S_MAKE(type, first, ...) (SPAN_S(type)(first, ##__VA_ARGS__)) + +#elif WITH_SPAN >= 1 + +// unchecked - just a no-op pointer wrapper, no extra functionality + +#define SPAN_0(type) Ptr +#define SPAN_P(type) Ptr +#define SPAN_S(type) Ptr + +// define a new variable +#define SPAN_0_VAR(type, var, first, ...) SPAN_0(type) var(first) +#define SPAN_P_VAR(type, var, first, ...) SPAN_P(type) var(first) +#define SPAN_S_VAR(type, var, first, ...) SPAN_S(type) var(first) + +// create a value +#define SPAN_0_MAKE(type, first, ...) (SPAN_0(type)(first)) +#define SPAN_P_MAKE(type, first, ...) (SPAN_P(type)(first)) +#define SPAN_S_MAKE(type, first, ...) (SPAN_S(type)(first)) + +#else + +// unchecked raw pointers + +// helper for implicit pointer conversions and MemBuffer overloads +template +inline R *span_make__(R * /*dummy*/, T *first) { + return first; // IMPORTANT: no cast here to detect bad usage +} +template +inline R *span_make__(R * /*dummy*/, MemBuffer &first) { + return (R *) membuffer_get_void_ptr(first); +} + +#define SPAN_0(type) type * +#define SPAN_P(type) type * +#define SPAN_S(type) type * + +// define a new variable +#define SPAN_0_VAR(type, var, first, ...) type *var = span_make__((type *) nullptr, first) +#define SPAN_P_VAR(type, var, first, ...) type *var = span_make__((type *) nullptr, first) +#define SPAN_S_VAR(type, var, first, ...) type *var = span_make__((type *) nullptr, first) + +// create a value +#define SPAN_0_MAKE(type, first, ...) (span_make__((type *) nullptr, first)) +#define SPAN_P_MAKE(type, first, ...) (span_make__((type *) nullptr, first)) +#define SPAN_S_MAKE(type, first, ...) (span_make__((type *) nullptr, first)) + +#endif // WITH_SPAN + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/util/xspan_fwd.h b/src/util/xspan_fwd.h new file mode 100644 index 00000000..1c1f1684 --- /dev/null +++ b/src/util/xspan_fwd.h @@ -0,0 +1,293 @@ +/* xspan -- a minimally invasive checked memory smart pointer + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + +// manually forward a number of well-known functions using a +// checked "raw_bytes()" call + +#define SPAN_FWD_TU(RType) \ + template \ + inline SPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION(T, U, RType) + +/************************************************************************* +// overloads for standard functions +**************************************************************************/ + +template +inline void *memchr(const C &a, int c, size_t n) { + return memchr(a.raw_bytes(n), c, n); +} +template +inline const void *memchr(const C &a, int c, size_t n) { + return memchr(a.raw_bytes(n), c, n); +} + +template +inline int memcmp(const C &a, const void *b, size_t n) { + return memcmp(a.raw_bytes(n), b, n); +} +template +inline int memcmp(const void *a, const C &b, size_t n) { + return memcmp(a, b.raw_bytes(n), n); +} +SPAN_FWD_TU(int) memcmp(const C &a, const C &b, size_t n) { + return memcmp(a.raw_bytes(n), b.raw_bytes(n), n); +} +#ifdef D +SPAN_FWD_TU(int) memcmp(const C &a, const D &b, size_t n) { + return memcmp(a.raw_bytes(n), b.raw_bytes(n), n); +} +#endif +#ifdef E +SPAN_FWD_TU(int) memcmp(const C &a, const E &b, size_t n) { + return memcmp(a.raw_bytes(n), b.raw_bytes(n), n); +} +#endif + +template +inline void *memcpy(C a, const void *b, size_t n) { + return memcpy(a.raw_bytes(n), b, n); +} +template +inline void *memcpy(void *a, const C &b, size_t n) { + return memcpy(a, b.raw_bytes(n), n); +} +SPAN_FWD_TU(void *) memcpy(const C &a, const C &b, size_t n) { + return memcpy(a.raw_bytes(n), b.raw_bytes(n), n); +} +#ifdef D +SPAN_FWD_TU(void *) memcpy(const C &a, const D &b, size_t n) { + return memcpy(a.raw_bytes(n), b.raw_bytes(n), n); +} +#endif +#ifdef E +SPAN_FWD_TU(void *) memcpy(const C &a, const E &b, size_t n) { + return memcpy(a.raw_bytes(n), b.raw_bytes(n), n); +} +#endif + +template +inline void *memmove(C a, const void *b, size_t n) { + return memmove(a.raw_bytes(n), b, n); +} +template +inline void *memmove(void *a, const C &b, size_t n) { + return memmove(a, b.raw_bytes(n), n); +} +SPAN_FWD_TU(void *) memmove(const C &a, const C &b, size_t n) { + return memmove(a.raw_bytes(n), b.raw_bytes(n), n); +} +#ifdef D +SPAN_FWD_TU(void *) memmove(const C &a, const D &b, size_t n) { + return memmove(a.raw_bytes(n), b.raw_bytes(n), n); +} +#endif +#ifdef E +SPAN_FWD_TU(void *) memmove(const C &a, const E &b, size_t n) { + return memmove(a.raw_bytes(n), b.raw_bytes(n), n); +} +#endif + +/************************************************************************* +// overloads for UPX extras +**************************************************************************/ + +template +inline int ptr_diff_bytes(const C &a, const void *b) { + return ptr_diff_bytes(a.raw_bytes(0), b); +} +template +inline int ptr_diff_bytes(const void *a, const C &b) { + return ptr_diff_bytes(a, b.raw_bytes(0)); +} +SPAN_FWD_TU(int) ptr_diff_bytes(const C &a, const C &b) { + return ptr_diff_bytes(a.raw_bytes(0), b.raw_bytes(0)); +} +#ifdef D +SPAN_FWD_TU(int) ptr_diff_bytes(const C &a, const D &b) { + return ptr_diff_bytes(a.raw_bytes(0), b.raw_bytes(0)); +} +#endif +#ifdef E +SPAN_FWD_TU(int) ptr_diff_bytes(const C &a, const E &b) { + return ptr_diff_bytes(a.raw_bytes(0), b.raw_bytes(0)); +} +#endif + +template +inline unsigned ptr_udiff_bytes(const C &a, const void *b) { + return ptr_udiff_bytes(a.raw_bytes(0), b); +} +template +inline unsigned ptr_udiff_bytes(const void *a, const C &b) { + return ptr_udiff_bytes(a, b.raw_bytes(0)); +} +SPAN_FWD_TU(unsigned) ptr_udiff_bytes(const C &a, const C &b) { + return ptr_udiff_bytes(a.raw_bytes(0), b.raw_bytes(0)); +} +#ifdef D +SPAN_FWD_TU(unsigned) ptr_udiff_bytes(const C &a, const D &b) { + return ptr_udiff_bytes(a.raw_bytes(0), b.raw_bytes(0)); +} +#endif +#ifdef E +SPAN_FWD_TU(unsigned) ptr_udiff_bytes(const C &a, const E &b) { + return ptr_udiff_bytes(a.raw_bytes(0), b.raw_bytes(0)); +} +#endif + +#ifdef UPX_VERSION_HEX + +template +unsigned get_ne16(const C &a) { + return get_ne16(a.raw_bytes(2)); +} +template +unsigned get_ne32(const C &a) { + return get_ne32(a.raw_bytes(4)); +} +template +upx_uint64_t get_ne64(const C &a) { + return get_ne64(a.raw_bytes(8)); +} + +template +unsigned get_be16(const C &a) { + return get_be16(a.raw_bytes(2)); +} +template +unsigned get_be32(const C &a) { + return get_be32(a.raw_bytes(4)); +} +template +upx_uint64_t get_be64(const C &a) { + return get_be64(a.raw_bytes(8)); +} + +template +unsigned get_le16(const C &a) { + return get_le16(a.raw_bytes(2)); +} +template +unsigned get_le24(const C &a) { + return get_le24(a.raw_bytes(3)); +} +template +unsigned get_le32(const C &a) { + return get_le32(a.raw_bytes(4)); +} +template +upx_uint64_t get_le64(const C &a) { + return get_le64(a.raw_bytes(8)); +} + +template +void set_ne16(const C &a, unsigned v) { + return set_ne16(a.raw_bytes(2), v); +} +template +void set_ne32(const C &a, unsigned v) { + return set_ne32(a.raw_bytes(4), v); +} +template +void set_ne64(const C &a, upx_uint64_t v) { + return set_ne64(a.raw_bytes(8), v); +} + +template +void set_be16(const C &a, unsigned v) { + return set_be16(a.raw_bytes(2), v); +} +template +void set_be32(const C &a, unsigned v) { + return set_be32(a.raw_bytes(4), v); +} +template +void set_be64(const C &a, upx_uint64_t v) { + return set_be64(a.raw_bytes(8), v); +} + +template +void set_le16(const C &a, unsigned v) { + return set_le16(a.raw_bytes(2), v); +} +template +void set_le24(const C &a, unsigned v) { + return set_le24(a.raw_bytes(3), v); +} +template +void set_le32(const C &a, unsigned v) { + return set_le32(a.raw_bytes(4), v); +} +template +void set_le64(const C &a, upx_uint64_t v) { + return set_le64(a.raw_bytes(8), v); +} + +template +inline C operator+(const C &a, const BE16 &v) { + return a + unsigned(v); +} +template +inline C operator+(const C &a, const BE32 &v) { + return a + unsigned(v); +} +template +inline C operator+(const C &a, const LE16 &v) { + return a + unsigned(v); +} +template +inline C operator+(const C &a, const LE32 &v) { + return a + unsigned(v); +} + +template +inline C operator-(const C &a, const BE16 &v) { + return a - unsigned(v); +} +template +inline C operator-(const C &a, const BE32 &v) { + return a - unsigned(v); +} +template +inline C operator-(const C &a, const LE16 &v) { + return a - unsigned(v); +} +template +inline C operator-(const C &a, const LE32 &v) { + return a - unsigned(v); +} + +template +typename std::enable_if::type upx_safe_strlen(const C &a) { + // not fully checked, but can require at least 1 byte + return upx_safe_strlen(a.raw_bytes(1)); +} + +#endif // UPX_VERSION_HEX + +#undef SPAN_FWD_TU + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/util/xspan_impl.h b/src/util/xspan_impl.h new file mode 100644 index 00000000..628a29be --- /dev/null +++ b/src/util/xspan_impl.h @@ -0,0 +1,240 @@ +/* xspan -- a minimally invasive checked memory smart pointer + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + +#pragma once + +#if WITH_SPAN + +#if 1 +#define SPAN_NAMESPACE_NAME XSpan +#define SPAN_NAMESPACE_BEGIN namespace SPAN_NAMESPACE_NAME { +#define SPAN_NAMESPACE_END } +#define SPAN_NS(x) SPAN_NAMESPACE_NAME ::x +#else +#define SPAN_NAMESPACE_BEGIN /*empty*/ +#define SPAN_NAMESPACE_END /*empty*/ +#define SPAN_NS(x) ::x +#endif + +SPAN_NAMESPACE_BEGIN + +__acc_noinline void span_fail_nullptr(); +__acc_noinline void span_fail_not_same_base(); +__acc_noinline void span_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes); + +// help constructor to distinguish between number of elements and bytes +struct SpanCount { + explicit SpanCount(size_t n) : count(n) {} + size_t count; // public +}; +struct SpanSizeInBytes { + explicit SpanSizeInBytes(size_t bytes) : size_in_bytes(bytes) {} + size_t size_in_bytes; // public +}; + +template +struct TypeForSizeOf { + typedef T type; +}; +template <> +struct TypeForSizeOf { + typedef char type; +}; +template <> +struct TypeForSizeOf { + typedef const char type; +}; + +template +struct ValueForSizeOf { + static const size_t value = sizeof(typename TypeForSizeOf::type); +}; + +ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf::value == 1) +ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf::value == 1) +ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf::value == 1) +ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf::value == 1) +ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf::value == 4) + +#ifndef span_mem_size_impl +template +inline size_t span_mem_size_impl(size_t n) { +#ifdef UPX_VERSION_HEX + // check for overflow and sane limits + return mem_size(sizeof(T), n); +#else + return sizeof(T) * n; +#endif +} +#endif + +template +inline size_t span_mem_size(size_t n) { + return span_mem_size_impl::type>(n); +} + +template +inline void span_mem_size_assert_ptrdiff(ptrdiff_t n) { + if (n >= 0) + (void) span_mem_size((size_t) n); + else + (void) span_mem_size((size_t) -n); +} + +#if 0 +template +struct Span_is_convertible : public std::is_convertible {}; +#else + +namespace detail { +template +struct Span_void_to_T { + typedef U type; +}; +template +struct Span_void_to_T { + typedef typename std::remove_const::type type; +}; +template +struct Span_void_to_T { + // typedef typename std::add_const::type type; + typedef T type; +}; + +template +struct Span_ptr_is_convertible : public std::false_type {}; +template +struct Span_ptr_is_convertible : public std::true_type {}; +template +struct Span_ptr_is_convertible : public std::true_type {}; +} // namespace detail + +template +struct Span_is_convertible + : public detail::Span_ptr_is_convertible::type> {}; +#endif + +#if 1 +// char => char +ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible::value)); + +// void => void +ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible::value)); + +// char => void +ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible::value)); + +// void => char +ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible::value)); + +// char => int +ACC_COMPILE_TIME_ASSERT_HEADER(!(Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER(!(Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER(!(Span_is_convertible::value)); +ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible::value)); +#endif + +/************************************************************************* +// PtrOrSpanOrNull +// PtrOrSpan +// Span +// Ptr +**************************************************************************/ + +// forward declarations + +template +struct PtrOrSpanOrNull; +template +struct PtrOrSpan; +template +struct Span; +template +struct Ptr; + +template +inline T *raw_bytes(const PtrOrSpanOrNull &a, size_t size_in_bytes); +template +inline T *raw_bytes(const PtrOrSpan &a, size_t size_in_bytes); +template +inline T *raw_bytes(const Span &a, size_t size_in_bytes); +template +inline T *raw_bytes(const Ptr &a, size_t size_in_bytes); + +class SpanInternalDummyArg; // not implemented + +SPAN_NAMESPACE_END + +#ifndef SPAN_DELETED_FUNCTION +#define SPAN_DELETED_FUNCTION = delete +#endif +#define SPAN_REQUIRES_CONVERTIBLE_UT(T, U, RType) \ + typename std::enable_if::value, RType > ::type +#define SPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION(T, U, RType) \ + typename std::enable_if::value || \ + SPAN_NS(Span_is_convertible)::value, \ + RType > ::type +// note: these use "T" and "U" +#define SPAN_REQUIRES_CONVERTIBLE_R(RType) SPAN_REQUIRES_CONVERTIBLE_UT(T, U, RType) +#define SPAN_REQUIRES_CONVERTIBLE_A \ + SPAN_REQUIRES_CONVERTIBLE_R(SPAN_NS(SpanInternalDummyArg) *) = nullptr +#define SPAN_REQUIRES_CONVERTIBLE_T SPAN_REQUIRES_CONVERTIBLE_R(SPAN_NS(SpanInternalDummyArg) *) +// note: these use "T" and "U" +#define SPAN_REQUIRES_SIZE_1_R(RType) \ + typename std::enable_if::value &&SPAN_NS( \ + ValueForSizeOf)::value == 1 && \ + SPAN_NS(ValueForSizeOf)::value == 1, \ + RType > ::type +#define SPAN_REQUIRES_SIZE_1_A SPAN_REQUIRES_SIZE_1_R(SPAN_NS(SpanInternalDummyArg) *) = nullptr + +#include "xspan_impl_ptr_or_null.h" +#include "xspan_impl_ptr_or_span.h" +#include "xspan_impl_span.h" +#include "xspan_impl_ptr.h" +#undef SPAN_REQUIRES_CONVERTIBLE_UT +#undef SPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION +#undef SPAN_REQUIRES_CONVERTIBLE_A +#undef SPAN_REQUIRES_CONVERTIBLE_R +#undef SPAN_REQUIRES_CONVERTIBLE_T +#undef SPAN_REQUIRES_SIZE_1_A +#undef SPAN_REQUIRES_SIZE_1_R + +#endif // WITH_SPAN + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/util/xspan_impl_common.h b/src/util/xspan_impl_common.h new file mode 100644 index 00000000..270564e8 --- /dev/null +++ b/src/util/xspan_impl_common.h @@ -0,0 +1,417 @@ +/* xspan -- a minimally invasive checked memory smart pointer + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + +/************************************************************************* +// +**************************************************************************/ + +public: +typedef T element_type; +typedef typename std::add_lvalue_reference::type reference; +// typedef typename std::add_pointer::type pointer; +typedef T *pointer; +typedef size_t size_type; + +// befriend all +template +friend struct PtrOrSpan; +template +friend struct PtrOrSpanOrNull; +template +friend struct Span; + +#if SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION +operator pointer() const { return ptr; } +#endif + +private: +pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr +pointer base; +size_type size_in_bytes; + +private: +// 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 SPAN_DELETED_FUNCTION; + +private: +static __acc_forceinline pointer makeNotNull(pointer p) { + if __acc_very_unlikely (p == nullptr) + span_fail_nullptr(); + return p; +} +// enforce config invariants at constructor time - static functions +static __acc_forceinline pointer makePtr(pointer p) { + if __acc_cte (configRequirePtr && p == nullptr) + span_fail_nullptr(); + return p; +} +static __acc_forceinline pointer makeBase(pointer b) { + if __acc_cte (configRequireBase && b == nullptr) + span_fail_nullptr(); + return b; +} +// inverse logic for ensuring valid pointers from existing objets +__acc_forceinline pointer ensurePtr() const { + if __acc_cte (!configRequirePtr && ptr == nullptr) + span_fail_nullptr(); + return ptr; +} +__acc_forceinline pointer ensureBase() const { + if __acc_cte (!configRequireBase && base == nullptr) + span_fail_nullptr(); + return ptr; +} +// debug - extra internal sanity checks +#if DEBUG || 1 +__acc_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)) + span_check_range(ptr, base, size_in_bytes); +} +#else +__acc_forceinline void assertInvariants() const {} +#endif + +public: +inline ~CSelf() {} +// constructors from pointers +CSelf(pointer first, SpanCount count) + : ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(span_mem_size(count.count)) { + assertInvariants(); +} +CSelf(pointer first, SpanSizeInBytes bytes) + : ptr(makePtr(first)), base(makeBase(first)), + size_in_bytes(span_mem_size(bytes.size_in_bytes)) { + assertInvariants(); +} +// enable this constructor only if the underlying type is char or void +template +CSelf(U *first, size_type count, SPAN_REQUIRES_SIZE_1_A) + : ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(span_mem_size(count)) { + assertInvariants(); +} +CSelf(pointer first, SpanCount count, pointer base_) + : ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(span_mem_size(count.count)) { + // check invariants + if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr)) + span_check_range(ptr, base, size_in_bytes); + // double sanity check + assertInvariants(); +} +CSelf(pointer first, SpanSizeInBytes bytes, pointer base_) + : ptr(makePtr(first)), base(makeBase(base_)), + size_in_bytes(span_mem_size(bytes.size_in_bytes)) { + // check invariants + if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr)) + span_check_range(ptr, base, size_in_bytes); + // double sanity check + assertInvariants(); +} +// enable this constructor only if the underlying type is char or void +template +CSelf(pointer first, size_type count, U *base_, SPAN_REQUIRES_SIZE_1_A) + : ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(span_mem_size(count)) { + // check invariants + if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr)) + span_check_range(ptr, base, size_in_bytes); + // double sanity check + assertInvariants(); +} +#ifdef UPX_VERSION_HEX +// constructors from MemBuffer +CSelf(MemBuffer &mb) + : CSelf(makeNotNull((pointer) membuffer_get_void_ptr(mb)), + SpanSizeInBytes(membuffer_get_size(mb))) {} +CSelf(pointer first, MemBuffer &mb) + : CSelf(first, SpanSizeInBytes(membuffer_get_size(mb)), + makeNotNull((pointer) membuffer_get_void_ptr(mb))) {} +CSelf(std::nullptr_t, MemBuffer &) SPAN_DELETED_FUNCTION; +#endif +// disable constructors from nullptr to catch compile-time misuse +private: +CSelf(std::nullptr_t, SpanCount) SPAN_DELETED_FUNCTION; +CSelf(std::nullptr_t, SpanCount, std::nullptr_t) SPAN_DELETED_FUNCTION; +CSelf(const void *, SpanCount, std::nullptr_t) SPAN_DELETED_FUNCTION; +CSelf(std::nullptr_t, SpanSizeInBytes) SPAN_DELETED_FUNCTION; +CSelf(std::nullptr_t, SpanSizeInBytes, std::nullptr_t) SPAN_DELETED_FUNCTION; +CSelf(const void *, SpanSizeInBytes, std::nullptr_t) SPAN_DELETED_FUNCTION; +CSelf(std::nullptr_t, size_type) SPAN_DELETED_FUNCTION; +CSelf(std::nullptr_t, size_type, std::nullptr_t) SPAN_DELETED_FUNCTION; +CSelf(const void *, size_type, std::nullptr_t) SPAN_DELETED_FUNCTION; + +// unchecked constructor +private: +enum ModeUnchecked { Unchecked }; +CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b) + : ptr(p), base(b), size_in_bytes(bytes) { + assertInvariants(); +} +#if 0 +// unchecked assignment +Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) { + ptr = p; + base = b; + size_in_bytes = bytes; + assertInvariants(); + return *this; +} +Self &assign(ModeUnchecked, const Self &other) { + ptr = other.ptr; + base = other.base; + size_in_bytes = other.size_in_bytes; + assertInvariants(); + return *this; +} +#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) { + assertInvariants(); + other = makePtr(other); + if __acc_cte ((configRequirePtr || other != nullptr) && (configRequireBase || base != nullptr)) + span_check_range(other, base, size_in_bytes); + // ok + ptr = other; + assertInvariants(); + return *this; +} +Self &assign(const Self &other) { + assertInvariants(); + other.assertInvariants(); + if __acc_cte (!configRequireBase && base == nullptr) { + // magic 1: if base is unset, automatically set base/size_in_bytes from other + if __acc_cte ((configRequirePtr || other.ptr != nullptr) && + (configRequireBase || other.base != nullptr)) + span_check_range(other.ptr, other.base, other.size_in_bytes); + // ok + ptr = other.ptr; + base = other.base; + size_in_bytes = other.size_in_bytes; + } else { + // magic 2: assert same base (but ignore size_in_bytes !) + if __acc_cte (configRequireBase || other.base != nullptr) + if __acc_very_unlikely (base != other.base) + span_fail_not_same_base(); + if __acc_cte ((configRequirePtr || other.ptr != nullptr) && + (configRequireBase || base != nullptr)) + span_check_range(other.ptr, base, size_in_bytes); + // ok + ptr = other.ptr; + } + assertInvariants(); + return *this; +} + +Self &operator=(pointer other) { return assign(other); } + +Self &operator=(const Self &other) { return assign(other); } + +// FIXME: this is not called?? +template +SPAN_REQUIRES_CONVERTIBLE_R(Self &) +operator=(const CSelf &other) { + // assert(0); + return assign(Self(other)); +} + +#ifdef UPX_VERSION_HEX +Self &operator=(MemBuffer &mb) { return assign(Self(mb)); } +#endif + +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 +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator==(U *other) const { + return ptr == other; +} +bool operator!=(pointer other) const { return ptr != other; } +template +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator!=(U *other) const { + return ptr != other; +} + +template +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator==(const PtrOrSpan &other) const { + return ptr == other.ptr; +} +template +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator==(const PtrOrSpanOrNull &other) const { + return ptr == other.ptr; +} +template +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator==(const Span &other) const { + return ptr == other.ptr; +} + +template +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator!=(const PtrOrSpan &other) const { + return !(*this == other); +} +template +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator!=(const PtrOrSpanOrNull &other) const { + return !(*this == other); +} +template +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator!=(const Span &other) const { + return !(*this == other); +} + +// check for notNull here +bool operator<(std::nullptr_t) const SPAN_DELETED_FUNCTION; +bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); } + +template +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator<(const PtrOrSpan &other) const { + return ensurePtr() < other.ensurePtr(); +} +template +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator<(const PtrOrSpanOrNull &other) const { + return ensurePtr() < other.ensurePtr(); +} +template +SPAN_REQUIRES_CONVERTIBLE_R(bool) +operator<(const Span &other) const { + return ensurePtr() < other.ensurePtr(); +} + +// dereference +reference operator*() const { return *check_deref(ptr); } + +// array access +reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); } + +// arrow operator +pointer operator->() const { return check_deref(ptr); } + +Self &operator++() { + ptr = check_add(ptr, 1); + return *this; +} +Self operator++(int) { + Self tmp = *this; + ++*this; + return tmp; +} +Self &operator--() { + ptr = check_add(ptr, -1); + return *this; +} +Self operator--(int) { + Self tmp = *this; + --*this; + return tmp; +} + +Self &operator+=(ptrdiff_t n) { + ptr = check_add(ptr, n); + return *this; +} +Self &operator-=(ptrdiff_t n) { + ptr = check_add(ptr, -n); + return *this; +} + +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 { + pointer first = check_add(ptr, -n); + return Self(Unchecked, first, size_in_bytes, base); +} + +private: +pointer check_deref(pointer p) const { + if __acc_cte (!configRequirePtr && p == nullptr) + span_fail_nullptr(); + if __acc_cte (configRequireBase || base != nullptr) + span_check_range(p, base, size_in_bytes - sizeof(T)); + assertInvariants(); + return p; +} +pointer check_deref(pointer p, ptrdiff_t n) const { + if __acc_cte (!configRequirePtr && p == nullptr) + span_fail_nullptr(); + span_mem_size_assert_ptrdiff(n); + p += n; + if __acc_cte (configRequireBase || base != nullptr) + span_check_range(p, base, size_in_bytes - sizeof(T)); + assertInvariants(); + return p; +} +pointer check_add(pointer p, ptrdiff_t n) const { + if __acc_cte (!configRequirePtr && p == nullptr) + span_fail_nullptr(); + span_mem_size_assert_ptrdiff(n); + p += n; + if __acc_cte (configRequireBase || base != nullptr) + span_check_range(p, base, size_in_bytes); + assertInvariants(); + return p; +} + +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_bytes(size_t bytes) const { + assertInvariants(); + if (bytes > 0) { + if __acc_cte (!configRequirePtr && ptr == nullptr) + span_fail_nullptr(); + if __acc_cte (configRequireBase || base != nullptr) { + span_check_range(ptr, base, size_in_bytes - bytes); + } + } + return ptr; +} + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/util/xspan_impl_ptr.h b/src/util/xspan_impl_ptr.h new file mode 100644 index 00000000..02ac34da --- /dev/null +++ b/src/util/xspan_impl_ptr.h @@ -0,0 +1,209 @@ +/* xspan -- a minimally invasive checked memory smart pointer + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + +#pragma once + +SPAN_NAMESPACE_BEGIN + +/************************************************************************* +// Ptr +**************************************************************************/ + +template +struct Ptr { +private: +#define CSelf Ptr + typedef CSelf Self; + +public: + // befriend all + template + friend struct CSelf; + + typedef T element_type; + typedef typename std::add_lvalue_reference::type reference; + // typedef T *pointer; + typedef typename std::add_pointer::type pointer; + +private: + pointer ptr; + + // enforce config invariants at constructor time - static functions + static __acc_forceinline pointer makePtr(pointer p) { return p; } + // inverse logic for ensuring valid pointers from existing objets + __acc_forceinline pointer ensurePtr() const { return ptr; } + // debug + __acc_forceinline void assertInvariants() const {} + +public: +#if SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1 + operator pointer() const { return ptr; } +#endif + + inline ~CSelf() {} + inline CSelf() {} + + // constructors from pointers + CSelf(pointer p) : ptr(makePtr(p)) {} + template + CSelf(U *p, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(makePtr(p)) {} + + // constructors + CSelf(const Self &other) : ptr(other.ptr) {} + template + CSelf(const CSelf &other, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(other.ptr) {} + + Self &assign(const Self &other) { + assertInvariants(); + other.assertInvariants(); + ptr = other.ptr; + assertInvariants(); + return *this; + } + + // assignment + Self &operator=(const Self &other) { return assign(other); } + + template + SPAN_REQUIRES_CONVERTIBLE_R(Self &) + operator=(U *other) { + assert(0); + return assign(Self(other)); + } + + // FIXME: this is not called !! + template + SPAN_REQUIRES_CONVERTIBLE_R(Self &) + operator=(const CSelf &other) { + assert(0); + return assign(Self(other)); + } + + // comparision + + bool operator==(pointer other) const { return ptr == other; } + template + SPAN_REQUIRES_CONVERTIBLE_R(bool) + operator==(U *other) const { + return ptr == other; + } + template + SPAN_REQUIRES_CONVERTIBLE_R(bool) + operator==(const Ptr &other) const { + return ptr == other.ptr; + } + + // dereference + reference operator*() const { return *check_deref(ptr); } + + // array access + reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); } + + // arrow operator + pointer operator->() const { return check_deref(ptr); } + + Self &operator++() { + ptr = check_add(ptr, 1); + return *this; + } + Self operator++(int) { + Self tmp = *this; + ++*this; + return tmp; + } + Self &operator--() { + ptr = check_add(ptr, -1); + return *this; + } + Self operator--(int) { + Self tmp = *this; + --*this; + return tmp; + } + + Self &operator+=(ptrdiff_t n) { + ptr = check_add(ptr, n); + return *this; + } + Self &operator-=(ptrdiff_t n) { + ptr = check_add(ptr, -n); + return *this; + } + + Self operator+(ptrdiff_t n) const { + pointer p = check_add(ptr, n); + return Self(p); + } + Self operator-(ptrdiff_t n) const { + pointer p = check_add(ptr, -n); + return Self(p); + } + +#ifdef UPX_VERSION_HEX + CSelf(MemBuffer &mb) : ptr((pointer) membuffer_get_void_ptr(mb)) {} + Self &operator=(MemBuffer &mb) { return assign(Self(mb)); } +#endif + +private: + __acc_forceinline pointer check_deref(pointer p) const { return p; } + __acc_forceinline pointer check_deref(pointer p, ptrdiff_t n) const { return p + n; } + __acc_forceinline pointer check_add(pointer p, ptrdiff_t n) const { return p + n; } + +public: // raw access + pointer raw_ptr() const { return ptr; } + + pointer raw_bytes(size_t bytes) const { + assertInvariants(); + if (bytes > 0) { + if __acc_cte (ptr == nullptr) + span_fail_nullptr(); + } + return ptr; + } + +#undef CSelf +}; + +template +inline T *raw_bytes(const Ptr &a, size_t size_in_bytes) { + return a.raw_bytes(size_in_bytes); +} + +/************************************************************************* +// +**************************************************************************/ + +SPAN_NAMESPACE_END + +#if 1 + +#define C SPAN_NS(Ptr) +#include "xspan_fwd.h" +#undef C + +#endif + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/util/xspan_impl_ptr_or_null.h b/src/util/xspan_impl_ptr_or_null.h new file mode 100644 index 00000000..a499f6f7 --- /dev/null +++ b/src/util/xspan_impl_ptr_or_null.h @@ -0,0 +1,108 @@ +/* xspan -- a minimally invasive checked memory smart pointer + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + +#pragma once + +SPAN_NAMESPACE_BEGIN + +/************************************************************************* +// PtrOrSpanOrNull +// +// invariants: +// ptr can be null +// if ptr != null && base != null then ptr is valid in base +**************************************************************************/ + +template +struct PtrOrSpanOrNull { +private: +#define CSelf PtrOrSpanOrNull + typedef CSelf Self; + // core config + enum { configRequirePtr = false }; + enum { configRequireBase = false }; + +#include "xspan_impl_common.h" +public: + // constructors from pointers + CSelf(pointer first) : ptr(first), base(nullptr), size_in_bytes(0) {} + + // constructors + CSelf(const Self &other) + : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {} + template + CSelf(const CSelf &other, SPAN_REQUIRES_CONVERTIBLE_A) + : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {} + + // constructors from Span friends + template + CSelf(const PtrOrSpan &other, SPAN_REQUIRES_CONVERTIBLE_A) + : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {} + template + CSelf(const Span &other, SPAN_REQUIRES_CONVERTIBLE_A) + : ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {} + + // assignment from Span friends + template + SPAN_REQUIRES_CONVERTIBLE_R(Self &) + operator=(const PtrOrSpan &other) { + return assign(Self(other)); + } + template + SPAN_REQUIRES_CONVERTIBLE_R(Self &) + operator=(const Span &other) { + return assign(Self(other)); + } + + // nullptr + CSelf(std::nullptr_t) : ptr(nullptr), base(nullptr), size_in_bytes(0) {} +#undef CSelf +}; + +template +inline T *raw_bytes(const PtrOrSpanOrNull &a, size_t size_in_bytes) { + return a.raw_bytes(size_in_bytes); +} + +/************************************************************************* +// +**************************************************************************/ + +SPAN_NAMESPACE_END + +#if !SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1 + +#define C SPAN_NS(PtrOrSpanOrNull) +#define D SPAN_NS(PtrOrSpan) +#define E SPAN_NS(Span) +#include "xspan_fwd.h" +#undef C +#undef D +#undef E + +#endif + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/util/xspan_impl_ptr_or_span.h b/src/util/xspan_impl_ptr_or_span.h new file mode 100644 index 00000000..caf2b49d --- /dev/null +++ b/src/util/xspan_impl_ptr_or_span.h @@ -0,0 +1,133 @@ +/* xspan -- a minimally invasive checked memory smart pointer + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + +#pragma once + +SPAN_NAMESPACE_BEGIN + +/************************************************************************* +// PtrOrSpan +// +// invariants: +// ptr != null +// if base != null then ptr is valid in base +**************************************************************************/ + +template +struct PtrOrSpan { +private: +#define CSelf PtrOrSpan + typedef CSelf Self; + // core config + enum { configRequirePtr = true }; + enum { configRequireBase = false }; + +#include "xspan_impl_common.h" +public: + // constructors from pointers + CSelf(pointer first) : ptr(makePtr(first)), base(nullptr), size_in_bytes(0) {} + + // constructors + CSelf(const Self &other) + : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {} + template + CSelf(const CSelf &other, SPAN_REQUIRES_CONVERTIBLE_A) + : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {} + + // constructors from Span friends + template + CSelf(const Span &other, SPAN_REQUIRES_CONVERTIBLE_A) + : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {} +#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION + template + CSelf(const PtrOrSpanOrNull &other, SPAN_REQUIRES_CONVERTIBLE_A) + : ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {} +#endif + + // assignment from Span friends + // TODO: use Unchecked to avoid double checks in both constructor and assignment + template + SPAN_REQUIRES_CONVERTIBLE_R(Self &) + operator=(const Span &other) { + return assign(Self(other)); + } +#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION + template + SPAN_REQUIRES_CONVERTIBLE_R(Self &) + operator=(const PtrOrSpanOrNull &other) { + if (other.base == nullptr) + return assign(Self(other.ptr, size_in_bytes, base)); + return assign(Self(other.ptr, other.size_in_bytes, other.base)); + } +#endif + + // nullptr + CSelf(std::nullptr_t) SPAN_DELETED_FUNCTION; + CSelf(std::nullptr_t, SpanSizeInBytes, const void *) SPAN_DELETED_FUNCTION; + CSelf(std::nullptr_t, SpanCount, const void *) SPAN_DELETED_FUNCTION; + CSelf(std::nullptr_t, size_type, const void *) SPAN_DELETED_FUNCTION; + Self &operator=(std::nullptr_t) SPAN_DELETED_FUNCTION; +#if 0 + // don't enable, this prevents generic usage + bool operator==(std::nullptr_t) const SPAN_DELETED_FUNCTION; + bool operator!=(std::nullptr_t) const SPAN_DELETED_FUNCTION; +#else + bool operator==(std::nullptr_t) const { + assertInvariants(); + return false; + } + bool operator!=(std::nullptr_t) const { + assertInvariants(); + return true; + } +#endif +#undef CSelf +}; + +template +inline T *raw_bytes(const PtrOrSpan &a, size_t size_in_bytes) { + return a.raw_bytes(size_in_bytes); +} + +/************************************************************************* +// +**************************************************************************/ + +SPAN_NAMESPACE_END + +#if !SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1 + +#define C SPAN_NS(PtrOrSpan) +#define D SPAN_NS(PtrOrSpanOrNull) +#define E SPAN_NS(Span) +#include "xspan_fwd.h" +#undef C +#undef D +#undef E + +#endif + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/util/xspan_impl_span.h b/src/util/xspan_impl_span.h new file mode 100644 index 00000000..a17c9110 --- /dev/null +++ b/src/util/xspan_impl_span.h @@ -0,0 +1,135 @@ +/* xspan -- a minimally invasive checked memory smart pointer + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2022 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + +#pragma once + +SPAN_NAMESPACE_BEGIN + +/************************************************************************* +// Span +// +// invariants: +// ptr != null, base != null +// ptr is valid in base +**************************************************************************/ + +template +struct Span { +private: +#define CSelf Span + typedef CSelf Self; + // core config + enum { configRequirePtr = true }; + enum { configRequireBase = true }; + +#include "xspan_impl_common.h" +public: + // constructors from pointers + CSelf(pointer first) SPAN_DELETED_FUNCTION; + + // constructors + CSelf(const Self &other) + : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {} + template + CSelf(const CSelf &other, SPAN_REQUIRES_CONVERTIBLE_A) + : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {} + + // constructors from Span friends +#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION + template + CSelf(const PtrOrSpanOrNull &other, SPAN_REQUIRES_CONVERTIBLE_A) + : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {} + template + CSelf(const PtrOrSpan &other, SPAN_REQUIRES_CONVERTIBLE_A) + : ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {} +#endif + + // assignment from Span friends +#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION + // TODO: use Unchecked to avoid double checks in both constructor and assignment + template + SPAN_REQUIRES_CONVERTIBLE_R(Self &) + operator=(const PtrOrSpan &other) { + if (other.base == nullptr) + return assign(Self(other.ptr, size_in_bytes, base)); + return assign(Self(other.ptr, other.size_in_bytes, other.base)); + } + template + SPAN_REQUIRES_CONVERTIBLE_R(Self &) + operator=(const PtrOrSpanOrNull &other) { + if (other.base == nullptr) + return assign(Self(other.ptr, size_in_bytes, base)); + return assign(Self(other.ptr, other.size_in_bytes, other.base)); + } +#endif + + // nullptr + CSelf(std::nullptr_t) SPAN_DELETED_FUNCTION; + CSelf(std::nullptr_t, SpanSizeInBytes, const void *) SPAN_DELETED_FUNCTION; + CSelf(std::nullptr_t, SpanCount, const void *) SPAN_DELETED_FUNCTION; + CSelf(std::nullptr_t, size_type, const void *) SPAN_DELETED_FUNCTION; + Self &operator=(std::nullptr_t) SPAN_DELETED_FUNCTION; +#if 0 + // don't enable, this prevents generic usage + bool operator==(std::nullptr_t) const SPAN_DELETED_FUNCTION; + bool operator!=(std::nullptr_t) const SPAN_DELETED_FUNCTION; +#else + bool operator==(std::nullptr_t) const { + assertInvariants(); + return false; + } + bool operator!=(std::nullptr_t) const { + assertInvariants(); + return true; + } +#endif +#undef CSelf +}; + +template +inline T *raw_bytes(const Span &a, size_t size_in_bytes) { + return a.raw_bytes(size_in_bytes); +} + +/************************************************************************* +// +**************************************************************************/ + +SPAN_NAMESPACE_END + +#if !SPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1 + +#define C SPAN_NS(Span) +#define D SPAN_NS(PtrOrSpanOrNull) +#define E SPAN_NS(PtrOrSpan) +#include "xspan_fwd.h" +#undef C +#undef D +#undef E + +#endif + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/work.cpp b/src/work.cpp index 5effbfe4..81e011d1 100644 --- a/src/work.cpp +++ b/src/work.cpp @@ -190,15 +190,15 @@ void do_one_file(const char *iname, char *oname) { r = chmod(iname, 0777); IGNORE_ERROR(r); #endif - File::unlink(iname); + FileBase::unlink(iname); } else { // make backup char bakname[ACC_FN_PATH_MAX + 1]; if (!makebakname(bakname, sizeof(bakname), iname)) throwIOException("could not create a backup file name"); - File::rename(iname, bakname); + FileBase::rename(iname, bakname); } - File::rename(oname, iname); + FileBase::rename(oname, iname); } // copy file attributes @@ -272,40 +272,40 @@ int do_files(int i, int argc, char *argv[]) { if (opt->verbose >= 1 || (opt->verbose >= 0 && !e.isWarning())) printErr(iname, &e); main_set_exit_code(e.isWarning() ? EXIT_WARN : EXIT_ERROR); - // continue processing more files + // this is not fatal, continue processing more files } catch (const Error &e) { unlink_ofile(oname); printErr(iname, &e); main_set_exit_code(EXIT_ERROR); - return -1; + return -1; // fatal error } catch (std::bad_alloc *e) { unlink_ofile(oname); printErr(iname, "out of memory"); UNUSED(e); // delete e; main_set_exit_code(EXIT_ERROR); - return -1; + return -1; // fatal error } catch (const std::bad_alloc &) { unlink_ofile(oname); printErr(iname, "out of memory"); main_set_exit_code(EXIT_ERROR); - return -1; + return -1; // fatal error } catch (std::exception *e) { unlink_ofile(oname); printUnhandledException(iname, e); // delete e; main_set_exit_code(EXIT_ERROR); - return -1; + return -1; // fatal error } catch (const std::exception &e) { unlink_ofile(oname); printUnhandledException(iname, &e); main_set_exit_code(EXIT_ERROR); - return -1; + return -1; // fatal error } catch (...) { unlink_ofile(oname); printUnhandledException(iname, nullptr); main_set_exit_code(EXIT_ERROR); - return -1; + return -1; // fatal error } }