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
This commit is contained in:
Markus F.X.J. Oberhumer 2022-09-11 16:03:56 +02:00
parent 4318cc22ee
commit c75d7a685d
54 changed files with 3521 additions and 1196 deletions

View File

@ -311,18 +311,18 @@ jobs:
@REM build UCL @REM build UCL
cd %BDIR%\ucl cd %BDIR%\ucl
set s=%H%\upx\vendor\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 link -lib -out:ucl.lib *.obj
@REM build zlib @REM build zlib
cd %BDIR%\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 link -lib -out:zlib.lib *.obj
@REM build UPX @REM build UPX
cd %BDIR%\upx cd %BDIR%\upx
set s=%H%\upx\src set s=%H%\upx\src
cat .GITREV.txt cat .GITREV.txt
set /p GITREV=<.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' - name: 'Basic tests'
shell: cmd shell: cmd

View File

@ -83,7 +83,7 @@ list(SORT zlib_SOURCES)
add_library(upx_vendor_zlib STATIC ${zlib_SOURCES}) add_library(upx_vendor_zlib STATIC ${zlib_SOURCES})
set_property(TARGET upx_vendor_zlib PROPERTY C_STANDARD 11) 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) list(SORT upx_SOURCES)
add_executable(upx ${upx_SOURCES}) add_executable(upx ${upx_SOURCES})
set_property(TARGET upx PROPERTY CXX_STANDARD 14) set_property(TARGET upx PROPERTY CXX_STANDARD 14)
@ -124,14 +124,14 @@ endif()
set(t upx_vendor_ucl) set(t upx_vendor_ucl)
target_include_directories(${t} PRIVATE vendor/ucl/include vendor/ucl) target_include_directories(${t} PRIVATE vendor/ucl/include vendor/ucl)
if(MSVC) if(MSVC)
target_compile_options(${t} PRIVATE -W4 ${warn_WX}) target_compile_options(${t} PRIVATE -J -W4 ${warn_WX})
else() else()
target_compile_options(${t} PRIVATE -Wall -Wextra -Wvla ${warn_Werror}) target_compile_options(${t} PRIVATE -Wall -Wextra -Wvla ${warn_Werror})
endif() endif()
set(t upx_vendor_zlib) set(t upx_vendor_zlib)
if(MSVC) 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() else()
target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_UNISTD_H -DHAVE_VSNPRINTF) target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_UNISTD_H -DHAVE_VSNPRINTF)
target_compile_options(${t} PRIVATE -Wall -Wextra -Wvla ${warn_Werror}) target_compile_options(${t} PRIVATE -Wall -Wextra -Wvla ${warn_Werror})

View File

