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
cd %BDIR%\ucl
set s=%H%\upx\vendor\ucl
cl -MT -O2 -W4 %DEFS% -I%s%\include -I%s% -c %s%\src\*.c
cl -MT -J -O2 -W4 %DEFS% -I%s%\include -I%s% -c %s%\src\*.c
link -lib -out:ucl.lib *.obj
@REM build zlib
cd %BDIR%\zlib
cl -MT -O2 -W3 %DEFS% -c %H%\upx\vendor\zlib\*.c
cl -MT -J -O2 -W3 %DEFS% -c %H%\upx\vendor\zlib\*.c
link -lib -out:zlib.lib *.obj
@REM build UPX
cd %BDIR%\upx
set s=%H%\upx\src
cat .GITREV.txt
set /p GITREV=<.GITREV.txt
cl -MT -EHsc -J -O2 -W4 -WX -DUPX_VERSION_GITREV="""%GITREV%""" %DEFS% -I%H%\upx\vendor\doctest -I%H%\upx\vendor\lzma-sdk -I%H%\upx\vendor\ucl\include -I%H%\upx\vendor\zlib -Feupx.exe %s%\*.cpp %BDIR%\ucl\ucl.lib %BDIR%\zlib\zlib.lib /link setargv.obj
cl -MT -EHsc -J -O2 -W4 -WX -DUPX_VERSION_GITREV="""%GITREV%""" %DEFS% -I%H%\upx\vendor\doctest -I%H%\upx\vendor\lzma-sdk -I%H%\upx\vendor\ucl\include -I%H%\upx\vendor\zlib -Feupx.exe %s%\*.cpp %s%\util\*.cpp %BDIR%\ucl\ucl.lib %BDIR%\zlib\zlib.lib /link setargv.obj
- name: 'Basic tests'
shell: cmd

View File

@ -83,7 +83,7 @@ list(SORT zlib_SOURCES)
add_library(upx_vendor_zlib STATIC ${zlib_SOURCES})
set_property(TARGET upx_vendor_zlib PROPERTY C_STANDARD 11)
file(GLOB upx_SOURCES "src/*.cpp")
file(GLOB upx_SOURCES "src/*.cpp" "src/util/*.cpp")
list(SORT upx_SOURCES)
add_executable(upx ${upx_SOURCES})
set_property(TARGET upx PROPERTY CXX_STANDARD 14)
@ -124,14 +124,14 @@ endif()
set(t upx_vendor_ucl)
target_include_directories(${t} PRIVATE vendor/ucl/include vendor/ucl)
if(MSVC)
target_compile_options(${t} PRIVATE -W4 ${warn_WX})
target_compile_options(${t} PRIVATE -J -W4 ${warn_WX})
else()
target_compile_options(${t} PRIVATE -Wall -Wextra -Wvla ${warn_Werror})
endif()
set(t upx_vendor_zlib)
if(MSVC)
target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_VSNPRINTF -W3 ${warn_WX})
target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_VSNPRINTF -J -W3 ${warn_WX})
else()
target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_UNISTD_H -DHAVE_VSNPRINTF)
target_compile_options(${t} PRIVATE -Wall -Wextra -Wvla ${warn_Werror})

View File

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

View File

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

View File