@ -55,7 +55,7 @@ ALL_LDFLAGS = $(strip $(call all_flags,LDFLAGS))
ALL_LDADD = $(strip $(call all_flags,LDADD)) ALL_LDADD = $(strip $(call all_flags,LDADD))
ALL_LIBS = $(strip $(call all_flags,LIBS)) 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))) upx_OBJECTS := $(notdir $(upx_SOURCES:.cpp=$(objext)))
ifneq ($(wildcard $(top_srcdir)/.git/.),) ifneq ($(wildcard $(top_srcdir)/.git/.),)
@ -131,6 +131,8 @@ upx$(exeext): $(upx_OBJECTS) $(upx_DEPENDENCIES)
%.o : %.cpp | ./.depend %.o : %.cpp | ./.depend
$(strip $(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -o $@ -c $<) $(strip $(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -o $@ -c $<)
%.o : util/%.cpp | ./.depend
$(strip $(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -o $@ -c $<)
%.cpp.ii : %.cpp %.cpp.ii : %.cpp
$(strip $(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -o $@ -E $<) $(strip $(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -o $@ -E $<)
@ -207,13 +209,14 @@ endif
# automatically format some C++ source code files # automatically format some C++ source code files
ifeq ($(shell uname),Linux) ifeq ($(shell uname),Linux)
CLANG_FORMAT_FILES += bele.h bele_policy.h 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 += 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 += main.cpp options.cpp options.h packer.cpp packer.h
CLANG_FORMAT_FILES += p_tos.cpp p_tos.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 += 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 work.cpp
CLANG_FORMAT_FILES += ui.cpp ui.h util.cpp util.h work.cpp CLANG_FORMAT_FILES += $(wildcard util/[a-ln-z]*.[ch]* util/mem*.[ch]*)
clang-format: clang-format:
$(top_srcdir)/misc/scripts/upx-clang-format -i $(addprefix $(top_srcdir)/src/,$(sort $(CLANG_FORMAT_FILES))) $(top_srcdir)/misc/scripts/upx-clang-format -i $(addprefix $(top_srcdir)/src/,$(sort $(CLANG_FORMAT_FILES)))
.PHONY: clang-format .PHONY: clang-format

View File

@ -25,8 +25,9 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#ifndef __UPX_BELE_H #pragma once
#define __UPX_BELE_H 1 #ifndef UPX_BELE_H__
#define UPX_BELE_H__ 1
// BE - Big Endian // BE - Big Endian
// LE - Little Endian // LE - Little Endian
@ -294,6 +295,8 @@ struct alignas(1) BE16 {
} }
operator unsigned() const { return get_be16(d); } operator unsigned() const { return get_be16(d); }
bool operator<(const BE16 &v) const { return unsigned(*this) < unsigned(v); }
}; };
struct alignas(1) BE32 { struct alignas(1) BE32 {
@ -341,6 +344,8 @@ struct alignas(1) BE32 {
} }
operator unsigned() const { return get_be32(d); } operator unsigned() const { return get_be32(d); }
bool operator<(const BE32 &v) const { return unsigned(*this) < unsigned(v); }
}; };
struct alignas(1) BE64 { struct alignas(1) BE64 {
@ -388,6 +393,8 @@ struct alignas(1) BE64 {
} }
operator upx_uint64_t() const { return get_be64(d); } 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 { struct alignas(1) LE16 {
@ -435,6 +442,8 @@ struct alignas(1) LE16 {
} }
operator unsigned() const { return get_le16(d); } operator unsigned() const { return get_le16(d); }
bool operator<(const LE16 &v) const { return unsigned(*this) < unsigned(v); }
}; };
struct alignas(1) LE32 { struct alignas(1) LE32 {
@ -482,6 +491,8 @@ struct alignas(1) LE32 {
} }
operator unsigned() const { return get_le32(d); } operator unsigned() const { return get_le32(d); }
bool operator<(const LE32 &v) const { return unsigned(*this) < unsigned(v); }
}; };
struct alignas(1) LE64 { struct alignas(1) LE64 {
@ -529,6 +540,8 @@ struct alignas(1) LE64 {
} }
operator upx_uint64_t() const { return get_le64(d); } 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 // native types
@ -548,20 +561,20 @@ typedef LE64 NE64;
template <class T> template <class T>
inline T *operator+(T *ptr, const BE16 &v) { inline T *operator+(T *ptr, const BE16 &v) {
return ptr + (unsigned) v; return ptr + unsigned(v);
} }
template <class T> template <class T>
inline T *operator-(T *ptr, const BE16 &v) { inline T *operator-(T *ptr, const BE16 &v) {
return ptr - (unsigned) v; return ptr - unsigned(v);
} }
template <class T> template <class T>
inline T *operator+(T *ptr, const BE32 &v) { inline T *operator+(T *ptr, const BE32 &v) {
return ptr + (unsigned) v; return ptr + unsigned(v);
} }
template <class T> template <class T>
inline T *operator-(T *ptr, const BE32 &v) { inline T *operator-(T *ptr, const BE32 &v) {
return ptr - (unsigned) v; return ptr - unsigned(v);
} }
// these are not implemented on purpose and will cause link-time errors // these are not implemented on purpose and will cause link-time errors
@ -572,20 +585,20 @@ T *operator-(T *ptr, const BE64 &v);
template <class T> template <class T>
inline T *operator+(T *ptr, const LE16 &v) { inline T *operator+(T *ptr, const LE16 &v) {
return ptr + (unsigned) v; return ptr + unsigned(v);
} }
template <class T> template <class T>
inline T *operator-(T *ptr, const LE16 &v) { inline T *operator-(T *ptr, const LE16 &v) {
return ptr - (unsigned) v; return ptr - unsigned(v);
} }
template <class T> template <class T>
inline T *operator+(T *ptr, const LE32 &v) { inline T *operator+(T *ptr, const LE32 &v) {
return ptr + (unsigned) v; return ptr + unsigned(v);
} }
template <class T> template <class T>
inline T *operator-(T *ptr, const LE32 &v) { inline T *operator-(T *ptr, const LE32 &v) {
return ptr - (unsigned) v; return ptr - unsigned(v);
} }
// these are not implemented on purpose and will cause link-time errors // 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 // global overloads
**************************************************************************/ **************************************************************************/
inline unsigned ALIGN_DOWN(unsigned a, const BE32 &b) { return ALIGN_DOWN(a, (unsigned) 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_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(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_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(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_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(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_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(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_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(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_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(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_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(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_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(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_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(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_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(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_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(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_MIN(const LE32 &a, unsigned b) { return UPX_MIN(unsigned(a), b); }
/************************************************************************* /*************************************************************************
// misc support // misc support

View File

@ -25,7 +25,7 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#ifndef __UPX_BELE_H #ifndef UPX_BELE_H__
#error "this is an internal include file" #error "this is an internal include file"
#endif #endif

View File

@ -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
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#ifndef __UPX_BPTR_H
#define __UPX_BPTR_H 1
/*************************************************************************
// BoundedPtr
**************************************************************************/
template <class T>
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: */

View File

@ -28,7 +28,7 @@
#include "conf.h" #include "conf.h"
#include "compress.h" #include "compress.h"
#include "mem.h" #include "util/membuffer.h"
/************************************************************************* /*************************************************************************

View File

@ -28,7 +28,7 @@
#include "conf.h" #include "conf.h"
#include "compress.h" #include "compress.h"
#include "mem.h" #include "util/membuffer.h"
#if (ACC_CC_CLANG) #if (ACC_CC_CLANG)
# pragma clang diagnostic ignored "-Wshadow" # pragma clang diagnostic ignored "-Wshadow"

View File

@ -291,7 +291,7 @@ unsigned upx_ucl_crc32(const void *buf, unsigned len, unsigned crc)
#if DEBUG && 1 #if DEBUG && 1
#include "mem.h" #include "util/membuffer.h"
static bool check_ucl(const int method, const unsigned expected_c_len) { static bool check_ucl(const int method, const unsigned expected_c_len) {
const unsigned u_len = 16384; const unsigned u_len = 16384;

View File

@ -28,7 +28,7 @@
#include "conf.h" #include "conf.h"
#include "compress.h" #include "compress.h"
#include "mem.h" #include "util/membuffer.h"
#include <zlib.h> #include <zlib.h>

View File

@ -25,9 +25,9 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#pragma once
#ifndef __UPX_CONF_H #ifndef UPX_CONF_H__
#define __UPX_CONF_H 1 #define UPX_CONF_H__ 1
#if defined(__cplusplus) #if defined(__cplusplus)
# if (__cplusplus >= 201402L) # if (__cplusplus >= 201402L)
@ -356,7 +356,7 @@ template <class T>
inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; } inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; }
// 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. // gets destructed when leaving scope or on exceptions.
#define Array(type, var, size) \ #define Array(type, var, size) \
MemBuffer var ## _membuf(mem_size(sizeof(type), 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 <class T>
inline T *raw_bytes(T *ptr, size_t size_in_bytes) {
if (size_in_bytes > 0) {
assert(ptr != nullptr);
}
return ptr;
}
/************************************************************************* /*************************************************************************
// constants // constants
**************************************************************************/ **************************************************************************/
@ -712,7 +729,7 @@ struct upx_compress_result_t
// globals // globals
**************************************************************************/ **************************************************************************/
#include "snprintf.h" // must get included first! #include "util/snprintf.h" // must get included first!
#include <exception> #include <exception>
#include <new> #include <new>
@ -722,19 +739,27 @@ struct upx_compress_result_t
#include "options.h" #include "options.h"
#include "except.h" #include "except.h"
#include "bele.h" #include "bele.h"
#include "util.h"
#include "console.h" #include "console.h"
#include "util/util.h"
//#define DOCTEST_CONFIG_DISABLE
#include <doctest/parts/doctest_fwd.h>
// classes // classes
class ElfLinker; class ElfLinker;
typedef ElfLinker Linker; typedef ElfLinker Linker;
// dt_check.cpp // util/membuffer.h
void upx_compiler_sanity_check(void); class MemBuffer;
bool upx_doctest_check(void); void *membuffer_get_void_ptr(MemBuffer &mb);
unsigned membuffer_get_size(MemBuffer &mb);
#include "util/xspan.h"
//#define DOCTEST_CONFIG_DISABLE
#include <doctest/parts/doctest_fwd.h>
// util/dt_check.cpp
void upx_compiler_sanity_check();
bool upx_doctest_check();
bool upx_doctest_check(int argc, char **argv);
// main.cpp // main.cpp
extern const char *progname; 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 infoWarning(const char *format, ...) attribute_format(1, 2);
void infoHeader(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 info(const char *format, ...) attribute_format(1, 2);
void infoHeader(void); void infoHeader();
void infoWriting(const char *what, long size); void infoWriting(const char *what, long size);
// work.cpp // work.cpp
@ -763,10 +788,10 @@ int do_files(int i, int argc, char *argv[]);
// help.cpp // help.cpp
extern const char gitrev[]; extern const char gitrev[];
void show_head(void); void show_head();
void show_help(int verbose=0); void show_help(int verbose=0);
void show_license(void); void show_license();
void show_usage(void); void show_usage();
void show_version(int); void show_version(int);
// compress.cpp // compress.cpp

View File

@ -25,8 +25,9 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#ifndef __UPX_EXCEPT_H #pragma once
#define __UPX_EXCEPT_H 1 #ifndef UPX_EXCEPT_H__
#define UPX_EXCEPT_H__ 1
#ifdef __cplusplus #ifdef __cplusplus
@ -50,16 +51,16 @@ public:
bool isWarning() const noexcept { return is_warning; } bool isWarning() const noexcept { return is_warning; }
private: private:
char *msg; char *msg = nullptr;
int err; int err = 0;
protected: protected:
bool is_warning; // can be set by subclasses bool is_warning = false; // can be set by subclasses
private: private:
// disable assignment // disable assignment
Throwable &operator=(const Throwable &); Throwable &operator=(const Throwable &) = delete;
// disable dynamic allocation // disable dynamic allocation => force throwing by value
ACC_CXX_DISABLE_NEW_DELETE ACC_CXX_DISABLE_NEW_DELETE
private: private:
@ -192,27 +193,27 @@ public:
#undef NORET #undef NORET
#if 1 && defined(__GNUC__) #if 1 && defined(__GNUC__)
#define NORET __attribute__((__noreturn__)) #define NORET __attribute__((__noreturn__)) __acc_noinline
#else #else
#define NORET /*empty*/ #define NORET __acc_noinline
#endif #endif
void throwCantPack(const char *msg) NORET; NORET void throwCantPack(const char *msg);
void throwCantPackExact() NORET; NORET void throwCantPackExact();
void throwUnknownExecutableFormat(const char *msg = nullptr, bool warn = false) NORET; NORET void throwUnknownExecutableFormat(const char *msg = nullptr, bool warn = false);
void throwNotCompressible(const char *msg = nullptr) NORET; NORET void throwNotCompressible(const char *msg = nullptr);
void throwAlreadyPacked(const char *msg = nullptr) NORET; NORET void throwAlreadyPacked(const char *msg = nullptr);
void throwAlreadyPackedByUPX(const char *msg = nullptr) NORET; NORET void throwAlreadyPackedByUPX(const char *msg = nullptr);
void throwCantUnpack(const char *msg) NORET; NORET void throwCantUnpack(const char *msg);
void throwNotPacked(const char *msg = nullptr) NORET; NORET void throwNotPacked(const char *msg = nullptr);
void throwFilterException() NORET; NORET void throwFilterException();
void throwBadLoader() NORET; NORET void throwBadLoader();
void throwChecksumError() NORET; NORET void throwChecksumError();
void throwCompressedDataViolation() NORET; NORET void throwCompressedDataViolation();
void throwInternalError(const char *msg) NORET; NORET void throwInternalError(const char *msg);
void throwOutOfMemoryException(const char *msg = nullptr) NORET; NORET void throwOutOfMemoryException(const char *msg = nullptr);
void throwIOException(const char *msg = nullptr, int e = 0) NORET; NORET void throwIOException(const char *msg = nullptr, int e = 0);
void throwEOFException(const char *msg = nullptr, int e = 0) NORET; NORET void throwEOFException(const char *msg = nullptr, int e = 0);
#undef NORET #undef NORET

View File

@ -25,59 +25,48 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#include "conf.h" #include "conf.h"
#include "file.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 (HAVE_CHMOD)
if (::chmod(name,mode) != 0) if (::chmod(name, mode) != 0)
throwIOException(name,errno); throwIOException(name, errno);
#else #else
UNUSED(name); UNUSED(mode); UNUSED(name);
UNUSED(mode);
#endif #endif
} }
void FileBase::rename(const char *old_, const char *new_) {
void File::rename(const char *old_, const char *new_)
{
#if (ACC_OS_DOS32) && defined(__DJGPP__) #if (ACC_OS_DOS32) && defined(__DJGPP__)
if (::_rename(old_,new_) != 0) if (::_rename(old_, new_) != 0)
#else #else
if (::rename(old_,new_) != 0) if (::rename(old_, new_) != 0)
#endif #endif
throwIOException("rename error",errno); throwIOException("rename error", errno);
} }
void FileBase::unlink(const char *name) {
void File::unlink(const char *name)
{
if (::unlink(name) != 0) if (::unlink(name) != 0)
throwIOException(name,errno); throwIOException(name, errno);
} }
/************************************************************************* /*************************************************************************
// //
**************************************************************************/ **************************************************************************/
FileBase::FileBase() : FileBase::FileBase()
_fd(-1), _flags(0), _shflags(0), _mode(0), _name(nullptr), _offset(0), _length(0) : _fd(-1), _flags(0), _shflags(0), _mode(0), _name(nullptr), _offset(0), _length(0) {
{ memset(&st, 0, sizeof(st));
memset(&st,0,sizeof(st));
} }
FileBase::~FileBase() {
FileBase::~FileBase() #if 0 && defined(__GNUC__) // debug
{
#if 0 && defined(__GNUC__) // debug
if (isOpen()) if (isOpen())
fprintf(stderr,"%s: %s\n", _name, __PRETTY_FUNCTION__); fprintf(stderr,"%s: %s\n", _name, __PRETTY_FUNCTION__);
#endif #endif
@ -87,17 +76,14 @@ FileBase::~FileBase()
closex(); closex();
} }
bool FileBase::do_sopen() {
bool FileBase::do_sopen()
{
if (_shflags < 0) if (_shflags < 0)
_fd = ::open(_name, _flags, _mode); _fd = ::open(_name, _flags, _mode);
else else {
{
#if (ACC_OS_DOS32) && defined(__DJGPP__) #if (ACC_OS_DOS32) && defined(__DJGPP__)
_fd = ::open(_name,_flags | _shflags, _mode); _fd = ::open(_name, _flags | _shflags, _mode);
#elif defined(__MINT__) #elif defined(__MINT__)
_fd = ::open(_name,_flags | (_shflags & O_SHMODE), _mode); _fd = ::open(_name, _flags | (_shflags & O_SHMODE), _mode);
#elif defined(SH_DENYRW) #elif defined(SH_DENYRW)
_fd = ::sopen(_name, _flags, _shflags, _mode); _fd = ::sopen(_name, _flags, _shflags, _mode);
#else #else
@ -112,9 +98,7 @@ bool FileBase::do_sopen()
return true; return true;
} }
bool FileBase::close() {
bool FileBase::close()
{
bool ok = true; bool ok = true;
if (isOpen() && _fd != STDIN_FILENO && _fd != STDOUT_FILENO && _fd != STDERR_FILENO) if (isOpen() && _fd != STDIN_FILENO && _fd != STDOUT_FILENO && _fd != STDERR_FILENO)
if (::close(_fd) == -1) if (::close(_fd) == -1)
@ -128,53 +112,15 @@ bool FileBase::close()
return ok; return ok;
} }
void FileBase::closex() {
void FileBase::closex()
{
if (!close()) if (!close())
throwIOException("close failed",errno); throwIOException("close failed", errno);
} }
upx_off_t FileBase::seek(upx_off_t off, int whence) {
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
if (!isOpen()) if (!isOpen())
throwIOException("bad seek 1"); throwIOException("bad seek 1");
mem_size_assert(1, off >= 0 ? off : -off); // sanity check
if (whence == SEEK_SET) { if (whence == SEEK_SET) {
if (off < 0) if (off < 0)
throwIOException("bad seek 2"); throwIOException("bad seek 2");
@ -186,51 +132,34 @@ upx_off_t FileBase::seek(upx_off_t off, int whence)
off += _offset + _length; off += _offset + _length;
whence = SEEK_SET; whence = SEEK_SET;
} }
if (::lseek(_fd,off,whence) < 0) if (::lseek(_fd, off, whence) < 0)
throwIOException("seek error",errno); throwIOException("seek error", errno);
return off - _offset; return off - _offset;
} }
upx_off_t FileBase::tell() const {
upx_off_t FileBase::tell() const
{
if (!isOpen()) if (!isOpen())
throwIOException("bad tell"); throwIOException("bad tell");
upx_off_t l = ::lseek(_fd, 0, SEEK_CUR); upx_off_t l = ::lseek(_fd, 0, SEEK_CUR);
if (l < 0) if (l < 0)
throwIOException("tell error",errno); throwIOException("tell error", errno);
return l - _offset; 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; _offset = offset;
_length = length; _length = length;
} }
upx_off_t FileBase::st_size() const upx_off_t FileBase::st_size() const { return _length; }
{
return _length;
}
/************************************************************************* /*************************************************************************
// //
**************************************************************************/ **************************************************************************/
InputFile::InputFile() InputFile::InputFile() {}
{
}
void InputFile::sopen(const char *name, int flags, int shflags) {
InputFile::~InputFile()
{
}
void InputFile::sopen(const char *name, int flags, int shflags)
{
close(); close();
_name = name; _name = name;
_flags = flags; _flags = flags;
@ -238,8 +167,7 @@ void InputFile::sopen(const char *name, int flags, int shflags)
_mode = 0; _mode = 0;
_offset = 0; _offset = 0;
_length = 0; _length = 0;
if (!FileBase::do_sopen()) if (!super::do_sopen()) {
{
if (errno == ENOENT) if (errno == ENOENT)
throw FileNotFoundException(_name, errno); throw FileNotFoundException(_name, errno);
else if (errno == EEXIST) else if (errno == EEXIST)
@ -250,80 +178,40 @@ void InputFile::sopen(const char *name, int flags, int shflags)
_length_orig = _length; _length_orig = _length;
} }
int InputFile::read(SPAN_P(void) buf, int len) {
int InputFile::read(void *buf, int len) if (!isOpen() || len < 0)
{ throwIOException("bad read");
return super::read(buf, len); 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) int InputFile::readx(SPAN_P(void) buf, int len) {
{ int l = this->read(buf, len);
return super::readx(buf, len); if (l != len)
throwEOFException();
return l;
} }
upx_off_t InputFile::seek(upx_off_t off, int whence) {
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 pos = super::seek(off, whence); upx_off_t pos = super::seek(off, whence);
if (_length < pos) if (_length < pos)
throwIOException("bad seek 4"); throwIOException("bad seek 4");
return pos; return pos;
} }
upx_off_t InputFile::st_size_orig() const { return _length_orig; }
upx_off_t InputFile::tell() const
{
return super::tell();
}
upx_off_t InputFile::st_size_orig() const
{
return _length_orig;
}
/************************************************************************* /*************************************************************************
// //
**************************************************************************/ **************************************************************************/
OutputFile::OutputFile() : OutputFile::OutputFile() : bytes_written(0) {}
bytes_written(0)
{
}
void OutputFile::sopen(const char *name, int flags, int shflags, int mode) {
OutputFile::~OutputFile()
{
}
void OutputFile::sopen(const char *name, int flags, int shflags, int mode)
{
close(); close();
_name = name; _name = name;
_flags = flags; _flags = flags;
@ -331,8 +219,7 @@ void OutputFile::sopen(const char *name, int flags, int shflags, int mode)
_mode = mode; _mode = mode;
_offset = 0; _offset = 0;
_length = 0; _length = 0;
if (!FileBase::do_sopen()) if (!super::do_sopen()) {
{
#if 0 #if 0
// don't throw FileNotFound here -- this is confusing // don't throw FileNotFound here -- this is confusing
if (errno == ENOENT) if (errno == ENOENT)
@ -340,15 +227,13 @@ void OutputFile::sopen(const char *name, int flags, int shflags, int mode)
else else
#endif #endif
if (errno == EEXIST) if (errno == EEXIST)
throw FileAlreadyExistsException(_name,errno); throw FileAlreadyExistsException(_name, errno);
else else
throwIOException(_name,errno); throwIOException(_name, errno);
} }
} }
bool OutputFile::openStdout(int flags, bool force) {
bool OutputFile::openStdout(int flags, bool force)
{
close(); close();
int fd = STDOUT_FILENO; int fd = STDOUT_FILENO;
if (!force && acc_isatty(fd)) if (!force && acc_isatty(fd))
@ -365,17 +250,27 @@ bool OutputFile::openStdout(int flags, bool force)
return true; return true;
} }
void OutputFile::write(SPAN_0(const void) buf, int len) {
void OutputFile::write(const void *buf, int len) if (!isOpen() || len < 0)
{ throwIOException("bad write");
super::write(buf, len); // 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; bytes_written += len;
} }
upx_off_t OutputFile::st_size() const upx_off_t OutputFile::st_size() const {
{ if (opt->to_stdout) { // might be a pipe ==> .st_size is invalid
if (opt->to_stdout) { // might be a pipe ==> .st_size is invalid return bytes_written; // too big if seek()+write() instead of rewrite()
return bytes_written; // too big if seek()+write() instead of rewrite()
} }
struct stat my_st; struct stat my_st;
my_st.st_size = 0; my_st.st_size = 0;
@ -384,34 +279,13 @@ upx_off_t OutputFile::st_size() const
return my_st.st_size; return my_st.st_size;
} }
void OutputFile::rewrite(SPAN_P(const void) buf, int len) {
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)
{
assert(!opt->to_stdout); assert(!opt->to_stdout);
write(buf, len); write(buf, len);
bytes_written -= len; // restore bytes_written -= len; // restore
} }
upx_off_t OutputFile::tell() const upx_off_t OutputFile::seek(upx_off_t off, int whence) {
{
return super::tell();
}
upx_off_t OutputFile::seek(upx_off_t off, int whence)
{
mem_size_assert(1, off >= 0 ? off : -off); // sanity check mem_size_assert(1, off >= 0 ? off : -off); // sanity check
assert(!opt->to_stdout); assert(!opt->to_stdout);
switch (whence) { switch (whence) {
@ -419,18 +293,18 @@ upx_off_t OutputFile::seek(upx_off_t off, int whence)
if (bytes_written < off) { if (bytes_written < off) {
bytes_written = off; bytes_written = off;
} }
_length = bytes_written; // cheap, lazy update; needed? _length = bytes_written; // cheap, lazy update; needed?
} break; } break;
case SEEK_END: { case SEEK_END: {
_length = bytes_written; // necessary _length = bytes_written; // necessary
} break; } break;
} }
return super::seek(off,whence); return super::seek(off, whence);
} }
// WARNING: fsync() does not exist in some Windows environments. // WARNING: fsync() does not exist in some Windows environments.
// This trick works only on UNIX-like systems. // This trick works only on UNIX-like systems.
//int OutputFile::read(void *buf, int len) // int OutputFile::read(void *buf, int len)
//{ //{
// fsync(_fd); // fsync(_fd);
// InputFile infile; // InputFile infile;
@ -439,19 +313,17 @@ upx_off_t OutputFile::seek(upx_off_t off, int whence)
// return infile.read(buf, len); // 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); super::set_extent(offset, length);
bytes_written = 0; bytes_written = 0;
if (0==offset && (upx_off_t)~0u==length) { if (0 == offset && (upx_off_t) ~0u == length) {
if (::fstat(_fd, &st) != 0) if (::fstat(_fd, &st) != 0)
throwIOException(_name, errno); throwIOException(_name, errno);
_length = st.st_size - offset; _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); upx_off_t l = ::lseek(_fd, 0, SEEK_END);
if (l < 0) if (l < 0)
throwIOException("lseek error", errno); throwIOException("lseek error", errno);
@ -461,44 +333,14 @@ upx_off_t OutputFile::unset_extent()
return _length; 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) if (flags < 0)
flags = O_CREAT | O_TRUNC; flags = O_CREAT | O_TRUNC;
flags |= O_WRONLY | O_BINARY; flags |= O_WRONLY | O_BINARY;
OutputFile f; OutputFile f;
f.open(name, flags, 0600); f.open(name, flags, 0600);
f.write(buf, len); f.write(raw_bytes(buf, len), len);
f.closex(); 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: */ /* vim:set ts=4 sw=4 et: */

View File

@ -25,165 +25,110 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#pragma once
#ifndef __UPX_FILE_H #ifndef UPX_FILE_H__
#define __UPX_FILE_H 1 #define UPX_FILE_H__ 1
class MemBuffer;
/************************************************************************* /*************************************************************************
// //
**************************************************************************/ **************************************************************************/
class File class FileBase {
{
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
{
protected: protected:
FileBase(); FileBase();
virtual ~FileBase(); virtual ~FileBase();
public: public:
virtual bool close(); bool close();
virtual void closex(); void closex();
virtual bool isOpen() const { return _fd >= 0; } bool isOpen() const { return _fd >= 0; }
int getFd() const { return _fd; } int getFd() const { return _fd; }
const char *getName() const { return _name; } 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); 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: protected:
bool do_sopen(); bool do_sopen();
virtual int read(void *buf, int len); int _fd = -1;
virtual int readx(void *buf, int len); int _flags = 0;
virtual void write(const void *buf, int len); int _shflags = 0;
virtual upx_off_t seek(upx_off_t off, int whence); int _mode = 0;
virtual upx_off_t tell() const; 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: public:
struct stat st; struct stat st = {};
}; };
/************************************************************************* /*************************************************************************
// //
**************************************************************************/ **************************************************************************/
class InputFile final : public FileBase class InputFile final : public FileBase {
{
typedef FileBase super; typedef FileBase super;
public: public:
InputFile(); InputFile();
virtual ~InputFile(); virtual ~InputFile() {}
virtual void sopen(const char *name, int flags, int shflags); void sopen(const char *name, int flags, int shflags);
virtual void open(const char *name, int flags) void open(const char *name, int flags) { sopen(name, flags, -1); }
{
sopen(name, flags, -1);
}
virtual int read(void *buf, int len) override; int read(SPAN_P(void) buf, int len);
virtual int readx(void *buf, int len) override; int readx(SPAN_P(void) buf, int len);
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);
virtual upx_off_t seek(upx_off_t off, int whence) override; virtual upx_off_t seek(upx_off_t off, int whence) override;
virtual upx_off_t tell() const override; upx_off_t st_size_orig() const;
virtual upx_off_t st_size_orig() const;
protected:
upx_off_t _length_orig;
};
protected:
upx_off_t _length_orig = 0;
};
/************************************************************************* /*************************************************************************
// //
**************************************************************************/ **************************************************************************/
class OutputFile final : public FileBase class OutputFile final : public FileBase {
{
typedef FileBase super; typedef FileBase super;
public: public:
OutputFile(); OutputFile();
virtual ~OutputFile(); virtual ~OutputFile() {}
virtual void sopen(const char *name, int flags, int shflags, int mode); void sopen(const char *name, int flags, int shflags, int mode);
virtual void open(const char *name, int flags, int mode) void open(const char *name, int flags, int mode) { sopen(name, flags, -1, mode); }
{ bool openStdout(int flags = 0, bool force = false);
sopen(name, flags, -1, mode);
}
virtual bool openStdout(int flags=0, bool force=false);
virtual void write(const void *buf, int len) override; // info: allow nullptr if len == 0
virtual void write(const MemBuffer *buf, int len); void write(SPAN_0(const void) buf, int len);
virtual void write(const MemBuffer &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 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; } 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 // FIXME - these won't work when using the '--stdout' option
virtual upx_off_t seek(upx_off_t off, int whence) override; void rewrite(SPAN_P(const void) buf, int len);
virtual upx_off_t tell() const override;
virtual void rewrite(const void *buf, int len);
// util // 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: protected:
upx_off_t bytes_written; upx_off_t bytes_written = 0;
}; };
#endif
/*************************************************************************
//
**************************************************************************/
#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 */
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -28,7 +28,7 @@
#include "conf.h" #include "conf.h"
#include "file.h" #include "file.h"
#include "mem.h" #include "util/membuffer.h"
#include "lefile.h" #include "lefile.h"
@ -77,7 +77,8 @@ LeFile::~LeFile()
void LeFile::readObjectTable() 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->seek(le_offset + ih.object_table_offset,SEEK_SET);
fif->readx(iobject_table,sizeof(*iobject_table)*objects); fif->readx(iobject_table,sizeof(*iobject_table)*objects);
} }
@ -92,7 +93,8 @@ void LeFile::writeObjectTable()
void LeFile::readPageMap() 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->seek(le_offset + ih.object_pagemap_offset,SEEK_SET);
fif->readx(ipm_entries,sizeof(*ipm_entries)*pages); fif->readx(ipm_entries,sizeof(*ipm_entries)*pages);
@ -112,7 +114,7 @@ void LeFile::writePageMap()
void LeFile::readResidentNames() void LeFile::readResidentNames()
{ {
sores_names = ih.entry_table_offset - ih.resident_names_offset; 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->seek(le_offset+ih.resident_names_offset,SEEK_SET);
fif->readx(ires_names,sores_names); fif->readx(ires_names,sores_names);
} }
@ -129,7 +131,7 @@ void LeFile::readEntryTable()
{ {
soentries = ih.fixup_page_table_offset - ih.entry_table_offset; soentries = ih.fixup_page_table_offset - ih.entry_table_offset;
fif->seek(le_offset + ih.entry_table_offset,SEEK_SET); fif->seek(le_offset + ih.entry_table_offset,SEEK_SET);
ientries = new upx_byte[soentries]; ientries = New(upx_byte, soentries);
fif->readx(ientries,soentries); fif->readx(ientries,soentries);
} }
@ -143,7 +145,8 @@ void LeFile::writeEntryTable()
void LeFile::readFixupPageTable() 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->seek(le_offset + ih.fixup_page_table_offset,SEEK_SET);
fif->readx(ifpage_table,4*sofpage_table); fif->readx(ifpage_table,4*sofpage_table);
} }
@ -159,7 +162,7 @@ void LeFile::writeFixupPageTable()
void LeFile::readFixups() void LeFile::readFixups()
{ {
sofixups = get_le32(ifpage_table+pages)-get_le32(ifpage_table); 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->seek(le_offset + ih.fixup_record_table_offset,SEEK_SET);
fif->readx(ifixups,sofixups); fif->readx(ifixups,sofixups);
} }
@ -187,8 +190,9 @@ unsigned LeFile::getImageSize() const
void LeFile::readImage() void LeFile::readImage()
{ {
soimage = pages*mps; soimage = pages*mps;
iimage.alloc(soimage); mb_iimage.alloc(soimage);
memset(iimage,0,soimage); mb_iimage.clear();
iimage = mb_iimage;
unsigned ic,jc; unsigned ic,jc;
for (ic = jc = 0; ic < pages; ic++) for (ic = jc = 0; ic < pages; ic++)
@ -197,7 +201,8 @@ void LeFile::readImage()
{ {
fif->seek(ih.data_pages_offset + exe_offset + fif->seek(ih.data_pages_offset + exe_offset +
(ipm_entries[ic].m*0x100 + ipm_entries[ic].l-1) * mps,SEEK_SET); (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; jc += mps;
} }
@ -207,7 +212,7 @@ void LeFile::readImage()
void LeFile::writeImage() void LeFile::writeImage()
{ {
if (fof && oimage != nullptr) 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) 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->seek(exe_offset+ih.non_resident_name_table_offset,SEEK_SET);
fif->readx(inonres_names,sononres_names); fif->readx(inonres_names,sononres_names);
} }

View File

@ -39,7 +39,7 @@ class OutputFile;
class LeFile class LeFile
{ {
public: protected:
LeFile(InputFile *); LeFile(InputFile *);
virtual ~LeFile(); virtual ~LeFile();
@ -198,8 +198,10 @@ protected:
upx_byte *ofixups; upx_byte *ofixups;
upx_byte *inonres_names; upx_byte *inonres_names;
upx_byte *ononres_names; upx_byte *ononres_names;
MemBuffer iimage; MemBuffer mb_iimage;
MemBuffer oimage; SPAN_0(upx_byte) iimage = nullptr;
MemBuffer mb_oimage;
SPAN_0(upx_byte) oimage = nullptr;
upx_byte *ientries; upx_byte *ientries;
upx_byte *oentries; upx_byte *oentries;

View File

@ -1122,7 +1122,7 @@ int upx_main(int argc, char *argv[]) {
argv0 = argv[0]; argv0 = argv[0];
upx_compiler_sanity_check(); upx_compiler_sanity_check();
if (!upx_doctest_check()) { if (!upx_doctest_check(argc, argv)) {
fprintf(stderr, "%s: internal error: doctest failed\n", argv0); fprintf(stderr, "%s: internal error: doctest failed\n", argv0);
e_exit(EXIT_INIT); e_exit(EXIT_INIT);
} }

View File

@ -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
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#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: */

View File

@ -25,8 +25,9 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#ifndef __UPX_OPTIONS_H #pragma once
#define __UPX_OPTIONS_H 1 #ifndef UPX_OPTIONS_H__
#define UPX_OPTIONS_H__ 1
/************************************************************************* /*************************************************************************
// globals // globals

View File

@ -34,35 +34,35 @@
// djgpp2/coff // djgpp2/coff
**************************************************************************/ **************************************************************************/
class PackDjgpp2 : public Packer class PackDjgpp2 final : public Packer
{ {
typedef Packer super; typedef Packer super;
public: public:
PackDjgpp2(InputFile *f); PackDjgpp2(InputFile *f);
virtual int getVersion() const { return 14; } virtual int getVersion() const override { return 14; }
virtual int getFormat() const { return UPX_F_DJGPP2_COFF; } virtual int getFormat() const override { return UPX_F_DJGPP2_COFF; }
virtual const char *getName() const { return "djgpp2/coff"; } virtual const char *getName() const override { return "djgpp2/coff"; }
virtual const char *getFullName(const options_t *) const { return "i386-dos32.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; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const; virtual const int *getFilters() const override;
virtual void pack(OutputFile *fo); virtual void pack(OutputFile *fo) override;
virtual void unpack(OutputFile *fo); virtual void unpack(OutputFile *fo) override;
virtual bool canPack(); virtual bool canPack() override;
virtual int canUnpack(); virtual int canUnpack() override;
protected: protected:
virtual void handleStub(OutputFile *fo); void handleStub(OutputFile *fo);
virtual int readFileHeader(); int readFileHeader();
virtual unsigned findOverlapOverhead(const upx_bytep buf, virtual unsigned findOverlapOverhead(const upx_bytep buf,
const upx_bytep tbuf, const upx_bytep tbuf,
unsigned range = 0, unsigned range = 0,
unsigned upper_limit = ~0u) const; unsigned upper_limit = ~0u) const override;
virtual void buildLoader(const Filter *ft); virtual void buildLoader(const Filter *ft) override;
virtual Linker* newLinker() const; virtual Linker* newLinker() const override;
unsigned coff_offset; unsigned coff_offset;

View File

@ -607,8 +607,8 @@ void PackExe::pack(OutputFile *fo)
} }
// g++ 3.1 does not like the following line... // g++ 3.1 does not like the following line...
// oh.relocoffs = offsetof(exe_header_t, firstreloc); oh.relocoffs = offsetof(exe_header_t, firstreloc);
oh.relocoffs = ptr_diff(&oh.firstreloc, &oh); //oh.relocoffs = ptr_udiff_bytes(&oh.firstreloc, &oh);
linker->defineSymbol("destination_segment", oh.ss - ph.c_len / 16 - e_len / 16); linker->defineSymbol("destination_segment", oh.ss - ph.c_len / 16 - e_len / 16);
linker->defineSymbol("source_segment", e_len / 16 + (copysize - firstcopy) / 16); linker->defineSymbol("source_segment", e_len / 16 + (copysize - firstcopy) / 16);
@ -658,7 +658,7 @@ void PackExe::pack(OutputFile *fo)
verifyOverlappingDecompression(); verifyOverlappingDecompression();
// copy the overlay // copy the overlay
copyOverlay(fo, ih_overlay, &obuf); copyOverlay(fo, ih_overlay, obuf);
//fprintf (stderr,"%x %x\n",relocsize,ph.u_len); //fprintf (stderr,"%x %x\n",relocsize,ph.u_len);
// finally check the compression ratio // finally check the compression ratio
@ -710,7 +710,7 @@ void PackExe::unpack(OutputFile *fo)
const unsigned char flag = ibuf[imagesize]; const unsigned char flag = ibuf[imagesize];
unsigned relocn = 0; unsigned relocn = 0;
upx_byte *relocs = obuf + ph.u_len; SPAN_S_VAR(upx_byte, relocs, obuf + ph.u_len, obuf);
MemBuffer wrkmem; MemBuffer wrkmem;
if (!(flag & NORELOC)) if (!(flag & NORELOC))
@ -721,7 +721,7 @@ void PackExe::unpack(OutputFile *fo)
wrkmem.alloc(4*MAXRELOCS); wrkmem.alloc(4*MAXRELOCS);
unsigned es = 0, ones = get_le16(relocs); unsigned es = 0, ones = get_le16(relocs);
const unsigned seghi = get_le16(relocs+2); const unsigned seghi = get_le16(relocs+2);
const upx_byte *p = relocs + 4; SPAN_S_VAR(const upx_byte, p, relocs + 4);
while (ones) while (ones)
{ {
@ -739,10 +739,11 @@ void PackExe::unpack(OutputFile *fo)
dorel = true; dorel = true;
if (*p == 0) 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++) 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) else if (*p == 1)
{ {
@ -768,7 +769,7 @@ void PackExe::unpack(OutputFile *fo)
set_le32(wrkmem+4*relocn++,0); 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.m512 = outputlen & 511;
oh.p512 = (outputlen + 511) >> 9; oh.p512 = (outputlen + 511) >> 9;
oh.headsize16 = 2+relocn/4; oh.headsize16 = 2+relocn/4;
@ -800,10 +801,10 @@ void PackExe::unpack(OutputFile *fo)
fo->write(&oh,sizeof(oh)); fo->write(&oh,sizeof(oh));
if (relocn) if (relocn)
fo->write(wrkmem,relocn*4); fo->write(wrkmem,relocn*4);
fo->write(obuf, ptr_diff(relocs, obuf)); fo->write(obuf, ptr_diff_bytes(relocs, obuf));
// copy the overlay // copy the overlay
copyOverlay(fo, ih_overlay, &obuf); copyOverlay(fo, ih_overlay, obuf);
} }

View File

@ -1456,8 +1456,6 @@ static const
static const static const
#include "stub/armeb.v4a-linux.elf-fold.h" #include "stub/armeb.v4a-linux.elf-fold.h"
#include "mem.h"
void void
PackLinuxElf32armBe::buildLoader(Filter const *ft) 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); unsigned tmp = sz_pack2 + get_te32(&elfout.phdr[C_TEXT].p_vaddr);
tmp |= (Elf32_Ehdr::EM_ARM==e_machine); // THUMB mode tmp |= (Elf32_Ehdr::EM_ARM==e_machine); // THUMB mode
set_te32(&tmp, tmp); 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)); fo->rewrite(&tmp, sizeof(tmp));
} }
} }

View File

@ -1529,7 +1529,7 @@ void PackMachBase<T>::unpack(OutputFile *fo)
if (is_bad_linker_command( ((Mach_command const *)ptr)->cmd, cmdsize, if (is_bad_linker_command( ((Mach_command const *)ptr)->cmd, cmdsize,
headway, lc_seg, sizeof(Addr))) { headway, lc_seg, sizeof(Addr))) {
char msg[50]; snprintf(msg, sizeof(msg), 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); throwCantUnpack(msg);
} }
memcpy(&msegcmd[j], ptr, umin(sizeof(Mach_segment_command), cmdsize)); memcpy(&msegcmd[j], ptr, umin(sizeof(Mach_segment_command), cmdsize));
@ -1905,7 +1905,7 @@ template <class T>
upx_uint64_t PackMachBase<T>::get_mod_init_func(Mach_segment_command const *segptr) upx_uint64_t PackMachBase<T>::get_mod_init_func(Mach_segment_command const *segptr)
{ {
for (Mach_section_command const *secptr = (Mach_section_command const *)(1+ 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 ++secptr
) { ) {
if (sizeof(Addr) == secptr->size if (sizeof(Addr) == secptr->size

View File

@ -38,34 +38,34 @@
// ps1/exe // ps1/exe
**************************************************************************/ **************************************************************************/
class PackPs1 : public Packer class PackPs1 final : public Packer
{ {
typedef Packer super; typedef Packer super;
public: public:
PackPs1(InputFile *f); PackPs1(InputFile *f);
virtual int getVersion() const { return 13; } virtual int getVersion() const override { return 13; }
virtual int getFormat() const { return UPX_F_PS1_EXE; } virtual int getFormat() const override { return UPX_F_PS1_EXE; }
virtual const char *getName() const { return "ps1/exe"; } virtual const char *getName() const override { return "ps1/exe"; }
virtual const char *getFullName(const options_t *) const { return "mipsel.r3000-ps1"; } virtual const char *getFullName(const options_t *) const override { return "mipsel.r3000-ps1"; }
virtual const int *getCompressionMethods(int method, int level) const; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const; virtual const int *getFilters() const override;
virtual void pack(OutputFile *fo); virtual void pack(OutputFile *fo) override;
virtual void unpack(OutputFile *fo); virtual void unpack(OutputFile *fo) override;
virtual bool canPack(); virtual bool canPack() override;
virtual int canUnpack(); virtual int canUnpack() override;
protected: protected:
virtual void putBkupHeader(const unsigned char *src, unsigned char *dst, unsigned *len); void putBkupHeader(const unsigned char *src, unsigned char *dst, unsigned *len);
virtual bool getBkupHeader(unsigned char *src, unsigned char * dst); bool getBkupHeader(unsigned char *src, unsigned char * dst);
virtual bool readBkupHeader(); bool readBkupHeader();
virtual void buildLoader(const Filter *ft); virtual void buildLoader(const Filter *ft) override;
virtual bool findBssSection(); bool findBssSection();
virtual Linker* newLinker() const; virtual Linker* newLinker() const override;
virtual int readFileHeader(); int readFileHeader();
virtual bool checkFileHeader(); bool checkFileHeader();
__packed_struct(ps1_exe_t) __packed_struct(ps1_exe_t)
// ident string // ident string

View File

@ -235,9 +235,7 @@ void PackTmt::pack(OutputFile *fo)
{ {
for (unsigned ic=4; ic<=rsize; ic+=4) for (unsigned ic=4; ic<=rsize; ic+=4)
set_le32(wrkmem+ic,get_le32(wrkmem+ic)-4); set_le32(wrkmem+ic,get_le32(wrkmem+ic)-4);
relocsize = ptr_diff( relocsize = optimizeReloc32(wrkmem+4,rsize/4,wrkmem,ibuf,file_size,1,&big_relocs);
optimizeReloc32(wrkmem+4,rsize/4,wrkmem,ibuf,file_size,1,&big_relocs),
wrkmem);
} }
wrkmem[relocsize++] = 0; wrkmem[relocsize++] = 0;
@ -300,7 +298,7 @@ void PackTmt::pack(OutputFile *fo)
verifyOverlappingDecompression(); verifyOverlappingDecompression();
// copy the overlay // copy the overlay
copyOverlay(fo, overlay, &obuf); copyOverlay(fo, overlay, obuf);
// finally check the compression ratio // finally check the compression ratio
if (!checkFinalCompressionRatio(fo)) if (!checkFinalCompressionRatio(fo))
@ -332,7 +330,7 @@ void PackTmt::unpack(OutputFile *fo)
// decode relocations // decode relocations
const unsigned osize = ph.u_len - get_le32(obuf+ph.u_len-4); 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); const unsigned origstart = get_le32(obuf+ph.u_len-8);
// unfilter // unfilter
@ -343,12 +341,13 @@ void PackTmt::unpack(OutputFile *fo)
ft.cto = (unsigned char) ph.filter_cto; ft.cto = (unsigned char) ph.filter_cto;
if (ph.version < 11) if (ph.version < 11)
ft.cto = (unsigned char) (get_le32(obuf+ph.u_len-12) >> 24); 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 // decode relocations
MemBuffer wrkmem; MemBuffer mb_wrkmem;
unsigned relocn = unoptimizeReloc32(&relocs,obuf,&wrkmem,1); unsigned relocn = unoptimizeReloc32(relocs, obuf, mb_wrkmem, true);
SPAN_S_VAR(upx_byte, wrkmem, mb_wrkmem);
for (unsigned ic = 0; ic < relocn; ic++) for (unsigned ic = 0; ic < relocn; ic++)
set_le32(wrkmem+ic*4,get_le32(wrkmem+ic*4)+4); 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(&oh,sizeof(oh));
fo->write(obuf,osize); fo->write(obuf,osize);
fo->write(wrkmem,relocn*4); fo->write(raw_bytes(wrkmem,relocn*4), relocn*4);
} }
// copy the overlay // copy the overlay
copyOverlay(fo, overlay, &obuf); copyOverlay(fo, overlay, obuf);
} }
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -34,33 +34,33 @@
// tmt/adam // tmt/adam
**************************************************************************/ **************************************************************************/
class PackTmt : public Packer class PackTmt final : public Packer
{ {
typedef Packer super; typedef Packer super;
public: public:
PackTmt(InputFile *f); PackTmt(InputFile *f);
virtual int getVersion() const { return 13; } virtual int getVersion() const override { return 13; }
virtual int getFormat() const { return UPX_F_TMT_ADAM; } virtual int getFormat() const override { return UPX_F_TMT_ADAM; }
virtual const char *getName() const { return "tmt/adam"; } virtual const char *getName() const override { return "tmt/adam"; }
virtual const char *getFullName(const options_t *) const { return "i386-dos32.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; virtual const int *getCompressionMethods(int method, int level) const override;
virtual const int *getFilters() const; virtual const int *getFilters() const override;
virtual void pack(OutputFile *fo); virtual void pack(OutputFile *fo) override;
virtual void unpack(OutputFile *fo); virtual void unpack(OutputFile *fo) override;
virtual bool canPack(); virtual bool canPack() override;
virtual int canUnpack(); virtual int canUnpack() override;
protected: protected:
virtual int readFileHeader(); int readFileHeader();
virtual unsigned findOverlapOverhead(const upx_bytep buf, virtual unsigned findOverlapOverhead(const upx_bytep buf,
const upx_bytep tbuf, const upx_bytep tbuf,
unsigned range = 0, unsigned range = 0,
unsigned upper_limit = ~0u) const; unsigned upper_limit = ~0u) const override;
virtual void buildLoader(const Filter *ft); virtual void buildLoader(const Filter *ft) override;
virtual Linker* newLinker() const; virtual Linker* newLinker() const override;
unsigned adam_offset; unsigned adam_offset;
int big_relocs; int big_relocs;

View File

@ -662,7 +662,7 @@ void PackTos::pack(OutputFile *fo) {
verifyOverlappingDecompression(); verifyOverlappingDecompression();
// copy the overlay // copy the overlay
copyOverlay(fo, overlay, &obuf); copyOverlay(fo, overlay, obuf);
// finally check the compression ratio // finally check the compression ratio
if (!checkFinalCompressionRatio(fo)) if (!checkFinalCompressionRatio(fo))
@ -713,7 +713,7 @@ void PackTos::unpack(OutputFile *fo) {
fo->write(obuf, ph.u_len - FH_SIZE); // orig. text+data+relocs fo->write(obuf, ph.u_len - FH_SIZE); // orig. text+data+relocs
// copy any overlay // copy any overlay
copyOverlay(fo, overlay, &obuf); copyOverlay(fo, overlay, obuf);
} }
} }

View File

@ -176,7 +176,7 @@ void PackWcle::encodeEntryTable()
//if (Opt_debug) printf("%d entries encoded.\n",n); //if (Opt_debug) printf("%d entries encoded.\n",n);
UNUSED(n); UNUSED(n);
soentries = ptr_diff(p, ientries) + 1; soentries = ptr_udiff_bytes(p, ientries) + 1;
oentries = ientries; oentries = ientries;
ientries = nullptr; ientries = nullptr;
} }
@ -290,12 +290,13 @@ void PackWcle::preprocessFixups()
throwCantPack("files without relocations are not supported"); throwCantPack("files without relocations are not supported");
} }
ByteArray(rl, jc); MemBuffer rl_membuf(jc);
ByteArray(srf, counts[objects+0]+1); ByteArray(srf, counts[objects+0]+1);
ByteArray(slf, counts[objects+1]+1); ByteArray(slf, counts[objects+1]+1);
upx_byte *selector_fixups = srf; SPAN_S_VAR(upx_byte, rl, rl_membuf);
upx_byte *selfrel_fixups = slf; SPAN_S_VAR(upx_byte, selector_fixups, srf_membuf);
SPAN_S_VAR(upx_byte, selfrel_fixups, slf_membuf);
unsigned rc = 0; unsigned rc = 0;
upx_byte *fix = ifixups; upx_byte *fix = ifixups;
@ -399,20 +400,20 @@ void PackWcle::preprocessFixups()
delete[] ifixups; delete[] ifixups;
ifixups = new upx_byte[1000]; ifixups = new upx_byte[1000];
} }
fix = optimizeReloc32 (rl,rc,ifixups,iimage,file_size,1,&big_relocs); fix = ifixups + optimizeReloc32 (rl,rc,ifixups,iimage,file_size,1,&big_relocs);
has_extra_code = srf != selector_fixups; has_extra_code = ptr_udiff_bytes(selector_fixups, srf) != 0;
// FIXME: this could be removed if has_extra_code = false // FIXME: this could be removed if has_extra_code = false
// but then we'll need a flag // but then we'll need a flag
*selector_fixups++ = 0xC3; // ret *selector_fixups++ = 0xC3; // ret
memcpy(fix,srf,selector_fixups-srf); // copy selector fixup code memcpy(fix,srf,ptr_udiff_bytes(selector_fixups, srf)); // copy selector fixup code
fix += selector_fixups-srf; fix += ptr_udiff_bytes(selector_fixups, srf);
memcpy(fix,slf,selfrel_fixups-slf); // copy self-relative fixup positions memcpy(fix,slf,ptr_udiff_bytes(selfrel_fixups,slf)); // copy self-relative fixup positions
fix += selfrel_fixups-slf; fix += ptr_udiff_bytes(selfrel_fixups, slf);
set_le32(fix,0xFFFFFFFFUL); set_le32(fix,0xFFFFFFFFUL);
fix += 4; 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; delete[] ifixups; ifixups = nullptr;
oimage.allocForCompression(isize, RESERVED+512); mb_oimage.allocForCompression(isize, RESERVED+512);
oimage = mb_oimage;
// prepare packheader // prepare packheader
ph.u_len = isize; ph.u_len = isize;
// prepare filter [already done] // prepare filter [already done]
@ -435,7 +437,7 @@ void PackWcle::encodeImage(Filter *ft)
upx_compress_config_t cconf; cconf.reset(); upx_compress_config_t cconf; cconf.reset();
cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack
compressWithFilters(ibuf, isize, compressWithFilters(ibuf, isize,
oimage + RESERVED, raw_bytes(oimage + RESERVED, mb_oimage.getSize() - RESERVED),
ibuf + ft->addvalue, ft->buf_len, ibuf + ft->addvalue, ft->buf_len,
nullptr, 0, nullptr, 0,
ft, 512, &cconf, 0); ft, 512, &cconf, 0);
@ -473,7 +475,7 @@ void PackWcle::pack(OutputFile *fo)
readNonResidentNames(); readNonResidentNames();
// if (find_le32(iimage,20,get_le32("UPX ")) >= 0) // 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(); throwAlreadyPacked();
if (ih.init_ss_object != objects) if (ih.init_ss_object != objects)
@ -556,14 +558,14 @@ void PackWcle::pack(OutputFile *fo)
writeFile(fo, opt->watcom_le.le); writeFile(fo, opt->watcom_le.le);
// verify // verify
verifyOverlappingDecompression(oimage + e_len, oimage.getSize() - e_len); verifyOverlappingDecompression(mb_oimage + e_len, mb_oimage.getSize() - e_len);
// copy the overlay // copy the overlay
const unsigned overlaystart = ih.data_pages_offset + exe_offset const unsigned overlaystart = ih.data_pages_offset + exe_offset
+ getImageSize(); + getImageSize();
const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length; const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length;
checkOverlay(overlay); checkOverlay(overlay);
copyOverlay(fo, overlay, &oimage); copyOverlay(fo, overlay, mb_oimage);
// finally check the compression ratio // finally check the compression ratio
if (!checkFinalCompressionRatio(fo)) if (!checkFinalCompressionRatio(fo))
@ -577,12 +579,14 @@ void PackWcle::pack(OutputFile *fo)
void PackWcle::decodeFixups() 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; MemBuffer tmpbuf;
unsigned const fixupn = unoptimizeReloc32(&p,oimage,&tmpbuf,1); unsigned const fixupn = unoptimizeReloc32(p,oimage,tmpbuf,true);
MemBuffer wrkmem(8*fixupn+8); MemBuffer wrkmem(8*fixupn+8);
unsigned ic,jc,o,r; unsigned ic,jc,o,r;
@ -600,10 +604,10 @@ void PackWcle::decodeFixups()
tmpbuf.dealloc(); tmpbuf.dealloc();
// selector fixups then self-relative fixups // 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. // 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). // The code is a subroutine that ends in RET (0xC3).
while (*q != 0xC3) { while (*q != 0xC3) {
// Defend against tampered selector_fixups; see PackWcle::preprocessFixups(). // Defend against tampered selector_fixups; see PackWcle::preprocessFixups().
@ -622,20 +626,21 @@ void PackWcle::decodeFixups()
} }
// Guard against run-away. // Guard against run-away.
static unsigned char const blank[9] = {0}; 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 || !memcmp(blank, q, sizeof(blank)) // no-good early warning
) { ) {
char msg[50]; snprintf(msg, sizeof(msg), 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); throwCantPack(msg);
} }
q += 9; q += 9;
} }
unsigned selectlen = ptr_diff(q, selector_fixups)/9; unsigned selectlen = ptr_udiff_bytes(q, selector_fixups)/9;
const upx_byte *selfrel_fixups = 1+ q; // Skip the 0xC3 SPAN_P_VAR(const upx_byte, selfrel_fixups, q + 1); // Skip the 0xC3
ofixups = New(upx_byte, fixupn*9+1000+selectlen*5); const unsigned fbytes = fixupn*9+1000+selectlen*5;
upx_bytep fp = ofixups; ofixups = New(upx_byte, fbytes);
SPAN_S_VAR(upx_byte, fp, ofixups, fbytes, ofixups);
for (ic = 1, jc = 0; ic <= opages; ic++) for (ic = 1, jc = 0; ic <= opages; ic++)
{ {
@ -698,11 +703,11 @@ void PackWcle::decodeFixups()
fp += fp[1] ? 9 : 7; fp += fp[1] ? 9 : 7;
jc += 2; 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++) for (ic=0; ic < FIXUP_EXTRA; ic++)
*fp++ = 0; *fp++ = 0;
sofixups = ptr_diff(fp, ofixups); sofixups = ptr_udiff_bytes(fp, ofixups);
} }
@ -751,7 +756,8 @@ void PackWcle::decodeObjectTable()
void PackWcle::decodeImage() 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); decompress(iimage + ph.buf_offset + ph.getPackHeaderSize(),oimage);
soimage = get_le32(oimage + ph.u_len - 5); soimage = get_le32(oimage + ph.u_len - 5);
@ -762,11 +768,13 @@ void PackWcle::decodeImage()
void PackWcle::decodeEntryTable() void PackWcle::decodeEntryTable()
{ {
unsigned count,object,r; unsigned count,object,n,r;
upx_byte *p = ientries; SPAN_S_VAR(upx_byte, p, ientries, soentries);
n = 0;
while (*p) while (*p)
{ {
count = *p; count = *p;
n += count;
if (p[1] == 0) // unused bundle if (p[1] == 0) // unused bundle
p += 2; p += 2;
else if (p[1] == 3) // 32-bit offset bundle 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); //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; oentries = ientries;
ientries = nullptr; ientries = nullptr;
} }
@ -852,7 +861,7 @@ void PackWcle::unpack(OutputFile *fo)
ft.cto = (unsigned char) ph.filter_cto; ft.cto = (unsigned char) ph.filter_cto;
if (ph.version < 11) if (ph.version < 11)
ft.cto = (unsigned char) (get_le32(oimage+ph.u_len-9) >> 24); 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(); decodeFixupPageTable();
@ -878,7 +887,7 @@ void PackWcle::unpack(OutputFile *fo)
+ getImageSize(); + getImageSize();
const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length; const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length;
checkOverlay(overlay); checkOverlay(overlay);
copyOverlay(fo, overlay, &oimage); copyOverlay(fo, overlay, mb_oimage);
} }
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -180,7 +180,7 @@ int forced_method(int method) // extract the forced method
// compress - wrap call to low-level upx_compress() // 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) { const upx_compress_config_t *cconf_parm) {
ph.u_len = i_len; ph.u_len = i_len;
ph.c_len = 0; 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_u_adler = ph.u_adler;
ph.saved_c_adler = ph.c_adler; ph.saved_c_adler = ph.c_adler;
// update checksum of uncompressed data // 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 // set compression parameters
upx_compress_config_t cconf; 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); // OutputFile::dump("data.raw", in, ph.u_len);
// compress // compress
int r = upx_compress(i_ptr, ph.u_len, o_ptr, &ph.c_len, uip->getCallback(), method, ph.level, int r = upx_compress(raw_bytes(i_ptr, ph.u_len), ph.u_len, raw_bytes(o_ptr, 0), &ph.c_len,
&cconf, &ph.compress_result); uip->getCallback(), method, ph.level, &cconf, &ph.compress_result);
// uip->finalCallback(ph.u_len, ph.c_len); // uip->finalCallback(ph.u_len, ph.c_len);
uip->endCallback(); uip->endCallback();
@ -277,12 +277,13 @@ bool Packer::compress(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr,
return false; return false;
// update checksum of compressed data // 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. // Decompress and verify. Skip this when using the fastest level.
if (!ph_skipVerify(ph)) { if (!ph_skipVerify(ph)) {
// decompress // decompress
unsigned new_len = ph.u_len; 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) if (r == UPX_E_OUT_OF_MEMORY)
throwOutOfMemoryException(); throwOutOfMemoryException();
// printf("%d %d: %d %d %d\n", method, r, ph.c_len, ph.u_len, new_len); // 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)"); throwInternalError("decompression failed (size error)");
// verify decompression // 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)"); throwInternalError("decompression failed (checksum error)");
} }
return true; return true;
@ -340,13 +341,13 @@ bool Packer::checkFinalCompressionRatio(const OutputFile *fo) const {
// decompress // decompress
**************************************************************************/ **************************************************************************/
void ph_decompress(PackHeader &ph, const upx_bytep in, upx_bytep out, bool verify_checksum, void ph_decompress(PackHeader &ph, SPAN_P(const upx_byte) in, SPAN_P(upx_byte) out,
Filter *ft) { bool verify_checksum, Filter *ft) {
unsigned adler; unsigned adler;
// verify checksum of compressed data // verify checksum of compressed data
if (verify_checksum) { 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) if (adler != ph.c_adler)
throwChecksumError(); throwChecksumError();
} }
@ -356,8 +357,8 @@ void ph_decompress(PackHeader &ph, const upx_bytep in, upx_bytep out, bool verif
throwCantUnpack("header corrupted"); throwCantUnpack("header corrupted");
} }
unsigned new_len = ph.u_len; unsigned new_len = ph.u_len;
int r = int r = upx_decompress(raw_bytes(in, ph.c_len), ph.c_len, raw_bytes(out, ph.u_len), &new_len,
upx_decompress(in, ph.c_len, out, &new_len, forced_method(ph.method), &ph.compress_result); forced_method(ph.method), &ph.compress_result);
if (r == UPX_E_OUT_OF_MEMORY) if (r == UPX_E_OUT_OF_MEMORY)
throwOutOfMemoryException(); throwOutOfMemoryException();
if (r != UPX_E_OK || new_len != ph.u_len) 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 // verify checksum of decompressed data
if (verify_checksum) { if (verify_checksum) {
if (ft) if (ft)
ft->unfilter(out, ph.u_len); ft->unfilter(raw_bytes(out, ph.u_len), ph.u_len);
adler = upx_adler32(out, ph.u_len, ph.saved_u_adler); adler = upx_adler32(raw_bytes(out, ph.u_len), ph.u_len, ph.saved_u_adler);
if (adler != ph.u_adler) if (adler != ph.u_adler)
throwChecksumError(); 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); 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'"); 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((int) overlay >= 0);
assert(overlay < file_size_u); assert(overlay < file_size_u);
buf->checkState(); buf.checkState();
if (!fo || overlay == 0) if (!fo || overlay == 0)
return; return;
if (opt->overlay != opt->COPY_OVERLAY) { 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); fi->seek(-(upx_off_t) overlay, SEEK_END);
// get buffer size, align to improve i/o speed // get buffer size, align to improve i/o speed
unsigned buf_size = buf->getSize(); unsigned buf_size = buf.getSize();
if (buf_size > 65536) if (buf_size > 65536)
buf_size = ALIGN_DOWN(buf_size, 4096u); buf_size = ALIGN_DOWN(buf_size, 4096u);
assert((int) buf_size > 0); assert((int) buf_size > 0);
@ -562,7 +564,7 @@ void Packer::copyOverlay(OutputFile *fo, unsigned overlay, MemBuffer *buf, bool
fo->write(buf, len); fo->write(buf, len);
overlay -= len; overlay -= len;
} while (overlay > 0); } while (overlay > 0);
buf->checkState(); buf.checkState();
} }
// Create a pseudo-unique program id. // 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); int boff = find_le32(b, blen, UPX_MAGIC_LE32);
checkPatch(b, blen, boff, size); checkPatch(b, blen, boff, size);
unsigned char *p = (unsigned char *) b + boff; auto bb = (upx_byte *) b;
ph.putPackHeader(p); ph.putPackHeader(SPAN_S_MAKE(upx_byte, bb + boff, blen, bb));
return boff; return boff;
} }
bool Packer::getPackHeader(void const *b, int blen, bool allow_incompressible) { bool Packer::getPackHeader(const void *b, int blen, bool allow_incompressible) {
if (!ph.fillPackHeader((unsigned char const *) b, blen)) auto bb = (const upx_byte *) b;
if (!ph.fillPackHeader(SPAN_S_MAKE(const upx_byte, bb, blen), blen))
return false; return false;
if (ph.version > getVersion()) if (ph.version > getVersion())
@ -825,18 +828,19 @@ int Packer::patch_le32(void *b, int blen, const void *old, unsigned new_) {
// relocation util // relocation util
**************************************************************************/ **************************************************************************/
upx_byte *Packer::optimizeReloc(upx_byte *in, unsigned relocnum, upx_byte *out, upx_byte *image, unsigned Packer::optimizeReloc(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
unsigned headway, int bswap, int *big, int bits) { SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big,
int bits) {
if (opt->exact) if (opt->exact)
throwCantPackExact(); throwCantPackExact();
*big = 0; *big = 0;
if (relocnum == 0) if (relocnum == 0)
return out; return 0;
qsort(in, relocnum, 4, le32_compare); qsort(raw_bytes(in, 4 * relocnum), relocnum, 4, le32_compare);
unsigned jc, pc, oc; unsigned jc, pc, oc;
upx_byte *fix = out; SPAN_P_VAR(upx_byte, fix, out);
pc = (unsigned) -4; pc = (unsigned) -4;
for (jc = 0; jc < relocnum; jc++) { for (jc = 0; jc < relocnum; jc++) {
@ -875,36 +879,35 @@ upx_byte *Packer::optimizeReloc(upx_byte *in, unsigned relocnum, upx_byte *out,
} }
} }
*fix++ = 0; *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 Packer::optimizeReloc32(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
unsigned headway, int bswap, int *big) { SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big) {
return optimizeReloc(in, relocnum, out, image, headway, bswap, big, 32); 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 Packer::optimizeReloc64(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
unsigned headway, int bswap, int *big) { SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big) {
return optimizeReloc(in, relocnum, out, image, headway, bswap, big, 64); return optimizeReloc(in, relocnum, out, image, headway, bswap, big, 64);
} }
unsigned Packer::unoptimizeReloc(upx_byte **in, upx_byte *image, MemBuffer *out, int bswap, unsigned Packer::unoptimizeReloc(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out,
int bits) { bool bswap, int bits) {
upx_byte *p; SPAN_P_VAR(upx_byte, p, in);
unsigned relocn = 0; unsigned relocn = 0;
for (p = *in; *p; p++, relocn++) for (; *p; p++, relocn++)
if (*p >= 0xF0) { if (*p >= 0xF0) {
if (*p == 0xF0 && get_le16(p + 1) == 0) if (*p == 0xF0 && get_le16(p + 1) == 0)
p += 4; p += 4;
p += 2; p += 2;
} }
upx_byte const *in_end = p; SPAN_P_VAR(upx_byte, const in_end, p);
// fprintf(stderr,"relocnum=%x\n",relocn); // fprintf(stderr,"relocnum=%x\n",relocn);
out->alloc(4 * relocn + 4); // one extra data out.alloc(4 * (relocn + 1)); // one extra entry
LE32 *const outp = (LE32 *) (unsigned char *) *out; SPAN_S_VAR(LE32, relocs, out);
LE32 *relocs = outp;
unsigned jc = (unsigned) -4; unsigned jc = (unsigned) -4;
for (p = *in; p < in_end; p++) { for (p = in; p < in_end; p++) {
if (*p < 0xF0) if (*p < 0xF0)
jc += *p; jc += *p;
else { else {
@ -920,32 +923,34 @@ unsigned Packer::unoptimizeReloc(upx_byte **in, upx_byte *image, MemBuffer *out,
if (!relocn--) { if (!relocn--) {
break; break;
} }
if (bswap && image) { if (bswap && image != nullptr) {
if (bits == 32) { if (bits == 32) {
set_be32(image + jc, get_le32(image + jc)); 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 // 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) { } else if (bits == 64) {
set_be64(image + jc, get_le64(image + jc)); 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 // data must not overlap control
p = (8 - 1) + image + jc; // -1: 'for' also increments p = image + jc + (8 - 1); // -1: 'for' also increments
} }
} else } else
throwInternalError("unoptimizeReloc problem"); throwInternalError("unoptimizeReloc problem");
} }
} }
*in = p + 1; in = p + 1;
return (unsigned) (relocs - outp); 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); 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); return unoptimizeReloc(in, image, out, bswap, 64);
} }

View File

@ -25,10 +25,11 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#ifndef __UPX_PACKER_H #pragma once
#define __UPX_PACKER_H 1 #ifndef UPX_PACKER_H__
#define UPX_PACKER_H__ 1
#include "mem.h" #include "util/membuffer.h"
class InputFile; class InputFile;
class OutputFile; class OutputFile;
@ -42,15 +43,14 @@ class Filter;
**************************************************************************/ **************************************************************************/
// see stub/src/include/header.S // see stub/src/include/header.S
class PackHeader { class PackHeader final {
friend class Packer; friend class Packer;
private: // these are strictly private to friend Packer
// these are strictly private to Packer and not accessible in subclasses
PackHeader(); PackHeader();
void putPackHeader(upx_bytep p); void putPackHeader(SPAN_S(upx_byte) p);
bool fillPackHeader(const upx_bytep b, int blen); bool fillPackHeader(SPAN_S(const upx_byte) b, int blen);
public: public:
int getPackHeaderSize() const; int getPackHeaderSize() const;
@ -95,9 +95,9 @@ public:
}; };
bool ph_skipVerify(const PackHeader &ph); bool ph_skipVerify(const PackHeader &ph);
void ph_decompress(PackHeader &ph, const upx_bytep in, upx_bytep out, bool verify_checksum, void ph_decompress(PackHeader &ph, SPAN_P(const upx_byte) in, SPAN_P(upx_byte) out,
Filter *ft); bool verify_checksum, Filter *ft);
bool ph_testOverlappingDecompression(const PackHeader &ph, const upx_bytep buf, bool ph_testOverlappingDecompression(const PackHeader &ph, SPAN_P(const upx_byte) buf,
unsigned overlap_overhead); unsigned overlap_overhead);
/************************************************************************* /*************************************************************************
@ -107,7 +107,6 @@ bool ph_testOverlappingDecompression(const PackHeader &ph, const upx_bytep buf,
**************************************************************************/ **************************************************************************/
class Packer { class Packer {
// friend class PackMaster;
friend class UiPacker; friend class UiPacker;
protected: protected:
@ -163,10 +162,10 @@ public:
protected: protected:
// main compression drivers // main compression drivers
virtual bool compress(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr, bool compress(SPAN_P(upx_byte) i_ptr, unsigned i_len, SPAN_P(upx_byte) o_ptr,
const upx_compress_config_t *cconf = nullptr); const upx_compress_config_t *cconf = nullptr);
virtual void decompress(const upx_bytep in, upx_bytep out, bool verify_checksum = true, void decompress(SPAN_P(const upx_byte) in, SPAN_P(upx_byte) out, bool verify_checksum = true,
Filter *ft = nullptr); Filter *ft = nullptr);
virtual bool checkDefaultCompressionRatio(unsigned u_len, unsigned c_len) const; virtual bool checkDefaultCompressionRatio(unsigned u_len, unsigned c_len) const;
virtual bool checkCompressionRatio(unsigned u_len, unsigned c_len) const; virtual bool checkCompressionRatio(unsigned u_len, unsigned c_len) const;
virtual bool checkFinalCompressionRatio(const OutputFile *fo) const; virtual bool checkFinalCompressionRatio(const OutputFile *fo) const;
@ -202,7 +201,7 @@ protected:
// packheader handling // packheader handling
virtual int patchPackHeader(void *b, int blen); 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 bool readPackHeader(int len, bool allow_incompressible = false);
virtual void checkAlreadyPacked(const void *b, int blen); virtual void checkAlreadyPacked(const void *b, int blen);
@ -256,7 +255,7 @@ protected:
// stub and overlay util // stub and overlay util
static void handleStub(InputFile *fi, OutputFile *fo, unsigned size); static void handleStub(InputFile *fi, OutputFile *fo, unsigned size);
virtual void checkOverlay(unsigned overlay); 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 // misc util
virtual unsigned getRandomId() const; virtual unsigned getRandomId() const;
@ -273,34 +272,37 @@ protected:
void checkPatch(void *b, int blen, int boff, int size); void checkPatch(void *b, int blen, int boff, int size);
// relocation util // relocation util
static upx_byte *optimizeReloc(upx_byte *in, unsigned relocnum, upx_byte *out, upx_byte *image, static unsigned optimizeReloc(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
unsigned headway, int bs, int *big, int bits); SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big,
static unsigned unoptimizeReloc(upx_byte **in, upx_byte *image, MemBuffer *out, int bs, int bits);
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, static unsigned optimizeReloc32(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
upx_byte *image, unsigned headway, int bs, int *big); SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big);
static unsigned unoptimizeReloc32(upx_byte **in, upx_byte *image, MemBuffer *out, int bs); 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, static unsigned optimizeReloc64(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
upx_byte *image, unsigned headway, int bs, int *big); SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big);
static unsigned unoptimizeReloc64(upx_byte **in, upx_byte *image, MemBuffer *out, int bs); 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_te16(const void *p) const { return bele->get16(p); }
unsigned get_te32(const void *p) const { return bele->get32(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); } 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_te16(void *p, unsigned v) { bele->set16(p, v); }
void set_te32(void *p, unsigned v) const { bele->set32(p, v); } void set_te32(void *p, unsigned v) { bele->set32(p, v); }
void set_te64(void *p, upx_uint64_t v) const { bele->set64(p, v); } void set_te64(void *p, upx_uint64_t v) { bele->set64(p, v); }
protected: protected:
const N_BELE_RTP::AbstractPolicy *bele = nullptr; // target endianness const N_BELE_RTP::AbstractPolicy *bele = nullptr; // target endianness
InputFile *fi = nullptr; InputFile *fi = nullptr;
union { // unnamed union union { // unnamed union
upx_int64_t file_size; // will get set by constructor upx_int64_t file_size = 0; // will get set by constructor
upx_uint64_t file_size_u; // explicitly unsigned upx_uint64_t file_size_u; // explicitly unsigned
}; };
PackHeader ph; // must be filled by canUnpack() PackHeader ph; // must be filled by canUnpack()

View File

@ -41,7 +41,7 @@ PackHeader::PackHeader() : version(-1), format(-1) {}
// simple checksum for the header itself (since version 10) // 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(len >= 4);
assert(get_le32(buf) == UPX_MAGIC_LE32); assert(get_le32(buf) == UPX_MAGIC_LE32);
// printf("1 %d\n", len); // printf("1 %d\n", len);
@ -92,7 +92,7 @@ int PackHeader::getPackHeaderSize() const {
// see stub/header.ash // 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 // NOTE: It is the caller's responsbility to ensure the buffer p has
// sufficient space for the header. // sufficient space for the header.
assert(get_le32(p) == UPX_MAGIC_LE32); 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) { bool PackHeader::fillPackHeader(SPAN_S(const upx_byte) buf, int blen) {
int boff = find_le32(buf, blen, UPX_MAGIC_LE32); int boff = find_le32(raw_bytes(buf, blen), blen, UPX_MAGIC_LE32);
if (boff < 0) if (boff < 0)
return false; 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 unsigned const headway = blen - boff; // bytes remaining in buf
if (headway < (1 + 7)) if (headway < (1 + 7))

View File

@ -39,42 +39,51 @@
// //
**************************************************************************/ **************************************************************************/
#include "bptr.h" #include "util/bptr.h"
#define IPTR(type, var) BoundedPtr<type> var(ibuf, ibuf.getSize()) #if (WITH_SPAN >= 2) && 1
#define OPTR(type, var) BoundedPtr<type> var(obuf, obuf.getSize()) //#define IPTR(type, var) Span<type> var(ibuf, ibuf.getSize(), ibuf)
#define IPTR_I_D(type, var, disp) \ //#define OPTR(type, var) Span<type> var(obuf, obuf.getSize(), obuf)
BoundedPtr<type> var(ibuf + (disp), ibuf.getSize() - (disp), ibuf + (disp)) #define IPTR_I_D(type, var, disp) Span<type> var(ibuf + (disp), ibuf.getSize() - (disp), ibuf + (disp))
#define IPTR_I(type, var, v) BoundedPtr<type> var(ibuf, ibuf.getSize(), v) #define IPTR_I(type, var, first) Span<type> var(first, ibuf)
#define OPTR_I(type, var, v) BoundedPtr<type> var(obuf, obuf.getSize(), v) #define OPTR_I(type, var, first) Span<type> var(first, obuf)
#define IPTR_C(type, var, v) const BoundedPtr<type> var(ibuf, ibuf.getSize(), v) #define IPTR_C(type, var, first) const Span<type> var(first, ibuf)
#define OPTR_C(type, var, v) const BoundedPtr<type> var(obuf, obuf.getSize(), v) #define OPTR_C(type, var, first) const Span<type> var(first, obuf)
#else
//#define IPTR(type, var) BoundedPtr<type> var(ibuf, ibuf.getSize())
//#define OPTR(type, var) BoundedPtr<type> var(obuf, obuf.getSize())
#define IPTR_I_D(type, var, disp) BoundedPtr<type> var(ibuf + (disp), ibuf.getSize() - (disp), ibuf + (disp))
#define IPTR_I(type, var, first) BoundedPtr<type> var(ibuf, ibuf.getSize(), first)
#define OPTR_I(type, var, first) BoundedPtr<type> var(obuf, obuf.getSize(), first)
#define IPTR_C(type, var, first) const BoundedPtr<type> var(ibuf, ibuf.getSize(), first)
#define OPTR_C(type, var, first) const BoundedPtr<type> var(obuf, obuf.getSize(), first)
#endif
static void xcheck(const void *p) static void xcheck(const void *p)
{ {
if (!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) static void xcheck(const void *p, size_t plen, const void *b, size_t blen)
{ {
const char *pp = (const char *) p; const char *pp = (const char *) p;
const char *bb = (const char *) b; const char *bb = (const char *) b;
if (pp < bb || pp > bb + blen || pp + plen > bb + blen) 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 #if 0
static void xcheck(size_t poff, size_t plen, const void *b, size_t blen) static void xcheck(size_t poff, size_t plen, const void *b, size_t blen)
{ {
ACC_UNUSED(b); ACC_UNUSED(b);
if (poff > blen || poff + plen > blen) if (poff > blen || poff + plen > blen)
throwCantUnpack("pointer out of range; take care!"); throwCantUnpack("xcheck pointer out of range; take care!");
} }
#endif #endif
#define ICHECK(x, size) xcheck(x, size, ibuf, ibuf.getSize()) #define ICHECK(x, size) xcheck(raw_bytes(x, 0), size, ibuf, ibuf.getSize())
#define OCHECK(x, size) xcheck(x, size, obuf, obuf.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 imemset(a,b,c) ICHECK(a,c), memset(a,b,c)
#define omemset(a,b,c) OCHECK(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 imemcpy(a,b,c) ICHECK(a,c), memcpy(a,b,c)
#define omemcpy(a,b,c) OCHECK(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) #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) 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) 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) 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) : PeFile::Reloc::Reloc(unsigned rnum) :
start(nullptr), size(0), rel(nullptr), rel1(nullptr) 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; counts[0] = 0;
} }
@ -314,7 +323,7 @@ bool PeFile::Reloc::next(unsigned &pos,unsigned &type)
{ {
if (!rel) if (!rel)
newRelocPos(start); newRelocPos(start);
if (ptr_diff(rel, start) >= (int) size) { if (ptr_diff_bytes(rel, start) >= (int) size) {
rel = nullptr; // rewind rel = nullptr; // rewind
return false; return false;
} }
@ -322,7 +331,7 @@ bool PeFile::Reloc::next(unsigned &pos,unsigned &type)
pos = rel->pagestart + (*rel1 & 0xfff); pos = rel->pagestart + (*rel1 & 0xfff);
type = *rel1++ >> 12; type = *rel1++ >> 12;
//printf("%x %d\n",pos,type); //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); newRelocPos(rel1);
return type == 0 ? next(pos,type) : true; return type == 0 ? next(pos,type) : true;
} }
@ -347,14 +356,14 @@ void PeFile::Reloc::finish(upx_byte *&p,unsigned &siz)
{ {
prev = pos; prev = pos;
*rel1 = 0; *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); newRelocPos((char *)rel + rel->size);
rel->pagestart = (pos >> 4) &~ 0xfff; rel->pagestart = (pos >> 4) &~ 0xfff;
} }
*rel1++ = (pos << 12) + ((pos >> 4) & 0xfff); *rel1++ = (pos << 12) + ((pos >> 4) & 0xfff);
} }
p = start; p = start;
siz = ptr_diff(rel1,start) &~ 3; siz = ptr_udiff_bytes(rel1,start) &~ 3;
siz -= 8; siz -= 8;
// siz can be 0 in 64-bit mode // assert(siz > 0); // siz can be 0 in 64-bit mode // assert(siz > 0);
start = nullptr; // safety start = nullptr; // safety
@ -389,7 +398,7 @@ void PeFile32::processRelocs() // pass1
ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects); ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects);
} }
mb_orelocs.alloc(1); mb_orelocs.alloc(1);
orelocs = (upx_byte *)mb_orelocs.getVoidPtr(); orelocs = mb_orelocs;
sorelocs = 0; sorelocs = 0;
return; return;
} }
@ -439,10 +448,9 @@ void PeFile32::processRelocs() // pass1
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
mb_orelocs.alloc(mem_size(4, rnum, 1024)); // 1024 - safety mb_orelocs.alloc(mem_size(4, rnum, 1024)); // 1024 - safety
orelocs = (upx_byte *)mb_orelocs.getVoidPtr(); orelocs = mb_orelocs;
sorelocs = ptr_diff(optimizeReloc32((upx_byte*) fix[3], xcounts[3], sorelocs = optimizeReloc32((upx_byte*) fix[3], xcounts[3],
orelocs, ibuf + rvamin, ibufgood - rvamin, 1, &big_relocs), orelocs, ibuf + rvamin, ibufgood - rvamin, true, &big_relocs);
orelocs);
delete [] fix[3]; delete [] fix[3];
// Malware that hides behind UPX often has PE header info that is // Malware that hides behind UPX often has PE header info that is
@ -492,7 +500,7 @@ void PeFile64::processRelocs() // pass1
ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects); ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects);
} }
mb_orelocs.alloc(1); mb_orelocs.alloc(1);
orelocs = (upx_byte *)mb_orelocs.getVoidPtr(); orelocs = mb_orelocs;
sorelocs = 0; sorelocs = 0;
return; return;
} }
@ -545,10 +553,9 @@ void PeFile64::processRelocs() // pass1
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
mb_orelocs.alloc(mem_size(4, rnum, 1024)); // 1024 - safety mb_orelocs.alloc(mem_size(4, rnum, 1024)); // 1024 - safety
orelocs = (upx_byte *)mb_orelocs.getVoidPtr(); orelocs = mb_orelocs;
sorelocs = ptr_diff(optimizeReloc64((upx_byte*) fix[10], xcounts[10], sorelocs = optimizeReloc64((upx_byte*) fix[10], xcounts[10],
orelocs, ibuf + rvamin, ibufgood - rvamin, 1, &big_relocs), orelocs, ibuf + rvamin, ibufgood - rvamin, true, &big_relocs);
orelocs);
for (ic = 15; ic; ic--) for (ic = 15; ic; ic--)
delete [] fix[ic]; delete [] fix[ic];
@ -896,7 +903,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
if (IDADDR(PEDIR_IMPORT)) if (IDADDR(PEDIR_IMPORT))
{ {
for (;; ++dllnum, ++im) { 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)); (void)ibuf.subref("bad import %#x", skip2, sizeof(*im));
if (!im->dllname) if (!im->dllname)
break; break;
@ -975,8 +982,8 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
} }
} }
mb_oimport.alloc(soimport); mb_oimport.alloc(soimport);
oimport = (upx_byte *)mb_oimport.getVoidPtr(); mb_oimport.clear();
memset(oimport,0,soimport); oimport = mb_oimport;
qsort(idlls,dllnum,sizeof (udll*),udll::compare); 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); Interval names(ibuf),iats(ibuf),lookups(ibuf);
// create the preprocessed data // 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++) for (ic = 0; ic < dllnum; ic++)
{ {
LEXX *tarr = idlls[ic]->lookupt; LEXX *tarr = idlls[ic]->lookupt;
@ -1052,7 +1059,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
} }
ppi++; 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); lookups.add(idlls[ic]->lookupt,esize);
if (ptr_diff(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1), (char *)idlls[ic]->lookupt)) 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; ppi += 4;
assert(ppi < oimport+soimport); assert(ppi < oimport+soimport);
soimport = ptr_diff(ppi,oimport); soimport = ptr_diff_bytes(ppi,oimport);
if (soimport == 4) if (soimport == 4)
soimport = 0; soimport = 0;
@ -1088,7 +1095,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
for (ic = 0; ic < dllnum; ic++, im++) for (ic = 0; ic < dllnum; ic++, im++)
{ {
memset(im,FILLVAL,sizeof(*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 else
@ -1250,14 +1257,14 @@ void PeFile::processExports(Export *xport) // pass1
xport->convert(IDADDR(PEDIR_EXPORT),IDSIZE(PEDIR_EXPORT)); xport->convert(IDADDR(PEDIR_EXPORT),IDSIZE(PEDIR_EXPORT));
soexport = ALIGN_UP(xport->getsize(), 4u); soexport = ALIGN_UP(xport->getsize(), 4u);
mb_oexport.alloc(soexport); mb_oexport.alloc(soexport);
oexport = (upx_byte *)mb_oexport.getVoidPtr(); mb_oexport.clear();
memset(oexport, 0, soexport); oexport = mb_oexport;
} }
void PeFile::processExports(Export *xport,unsigned newoffs) // pass2 void PeFile::processExports(Export *xport,unsigned newoffs) // pass2
{ {
if (soexport) 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 // the PE loader wants this stuff uncompressed
mb_otls.alloc(sotls); mb_otls.alloc(sotls);
otls = (upx_byte *)mb_otls.getVoidPtr(); mb_otls.clear();
memset(otls,0,sotls); otls = mb_otls; // => SPAN_S
unsigned const take1 = sizeof(tls); unsigned const take1 = sizeof(tls);
unsigned const skip1 = IDADDR(PEDIR_TLS); unsigned const skip1 = IDADDR(PEDIR_TLS);
memcpy(otls,ibuf.subref("bad tls %#x", skip1, take1), take1); memcpy(otls,ibuf.subref("bad tls %#x", skip1, take1), take1);
@ -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) for (ic = 0; ic < (use_tls_callbacks ? 4 * cb_size : 3 * cb_size); ic += cb_size)
rel->add(newaddr + ic, reloc_type); 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 // now the relocation entries in the tls data area
for (ic = 0; ic < iv->ivnum; ic += 4) for (ic = 0; ic < iv->ivnum; ic += 4)
{ {
void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - imagebase) + sizeof(tls); SPAN_S_VAR(upx_byte, pp, otls + (iv->ivarr[ic].start - (tlsp->datastart - imagebase) + sizeof(tls)));
cb_value_t kc = *(LEXX*)(p); LEXX * const p = (LEXX *) raw_bytes(pp, sizeof(LEXX));
cb_value_t kc = *p;
if (kc < tlsp->dataend && kc >= tlsp->datastart) if (kc < tlsp->dataend && kc >= tlsp->datastart)
{ {
kc += newaddr + sizeof(tls) - tlsp->datastart; kc += newaddr + sizeof(tls) - tlsp->datastart;
*(LEXX*)(p) = kc + imagebase; *p = kc + imagebase;
rel->add(kc,iv->ivarr[ic].len); rel->add(kc,iv->ivarr[ic].len);
} }
else else
@ -1442,16 +1450,19 @@ void PeFile::processTls2(Reloc *rel,const Interval *iv,unsigned newaddr,
tlsp->datastart = newaddr + sizeof(tls) + imagebase; tlsp->datastart = newaddr + sizeof(tls) + imagebase;
tlsp->dataend = tlsp->datastart + tls_data_size; 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); tlsp->callbacks = (use_tls_callbacks ? newaddr + sotls + imagebase - 2 * cb_size : 0);
if (use_tls_callbacks) if (use_tls_callbacks)
{ {
//set handler offset // set handler offset
*(LEXX*)(otls + sotls - 2 * cb_size) = tls_handler_offset + imagebase; SPAN_S_VAR(upx_byte, pp, otls);
*(LEXX*)(otls + sotls - 1 * cb_size) = 0; // end of one-item list pp = otls + (sotls - 2 * cb_size);
//add relocation for TLS handler offset * (LEXX *) raw_bytes(pp, sizeof(LEXX)) = tls_handler_offset + imagebase;
rel->add(newaddr + sotls - 2 * cb_size, reloc_type); 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()) for (soresources = res->dirsize(); res->next(); soresources += 4 + res->size())
; ;
mb_oresources.alloc(soresources); mb_oresources.alloc(soresources);
oresources = (upx_byte *)mb_oresources.getVoidPtr(); mb_oresources.clear();
upx_byte *ores = oresources + res->dirsize(); 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 char *keep_icons = nullptr; // icon ids in the first icon group
unsigned iconsin1stdir = 0; unsigned iconsin1stdir = 0;
@ -2026,14 +2038,14 @@ void PeFile::processResources(Resource *res)
ICHECK(ibuf + res->offs(), take); ICHECK(ibuf + res->offs(), take);
memcpy(ores, ibuf.subref("bad resoff %#x", res->offs(), take), take); memcpy(ores, ibuf.subref("bad resoff %#x", res->offs(), take), take);
ibuf.fill(res->offs(), take, FILLVAL); 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) if (rtype == RT_ICON && opt->win32_pe.compress_icons == 1)
compress_icon = true; compress_icon = true;
else if (rtype == RT_GROUP_ICON) else if (rtype == RT_GROUP_ICON)
{ {
if (opt->win32_pe.compress_icons == 1) 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); icondir_count = get_le16(oresources + icondir_offset);
set_le16(oresources + icondir_offset,1); set_le16(oresources + icondir_offset,1);
} }
@ -2041,7 +2053,7 @@ void PeFile::processResources(Resource *res)
} }
ores += res->size(); ores += res->size();
} }
soresources = ptr_diff(ores,oresources); soresources = ptr_diff_bytes(ores,oresources);
delete[] keep_icons; delete[] keep_icons;
if (!res->clear()) if (!res->clear())
@ -2446,7 +2458,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh,
s += 2; s += 2;
} }
// end of extra data // 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; s += 4;
ph.u_len += s; ph.u_len += s;
obuf.allocForCompression(ph.u_len); 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); OutputFile::dump(opt->debug.dump_stub_loader, loader, codesize);
if ((ic = fo->getBytesWritten() & (sizeof(LEXX) - 1)) != 0) if ((ic = fo->getBytesWritten() & (sizeof(LEXX) - 1)) != 0)
fo->write(ibuf, sizeof(LEXX) - ic); fo->write(ibuf, sizeof(LEXX) - ic);
fo->write(otls, aligned_sotls); fo->write(raw_bytes(otls, aligned_sotls), aligned_sotls);
fo->write(oloadconf, soloadconf); fo->write(oloadconf, soloadconf);
if ((ic = fo->getBytesWritten() & fam1) != 0) if ((ic = fo->getBytesWritten() & fam1) != 0)
fo->write(ibuf,oh.filealign - ic); fo->write(ibuf,oh.filealign - ic);
if (!last_section_rsrc_only) if (!last_section_rsrc_only)
fo->write(oresources,soresources); fo->write(raw_bytes(oresources, soresources) ,soresources);
else else
fo->write(oxrelocs,soxrelocs); fo->write(oxrelocs,soxrelocs);
fo->write(oimpdlls,soimpdlls); fo->write(oimpdlls,soimpdlls);
fo->write(oexport,soexport); fo->write(raw_bytes(oexport, soexport), soexport);
if (!last_section_rsrc_only) if (!last_section_rsrc_only)
fo->write(oxrelocs,soxrelocs); fo->write(oxrelocs,soxrelocs);
@ -2728,7 +2740,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh,
if (last_section_rsrc_only) if (last_section_rsrc_only)
{ {
fo->write(oresources,soresources); fo->write(raw_bytes(oresources, soresources) ,soresources);
if ((ic = fo->getBytesWritten() & fam1) != 0) if ((ic = fo->getBytesWritten() & fam1) != 0)
fo->write(ibuf,oh.filealign - ic); fo->write(ibuf,oh.filealign - ic);
} }
@ -2752,7 +2764,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh,
verifyOverlappingDecompression(); verifyOverlappingDecompression();
// copy the overlay // copy the overlay
copyOverlay(fo, overlay, &obuf); copyOverlay(fo, overlay, obuf);
// finally check the compression ratio // finally check the compression ratio
if (!checkFinalCompressionRatio(fo)) if (!checkFinalCompressionRatio(fo))
@ -2763,7 +2775,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh,
// unpack // 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) unsigned flags, upx_uint64_t imagebase)
{ {
assert(bits == 32 || bits == 64); assert(bits == 32 || bits == 64);
@ -2776,18 +2788,17 @@ void PeFile::rebuildRelocs(upx_byte *& extrainfo, unsigned bits,
return; 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]; const upx_byte big = extrainfo[4];
extrainfo += 5; extrainfo += 5;
// upx_byte *p = rdata; MemBuffer mb_wrkmem;
OPTR_I(upx_byte, p, rdata); unsigned relocn = unoptimizeReloc(rdata,obuf,mb_wrkmem,true,bits);
MemBuffer wrkmem;
unsigned relocn = unoptimizeReloc(&rdata,obuf,&wrkmem,1,bits);
unsigned r16 = 0; unsigned r16 = 0;
if (big & 6) // 16 bit relocations 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++) while (*q++)
r16++; r16++;
if ((big & 6) == 6) if ((big & 6) == 6)
@ -2798,31 +2809,30 @@ void PeFile::rebuildRelocs(upx_byte *& extrainfo, unsigned bits,
if (big & 6) if (big & 6)
{ {
LE32 *q = (LE32*) rdata; SPAN_S_VAR(LE32, q, (LE32 *) raw_bytes(rdata, 0), obuf);
while (*q) while (*q)
rel.add(*q++ + rvamin,(big & 4) ? 2 : 1); rel.add(*q++ + rvamin,(big & 4) ? 2 : 1);
if ((big & 6) == 6) if ((big & 6) == 6)
while (*++q) while (*++q)
rel.add(*q + rvamin,1); 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++) 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) if (bits == 32)
set_le32(p, get_le32((unsigned char *)p) + imagebase + rvamin); set_le32(p, get_le32(p) + imagebase + rvamin);
else 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.add(rvamin + get_le32(wrkmem + 4 * ic), bits == 32 ? 3 : 10);
} }
rel.finish (oxrelocs,soxrelocs); rel.finish (oxrelocs,soxrelocs);
omemcpy(obuf + ODADDR(PEDIR_RELOC) - rvamin,oxrelocs,soxrelocs); omemcpy(obuf + ODADDR(PEDIR_RELOC) - rvamin,oxrelocs,soxrelocs);
delete [] oxrelocs; oxrelocs = nullptr; delete [] oxrelocs; oxrelocs = nullptr;
wrkmem.dealloc(); mb_wrkmem.dealloc();
ODSIZE(PEDIR_RELOC) = soxrelocs; ODSIZE(PEDIR_RELOC) = soxrelocs;
} }
@ -2836,7 +2846,7 @@ void PeFile::rebuildExports()
Export xport((char*)(unsigned char*) ibuf - isection[2].vaddr); Export xport((char*)(unsigned char*) ibuf - isection[2].vaddr);
processExports(&xport); processExports(&xport);
processExports(&xport,ODADDR(PEDIR_EXPORT)); processExports(&xport,ODADDR(PEDIR_EXPORT));
omemcpy(obuf + ODADDR(PEDIR_EXPORT) - rvamin,oexport,soexport); omemcpy(obuf + ODADDR(PEDIR_EXPORT) - rvamin, oexport, soexport);
} }
void PeFile::rebuildTls() void PeFile::rebuildTls()
@ -2844,7 +2854,7 @@ void PeFile::rebuildTls()
// this is an easy one : just do nothing ;-) // 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) if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0)
return; return;
@ -2857,7 +2867,8 @@ void PeFile::rebuildResources(upx_byte *& extrainfo, unsigned lastvaddr)
if (lastvaddr > vaddr || (vaddr - lastvaddr) > ibuf.getSize()) if (lastvaddr > vaddr || (vaddr - lastvaddr) > ibuf.getSize())
throwCantUnpack("corrupted PE header"); 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()); Resource res(r + vaddr, ibuf, ibuf + ibuf.getSize());
while (res.next()) while (res.next())
if (res.offs() > vaddr) if (res.offs() > vaddr)
@ -2882,29 +2893,25 @@ void PeFile::rebuildResources(upx_byte *& extrainfo, unsigned lastvaddr)
} }
template <typename LEXX, typename ord_mask_t> template <typename LEXX, typename ord_mask_t>
void PeFile::rebuildImports(upx_byte *& extrainfo, void PeFile::rebuildImports(SPAN_S(upx_byte) & extrainfo,
ord_mask_t ord_mask, bool set_oft) ord_mask_t ord_mask, bool set_oft)
{ {
if (ODADDR(PEDIR_IMPORT) == 0 if (ODADDR(PEDIR_IMPORT) == 0
|| ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc)) || ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc))
return; return;
// const upx_byte * const idata = obuf + get_le32(extrainfo);
OPTR_C(const upx_byte, idata, obuf + get_le32(extrainfo)); OPTR_C(const upx_byte, idata, obuf + get_le32(extrainfo));
const unsigned inamespos = get_le32(extrainfo + 4); const unsigned inamespos = get_le32(extrainfo + 4);
extrainfo += 8; extrainfo += 8;
unsigned sdllnames = 0; 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); 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; const upx_byte *dname = raw_bytes(import + get_le32(p), 1);
ICHECK(dname, 1);
const unsigned dlen = strlen(dname); const unsigned dlen = strlen(dname);
ICHECK(dname, dlen + 1); ICHECK(dname, dlen + 1);
@ -2919,18 +2926,26 @@ void PeFile::rebuildImports(upx_byte *& extrainfo,
} }
sdllnames = ALIGN_UP(sdllnames, 2u); 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 * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT));
import_desc *im = im0; import_desc *im = im0;
upx_byte *dllnames = Obuf + inamespos; upx_byte *dllnames = Obuf + inamespos;
upx_byte *importednames = dllnames + sdllnames; upx_byte *importednames = dllnames + sdllnames;
upx_byte * const importednames_start = importednames; 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) for (p = idata; get_le32(p) != 0; ++p)
{ {
// restore the name of the dll // restore the name of the dll
const upx_byte *dname = get_le32(p) + import; const upx_byte *dname = raw_bytes(import + get_le32(p), 1);
ICHECK(dname, 1);
const unsigned dlen = strlen(dname); const unsigned dlen = strlen(dname);
ICHECK(dname, dlen + 1); ICHECK(dname, dlen + 1);
@ -2939,7 +2954,7 @@ void PeFile::rebuildImports(upx_byte *& extrainfo,
{ {
// now I rebuild the dll names // now I rebuild the dll names
omemcpy(dllnames, dname, dlen + 1); omemcpy(dllnames, dname, dlen + 1);
im->dllname = ptr_diff(dllnames,Obuf); im->dllname = ptr_diff_bytes(dllnames,Obuf);
//;;;printf("\ndll: %s:",dllnames); //;;;printf("\ndll: %s:",dllnames);
dllnames += dlen + 1; dllnames += dlen + 1;
} }
@ -2960,11 +2975,11 @@ void PeFile::rebuildImports(upx_byte *& extrainfo,
const unsigned ilen = strlen(++p) + 1; const unsigned ilen = strlen(++p) + 1;
if (inamespos) if (inamespos)
{ {
if (ptr_diff(importednames, importednames_start) & 1) if (ptr_diff_bytes(importednames, importednames_start) & 1)
importednames -= 1; importednames -= 1;
omemcpy(importednames + 2, p, ilen); omemcpy(importednames + 2, p, ilen);
//;;;printf(" %s",importednames+2); //;;;printf(" %s",importednames+2);
*newiat = ptr_diff(importednames, Obuf); *newiat = ptr_diff_bytes(importednames, Obuf);
importednames += 2 + ilen; importednames += 2 + ilen;
} }
else else
@ -2982,7 +2997,7 @@ void PeFile::rebuildImports(upx_byte *& extrainfo,
} }
else 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); assert(*newiat & ord_mask);
p += 5; p += 5;
} }
@ -3017,8 +3032,9 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh,
decompress(ibuf,obuf); decompress(ibuf,obuf);
unsigned skip = get_le32(obuf + ph.u_len - 4); unsigned skip = get_le32(obuf + ph.u_len - 4);
unsigned take = sizeof(oh); unsigned take = sizeof(oh);
upx_byte *extrainfo = obuf.subref("bad extrainfo offset %#x", skip, take); SPAN_S_VAR(upx_byte, extrainfo, obuf);
//upx_byte * const eistart = extrainfo; extrainfo = obuf.subref("bad extrainfo offset %#x", skip, take);
//upx_byte * const eistart = raw_bytes(extrainfo, 0);
memcpy(&oh, extrainfo, take); memcpy(&oh, extrainfo, take);
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 //FIXME: this does bad things if the relocation section got removed
// during compression ... // during compression ...
//memset(eistart,0,extrainfo - eistart + 4); //memset(eistart, 0, ptr_udiff_bytes(extrainfo, eistart) + 4);
// fill the data directory // fill the data directory
ODADDR(PEDIR_DEBUG) = 0; ODADDR(PEDIR_DEBUG) = 0;
@ -3112,7 +3128,7 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh,
for (ic = 0; ic < objs; ic++) for (ic = 0; ic < objs; ic++)
if (osection[ic].rawdataptr) if (osection[ic].rawdataptr)
fo->write(obuf + osection[ic].vaddr - rvamin,ALIGN_UP(osection[ic].size,oh.filealign)); fo->write(obuf + osection[ic].vaddr - rvamin,ALIGN_UP(osection[ic].size,oh.filealign));
copyOverlay(fo, overlay, &obuf); copyOverlay(fo, overlay, obuf);
} }
ibuf.dealloc(); ibuf.dealloc();
} }

View File

@ -29,7 +29,7 @@
#ifndef __UPX_PEFILE_H #ifndef __UPX_PEFILE_H
#define __UPX_PEFILE_H 1 #define __UPX_PEFILE_H 1
#include "mem.h" #include "util/membuffer.h"
/************************************************************************* /*************************************************************************
@ -40,7 +40,7 @@ class PeFile : public Packer
{ {
typedef Packer super; typedef Packer super;
public: public:
virtual int getVersion() const { return 13; } virtual int getVersion() const override { return 13; }
protected: protected:
class Interval; class Interval;
class Reloc; class Reloc;
@ -84,7 +84,7 @@ protected:
ord_mask_t ord_mask, bool set_oft); ord_mask_t ord_mask, bool set_oft);
// unpacker capabilities // unpacker capabilities
virtual bool canUnpackVersion(int version) const virtual bool canUnpackVersion(int version) const override
{ return (version >= 12 && version <= 13); } { return (version >= 12 && version <= 13); }
int canUnpack0(unsigned max_sections, LE16 &ih_objects, int canUnpack0(unsigned max_sections, LE16 &ih_objects,
@ -92,7 +92,7 @@ protected:
protected: protected:
virtual int readFileHeader(); virtual int readFileHeader();
virtual bool testUnpackVersion(int version) const; virtual bool testUnpackVersion(int version) const override;
virtual void readPeHeader() = 0; virtual void readPeHeader() = 0;
unsigned pe_offset; unsigned pe_offset;
@ -101,12 +101,12 @@ protected:
unsigned processImports0(ord_mask_t ord_mask); unsigned processImports0(ord_mask_t ord_mask);
template <typename LEXX, typename ord_mask_t> template <typename LEXX, typename ord_mask_t>
void rebuildImports(upx_byte *& extrainfo, void rebuildImports(SPAN_S(upx_byte) & extrainfo,
ord_mask_t ord_mask, bool set_oft); ord_mask_t ord_mask, bool set_oft);
virtual unsigned processImports() = 0; virtual unsigned processImports() = 0;
virtual void processImports2(unsigned, unsigned); virtual void processImports2(unsigned, unsigned);
MemBuffer mb_oimport; MemBuffer mb_oimport;
upx_byte *oimport; SPAN_0(upx_byte) oimport = nullptr;
unsigned soimport; unsigned soimport;
upx_byte *oimpdlls; upx_byte *oimpdlls;
unsigned soimpdlls; unsigned soimpdlls;
@ -118,26 +118,26 @@ protected:
virtual void processRelocs() = 0; virtual void processRelocs() = 0;
void processRelocs(Reloc *); void processRelocs(Reloc *);
void rebuildRelocs(upx_byte *&, unsigned bits, void rebuildRelocs(SPAN_S(upx_byte) &, unsigned bits,
unsigned flags, upx_uint64_t imagebase); unsigned flags, upx_uint64_t imagebase);
MemBuffer mb_orelocs; MemBuffer mb_orelocs;
upx_byte *orelocs; SPAN_0(upx_byte) orelocs = nullptr;
unsigned sorelocs; unsigned sorelocs;
upx_byte *oxrelocs; upx_byte *oxrelocs = nullptr;
unsigned soxrelocs; unsigned soxrelocs;
void processExports(Export *); void processExports(Export *);
void processExports(Export *,unsigned); void processExports(Export *,unsigned);
void rebuildExports(); void rebuildExports();
MemBuffer mb_oexport; MemBuffer mb_oexport;
upx_byte *oexport; SPAN_0(upx_byte) oexport = nullptr;
unsigned soexport; unsigned soexport;
void processResources(Resource *); void processResources(Resource *);
void processResources(Resource *, unsigned); void processResources(Resource *, unsigned);
void rebuildResources(upx_byte *&, unsigned); void rebuildResources(SPAN_S(upx_byte) &, unsigned);
MemBuffer mb_oresources; MemBuffer mb_oresources;
upx_byte *oresources; SPAN_0(upx_byte) oresources = nullptr;
unsigned soresources; unsigned soresources;
template <typename> template <typename>
@ -154,7 +154,7 @@ protected:
void rebuildTls(); void rebuildTls();
MemBuffer mb_otls; MemBuffer mb_otls;
upx_byte *otls; SPAN_0(upx_byte) otls = nullptr;
unsigned sotls; unsigned sotls;
unsigned tlsindex; unsigned tlsindex;
unsigned tlscb_ptr; unsigned tlscb_ptr;
@ -357,7 +357,7 @@ protected:
const unsigned *getcounts() const { return counts; } const unsigned *getcounts() const { return counts; }
// //
void add(unsigned pos,unsigned type); void add(unsigned pos,unsigned type);
void finish(upx_byte *&p,unsigned &size); void finish(upx_byte* &p,unsigned &size);
}; };
class Resource : private noncopyable class Resource : private noncopyable
@ -460,15 +460,15 @@ protected:
virtual ~PeFile32(); virtual ~PeFile32();
void pack0(OutputFile *fo, unsigned subsystem_mask, void pack0(OutputFile *fo, unsigned subsystem_mask,
upx_uint64_t default_imagebase, bool last_section_rsrc_only); upx_uint64_t default_imagebase, bool last_section_rsrc_only);
virtual void unpack(OutputFile *fo); virtual void unpack(OutputFile *fo) override;
virtual int canUnpack(); virtual int canUnpack() override;
virtual void readPeHeader(); virtual void readPeHeader() override;
virtual unsigned processImports(); virtual unsigned processImports() override;
virtual void processRelocs(); virtual void processRelocs() override;
virtual void processTls(Interval *); virtual void processTls(Interval *) override;
virtual void processTls(Reloc *, const Interval *, unsigned); virtual void processTls(Reloc *, const Interval *, unsigned) override;
__packed_struct(pe_header_t) __packed_struct(pe_header_t)
// 0x0 // 0x0
@ -522,15 +522,15 @@ protected:
void pack0(OutputFile *fo, unsigned subsystem_mask, void pack0(OutputFile *fo, unsigned subsystem_mask,
upx_uint64_t default_imagebase); upx_uint64_t default_imagebase);
virtual void unpack(OutputFile *fo); virtual void unpack(OutputFile *fo) override;
virtual int canUnpack(); virtual int canUnpack() override;
virtual void readPeHeader(); virtual void readPeHeader() override;
virtual unsigned processImports(); virtual unsigned processImports() override;
virtual void processRelocs(); virtual void processRelocs() override;
virtual void processTls(Interval *); virtual void processTls(Interval *) override;
virtual void processTls(Reloc *, const Interval *, unsigned); virtual void processTls(Reloc *, const Interval *, unsigned) override;
__packed_struct(pe_header_t) __packed_struct(pe_header_t)
// 0x0 // 0x0

View File

@ -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. // Copyright 2022 BitWagon Software LLC. All rights reserved.
#include <errno.h> #include <errno.h>

View File

@ -25,6 +25,7 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#pragma once
#ifndef __UPX_UI_H #ifndef __UPX_UI_H
#define __UPX_UI_H 1 #define __UPX_UI_H 1

142
src/util/bptr.h Normal file
View File

@ -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
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#pragma once
#ifndef UPX_BPTR_H__
#define UPX_BPTR_H__ 1
/*************************************************************************
// BoundedPtr
**************************************************************************/
template <class T>
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<T> *operator&() const = delete;
};
// raw_bytes overload
template <class T>
inline T *raw_bytes(const BoundedPtr<T> &a, size_t size_in_bytes) {
return a.raw_bytes(size_in_bytes);
}
#endif /* already included */
/* vim:set ts=4 sw=4 et: */