@ -25,7 +25,7 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#ifndef __UPX_BELE_H
#ifndef UPX_BELE_H__
#error "this is an internal include file"
#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 "compress.h"
#include "mem.h"
#include "util/membuffer.h"
/*************************************************************************

View File

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

View File

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

View File

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

View File

@ -25,9 +25,9 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#ifndef __UPX_CONF_H
#define __UPX_CONF_H 1
#pragma once
#ifndef UPX_CONF_H__
#define UPX_CONF_H__ 1
#if defined(__cplusplus)
# if (__cplusplus >= 201402L)
@ -356,7 +356,7 @@ template <class T>
inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; }
// An Array allocates memory on the heap, but automatically
// An Array allocates memory on the heap, and automatically
// gets destructed when leaving scope or on exceptions.
#define Array(type, var, size) \
MemBuffer var ## _membuf(mem_size(sizeof(type), size)); \
@ -397,6 +397,23 @@ constexpr bool string_ge(const char *a, const char *b) {
}
}
/*************************************************************************
// raw_bytes() - get underlying memory from checked buffers/pointers.
// This is overloaded by various utility classes like BoundedPtr,
// MemBuffer and Span.
//
// Note that the pointer type is retained, the "_bytes" hints size_in_bytes
**************************************************************************/
// default: for any regular pointer, raw_bytes() is just the pointer itself
template <class T>
inline T *raw_bytes(T *ptr, size_t size_in_bytes) {
if (size_in_bytes > 0) {
assert(ptr != nullptr);
}
return ptr;
}
/*************************************************************************
// constants
**************************************************************************/
@ -712,7 +729,7 @@ struct upx_compress_result_t
// globals
**************************************************************************/
#include "snprintf.h" // must get included first!
#include "util/snprintf.h" // must get included first!
#include <exception>
#include <new>
@ -722,19 +739,27 @@ struct upx_compress_result_t
#include "options.h"
#include "except.h"
#include "bele.h"
#include "util.h"
#include "console.h"
//#define DOCTEST_CONFIG_DISABLE
#include <doctest/parts/doctest_fwd.h>
#include "util/util.h"
// classes
class ElfLinker;
typedef ElfLinker Linker;
// dt_check.cpp
void upx_compiler_sanity_check(void);
bool upx_doctest_check(void);
// util/membuffer.h
class MemBuffer;
void *membuffer_get_void_ptr(MemBuffer &mb);
unsigned membuffer_get_size(MemBuffer &mb);
#include "util/xspan.h"
//#define DOCTEST_CONFIG_DISABLE
#include <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
extern const char *progname;
@ -754,7 +779,7 @@ void printWarn(const char *iname, const char *format, ...) attribute_format(2, 3
void infoWarning(const char *format, ...) attribute_format(1, 2);
void infoHeader(const char *format, ...) attribute_format(1, 2);
void info(const char *format, ...) attribute_format(1, 2);
void infoHeader(void);
void infoHeader();
void infoWriting(const char *what, long size);
// work.cpp
@ -763,10 +788,10 @@ int do_files(int i, int argc, char *argv[]);
// help.cpp
extern const char gitrev[];
void show_head(void);
void show_head();
void show_help(int verbose=0);
void show_license(void);
void show_usage(void);
void show_license();
void show_usage();
void show_version(int);
// compress.cpp

View File

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

View File

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

View File

@ -25,165 +25,110 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#ifndef __UPX_FILE_H
#define __UPX_FILE_H 1
class MemBuffer;
#pragma once
#ifndef UPX_FILE_H__
#define UPX_FILE_H__ 1
/*************************************************************************
//
**************************************************************************/
class File
{
protected:
File() { }
virtual ~File() { }
public:
static void chmod(const char *name, int mode);
static void rename(const char *old_, const char *new_);
static void unlink(const char *name);
};
class FileBase : public File
{
class FileBase {
protected:
FileBase();
virtual ~FileBase();
public:
virtual bool close();
virtual void closex();
virtual bool isOpen() const { return _fd >= 0; }
bool close();
void closex();
bool isOpen() const { return _fd >= 0; }
int getFd() const { return _fd; }
const char *getName() const { return _name; }
virtual upx_off_t seek(upx_off_t off, int whence);
upx_off_t tell() const;
virtual upx_off_t st_size() const; // { return _length; }
virtual void set_extent(upx_off_t offset, upx_off_t length);
public:
// static file-related util functions
static void chmod(const char *name, int mode);
static void rename(const char *old_, const char *new_);
static void unlink(const char *name);
protected:
bool do_sopen();
virtual int read(void *buf, int len);
virtual int readx(void *buf, int len);
virtual void write(const void *buf, int len);
virtual upx_off_t seek(upx_off_t off, int whence);
virtual upx_off_t tell() const;
int _fd = -1;
int _flags = 0;
int _shflags = 0;
int _mode = 0;
const char *_name = nullptr;
upx_off_t _offset = 0;
upx_off_t _length = 0;
int _fd;
int _flags;
int _shflags;
int _mode;
const char *_name;
upx_off_t _offset;
upx_off_t _length;
public:
struct stat st;
struct stat st = {};
};
/*************************************************************************
//
**************************************************************************/
class InputFile final : public FileBase
{
class InputFile final : public FileBase {
typedef FileBase super;
public:
InputFile();
virtual ~InputFile();
virtual ~InputFile() {}
virtual void sopen(const char *name, int flags, int shflags);
virtual void open(const char *name, int flags)
{
sopen(name, flags, -1);
}
void sopen(const char *name, int flags, int shflags);
void open(const char *name, int flags) { sopen(name, flags, -1); }
virtual int read(void *buf, int len) override;
virtual int readx(void *buf, int len) override;
virtual int read(MemBuffer *buf, int len);
virtual int readx(MemBuffer *buf, int len);
virtual int read(MemBuffer &buf, int len);
virtual int readx(MemBuffer &buf, int len);
int read(SPAN_P(void) buf, int len);
int readx(SPAN_P(void) buf, int len);
virtual upx_off_t seek(upx_off_t off, int whence) override;
virtual upx_off_t tell() const override;
virtual upx_off_t st_size_orig() const;
protected:
upx_off_t _length_orig;
};
upx_off_t st_size_orig() const;
protected:
upx_off_t _length_orig = 0;
};
/*************************************************************************
//
**************************************************************************/
class OutputFile final : public FileBase
{
class OutputFile final : public FileBase {
typedef FileBase super;
public:
OutputFile();
virtual ~OutputFile();
virtual ~OutputFile() {}
virtual void sopen(const char *name, int flags, int shflags, int mode);
virtual void open(const char *name, int flags, int mode)
{
sopen(name, flags, -1, mode);
}
virtual bool openStdout(int flags=0, bool force=false);
void sopen(const char *name, int flags, int shflags, int mode);
void open(const char *name, int flags, int mode) { sopen(name, flags, -1, mode); }
bool openStdout(int flags = 0, bool force = false);
virtual void write(const void *buf, int len) override;
virtual void write(const MemBuffer *buf, int len);
virtual void write(const MemBuffer &buf, int len);
// info: allow nullptr if len == 0
void write(SPAN_0(const void) buf, int len);
virtual upx_off_t seek(upx_off_t off, int whence) override;
virtual upx_off_t st_size() const override; // { return _length; }
virtual void set_extent(upx_off_t offset, upx_off_t length) override;
virtual upx_off_t unset_extent(); // returns actual length
upx_off_t unset_extent(); // returns actual length
upx_off_t getBytesWritten() const { return bytes_written; }
virtual upx_off_t st_size() const override; // { return _length; }
// FIXME - these won't work when using the '--stdout' option
virtual upx_off_t seek(upx_off_t off, int whence) override;
virtual upx_off_t tell() const override;
virtual void rewrite(const void *buf, int len);
void rewrite(SPAN_P(const void) buf, int len);
// util
static void dump(const char *name, const void *buf, int len, int flags=-1);
static void dump(const char *name, SPAN_P(const void) buf, int len, int flags = -1);
protected:
upx_off_t bytes_written;
upx_off_t bytes_written = 0;
};
/*************************************************************************
//
**************************************************************************/
#if 0 /* NOT USED */
class MemoryOutputFile : public FileBase
{
typedef FileBase super;
public:
MemoryOutputFile();
virtual ~MemoryOutputFile() { b = nullptr; }
virtual bool close() { b = nullptr; return true; }
virtual bool isOpen() const { return b != nullptr; }
virtual void open(void *buf, unsigned size)
{ b = (upx_bytep) buf; b_size = size; }
virtual void write(const void *buf, int len);
upx_off_t getBytesWritten() const { return bytes_written; }
protected:
upx_bytep b;
unsigned b_size;
unsigned b_pos;
upx_off_t bytes_written;
};
#endif /* if 0 */
#endif /* already included */
#endif
/* vim:set ts=4 sw=4 et: */

View File

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

View File

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

View File

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

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>
*/
#ifndef __UPX_OPTIONS_H
#define __UPX_OPTIONS_H 1
#pragma once
#ifndef UPX_OPTIONS_H__
#define UPX_OPTIONS_H__ 1
/*************************************************************************
// globals

View File

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

View File

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

View File

@ -1456,8 +1456,6 @@ static const
static const
#include "stub/armeb.v4a-linux.elf-fold.h"
#include "mem.h"
void
PackLinuxElf32armBe::buildLoader(Filter const *ft)
{
@ -4611,7 +4609,7 @@ void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
unsigned tmp = sz_pack2 + get_te32(&elfout.phdr[C_TEXT].p_vaddr);
tmp |= (Elf32_Ehdr::EM_ARM==e_machine); // THUMB mode
set_te32(&tmp, tmp);
fo->seek(ptr_udiff(&jni_onload_sym->st_value, file_image), SEEK_SET);
fo->seek(ptr_udiff_bytes(&jni_onload_sym->st_value, file_image), SEEK_SET);
fo->rewrite(&tmp, sizeof(tmp));
}
}

View File

@ -1529,7 +1529,7 @@ void PackMachBase<T>::unpack(OutputFile *fo)
if (is_bad_linker_command( ((Mach_command const *)ptr)->cmd, cmdsize,
headway, lc_seg, sizeof(Addr))) {
char msg[50]; snprintf(msg, sizeof(msg),
"bad packed Mach load_command @%#x", ptr_udiff(ptr, mhdr));
"bad packed Mach load_command @%#x", ptr_udiff_bytes(ptr, mhdr));
throwCantUnpack(msg);
}
memcpy(&msegcmd[j], ptr, umin(sizeof(Mach_segment_command), cmdsize));
@ -1905,7 +1905,7 @@ template <class T>
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);
ptr_udiff(secptr, segptr) < segptr->cmdsize;
ptr_udiff_bytes(secptr, segptr) < segptr->cmdsize;
++secptr
) {
if (sizeof(Addr) == secptr->size

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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.
#include <errno.h>

View File

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

View File

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

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>
*/
#include "conf.h"
#include "../conf.h"
/*************************************************************************
// UPX version of string functions, with assertions and sane limits

View File

@ -25,8 +25,9 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#ifndef __UPX_SNPRINTF_H
#define __UPX_SNPRINTF_H 1
#pragma once
#ifndef UPX_SNPRINTF_H__
#define UPX_SNPRINTF_H__ 1
/*************************************************************************
// UPX version of string functions, with assertions and sane limits
@ -35,11 +36,12 @@
// info: snprintf() returns length and NOT size, but max_size is indeed size (incl NUL)
int upx_safe_vsnprintf(char *str, upx_rsize_t max_size, const char *format, va_list ap);
int upx_safe_snprintf (char *str, upx_rsize_t max_size, const char *format, ...) attribute_format(3, 4);
int upx_safe_snprintf(char *str, upx_rsize_t max_size, const char *format, ...)
attribute_format(3, 4);
// malloc's *ptr
int upx_safe_vasprintf(char **ptr, const char *format, va_list ap);
int upx_safe_asprintf (char **ptr, const char *format, ...) attribute_format(2, 3);
int upx_safe_asprintf(char **ptr, const char *format, ...) attribute_format(2, 3);
// returns a malloc'd pointer
char *upx_safe_xprintf(const char *format, ...) attribute_format(1, 2);

View File

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

View File

@ -25,32 +25,72 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#ifndef __UPX_UTIL_H
#define __UPX_UTIL_H 1
#pragma once
#ifndef UPX_UTIL_H__
#define UPX_UTIL_H__ 1
/*************************************************************************
// protect against integer overflows and malicious header fields
// assert sane memory buffer sizes to protect against integer overflows
// and malicious header fields
// see C 11 standard, Annex K
**************************************************************************/
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0,
upx_uint64_t extra2 = 0);
upx_rsize_t mem_size_get_n(upx_uint64_t element_size, upx_uint64_t n);
inline void mem_size_assert(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0,
upx_uint64_t extra2 = 0) {
(void) mem_size(element_size, n, extra1, extra2); // sanity check
}
inline bool mem_size_valid_bytes(upx_uint64_t bytes) noexcept { return bytes <= UPX_RSIZE_MAX; }
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0,
upx_uint64_t extra2 = 0) noexcept;
// new with asserted size; will throw on failure
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
// will throw on invalid size
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
upx_uint64_t extra2 = 0);
bool mem_size_valid_bytes(upx_uint64_t bytes);
int ptr_diff(const void *p1, const void *p2);
unsigned ptr_udiff(const void *p1, const void *p2); // asserts p1 >= p2
// inline fast paths:
void mem_clear(void *p, size_t n);
// 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

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);
IGNORE_ERROR(r);
#endif
File::unlink(iname);
FileBase::unlink(iname);
} else {
// make backup
char bakname[ACC_FN_PATH_MAX + 1];
if (!makebakname(bakname, sizeof(bakname), iname))
throwIOException("could not create a backup file name");
File::rename(iname, bakname);
FileBase::rename(iname, bakname);
}
File::rename(oname, iname);
FileBase::rename(oname, iname);
}
// copy file attributes
@ -272,40 +272,40 @@ int do_files(int i, int argc, char *argv[]) {
if (opt->verbose >= 1 || (opt->verbose >= 0 && !e.isWarning()))
printErr(iname, &e);
main_set_exit_code(e.isWarning() ? EXIT_WARN : EXIT_ERROR);
// continue processing more files
// this is not fatal, continue processing more files
} catch (const Error &e) {
unlink_ofile(oname);
printErr(iname, &e);
main_set_exit_code(EXIT_ERROR);
return -1;
return -1; // fatal error
} catch (std::bad_alloc *e) {
unlink_ofile(oname);
printErr(iname, "out of memory");
UNUSED(e);
// delete e;
main_set_exit_code(EXIT_ERROR);
return -1;
return -1; // fatal error
} catch (const std::bad_alloc &) {
unlink_ofile(oname);
printErr(iname, "out of memory");
main_set_exit_code(EXIT_ERROR);
return -1;
return -1; // fatal error
} catch (std::exception *e) {
unlink_ofile(oname);
printUnhandledException(iname, e);
// delete e;
main_set_exit_code(EXIT_ERROR);
return -1;
return -1; // fatal error
} catch (const std::exception &e) {
unlink_ofile(oname);
printUnhandledException(iname, &e);
main_set_exit_code(EXIT_ERROR);
return -1;
return -1; // fatal error
} catch (...) {
unlink_ofile(oname);
printUnhandledException(iname, nullptr);
main_set_exit_code(EXIT_ERROR);
return -1;
return -1; // fatal error
}
}