View File

@ -25,36 +25,52 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#include "conf.h" #include "../conf.h"
/************************************************************************* /*************************************************************************
// upx_doctest_check() // upx_doctest_check()
**************************************************************************/ **************************************************************************/
bool upx_doctest_check(void) { bool upx_doctest_check(int argc, char **argv) {
bool minimal = true; // only show failing tests bool minimal = true; // only show failing tests
bool duration = false; // show timings bool duration = false; // show timings
bool success = false; // show all tests
const char *e = getenv("UPX_DEBUG_DOCTEST_VERBOSE"); const char *e = getenv("UPX_DEBUG_DOCTEST_VERBOSE");
if (e && e[0] && strcmp(e, "0") != 0) { if (e && e[0] && strcmp(e, "0") != 0) {
minimal = false; minimal = false;
if (strcmp(e, "2") == 0) if (strcmp(e, "2") == 0)
duration = true; duration = true;
if (strcmp(e, "3") == 0) {
duration = true;
success = true;
}
} }
#if DEBUG #if DEBUG
minimal = false; minimal = false;
// duration = true; // duration = true;
#endif #endif
doctest::Context context; doctest::Context context;
#if 0
if (argc > 0 && argv != nullptr)
context.applyCommandLine(argc, argv);
#else
UNUSED(argc);
UNUSED(argv);
#endif
if (minimal) if (minimal)
context.setOption("dt-minimal", true); context.setOption("dt-minimal", true);
if (duration) if (duration)
context.setOption("dt-duration", true); context.setOption("dt-duration", true);
if (success)
context.setOption("dt-success", true);
int r = context.run(); int r = context.run();
if (context.shouldExit() || r != 0) if (context.shouldExit() || r != 0)
return false; return false;
return true; return true;
} }
bool upx_doctest_check() { return upx_doctest_check(0, nullptr); }
/************************************************************************* /*************************************************************************
// compile-time checks // compile-time checks
**************************************************************************/ **************************************************************************/
@ -194,13 +210,13 @@ struct TestIntegerWrap {
#define ACC_WANT_ACC_CHK_CH 1 #define ACC_WANT_ACC_CHK_CH 1
#undef ACCCHK_ASSERT #undef ACCCHK_ASSERT
#include "miniacc.h" #include "../miniacc.h"
void upx_compiler_sanity_check(void) { void upx_compiler_sanity_check(void) {
#define ACC_WANT_ACC_CHK_CH 1 #define ACC_WANT_ACC_CHK_CH 1
#undef ACCCHK_ASSERT #undef ACCCHK_ASSERT
#define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT(expr) #define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT(expr)
#include "miniacc.h" #include "../miniacc.h"
#undef ACCCHK_ASSERT #undef ACCCHK_ASSERT
COMPILE_TIME_ASSERT(sizeof(char) == 1) COMPILE_TIME_ASSERT(sizeof(char) == 1)
@ -390,11 +406,21 @@ TEST_CASE("working -fno-strict-overflow") {
TEST_CASE("libc snprintf") { TEST_CASE("libc snprintf") {
// runtime check that Win32/MinGW <stdio.h> works as expected // runtime check that Win32/MinGW <stdio.h> works as expected
char buf[64];
long long ll = acc_vget_int(-1, 0); long long ll = acc_vget_int(-1, 0);
unsigned long long llu = (unsigned long long) ll; unsigned long long llu = (unsigned long long) ll;
char buf[64]; snprintf(buf, sizeof(buf), "%d.%ld.%lld.%u.%lu.%llu", -3, -2L, ll, 3U, 2LU, llu);
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);
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: */ /* vim:set ts=4 sw=4 et: */

View File

@ -1,4 +1,4 @@
/* mem.cpp -- /* membuffer.cpp --
This file is part of the UPX executable compressor. This file is part of the UPX executable compressor.
@ -25,10 +25,12 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#include "../conf.h"
#include "membuffer.h"
#include "conf.h" // extra functions to reduce dependency on membuffer.h
#include "mem.h" void *membuffer_get_void_ptr(MemBuffer &mb) { return mb.getVoidPtr(); }
unsigned membuffer_get_size(MemBuffer &mb) { return mb.getSize(); }
/************************************************************************* /*************************************************************************
// bool use_simple_mcheck() // bool use_simple_mcheck()
@ -38,17 +40,15 @@
__acc_static_forceinline constexpr bool use_simple_mcheck() { return false; } __acc_static_forceinline constexpr bool use_simple_mcheck() { return false; }
#elif (WITH_VALGRIND) && defined(RUNNING_ON_VALGRIND) #elif (WITH_VALGRIND) && defined(RUNNING_ON_VALGRIND)
static int use_simple_mcheck_flag = -1; 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; use_simple_mcheck_flag = 1;
if (RUNNING_ON_VALGRIND) { if (RUNNING_ON_VALGRIND) {
use_simple_mcheck_flag = 0; 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() __acc_static_forceinline bool use_simple_mcheck() {
{ if __acc_unlikely (use_simple_mcheck_flag < 0)
if __acc_unlikely(use_simple_mcheck_flag < 0)
use_simple_mcheck_init(); use_simple_mcheck_init();
return (bool) use_simple_mcheck_flag; 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; } __acc_static_forceinline constexpr bool use_simple_mcheck() { return true; }
#endif #endif
/************************************************************************* /*************************************************************************
// //
**************************************************************************/ **************************************************************************/
MemBuffer::MemBuffer(upx_uint64_t size) : MemBuffer::MemBuffer(upx_uint64_t size_in_bytes) { alloc(size_in_bytes); }
b(nullptr), b_size(0)
{
alloc(size);
}
MemBuffer::~MemBuffer() { this->dealloc(); }
MemBuffer::~MemBuffer()
{
this->dealloc();
}
// similar to BoundedPtr, except checks only at creation // similar to BoundedPtr, except checks only at creation
unsigned char *MemBuffer::subref(char const *errfmt, unsigned skip, unsigned take) // skip == offset, take == size_in_bytes
{ void *MemBuffer::subref_impl(const char *errfmt, size_t skip, size_t take) {
if ((take + skip) < take // wrap-around // check overrun and wrap-around
|| (take + skip) > b_size // overrun if (skip + take > b_size_in_bytes || skip + take < skip) {
) { char buf[100];
char buf[100]; snprintf(buf, sizeof(buf), errfmt, skip, take); // 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); throwCantPack(buf);
} }
return &b[skip]; return &b[skip];
} }
void MemBuffer::dealloc() static unsigned width(unsigned x) {
{
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)
{
unsigned w = 0; unsigned w = 0;
if ((~0u << 16) & x) { w += 16; x >>= 16; } if ((~0u << 16) & x) {
if ((~0u << 8) & x) { w += 8; x >>= 8; } w += 16;
if ((~0u << 4) & x) { w += 4; x >>= 4; } x >>= 16;
if ((~0u << 2) & x) { w += 2; x >>= 2; } }
if ((~0u << 1) & x) { w += 1; x >>= 1; } if ((~0u << 8) & x) {
return 1+ w; 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) static inline unsigned umax(unsigned a, unsigned b) { return (a >= b) ? a : b; }
{
return (a >= b) ? a : b;
}
unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned extra) unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned extra) {
{ size_t const z = uncompressed_size; // fewer keystrokes and display columns
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, extra); size_t bytes = mem_size(1, z);
size_t const w = umax(8, width(z -1)); // ignore tiny offsets // Worst matching: All match at max_offset, which implies 3==min_match
bytes = 256 + // safety? // All literal: 1 bit overhead per literal byte
umax(bytes + z/8, // All literal: 1 bit overhead per literal byte bytes = umax(bytes, bytes + z / 8);
// Worst matching: All match at max_offset, which implies 3==min_match // NRV2B: 1 byte plus 2 bits per width exceeding 8 ("ss11")
// NRV2B: 1 byte plus 2 bits per width exceeding 8 ("ss11") bytes = umax(bytes, (z / 3 * (8 + 2 * (w - 8) / 1)) / 8);
umax((z/3 * (8+ 2*(w - 8)/1))/8, // NRV2E: 1 byte plus 3 bits per pair of width exceeding 7 ("ss12")
// NRV2E: 1 byte plus 3 bits per pair of width exceeding 7 ("ss12") bytes = umax(bytes, (z / 3 * (8 + 3 * (w - 7) / 2)) / 8);
(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); 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); 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); 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); unsigned size = getSizeForCompression(uncompressed_size, extra);
alloc(size); alloc(size);
} }
void MemBuffer::allocForUncompression(unsigned uncompressed_size, unsigned extra) {
void MemBuffer::allocForUncompression(unsigned uncompressed_size, unsigned extra)
{
unsigned size = getSizeForUncompression(uncompressed_size, extra); unsigned size = getSizeForUncompression(uncompressed_size, extra);
alloc(size); alloc(size);
} }
void MemBuffer::fill(unsigned off, unsigned len, int value) {
void MemBuffer::fill(unsigned off, unsigned len, int value)
{
checkState(); checkState();
assert((int)off >= 0); assert((int) off >= 0);
assert((int)len >= 0); assert((int) len >= 0);
assert(off <= b_size); assert(off <= b_size_in_bytes);
assert(len <= b_size); assert(len <= b_size_in_bytes);
assert(off + len <= b_size); assert(off + len <= b_size_in_bytes);
if (len > 0) if (len > 0)
memset(b + off, value, len); memset(b + off, value, len);
} }
/************************************************************************* /*************************************************************************
// //
**************************************************************************/ **************************************************************************/
#define PTR(p) ((unsigned) ((upx_uintptr_t)(p) & 0xffffffff)) #define PTR(p) ((unsigned) ((upx_uintptr_t)(p) &0xffffffff))
#define MAGIC1(p) (PTR(p) ^ 0xfefdbeeb) #define MAGIC1(p) (PTR(p) ^ 0xfefdbeeb)
#define MAGIC2(p) (PTR(p) ^ 0xfefdbeeb ^ 0x80024001) #define MAGIC2(p) (PTR(p) ^ 0xfefdbeeb ^ 0x80024001)
unsigned MemBuffer::global_alloc_counter = 0; unsigned MemBuffer::global_alloc_counter = 0;
void MemBuffer::checkState() const {
void MemBuffer::checkState() const
{
if (!b) if (!b)
throwInternalError("block not allocated"); throwInternalError("block not allocated");
if (use_simple_mcheck()) if (use_simple_mcheck()) {
{
if (get_be32(b - 4) != MAGIC1(b)) if (get_be32(b - 4) != MAGIC1(b))
throwInternalError("memory clobbered before allocated block 1"); 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"); 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"); 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 // NOTE: we don't automatically free a used buffer
assert(b == nullptr); assert(b == nullptr);
assert(b_size == 0); assert(b_size_in_bytes == 0);
// //
assert(size > 0); assert(size > 0);
size_t bytes = mem_size(1, size, use_simple_mcheck() ? 32 : 0); size_t bytes = mem_size(1, size, use_simple_mcheck() ? 32 : 0);
unsigned char *p = (unsigned char *) malloc(bytes); unsigned char *p = (unsigned char *) malloc(bytes);
if (!p) if (!p)
throwOutOfMemoryException(); throwOutOfMemoryException();
b_size = ACC_ICONV(unsigned, size); b_size_in_bytes = ACC_ICONV(unsigned, size);
if (use_simple_mcheck()) if (use_simple_mcheck()) {
{
b = p + 16; b = p + 16;
// store magic constants to detect buffer overruns // 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 - 4, MAGIC1(b));
set_be32(b + b_size, MAGIC2(b)); set_be32(b + b_size_in_bytes, MAGIC2(b));
set_be32(b + b_size + 4, global_alloc_counter++); set_be32(b + b_size_in_bytes + 4, global_alloc_counter++);
} } else
else b = p;
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: */ /* vim:set ts=4 sw=4 et: */

127
src/util/membuffer.h Normal file
View File

@ -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
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#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 T>
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 <class U, class V = typename std::enable_if<std::is_integral<U>::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 <class U, class V = typename std::enable_if<std::is_integral<U>::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<unsigned char> {
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 <class T>
inline T *raw_bytes(const MemBufferBase<T> &a, size_t size_in_bytes) {
return a.raw_bytes(size_in_bytes);
}
/* vim:set ts=4 sw=4 et: */

View File

@ -25,7 +25,7 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#include "conf.h" #include "../conf.h"
/************************************************************************* /*************************************************************************
// UPX version of string functions, with assertions and sane limits // UPX version of string functions, with assertions and sane limits

View File

@ -25,8 +25,9 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#ifndef __UPX_SNPRINTF_H #pragma once
#define __UPX_SNPRINTF_H 1 #ifndef UPX_SNPRINTF_H__
#define UPX_SNPRINTF_H__ 1
/************************************************************************* /*************************************************************************
// UPX version of string functions, with assertions and sane limits // 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) // 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_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 // malloc's *ptr
int upx_safe_vasprintf(char **ptr, const char *format, va_list ap); 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 // returns a malloc'd pointer
char *upx_safe_xprintf(const char *format, ...) attribute_format(1, 2); 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 snprintf
#undef sprintf #undef sprintf
#undef vsnprintf #undef vsnprintf
#define snprintf upx_safe_snprintf #define snprintf upx_safe_snprintf
#define sprintf ERROR_sprintf_IS_DANGEROUS_USE_snprintf #define sprintf ERROR_sprintf_IS_DANGEROUS_USE_snprintf
#define vsnprintf upx_safe_vsnprintf #define vsnprintf upx_safe_vsnprintf
#undef strlen #undef strlen
#define strlen upx_safe_strlen #define strlen upx_safe_strlen
/************************************************************************* /*************************************************************************
// some unsigned char string support functions // some unsigned char string support functions

View File

@ -25,18 +25,18 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#include "conf.h" #include "../conf.h"
#include "util.h" #include "util.h"
#define ACC_WANT_ACC_INCI_H 1 #define ACC_WANT_ACC_INCI_H 1
#include "miniacc.h" #include "../miniacc.h"
#define ACC_WANT_ACCLIB_GETOPT 1 #define ACC_WANT_ACCLIB_GETOPT 1
#define ACC_WANT_ACCLIB_HSREAD 1 #define ACC_WANT_ACCLIB_HSREAD 1
#define ACC_WANT_ACCLIB_MISC 1 #define ACC_WANT_ACCLIB_MISC 1
#define ACC_WANT_ACCLIB_VGET 1 #define ACC_WANT_ACCLIB_VGET 1
#define ACC_WANT_ACCLIB_WILDARGV 1 #define ACC_WANT_ACCLIB_WILDARGV 1
#undef HAVE_MKDIR #undef HAVE_MKDIR
#include "miniacc.h" #include "../miniacc.h"
/************************************************************************* /*************************************************************************
// assert sane memory buffer sizes to protect against integer overflows // 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_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
upx_uint64_t extra2) { upx_uint64_t extra2) {
assert(element_size > 0); 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"); 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"); 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"); 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"); throwCantPack("mem_size 4; take care");
upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow 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"); throwCantPack("mem_size 5; take care");
return ACC_ICONV(upx_rsize_t, bytes); 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, 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); assert(element_size > 0);
if (element_size > UPX_RSIZE_MAX) if __acc_very_unlikely (element_size > UPX_RSIZE_MAX)
return false; return false;
if (n > UPX_RSIZE_MAX) if __acc_very_unlikely (n > UPX_RSIZE_MAX)
return false; return false;
if (extra1 > UPX_RSIZE_MAX) if __acc_very_unlikely (extra1 > UPX_RSIZE_MAX)
return false; return false;
if (extra2 > UPX_RSIZE_MAX) if __acc_very_unlikely (extra2 > UPX_RSIZE_MAX)
return false; return false;
upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow
if (bytes > UPX_RSIZE_MAX) if __acc_very_unlikely (bytes > UPX_RSIZE_MAX)
return false;
return true;
}
bool mem_size_valid_bytes(upx_uint64_t bytes) {
if (bytes > UPX_RSIZE_MAX)
return false; return false;
return true; return true;
} }
@ -100,28 +89,49 @@ TEST_CASE("mem_size") {
CHECK(!mem_size_valid(1, 0x30000000, 1)); CHECK(!mem_size_valid(1, 0x30000000, 1));
CHECK(!mem_size_valid(1, 0x30000000, 0, 1)); CHECK(!mem_size_valid(1, 0x30000000, 0, 1));
CHECK(!mem_size_valid(1, 0x30000000, 0x30000000, 0x30000000)); 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) { int ptr_diff_bytes(const void *a, const void *b) {
assert(p1 != nullptr); if __acc_very_unlikely (a == nullptr) {
assert(p2 != nullptr); throwCantPack("ptr_diff_bytes null 1; take care");
ptrdiff_t d = (const char *) p1 - (const char *) p2; }
if (p1 >= p2) if __acc_very_unlikely (b == nullptr) {
assert(mem_size_valid_bytes(d)); throwCantPack("ptr_diff_bytes null 2; take care");
else }
assert(mem_size_valid_bytes(-d)); 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); return ACC_ICONV(int, d);
} }
unsigned ptr_udiff(const void *p1, const void *p2) { unsigned ptr_udiff_bytes(const void *a, const void *b) {
int d = ptr_diff(p1, p2); int d = ptr_diff_bytes(a, b);
assert(d >= 0); if __acc_very_unlikely (d < 0)
throwCantPack("ptr_udiff_bytes; take care");
return ACC_ICONV(unsigned, d); return ACC_ICONV(unsigned, d);
} }
void mem_clear(void *p, size_t n) { TEST_CASE("ptr_diff") {
mem_size_assert(1, n); char buf[4] = {0, 1, 2, 3};
memset(p, 0, n); 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(1, 11) == 9999999);
CHECK(get_ratio(100000, 100000) == 1000050); CHECK(get_ratio(100000, 100000) == 1000050);
CHECK(get_ratio(100000, 200000) == 2000050); 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: */ /* vim:set ts=4 sw=4 et: */

View File

@ -25,32 +25,72 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#ifndef __UPX_UTIL_H #pragma once
#define __UPX_UTIL_H 1 #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)] inline bool mem_size_valid_bytes(upx_uint64_t bytes) noexcept { return bytes <= UPX_RSIZE_MAX; }
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
}
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0, bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0,
upx_uint64_t extra2 = 0); upx_uint64_t extra2 = 0) noexcept;
bool mem_size_valid_bytes(upx_uint64_t bytes);
int ptr_diff(const void *p1, const void *p2); // new with asserted size; will throw on failure
unsigned ptr_udiff(const void *p1, const void *p2); // asserts p1 >= p2 #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 <class T, class U>
inline typename std::enable_if<sizeof(T) == 1 && sizeof(U) == 1, int>::type ptr_diff(const T *a,
const U *b) {
return ptr_diff_bytes(a, b);
}
template <class T, class U>
inline typename std::enable_if<sizeof(T) == 1 && sizeof(U) == 1, unsigned>::type
ptr_udiff(const T *a, const U *b) {
return ptr_udiff_bytes(a, b);
}
/************************************************************************* /*************************************************************************
// misc. support functions // misc. support functions

637
src/util/xspan.cpp Normal file
View File

@ -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
<markus@oberhumer.com>
*/
#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<char> 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<char> 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<char> 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<char> 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<char> 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<char> 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 <class T>
__acc_static_noinline int foo(T p) {
unsigned r = 0;
r += *p++;
r += *++p;
p += 3;
r += *p;
return r;
}
template <class T>
SPAN_0(T)
make_span_0(T *ptr, size_t count) {
return PtrOrSpanOrNull<T>(ptr, count);
}
template <class T>
SPAN_P(T)
make_span_p(T *ptr, size_t count) {
return PtrOrSpan<T>(ptr, count);
}
template <class T>
SPAN_S(T)
make_span_s(T *ptr, size_t count) {
return Span<T>(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: */

144
src/util/xspan.h Normal file
View File

@ -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
<markus@oberhumer.com>
*/
#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<type>
#define SPAN_P(type) PtrOrSpan<type>
#define SPAN_S(type) Span<type>
// 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<type>
#define SPAN_P(type) Ptr<type>
#define SPAN_S(type) Ptr<type>
// 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 <class R, class T>
inline R *span_make__(R * /*dummy*/, T *first) {
return first; // IMPORTANT: no cast here to detect bad usage
}
template <class R>
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: */

293
src/util/xspan_fwd.h Normal file
View File

@ -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
<markus@oberhumer.com>
*/
// manually forward a number of well-known functions using a
// checked "raw_bytes()" call
#define SPAN_FWD_TU(RType) \
template <class T, class U> \
inline SPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION(T, U, RType)
/*************************************************************************
// overloads for standard functions
**************************************************************************/
template <class T>
inline void *memchr(const C<T> &a, int c, size_t n) {
return memchr(a.raw_bytes(n), c, n);
}
template <class T>
inline const void *memchr(const C<const T> &a, int c, size_t n) {
return memchr(a.raw_bytes(n), c, n);
}
template <class T>
inline int memcmp(const C<T> &a, const void *b, size_t n) {
return memcmp(a.raw_bytes(n), b, n);
}
template <class T>
inline int memcmp(const void *a, const C<T> &b, size_t n) {
return memcmp(a, b.raw_bytes(n), n);
}
SPAN_FWD_TU(int) memcmp(const C<T> &a, const C<U> &b, size_t n) {
return memcmp(a.raw_bytes(n), b.raw_bytes(n), n);
}
#ifdef D
SPAN_FWD_TU(int) memcmp(const C<T> &a, const D<U> &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<T> &a, const E<U> &b, size_t n) {
return memcmp(a.raw_bytes(n), b.raw_bytes(n), n);
}
#endif
template <class T>
inline void *memcpy(C<T> a, const void *b, size_t n) {
return memcpy(a.raw_bytes(n), b, n);
}
template <class T>
inline void *memcpy(void *a, const C<T> &b, size_t n) {
return memcpy(a, b.raw_bytes(n), n);
}
SPAN_FWD_TU(void *) memcpy(const C<T> &a, const C<U> &b, size_t n) {
return memcpy(a.raw_bytes(n), b.raw_bytes(n), n);
}
#ifdef D
SPAN_FWD_TU(void *) memcpy(const C<T> &a, const D<U> &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<T> &a, const E<U> &b, size_t n) {
return memcpy(a.raw_bytes(n), b.raw_bytes(n), n);
}
#endif
template <class T>
inline void *memmove(C<T> a, const void *b, size_t n) {
return memmove(a.raw_bytes(n), b, n);
}
template <class T>
inline void *memmove(void *a, const C<T> &b, size_t n) {
return memmove(a, b.raw_bytes(n), n);
}
SPAN_FWD_TU(void *) memmove(const C<T> &a, const C<U> &b, size_t n) {
return memmove(a.raw_bytes(n), b.raw_bytes(n), n);
}
#ifdef D
SPAN_FWD_TU(void *) memmove(const C<T> &a, const D<U> &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<T> &a, const E<U> &b, size_t n) {
return memmove(a.raw_bytes(n), b.raw_bytes(n), n);
}
#endif
/*************************************************************************
// overloads for UPX extras
**************************************************************************/
template <class T>
inline int ptr_diff_bytes(const C<T> &a, const void *b) {
return ptr_diff_bytes(a.raw_bytes(0), b);
}
template <class T>
inline int ptr_diff_bytes(const void *a, const C<T> &b) {
return ptr_diff_bytes(a, b.raw_bytes(0));
}
SPAN_FWD_TU(int) ptr_diff_bytes(const C<T> &a, const C<U> &b) {
return ptr_diff_bytes(a.raw_bytes(0), b.raw_bytes(0));
}
#ifdef D
SPAN_FWD_TU(int) ptr_diff_bytes(const C<T> &a, const D<U> &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<T> &a, const E<U> &b) {
return ptr_diff_bytes(a.raw_bytes(0), b.raw_bytes(0));
}
#endif
template <class T>
inline unsigned ptr_udiff_bytes(const C<T> &a, const void *b) {
return ptr_udiff_bytes(a.raw_bytes(0), b);
}
template <class T>
inline unsigned ptr_udiff_bytes(const void *a, const C<T> &b) {
return ptr_udiff_bytes(a, b.raw_bytes(0));
}
SPAN_FWD_TU(unsigned) ptr_udiff_bytes(const C<T> &a, const C<U> &b) {
return ptr_udiff_bytes(a.raw_bytes(0), b.raw_bytes(0));
}
#ifdef D
SPAN_FWD_TU(unsigned) ptr_udiff_bytes(const C<T> &a, const D<U> &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<T> &a, const E<U> &b) {
return ptr_udiff_bytes(a.raw_bytes(0), b.raw_bytes(0));
}
#endif
#ifdef UPX_VERSION_HEX
template <class T>
unsigned get_ne16(const C<T> &a) {
return get_ne16(a.raw_bytes(2));
}
template <class T>
unsigned get_ne32(const C<T> &a) {
return get_ne32(a.raw_bytes(4));
}
template <class T>
upx_uint64_t get_ne64(const C<T> &a) {
return get_ne64(a.raw_bytes(8));
}
template <class T>
unsigned get_be16(const C<T> &a) {
return get_be16(a.raw_bytes(2));
}
template <class T>
unsigned get_be32(const C<T> &a) {
return get_be32(a.raw_bytes(4));
}
template <class T>
upx_uint64_t get_be64(const C<T> &a) {
return get_be64(a.raw_bytes(8));
}
template <class T>
unsigned get_le16(const C<T> &a) {
return get_le16(a.raw_bytes(2));
}
template <class T>
unsigned get_le24(const C<T> &a) {
return get_le24(a.raw_bytes(3));
}
template <class T>
unsigned get_le32(const C<T> &a) {
return get_le32(a.raw_bytes(4));
}
template <class T>
upx_uint64_t get_le64(const C<T> &a) {
return get_le64(a.raw_bytes(8));
}
template <class T>
void set_ne16(const C<T> &a, unsigned v) {
return set_ne16(a.raw_bytes(2), v);
}
template <class T>
void set_ne32(const C<T> &a, unsigned v) {
return set_ne32(a.raw_bytes(4), v);
}
template <class T>
void set_ne64(const C<T> &a, upx_uint64_t v) {
return set_ne64(a.raw_bytes(8), v);
}
template <class T>
void set_be16(const C<T> &a, unsigned v) {
return set_be16(a.raw_bytes(2), v);
}
template <class T>
void set_be32(const C<T> &a, unsigned v) {
return set_be32(a.raw_bytes(4), v);
}
template <class T>
void set_be64(const C<T> &a, upx_uint64_t v) {
return set_be64(a.raw_bytes(8), v);
}
template <class T>
void set_le16(const C<T> &a, unsigned v) {
return set_le16(a.raw_bytes(2), v);
}
template <class T>
void set_le24(const C<T> &a, unsigned v) {
return set_le24(a.raw_bytes(3), v);
}
template <class T>
void set_le32(const C<T> &a, unsigned v) {
return set_le32(a.raw_bytes(4), v);
}
template <class T>
void set_le64(const C<T> &a, upx_uint64_t v) {
return set_le64(a.raw_bytes(8), v);
}
template <class T>
inline C<T> operator+(const C<T> &a, const BE16 &v) {
return a + unsigned(v);
}
template <class T>
inline C<T> operator+(const C<T> &a, const BE32 &v) {
return a + unsigned(v);
}
template <class T>
inline C<T> operator+(const C<T> &a, const LE16 &v) {
return a + unsigned(v);
}
template <class T>
inline C<T> operator+(const C<T> &a, const LE32 &v) {
return a + unsigned(v);
}
template <class T>
inline C<T> operator-(const C<T> &a, const BE16 &v) {
return a - unsigned(v);
}
template <class T>
inline C<T> operator-(const C<T> &a, const BE32 &v) {
return a - unsigned(v);
}
template <class T>
inline C<T> operator-(const C<T> &a, const LE16 &v) {
return a - unsigned(v);
}
template <class T>
inline C<T> operator-(const C<T> &a, const LE32 &v) {
return a - unsigned(v);
}
template <class T>
typename std::enable_if<sizeof(T) == 1, upx_rsize_t>::type upx_safe_strlen(const C<T> &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: */

240
src/util/xspan_impl.h Normal file
View File

@ -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
<markus@oberhumer.com>
*/
#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 <class T>
struct TypeForSizeOf {
typedef T type;
};
template <>
struct TypeForSizeOf<void> {
typedef char type;
};
template <>
struct TypeForSizeOf<const void> {
typedef const char type;
};
template <class T>
struct ValueForSizeOf {
static const size_t value = sizeof(typename TypeForSizeOf<T>::type);
};
ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf<char>::value == 1)
ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf<const char>::value == 1)
ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf<void>::value == 1)
ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf<const void>::value == 1)
ACC_COMPILE_TIME_ASSERT_HEADER(ValueForSizeOf<int>::value == 4)
#ifndef span_mem_size_impl
template <class T>
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 <class T>
inline size_t span_mem_size(size_t n) {
return span_mem_size_impl<typename TypeForSizeOf<T>::type>(n);
}
template <class T>
inline void span_mem_size_assert_ptrdiff(ptrdiff_t n) {
if (n >= 0)
(void) span_mem_size<T>((size_t) n);
else
(void) span_mem_size<T>((size_t) -n);
}
#if 0
template <class From, class To>
struct Span_is_convertible : public std::is_convertible<From *, To *> {};
#else
namespace detail {
template <class T, class U>
struct Span_void_to_T {
typedef U type;
};
template <class T>
struct Span_void_to_T<T, void> {
typedef typename std::remove_const<T>::type type;
};
template <class T>
struct Span_void_to_T<T, const void> {
// typedef typename std::add_const<T>::type type;
typedef T type;
};
template <class From, class To>
struct Span_ptr_is_convertible : public std::false_type {};
template <class T>
struct Span_ptr_is_convertible<T, T> : public std::true_type {};
template <class T>
struct Span_ptr_is_convertible<T, const T> : public std::true_type {};
} // namespace detail
template <class From, class To>
struct Span_is_convertible
: public detail::Span_ptr_is_convertible<From,
typename detail::Span_void_to_T<From, To>::type> {};
#endif
#if 1
// char => char
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<char, char>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<char, const char>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<const char, const char>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const char, char>::value));
// void => void
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<void, void>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<void, const void>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<const void, const void>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const void, void>::value));
// char => void
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<char, void>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<char, const void>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((Span_is_convertible<const char, const void>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const char, void>::value));
// void => char
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<void, char>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<void, const char>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const void, const char>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const void, char>::value));
// char => int
ACC_COMPILE_TIME_ASSERT_HEADER(!(Span_is_convertible<char, int>::value));
ACC_COMPILE_TIME_ASSERT_HEADER(!(Span_is_convertible<char, const int>::value));
ACC_COMPILE_TIME_ASSERT_HEADER(!(Span_is_convertible<const char, const int>::value));
ACC_COMPILE_TIME_ASSERT_HEADER((!Span_is_convertible<const char, int>::value));
#endif
/*************************************************************************
// PtrOrSpanOrNull
// PtrOrSpan
// Span
// Ptr
**************************************************************************/
// forward declarations
template <class T>
struct PtrOrSpanOrNull;
template <class T>
struct PtrOrSpan;
template <class T>
struct Span;
template <class T>
struct Ptr;
template <class T>
inline T *raw_bytes(const PtrOrSpanOrNull<T> &a, size_t size_in_bytes);
template <class T>
inline T *raw_bytes(const PtrOrSpan<T> &a, size_t size_in_bytes);
template <class T>
inline T *raw_bytes(const Span<T> &a, size_t size_in_bytes);
template <class T>
inline T *raw_bytes(const Ptr<T> &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<SPAN_NS(Span_is_convertible) < U, T>::value, RType > ::type
#define SPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION(T, U, RType) \
typename std::enable_if<SPAN_NS(Span_is_convertible) < U, T>::value || \
SPAN_NS(Span_is_convertible)<T, U>::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<SPAN_NS(Span_is_convertible) < U, T>::value &&SPAN_NS( \
ValueForSizeOf)<T>::value == 1 && \
SPAN_NS(ValueForSizeOf)<U>::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: */

View File

@ -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
<markus@oberhumer.com>
*/
/*************************************************************************
//
**************************************************************************/
public:
typedef T element_type;
typedef typename std::add_lvalue_reference<T>::type reference;
// typedef typename std::add_pointer<T>::type pointer;
typedef T *pointer;
typedef size_t size_type;
// befriend all
template <class>
friend struct PtrOrSpan;
template <class>
friend struct PtrOrSpanOrNull;
template <class>
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<T>(count.count)) {
assertInvariants();
}
CSelf(pointer first, SpanSizeInBytes bytes)
: ptr(makePtr(first)), base(makeBase(first)),
size_in_bytes(span_mem_size<char>(bytes.size_in_bytes)) {
assertInvariants();
}
// enable this constructor only if the underlying type is char or void
template <class U>
CSelf(U *first, size_type count, SPAN_REQUIRES_SIZE_1_A)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(span_mem_size<T>(count)) {
assertInvariants();
}
CSelf(pointer first, SpanCount count, pointer base_)
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(span_mem_size<T>(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<char>(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 <class U>
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<T>(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 <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const CSelf<U> &other) {
// assert(0);
return assign(Self(other));
}
#ifdef UPX_VERSION_HEX
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
#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 <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(U *other) const {
return ptr == other;
}
bool operator!=(pointer other) const { return ptr != other; }
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(U *other) const {
return ptr != other;
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpan<U> &other) const {
return ptr == other.ptr;
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const PtrOrSpanOrNull<U> &other) const {
return ptr == other.ptr;
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const Span<U> &other) const {
return ptr == other.ptr;
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpan<U> &other) const {
return !(*this == other);
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const PtrOrSpanOrNull<U> &other) const {
return !(*this == other);
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator!=(const Span<U> &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 <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpan<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const PtrOrSpanOrNull<U> &other) const {
return ensurePtr() < other.ensurePtr();
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator<(const Span<U> &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<T>(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<T>(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: */

209
src/util/xspan_impl_ptr.h Normal file
View File

@ -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
<markus@oberhumer.com>
*/
#pragma once
SPAN_NAMESPACE_BEGIN
/*************************************************************************
// Ptr
**************************************************************************/
template <class T>
struct Ptr {
private:
#define CSelf Ptr
typedef CSelf<T> Self;
public:
// befriend all
template <class>
friend struct CSelf;
typedef T element_type;
typedef typename std::add_lvalue_reference<T>::type reference;
// typedef T *pointer;
typedef typename std::add_pointer<T>::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 <class U>
CSelf(U *p, SPAN_REQUIRES_CONVERTIBLE_A) : ptr(makePtr(p)) {}
// constructors
CSelf(const Self &other) : ptr(other.ptr) {}
template <class U>
CSelf(const CSelf<U> &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 <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(U *other) {
assert(0);
return assign(Self(other));
}
// FIXME: this is not called !!
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const CSelf<U> &other) {
assert(0);
return assign(Self(other));
}
// comparision
bool operator==(pointer other) const { return ptr == other; }
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(U *other) const {
return ptr == other;
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(bool)
operator==(const Ptr<U> &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 <class T>
inline T *raw_bytes(const Ptr<T> &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: */

View File

@ -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
<markus@oberhumer.com>
*/
#pragma once
SPAN_NAMESPACE_BEGIN
/*************************************************************************
// PtrOrSpanOrNull
//
// invariants:
// ptr can be null
// if ptr != null && base != null then ptr is valid in base
**************************************************************************/
template <class T>
struct PtrOrSpanOrNull {
private:
#define CSelf PtrOrSpanOrNull
typedef CSelf<T> 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 <class U>
CSelf(const CSelf<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
: ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {}
// constructors from Span friends
template <class U>
CSelf(const PtrOrSpan<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
: ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {}
template <class U>
CSelf(const Span<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
: ptr(other.ptr), base(other.base), size_in_bytes(other.size_in_bytes) {}
// assignment from Span friends
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const PtrOrSpan<U> &other) {
return assign(Self(other));
}
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const Span<U> &other) {
return assign(Self(other));
}
// nullptr
CSelf(std::nullptr_t) : ptr(nullptr), base(nullptr), size_in_bytes(0) {}
#undef CSelf
};
template <class T>
inline T *raw_bytes(const PtrOrSpanOrNull<T> &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: */

View File

@ -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
<markus@oberhumer.com>
*/
#pragma once
SPAN_NAMESPACE_BEGIN
/*************************************************************************
// PtrOrSpan
//
// invariants:
// ptr != null
// if base != null then ptr is valid in base
**************************************************************************/
template <class T>
struct PtrOrSpan {
private:
#define CSelf PtrOrSpan
typedef CSelf<T> 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 <class U>
CSelf(const CSelf<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
: ptr(other.ensurePtr()), base(other.base), size_in_bytes(other.size_in_bytes) {}
// constructors from Span friends
template <class U>
CSelf(const Span<U> &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 <class U>
CSelf(const PtrOrSpanOrNull<U> &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 <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const Span<U> &other) {
return assign(Self(other));
}
#if SPAN_CONFIG_ENABLE_SPAN_CONVERSION
template <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const PtrOrSpanOrNull<U> &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 <class T>
inline T *raw_bytes(const PtrOrSpan<T> &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: */

135
src/util/xspan_impl_span.h Normal file
View File

@ -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
<markus@oberhumer.com>
*/
#pragma once
SPAN_NAMESPACE_BEGIN
/*************************************************************************
// Span
//
// invariants:
// ptr != null, base != null
// ptr is valid in base
**************************************************************************/
template <class T>
struct Span {
private:
#define CSelf Span
typedef CSelf<T> 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 <class U>
CSelf(const CSelf<U> &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 <class U>
CSelf(const PtrOrSpanOrNull<U> &other, SPAN_REQUIRES_CONVERTIBLE_A)
: ptr(other.ensurePtr()), base(other.ensureBase()), size_in_bytes(other.size_in_bytes) {}
template <class U>
CSelf(const PtrOrSpan<U> &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 <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const PtrOrSpan<U> &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 <class U>
SPAN_REQUIRES_CONVERTIBLE_R(Self &)
operator=(const PtrOrSpanOrNull<U> &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 <class T>
inline T *raw_bytes(const Span<T> &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: */

View File

@ -190,15 +190,15 @@ void do_one_file(const char *iname, char *oname) {
r = chmod(iname, 0777); r = chmod(iname, 0777);
IGNORE_ERROR(r); IGNORE_ERROR(r);
#endif #endif
File::unlink(iname); FileBase::unlink(iname);
} else { } else {
// make backup // make backup
char bakname[ACC_FN_PATH_MAX + 1]; char bakname[ACC_FN_PATH_MAX + 1];
if (!makebakname(bakname, sizeof(bakname), iname)) if (!makebakname(bakname, sizeof(bakname), iname))
throwIOException("could not create a backup file name"); 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 // 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())) if (opt->verbose >= 1 || (opt->verbose >= 0 && !e.isWarning()))
printErr(iname, &e); printErr(iname, &e);
main_set_exit_code(e.isWarning() ? EXIT_WARN : EXIT_ERROR); 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) { } catch (const Error &e) {
unlink_ofile(oname); unlink_ofile(oname);
printErr(iname, &e); printErr(iname, &e);
main_set_exit_code(EXIT_ERROR); main_set_exit_code(EXIT_ERROR);
return -1; return -1; // fatal error
} catch (std::bad_alloc *e) { } catch (std::bad_alloc *e) {
unlink_ofile(oname); unlink_ofile(oname);
printErr(iname, "out of memory"); printErr(iname, "out of memory");
UNUSED(e); UNUSED(e);
// delete e; // delete e;
main_set_exit_code(EXIT_ERROR); main_set_exit_code(EXIT_ERROR);
return -1; return -1; // fatal error
} catch (const std::bad_alloc &) { } catch (const std::bad_alloc &) {
unlink_ofile(oname); unlink_ofile(oname);
printErr(iname, "out of memory"); printErr(iname, "out of memory");
main_set_exit_code(EXIT_ERROR); main_set_exit_code(EXIT_ERROR);
return -1; return -1; // fatal error
} catch (std::exception *e) { } catch (std::exception *e) {
unlink_ofile(oname); unlink_ofile(oname);
printUnhandledException(iname, e); printUnhandledException(iname, e);
// delete e; // delete e;
main_set_exit_code(EXIT_ERROR); main_set_exit_code(EXIT_ERROR);
return -1; return -1; // fatal error
} catch (const std::exception &e) { } catch (const std::exception &e) {
unlink_ofile(oname); unlink_ofile(oname);
printUnhandledException(iname, &e); printUnhandledException(iname, &e);
main_set_exit_code(EXIT_ERROR); main_set_exit_code(EXIT_ERROR);
return -1; return -1; // fatal error
} catch (...) { } catch (...) {
unlink_ofile(oname); unlink_ofile(oname);
printUnhandledException(iname, nullptr); printUnhandledException(iname, nullptr);
main_set_exit_code(EXIT_ERROR); main_set_exit_code(EXIT_ERROR);
return -1; return -1; // fatal error
} }
} }