mirror of
https://github.com/upx/upx.git
synced 2025-08-11 22:52:30 +08:00
all: more cleanups; NFCI
This commit is contained in:
@ -18,6 +18,8 @@ AttributeMacros:
|
|||||||
- __acc_noinline
|
- __acc_noinline
|
||||||
- __acc_static_noinline
|
- __acc_static_noinline
|
||||||
- __acc_static_forceinline
|
- __acc_static_forceinline
|
||||||
|
- forceinline
|
||||||
|
- noinline
|
||||||
EmptyLineBeforeAccessModifier: Leave
|
EmptyLineBeforeAccessModifier: Leave
|
||||||
SortIncludes: false
|
SortIncludes: false
|
||||||
SpaceAfterCStyleCast: true
|
SpaceAfterCStyleCast: true
|
||||||
|
45
.github/workflows/ci.yml
vendored
45
.github/workflows/ci.yml
vendored
@ -54,15 +54,15 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- { os: ubuntu-20.04, use_m32: false }
|
|
||||||
- { os: ubuntu-22.04, use_m32: true }
|
- { os: ubuntu-22.04, use_m32: true }
|
||||||
|
- { os: ubuntu-20.04, use_m32: false }
|
||||||
steps:
|
steps:
|
||||||
- name: 'Install extra 32-bit packages'
|
- name: 'Install extra 32-bit and Windows packages'
|
||||||
if: ${{ matrix.use_m32 }}
|
if: ${{ matrix.use_m32 }}
|
||||||
run: |
|
run: |
|
||||||
sudo dpkg --add-architecture i386
|
sudo dpkg --add-architecture i386
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y gcc-multilib g++-multilib
|
sudo apt-get install -y g++-multilib g++-mingw-w64-i686 g++-mingw-w64-x86-64
|
||||||
- name: 'Check out code'
|
- name: 'Check out code'
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with: { submodules: true }
|
with: { submodules: true }
|
||||||
@ -82,11 +82,17 @@ jobs:
|
|||||||
- name: 'Build cmake extra/gcc-m32/release'
|
- name: 'Build cmake extra/gcc-m32/release'
|
||||||
if: ${{ matrix.use_m32 }}
|
if: ${{ matrix.use_m32 }}
|
||||||
run: 'make build/extra/gcc-m32/release'
|
run: 'make build/extra/gcc-m32/release'
|
||||||
|
- name: 'Build cmake extra/cross-windows-mingw32/release'
|
||||||
|
if: ${{ matrix.use_m32 }}
|
||||||
|
run: 'make build/extra/cross-windows-mingw32/release'
|
||||||
|
- name: 'Build cmake extra/cross-windows-mingw64/release'
|
||||||
|
if: ${{ matrix.use_m32 }}
|
||||||
|
run: 'make build/extra/cross-windows-mingw64/release'
|
||||||
- name: 'Make artifact'
|
- name: 'Make artifact'
|
||||||
run: |
|
run: |
|
||||||
N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-${{ matrix.os }}
|
N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-${{ matrix.os }}
|
||||||
mkdir -p "tmp/artifact/$N"
|
mkdir -p "tmp/artifact/$N"
|
||||||
(cd build/extra && cp -ai --parents */*/upx "../../tmp/artifact/$N")
|
(cd build && shopt -s nullglob && cp -ai --parents */upx{,.exe} */*/*/upx{,.exe} "../tmp/artifact/$N")
|
||||||
(cd tmp/artifact && tar --sort=name -czf "$N.tar.gz" "$N" && rm -rf "./$N")
|
(cd tmp/artifact && tar --sort=name -czf "$N.tar.gz" "$N" && rm -rf "./$N")
|
||||||
# GitHub Actions magic: set "artifact_name" environment value for use in next step
|
# GitHub Actions magic: set "artifact_name" environment value for use in next step
|
||||||
echo "artifact_name=$N" >> $GITHUB_ENV
|
echo "artifact_name=$N" >> $GITHUB_ENV
|
||||||
@ -121,8 +127,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- { os: macos-11, gcc: gcc-10, gxx: 'g++-10', testsuite: true }
|
- { os: macos-11, gcc: gcc-10, gxx: 'g++-10', testsuite: true }
|
||||||
# { os: macos-12, gcc: gcc-11, gxx: 'g++-11', testsuite: true } # disable gcc - XCode 14.0.1 ld bug; supposed to be fixed in 14.1
|
- { os: macos-12, gcc: gcc-11, gxx: 'g++-11', testsuite: true }
|
||||||
- { os: macos-12, testsuite: true }
|
|
||||||
steps:
|
steps:
|
||||||
- name: 'Install brew packages'
|
- name: 'Install brew packages'
|
||||||
if: ${{ matrix.testsuite }}
|
if: ${{ matrix.testsuite }}
|
||||||
@ -145,11 +150,15 @@ jobs:
|
|||||||
- name: 'Build cmake extra/gcc/release'
|
- name: 'Build cmake extra/gcc/release'
|
||||||
if: ${{ matrix.gcc != '' }}
|
if: ${{ matrix.gcc != '' }}
|
||||||
run: 'make build/extra/gcc/release CC=${{ matrix.gcc }} CXX=${{ matrix.gxx }}'
|
run: 'make build/extra/gcc/release CC=${{ matrix.gcc }} CXX=${{ matrix.gxx }}'
|
||||||
|
- name: 'Build cmake xtarget/cross-darwin-arm64/release'
|
||||||
|
run: |
|
||||||
|
export CC="clang -target arm64-apple-darwin" CXX="clang++ -target arm64-apple-darwin"
|
||||||
|
make UPX_XTARGET=cross-darwin-arm64
|
||||||
- name: 'Make artifact'
|
- name: 'Make artifact'
|
||||||
run: |
|
run: |
|
||||||
N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-${{ matrix.os }}
|
N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-${{ matrix.os }}
|
||||||
mkdir -p "tmp/artifact/$N"
|
mkdir -p "tmp/artifact/$N"
|
||||||
(cd build/extra && rsync -R -a */*/upx "../../tmp/artifact/$N/")
|
(cd build && rsync -R -a */*/*/upx "../tmp/artifact/$N/")
|
||||||
(cd tmp/artifact && gtar --sort=name -czf "$N.tar.gz" "$N" && rm -rf "./$N")
|
(cd tmp/artifact && gtar --sort=name -czf "$N.tar.gz" "$N" && rm -rf "./$N")
|
||||||
# GitHub Actions magic: set "artifact_name" environment value for use in next step
|
# GitHub Actions magic: set "artifact_name" environment value for use in next step
|
||||||
echo "artifact_name=$N" >> $GITHUB_ENV
|
echo "artifact_name=$N" >> $GITHUB_ENV
|
||||||
@ -325,14 +334,17 @@ jobs:
|
|||||||
needs: [ job-rebuild-and-verify-stubs ]
|
needs: [ job-rebuild-and-verify-stubs ]
|
||||||
name: ${{ format('zigcc {0} {1}', matrix.zig_target, matrix.zig_pic) }}
|
name: ${{ format('zigcc {0} {1}', matrix.zig_target, matrix.zig_pic) }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
##container: alpine:3.17 # older versions such as alpine:3.12 also work; no-container also works
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
- { zig_target: aarch64-linux-musl }
|
||||||
- { zig_target: aarch64-macos.11-none }
|
- { zig_target: aarch64-macos.11-none }
|
||||||
- { zig_target: aarch64-macos.12-none }
|
- { zig_target: aarch64-macos.12-none }
|
||||||
- { zig_target: aarch64-macos.13-none }
|
- { zig_target: aarch64-macos.13-none }
|
||||||
- { zig_target: aarch64-windows-gnu }
|
- { zig_target: aarch64-windows-gnu }
|
||||||
|
- { zig_target: i386-linux-musl }
|
||||||
- { zig_target: i386-windows-gnu }
|
- { zig_target: i386-windows-gnu }
|
||||||
- { zig_target: x86_64-linux-musl }
|
- { zig_target: x86_64-linux-musl }
|
||||||
- { zig_target: x86_64-linux-musl, zig_pic: -fPIE }
|
- { zig_target: x86_64-linux-musl, zig_pic: -fPIE }
|
||||||
@ -341,18 +353,28 @@ jobs:
|
|||||||
- { zig_target: x86_64-macos.13-none }
|
- { zig_target: x86_64-macos.13-none }
|
||||||
- { zig_target: x86_64-windows-gnu }
|
- { zig_target: x86_64-windows-gnu }
|
||||||
env:
|
env:
|
||||||
# 2023-01-22
|
# 2023-01-24
|
||||||
ZIG_DIST_VERSION: 0.11.0-dev.1413+a51c76541
|
ZIG_DIST_VERSION: 0.11.0-dev.1436+59d9afcb5
|
||||||
# for zig-cc wrapper scripts (see below):
|
# for zig-cc wrapper scripts (see below):
|
||||||
ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING
|
ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING
|
||||||
ZIG_FLAGS: ${{ matrix.zig_flags }}
|
ZIG_FLAGS: ${{ matrix.zig_flags }}
|
||||||
ZIG_PIC: ${{ matrix.zig_pic }}
|
ZIG_PIC: ${{ matrix.zig_pic }}
|
||||||
ZIG_TARGET: ${{ matrix.zig_target }}
|
ZIG_TARGET: ${{ matrix.zig_target }}
|
||||||
steps:
|
steps:
|
||||||
|
- name: 'Install Alpine packages'
|
||||||
|
if: ${{ job.container }}
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
apk update && apk upgrade && apk add bash cmake file git make tar xz
|
||||||
|
# set PATH like in Ubuntu
|
||||||
|
echo "PATH=$HOME/.local/bin:$PATH" >> $GITHUB_ENV
|
||||||
|
# this seems to be needed when running in a container (beause of UID mismatch??)
|
||||||
|
git config --global --add safe.directory '*'
|
||||||
- name: 'Check out code'
|
- name: 'Check out code'
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with: { submodules: true }
|
with: { submodules: true }
|
||||||
- name: ${{ format('Install Zig {0}', env.ZIG_DIST_VERSION) }}
|
- name: ${{ format('Install Zig {0}', env.ZIG_DIST_VERSION) }}
|
||||||
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
# GitHub Actions magic: set "UPX_GITREV_SHORT" environment value for use in steps below
|
# GitHub Actions magic: set "UPX_GITREV_SHORT" environment value for use in steps below
|
||||||
rev=$(git rev-parse --short=7 HEAD)
|
rev=$(git rev-parse --short=7 HEAD)
|
||||||
@ -392,11 +414,12 @@ jobs:
|
|||||||
cmake ../../../.. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_AR=$HOME/.local/bin/zig-ar -DCMAKE_C_COMPILER=zig-cc -DCMAKE_CXX_COMPILER=zig-cxx -DCMAKE_RANLIB=$HOME/.local/bin/zig-ranlib $EXTRA_CMAKE_CONFIG_FLAGS_DEBUG
|
cmake ../../../.. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_AR=$HOME/.local/bin/zig-ar -DCMAKE_C_COMPILER=zig-cc -DCMAKE_CXX_COMPILER=zig-cxx -DCMAKE_RANLIB=$HOME/.local/bin/zig-ranlib $EXTRA_CMAKE_CONFIG_FLAGS_DEBUG
|
||||||
cmake --build . --config Debug --parallel --verbose
|
cmake --build . --config Debug --parallel --verbose
|
||||||
file ./upx*
|
file ./upx*
|
||||||
- name: ${{ format('Make artifact from upx-{0}-{1}', env.GITHUB_REF_NAME, env.UPX_GITREV_SHORT) }}
|
- name: ${{ format('Make artifact from upx-{0}-{1}', github.ref_name, env.UPX_GITREV_SHORT) }}
|
||||||
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-zigcc-${{ matrix.zig_target }}${ZIG_PIC}
|
N=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-zigcc-${{ matrix.zig_target }}${ZIG_PIC}
|
||||||
mkdir -p "tmp/artifact/$N"
|
mkdir -p "tmp/artifact/$N"
|
||||||
(cd build && shopt -s nullglob && cp -ai --parents */upx* zig/*/*/upx* "../tmp/artifact/$N")
|
(cd build && shopt -s nullglob && cp -ai --parents */upx{,.exe} */*/*/upx{,.exe} "../tmp/artifact/$N")
|
||||||
(cd tmp/artifact && tar --sort=name -czf "$N.tar.gz" "$N" && rm -rf "./$N")
|
(cd tmp/artifact && tar --sort=name -czf "$N.tar.gz" "$N" && rm -rf "./$N")
|
||||||
# GitHub Actions magic: set "artifact_name" environment value for use in next step
|
# GitHub Actions magic: set "artifact_name" environment value for use in next step
|
||||||
echo "artifact_name=$N" >> $GITHUB_ENV
|
echo "artifact_name=$N" >> $GITHUB_ENV
|
||||||
|
33
Makefile
33
Makefile
@ -8,7 +8,7 @@
|
|||||||
# mkdir -p build/release
|
# mkdir -p build/release
|
||||||
# cd build/release
|
# cd build/release
|
||||||
# cmake ../..
|
# cmake ../..
|
||||||
# cmake --build .
|
# cmake --build . --parallel # (or just use "make -j" instead)
|
||||||
|
|
||||||
CMAKE = cmake
|
CMAKE = cmake
|
||||||
UPX_CMAKE_BUILD_FLAGS += --parallel
|
UPX_CMAKE_BUILD_FLAGS += --parallel
|
||||||
@ -44,6 +44,7 @@ release: build/release
|
|||||||
|
|
||||||
.PHONY: PHONY
|
.PHONY: PHONY
|
||||||
.NOTPARALLEL: # because the actual builds use "cmake --parallel"
|
.NOTPARALLEL: # because the actual builds use "cmake --parallel"
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
# extra builds: some pre-defined build configurations
|
# extra builds: some pre-defined build configurations
|
||||||
@ -133,18 +134,42 @@ build/extra/cross-windows-mingw64/release: PHONY; $(call run_config_and_build,$@
|
|||||||
build/extra/cross-windows-mingw64/%: export CC = x86_64-w64-mingw32-gcc
|
build/extra/cross-windows-mingw64/%: export CC = x86_64-w64-mingw32-gcc
|
||||||
build/extra/cross-windows-mingw64/%: export CXX = x86_64-w64-mingw32-g++
|
build/extra/cross-windows-mingw64/%: export CXX = x86_64-w64-mingw32-g++
|
||||||
|
|
||||||
# advanced: generic eXtra target; usage:
|
# cross compiler: macOS arm64
|
||||||
|
build/extra/cross-darwin-arm64/debug: PHONY; $(call run_config_and_build,$@,Debug)
|
||||||
|
build/extra/cross-darwin-arm64/release: PHONY; $(call run_config_and_build,$@,Release)
|
||||||
|
build/extra/cross-darwin-arm64/%: export CC = clang -target arm64-apple-darwin
|
||||||
|
build/extra/cross-darwin-arm64/%: export CXX = clang++ -target arm64-apple-darwin
|
||||||
|
|
||||||
|
# cross compiler: macOS x86_64
|
||||||
|
build/extra/cross-darwin-x86_64/debug: PHONY; $(call run_config_and_build,$@,Debug)
|
||||||
|
build/extra/cross-darwin-x86_64/release: PHONY; $(call run_config_and_build,$@,Release)
|
||||||
|
build/extra/cross-darwin-x86_64/%: export CC = clang -target x86_64-apple-darwin
|
||||||
|
build/extra/cross-darwin-x86_64/%: export CXX = clang++ -target x86_64-apple-darwin
|
||||||
|
|
||||||
|
#***********************************************************************
|
||||||
|
# advanced: generic eXtra target
|
||||||
|
#***********************************************************************
|
||||||
|
|
||||||
|
# usage:
|
||||||
# make UPX_XTARGET=mytarget CC="my-cc -flags" CXX="my-cxx -flags"
|
# make UPX_XTARGET=mytarget CC="my-cc -flags" CXX="my-cxx -flags"
|
||||||
# make UPX_XTARGET=mytarget CC="my-cc -flags" CXX="my-cxx -flags" build/xtarget/mytarget/debug
|
# make UPX_XTARGET=mytarget CC="my-cc -flags" CXX="my-cxx -flags" xtarget/debug
|
||||||
|
|
||||||
ifneq ($(UPX_XTARGET),)
|
ifneq ($(UPX_XTARGET),)
|
||||||
ifneq ($(CC),)
|
ifneq ($(CC),)
|
||||||
ifneq ($(CXX),)
|
ifneq ($(CXX),)
|
||||||
|
|
||||||
UPX_XTARGET := $(UPX_XTARGET)
|
UPX_XTARGET := $(UPX_XTARGET)
|
||||||
$(eval .DEFAULT_GOAL = build/xtarget/$(UPX_XTARGET)/release)
|
|
||||||
build/xtarget/$(UPX_XTARGET)/debug: PHONY; $(call run_config_and_build,$@,Debug)
|
build/xtarget/$(UPX_XTARGET)/debug: PHONY; $(call run_config_and_build,$@,Debug)
|
||||||
build/xtarget/$(UPX_XTARGET)/release: PHONY; $(call run_config_and_build,$@,Release)
|
build/xtarget/$(UPX_XTARGET)/release: PHONY; $(call run_config_and_build,$@,Release)
|
||||||
build/xtarget/$(UPX_XTARGET)/%: export CC
|
build/xtarget/$(UPX_XTARGET)/%: export CC
|
||||||
build/xtarget/$(UPX_XTARGET)/%: export CXX
|
build/xtarget/$(UPX_XTARGET)/%: export CXX
|
||||||
|
# shortcuts
|
||||||
|
xtarget/debug: build/xtarget/$(UPX_XTARGET)/debug
|
||||||
|
xtarget/release: build/xtarget/$(UPX_XTARGET)/release
|
||||||
|
# set new default
|
||||||
|
.DEFAULT_GOAL = xtarget/release
|
||||||
|
##$(eval .DEFAULT_GOAL = build/xtarget/$(UPX_XTARGET)/release)
|
||||||
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
49
src/bele.h
49
src/bele.h
@ -38,35 +38,35 @@
|
|||||||
// core - NE
|
// core - NE
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
__acc_static_forceinline unsigned get_ne16(const void *p) {
|
static forceinline unsigned get_ne16(const void *p) {
|
||||||
upx_uint16_t v = 0;
|
upx_uint16_t v = 0;
|
||||||
upx_memcpy_inline(&v, p, sizeof(v));
|
upx_memcpy_inline(&v, p, sizeof(v));
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
__acc_static_forceinline unsigned get_ne32(const void *p) {
|
static forceinline unsigned get_ne32(const void *p) {
|
||||||
upx_uint32_t v = 0;
|
upx_uint32_t v = 0;
|
||||||
upx_memcpy_inline(&v, p, sizeof(v));
|
upx_memcpy_inline(&v, p, sizeof(v));
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
__acc_static_forceinline upx_uint64_t get_ne64(const void *p) {
|
static forceinline upx_uint64_t get_ne64(const void *p) {
|
||||||
upx_uint64_t v = 0;
|
upx_uint64_t v = 0;
|
||||||
upx_memcpy_inline(&v, p, sizeof(v));
|
upx_memcpy_inline(&v, p, sizeof(v));
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
__acc_static_forceinline void set_ne16(void *p, unsigned vv) {
|
static forceinline void set_ne16(void *p, unsigned vv) {
|
||||||
upx_uint16_t v = (upx_uint16_t) (vv & 0xffff);
|
upx_uint16_t v = (upx_uint16_t) (vv & 0xffff);
|
||||||
upx_memcpy_inline(p, &v, sizeof(v));
|
upx_memcpy_inline(p, &v, sizeof(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
__acc_static_forceinline void set_ne32(void *p, unsigned vv) {
|
static forceinline void set_ne32(void *p, unsigned vv) {
|
||||||
upx_uint32_t v = vv;
|
upx_uint32_t v = vv;
|
||||||
upx_memcpy_inline(p, &v, sizeof(v));
|
upx_memcpy_inline(p, &v, sizeof(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
__acc_static_forceinline void set_ne64(void *p, upx_uint64_t vv) {
|
static forceinline void set_ne64(void *p, upx_uint64_t vv) {
|
||||||
upx_uint64_t v = vv;
|
upx_uint64_t v = vv;
|
||||||
upx_memcpy_inline(p, &v, sizeof(v));
|
upx_memcpy_inline(p, &v, sizeof(v));
|
||||||
}
|
}
|
||||||
@ -79,34 +79,31 @@ __acc_static_forceinline void set_ne64(void *p, upx_uint64_t vv) {
|
|||||||
|
|
||||||
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)
|
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)
|
||||||
|
|
||||||
__acc_static_forceinline unsigned bswap16(unsigned v) {
|
// unfortunately *not* constexpr with MSVC
|
||||||
return (unsigned) _byteswap_ulong(v << 16);
|
static forceinline unsigned bswap16(unsigned v) { return (unsigned) _byteswap_ulong(v << 16); }
|
||||||
}
|
static forceinline unsigned bswap32(unsigned v) { return (unsigned) _byteswap_ulong(v); }
|
||||||
__acc_static_forceinline unsigned bswap32(unsigned v) { return (unsigned) _byteswap_ulong(v); }
|
static forceinline upx_uint64_t bswap64(upx_uint64_t v) { return _byteswap_uint64(v); }
|
||||||
__acc_static_forceinline upx_uint64_t bswap64(upx_uint64_t v) { return _byteswap_uint64(v); }
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
__acc_static_forceinline constexpr unsigned bswap16(unsigned v) {
|
static forceinline constexpr unsigned bswap16(unsigned v) {
|
||||||
// return __builtin_bswap16((upx_uint16_t) (v & 0xffff));
|
// return __builtin_bswap16((upx_uint16_t) (v & 0xffff));
|
||||||
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48);
|
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48);
|
||||||
return __builtin_bswap32(v << 16);
|
return __builtin_bswap32(v << 16);
|
||||||
}
|
}
|
||||||
__acc_static_forceinline constexpr unsigned bswap32(unsigned v) {
|
static forceinline constexpr unsigned bswap32(unsigned v) {
|
||||||
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 32);
|
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 32);
|
||||||
return __builtin_bswap32(v);
|
return __builtin_bswap32(v);
|
||||||
}
|
}
|
||||||
__acc_static_forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) {
|
static forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) { return __builtin_bswap64(v); }
|
||||||
return __builtin_bswap64(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__acc_static_forceinline constexpr unsigned no_bswap16(unsigned v) {
|
static forceinline constexpr unsigned no_bswap16(unsigned v) {
|
||||||
return v & 0xffff; // needed so that this is equivalent to bswap16() above
|
return v & 0xffff; // needed so that this is equivalent to bswap16() above
|
||||||
}
|
}
|
||||||
__acc_static_forceinline constexpr unsigned no_bswap32(unsigned v) { return v; }
|
static forceinline constexpr unsigned no_bswap32(unsigned v) { return v; }
|
||||||
__acc_static_forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) { return v; }
|
static forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) { return v; }
|
||||||
|
|
||||||
#if (ACC_ABI_BIG_ENDIAN)
|
#if (ACC_ABI_BIG_ENDIAN)
|
||||||
#define ne16_to_be16(v) no_bswap16(v)
|
#define ne16_to_be16(v) no_bswap16(v)
|
||||||
@ -186,14 +183,14 @@ inline void set_le26(void *p, unsigned v) {
|
|||||||
// get signed values
|
// get signed values
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
__acc_static_forceinline int sign_extend(unsigned v, unsigned bits) {
|
static forceinline int sign_extend(unsigned v, unsigned bits) {
|
||||||
const unsigned sign_bit = 1u << (bits - 1);
|
const unsigned sign_bit = 1u << (bits - 1);
|
||||||
v &= sign_bit | (sign_bit - 1);
|
v &= sign_bit | (sign_bit - 1);
|
||||||
v |= 0 - (v & sign_bit);
|
v |= 0 - (v & sign_bit);
|
||||||
return ACC_ICAST(int, v);
|
return ACC_ICAST(int, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
__acc_static_forceinline upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) {
|
static forceinline upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) {
|
||||||
const upx_uint64_t sign_bit = 1ull << (bits - 1);
|
const upx_uint64_t sign_bit = 1ull << (bits - 1);
|
||||||
v &= sign_bit | (sign_bit - 1);
|
v &= sign_bit | (sign_bit - 1);
|
||||||
v |= 0 - (v & sign_bit);
|
v |= 0 - (v & sign_bit);
|
||||||
@ -599,15 +596,15 @@ inline T *operator-(T *ptr, const LE32 &v) {
|
|||||||
return ptr - unsigned(v);
|
return ptr - unsigned(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// these are not implemented on purpose and will cause link-time errors
|
// these are not implemented on purpose and will cause errors
|
||||||
template <class T>
|
template <class T>
|
||||||
T *operator+(T *ptr, const BE64 &v);
|
T *operator+(T *ptr, const BE64 &v) DELETED_FUNCTION;
|
||||||
template <class T>
|
template <class T>
|
||||||
T *operator-(T *ptr, const BE64 &v);
|
T *operator-(T *ptr, const BE64 &v) DELETED_FUNCTION;
|
||||||
template <class T>
|
template <class T>
|
||||||
T *operator+(T *ptr, const LE64 &v);
|
T *operator+(T *ptr, const LE64 &v) DELETED_FUNCTION;
|
||||||
template <class T>
|
template <class T>
|
||||||
T *operator-(T *ptr, const LE64 &v);
|
T *operator-(T *ptr, const LE64 &v) DELETED_FUNCTION;
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
// global overloads
|
// global overloads
|
||||||
|
@ -29,7 +29,34 @@
|
|||||||
#include "../conf.h"
|
#include "../conf.h"
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
// basic
|
// raw_bytes
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
TEST_CASE("raw_bytes ptr") {
|
||||||
|
upx_uint32_t *ptr = nullptr;
|
||||||
|
CHECK_NOTHROW(raw_bytes(ptr, 0));
|
||||||
|
CHECK_THROWS(raw_bytes(ptr, 1));
|
||||||
|
CHECK_THROWS(raw_index_bytes(ptr, 0, 0));
|
||||||
|
CHECK_THROWS(raw_index_bytes(ptr, 1, 0));
|
||||||
|
CHECK_THROWS(raw_index_bytes(ptr, 0, 1));
|
||||||
|
upx_uint32_t buf[4];
|
||||||
|
ptr = buf;
|
||||||
|
CHECK(ptr_udiff_bytes(raw_index_bytes(ptr, 1, 1), ptr) == 4u);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("raw_bytes bounded array") {
|
||||||
|
upx_uint32_t buf[4];
|
||||||
|
CHECK_NOTHROW(raw_bytes(buf, 16));
|
||||||
|
CHECK_THROWS(raw_bytes(buf, 17));
|
||||||
|
CHECK_NOTHROW(raw_index_bytes(buf, 4, 0));
|
||||||
|
CHECK_THROWS(raw_index_bytes(buf, 4, 1));
|
||||||
|
CHECK_NOTHROW(raw_index_bytes(buf, 3, 4));
|
||||||
|
CHECK_THROWS(raw_index_bytes(buf, 3, 5));
|
||||||
|
CHECK(ptr_udiff_bytes(raw_index_bytes(buf, 1, 1), buf) == 4u);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
// basic xspan
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
TEST_CASE("basic xspan usage") {
|
TEST_CASE("basic xspan usage") {
|
||||||
|
82
src/conf.h
82
src/conf.h
@ -149,6 +149,12 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
|
|||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
// <type_traits> C++20 std::is_bounded_array
|
||||||
|
template <class T>
|
||||||
|
struct std_is_bounded_array : public std::false_type {};
|
||||||
|
template <class T, size_t N>
|
||||||
|
struct std_is_bounded_array<T[N]> : public std::true_type {};
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
// core
|
// core
|
||||||
@ -185,6 +191,24 @@ typedef upx_int64_t upx_off_t;
|
|||||||
#define off_t upx_off_t
|
#define off_t upx_off_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// shortcuts
|
||||||
|
#define forceinline __acc_forceinline
|
||||||
|
#if _MSC_VER
|
||||||
|
#define noinline __declspec(noinline)
|
||||||
|
#undef __acc_noinline
|
||||||
|
#define __acc_noinline noinline
|
||||||
|
#else
|
||||||
|
#define noinline __acc_noinline
|
||||||
|
#endif
|
||||||
|
#define likely __acc_likely
|
||||||
|
#define unlikely __acc_unlikely
|
||||||
|
#define very_likely __acc_very_likely
|
||||||
|
#define very_unlikely __acc_very_unlikely
|
||||||
|
|
||||||
|
#define COMPILE_TIME_ASSERT(e) ACC_COMPILE_TIME_ASSERT(e)
|
||||||
|
#define DELETED_FUNCTION = delete
|
||||||
|
#define UNUSED(var) ACC_UNUSED(var)
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
// portab
|
// portab
|
||||||
@ -341,19 +365,16 @@ inline void NO_fprintf(FILE *, const char *, ...) {}
|
|||||||
# define upx_return_address() nullptr
|
# define upx_return_address() nullptr
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define UNUSED(var) ACC_UNUSED(var)
|
|
||||||
#define COMPILE_TIME_ASSERT(e) ACC_COMPILE_TIME_ASSERT(e)
|
|
||||||
|
|
||||||
// TODO cleanup: we now require C++14, so remove all __packed_struct usage
|
// TODO cleanup: we now require C++14, so remove all __packed_struct usage
|
||||||
#define __packed_struct(s) struct alignas(1) s {
|
#define __packed_struct(s) struct alignas(1) s {
|
||||||
#define __packed_struct_end() };
|
#define __packed_struct_end() };
|
||||||
|
|
||||||
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
|
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
|
||||||
// horrible hack for broken compiler
|
// horrible hack for broken compiler
|
||||||
#define upx_alignas_1 __attribute__((__aligned__(1),__packed__))
|
#define upx_fake_alignas_1 __attribute__((__aligned__(1),__packed__))
|
||||||
#define upx_alignas_16 __attribute__((__aligned__(2))) // object file maximum 2 ???
|
#define upx_fake_alignas_16 __attribute__((__aligned__(2))) // object file maximum 2 ???
|
||||||
#define upx_alignas__(a) upx_alignas_ ## a
|
#define upx_fake_alignas__(a) upx_fake_alignas_ ## a
|
||||||
#define alignas(x) upx_alignas__(x)
|
#define alignas(x) upx_fake_alignas__(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define COMPILE_TIME_ASSERT_ALIGNOF_USING_SIZEOF__(a,b) { \
|
#define COMPILE_TIME_ASSERT_ALIGNOF_USING_SIZEOF__(a,b) { \
|
||||||
@ -385,7 +406,7 @@ inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b;
|
|||||||
|
|
||||||
template <size_t TypeSize>
|
template <size_t TypeSize>
|
||||||
struct USizeOfTypeImpl {
|
struct USizeOfTypeImpl {
|
||||||
__acc_static_forceinline constexpr unsigned value() {
|
static forceinline constexpr unsigned value() {
|
||||||
COMPILE_TIME_ASSERT(TypeSize >= 1 && TypeSize <= 64 * 1024); // arbitrary limit
|
COMPILE_TIME_ASSERT(TypeSize >= 1 && TypeSize <= 64 * 1024); // arbitrary limit
|
||||||
return ACC_ICONV(unsigned, TypeSize);
|
return ACC_ICONV(unsigned, TypeSize);
|
||||||
}
|
}
|
||||||
@ -408,8 +429,10 @@ protected:
|
|||||||
inline noncopyable() {}
|
inline noncopyable() {}
|
||||||
inline ~noncopyable() {}
|
inline ~noncopyable() {}
|
||||||
private:
|
private:
|
||||||
noncopyable(const noncopyable &); // undefined
|
noncopyable(const noncopyable &) DELETED_FUNCTION; // copy constuctor
|
||||||
const noncopyable& operator=(const noncopyable &); // undefined
|
noncopyable& operator=(const noncopyable &) DELETED_FUNCTION; // copy assignment
|
||||||
|
noncopyable(noncopyable &&) DELETED_FUNCTION; // move constructor
|
||||||
|
noncopyable& operator=(noncopyable &&) DELETED_FUNCTION; // move assignment
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -630,25 +653,26 @@ struct OptVar
|
|||||||
assertValue(v);
|
assertValue(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
OptVar() : v(default_value), is_set(0) { }
|
OptVar() : v(default_value), is_set(false) { }
|
||||||
OptVar& operator= (const T &other) {
|
OptVar& operator= (const T &other) {
|
||||||
v = other; is_set = 1;
|
assertValue(other);
|
||||||
assertValue();
|
v = other;
|
||||||
|
is_set = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() { v = default_value; is_set = 0; }
|
void reset() { v = default_value; is_set = false; }
|
||||||
operator T () const { return v; }
|
operator T () const { return v; }
|
||||||
|
|
||||||
T v;
|
T v;
|
||||||
unsigned is_set;
|
bool is_set;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// optional assignments
|
// optional assignments
|
||||||
template <class T, T a, T b, T c>
|
template <class T, T a, T b, T c>
|
||||||
inline void oassign(OptVar<T,a,b,c> &self, const OptVar<T,a,b,c> &other) {
|
inline void oassign(OptVar<T,a,b,c> &self, const OptVar<T,a,b,c> &other) {
|
||||||
if (other.is_set) { self.v = other.v; self.is_set = 1; }
|
if (other.is_set) { self.v = other.v; self.is_set = true; }
|
||||||
}
|
}
|
||||||
template <class T, T a, T b, T c>
|
template <class T, T a, T b, T c>
|
||||||
inline void oassign(T &v, const OptVar<T,a,b,c> &other) {
|
inline void oassign(T &v, const OptVar<T,a,b,c> &other) {
|
||||||
@ -855,32 +879,6 @@ int upx_test_overlap ( const upx_bytep buf,
|
|||||||
const upx_compress_result_t *cresult );
|
const upx_compress_result_t *cresult );
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
// 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) {
|
|
||||||
if __acc_very_unlikely (ptr == nullptr)
|
|
||||||
throwInternalError("raw_bytes unexpected NULL ptr");
|
|
||||||
}
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// default: for any regular pointer, raw_index_bytes() is just "pointer + index"
|
|
||||||
// NOTE: index == number of elements, *NOT* size in bytes!
|
|
||||||
template <class T>
|
|
||||||
inline T *raw_index_bytes(T *ptr, size_t index, size_t size_in_bytes) {
|
|
||||||
typedef T element_type;
|
|
||||||
return raw_bytes(ptr, mem_size(sizeof(element_type), index, size_in_bytes)) + index;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (ACC_OS_CYGWIN || ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_EMX || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64)
|
#if (ACC_OS_CYGWIN || ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_EMX || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64)
|
||||||
# if defined(INVALID_HANDLE_VALUE) || defined(MAKEWORD) || defined(RT_CURSOR)
|
# if defined(INVALID_HANDLE_VALUE) || defined(MAKEWORD) || defined(RT_CURSOR)
|
||||||
# error "something pulled in <windows.h>"
|
# error "something pulled in <windows.h>"
|
||||||
|
@ -109,14 +109,14 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void checkNULL() const {
|
void checkNULL() const {
|
||||||
if __acc_very_unlikely (!ptr_)
|
if very_unlikely (!ptr_)
|
||||||
throwCantUnpack("unexpected NULL pointer; take care!");
|
throwCantUnpack("unexpected NULL pointer; take care!");
|
||||||
}
|
}
|
||||||
__acc_forceinline void checkRange() const { checkRange(ptr_, base_, size_in_bytes_); }
|
forceinline void checkRange() const { checkRange(ptr_, base_, size_in_bytes_); }
|
||||||
__acc_forceinline void checkRange(const void *p) const { checkRange(p, base_, size_in_bytes_); }
|
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) {
|
static void checkRange(const void *ptr, const void *base, size_t size_in_bytes) {
|
||||||
size_t off = (const char *) ptr - (const char *) base;
|
size_t off = (const char *) ptr - (const char *) base;
|
||||||
if __acc_very_unlikely (off > size_in_bytes)
|
if very_unlikely (off > size_in_bytes)
|
||||||
throwCantUnpack("pointer out of range; take care!");
|
throwCantUnpack("pointer out of range; take care!");
|
||||||
}
|
}
|
||||||
void check() const { // check ptr_ invariant: either NULL or valid checkRange()
|
void check() const { // check ptr_ invariant: either NULL or valid checkRange()
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
void *membuffer_get_void_ptr(MemBuffer &mb) { return mb.getVoidPtr(); }
|
void *membuffer_get_void_ptr(MemBuffer &mb) { return mb.getVoidPtr(); }
|
||||||
unsigned membuffer_get_size(MemBuffer &mb) { return mb.getSize(); }
|
unsigned membuffer_get_size(MemBuffer &mb) { return mb.getSize(); }
|
||||||
|
|
||||||
MemBuffer::Stats MemBuffer::stats;
|
/*static*/ MemBuffer::Stats MemBuffer::stats;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
#define debug_set(var, expr) (var) = (expr)
|
#define debug_set(var, expr) (var) = (expr)
|
||||||
@ -45,23 +45,23 @@ MemBuffer::Stats MemBuffer::stats;
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#if defined(__SANITIZE_ADDRESS__)
|
#if defined(__SANITIZE_ADDRESS__)
|
||||||
__acc_static_forceinline constexpr bool use_simple_mcheck() { return false; }
|
static forceinline constexpr bool use_simple_mcheck() { return false; }
|
||||||
#elif (WITH_VALGRIND) && defined(RUNNING_ON_VALGRIND)
|
#elif (WITH_VALGRIND) && defined(RUNNING_ON_VALGRIND)
|
||||||
static int use_simple_mcheck_flag = -1;
|
static int use_simple_mcheck_flag = -1;
|
||||||
__acc_static_noinline void use_simple_mcheck_init() {
|
static noinline void use_simple_mcheck_init() {
|
||||||
use_simple_mcheck_flag = 1;
|
use_simple_mcheck_flag = 1;
|
||||||
if (RUNNING_ON_VALGRIND) {
|
if (RUNNING_ON_VALGRIND) {
|
||||||
use_simple_mcheck_flag = 0;
|
use_simple_mcheck_flag = 0;
|
||||||
// fprintf(stderr, "upx: detected RUNNING_ON_VALGRIND\n");
|
// fprintf(stderr, "upx: detected RUNNING_ON_VALGRIND\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__acc_static_forceinline bool use_simple_mcheck() {
|
static forceinline bool use_simple_mcheck() {
|
||||||
if __acc_unlikely (use_simple_mcheck_flag < 0)
|
if very_unlikely (use_simple_mcheck_flag < 0)
|
||||||
use_simple_mcheck_init();
|
use_simple_mcheck_init();
|
||||||
return (bool) use_simple_mcheck_flag;
|
return (bool) use_simple_mcheck_flag;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
__acc_static_forceinline constexpr bool use_simple_mcheck() { return true; }
|
static forceinline constexpr bool use_simple_mcheck() { return true; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
@ -119,12 +119,14 @@ static unsigned width(unsigned x) {
|
|||||||
static inline 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) {
|
||||||
unsigned const z = uncompressed_size; // fewer keystrokes and display columns
|
if (uncompressed_size == 0)
|
||||||
unsigned const w = umax(8, width(z - 1)); // ignore tiny offsets
|
throwCantPack("invalid uncompressed_size");
|
||||||
|
const unsigned z = uncompressed_size; // fewer keystrokes and display columns
|
||||||
|
const unsigned w = umax(8, width(z - 1)); // ignore tiny offsets
|
||||||
unsigned bytes = ACC_ICONV(unsigned, mem_size(1, z)); // check
|
unsigned bytes = ACC_ICONV(unsigned, mem_size(1, z)); // check
|
||||||
// Worst matching: All match at max_offset, which implies 3==min_match
|
// Worst matching: All match at max_offset, which implies 3==min_match
|
||||||
// All literal: 1 bit overhead per literal byte
|
// All literal: 1 bit overhead per literal byte
|
||||||
bytes = umax(bytes, bytes + z / 8);
|
bytes = umax(bytes, z + z / 8);
|
||||||
// NRV2B: 1 byte plus 2 bits per width exceeding 8 ("ss11")
|
// NRV2B: 1 byte plus 2 bits per width exceeding 8 ("ss11")
|
||||||
bytes = umax(bytes, (z / 3 * (8 + 2 * (w - 8) / 1)) / 8);
|
bytes = umax(bytes, (z / 3 * (8 + 2 * (w - 8) / 1)) / 8);
|
||||||
// NRV2E: 1 byte plus 3 bits per pair of width exceeding 7 ("ss12")
|
// NRV2E: 1 byte plus 3 bits per pair of width exceeding 7 ("ss12")
|
||||||
@ -133,21 +135,28 @@ unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned e
|
|||||||
bytes = umax(bytes, z + (z >> 8) + ((z < (128 << 10)) ? (((128 << 10) - z) >> 11) : 0));
|
bytes = umax(bytes, z + (z >> 8) + ((z < (128 << 10)) ? (((128 << 10) - z) >> 11) : 0));
|
||||||
// extra + 256 safety for rounding
|
// extra + 256 safety for rounding
|
||||||
bytes = mem_size(1, bytes, extra, 256);
|
bytes = mem_size(1, bytes, extra, 256);
|
||||||
|
UNUSED(w);
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned MemBuffer::getSizeForDecompression(unsigned uncompressed_size, unsigned extra) {
|
unsigned MemBuffer::getSizeForDecompression(unsigned uncompressed_size, unsigned extra) {
|
||||||
|
if (uncompressed_size == 0)
|
||||||
|
throwCantPack("invalid uncompressed_size");
|
||||||
size_t bytes = mem_size(1, uncompressed_size, extra); // check
|
size_t bytes = mem_size(1, uncompressed_size, extra); // check
|
||||||
return ACC_ICONV(unsigned, bytes);
|
return ACC_ICONV(unsigned, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemBuffer::allocForCompression(unsigned uncompressed_size, unsigned extra) {
|
void MemBuffer::allocForCompression(unsigned uncompressed_size, unsigned extra) {
|
||||||
|
if (uncompressed_size == 0)
|
||||||
|
throwCantPack("invalid uncompressed_size");
|
||||||
unsigned size = getSizeForCompression(uncompressed_size, extra);
|
unsigned size = getSizeForCompression(uncompressed_size, extra);
|
||||||
alloc(size);
|
alloc(size);
|
||||||
debug_set(debug.last_return_address_alloc, upx_return_address());
|
debug_set(debug.last_return_address_alloc, upx_return_address());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemBuffer::allocForDecompression(unsigned uncompressed_size, unsigned extra) {
|
void MemBuffer::allocForDecompression(unsigned uncompressed_size, unsigned extra) {
|
||||||
|
if (uncompressed_size == 0)
|
||||||
|
throwCantPack("invalid uncompressed_size");
|
||||||
unsigned size = getSizeForDecompression(uncompressed_size, extra);
|
unsigned size = getSizeForDecompression(uncompressed_size, extra);
|
||||||
alloc(size);
|
alloc(size);
|
||||||
debug_set(debug.last_return_address_alloc, upx_return_address());
|
debug_set(debug.last_return_address_alloc, upx_return_address());
|
||||||
@ -254,6 +263,10 @@ TEST_CASE("MemBuffer") {
|
|||||||
CHECK(raw_bytes(mb, 64) != nullptr);
|
CHECK(raw_bytes(mb, 64) != nullptr);
|
||||||
CHECK(raw_bytes(mb, 64) == mb.getVoidPtr());
|
CHECK(raw_bytes(mb, 64) == mb.getVoidPtr());
|
||||||
CHECK_THROWS(raw_bytes(mb, 65));
|
CHECK_THROWS(raw_bytes(mb, 65));
|
||||||
|
CHECK_NOTHROW(mb + 64);
|
||||||
|
CHECK_NOTHROW(64 + mb);
|
||||||
|
CHECK_THROWS(mb + 65);
|
||||||
|
CHECK_THROWS(65 + mb);
|
||||||
if (use_simple_mcheck()) {
|
if (use_simple_mcheck()) {
|
||||||
upx_byte *b = raw_bytes(mb, 0);
|
upx_byte *b = raw_bytes(mb, 0);
|
||||||
unsigned magic1 = get_ne32(b - 4);
|
unsigned magic1 = get_ne32(b - 4);
|
||||||
@ -264,4 +277,14 @@ TEST_CASE("MemBuffer") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("MemBuffer::getSizeForCompression") {
|
||||||
|
CHECK_THROWS(MemBuffer::getSizeForCompression(0));
|
||||||
|
CHECK_THROWS(MemBuffer::getSizeForDecompression(0));
|
||||||
|
CHECK(MemBuffer::getSizeForCompression(1) == 320);
|
||||||
|
CHECK(MemBuffer::getSizeForCompression(256) == 576);
|
||||||
|
CHECK(MemBuffer::getSizeForCompression(1024) == 1408);
|
||||||
|
// CHECK(MemBuffer::getSizeForCompression(1024 * 1024) == 0); // TODO
|
||||||
|
// CHECK(MemBuffer::getSizeForCompression(UPX_RSIZE_MAX) == 0); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
/* vim:set ts=4 sw=4 et: */
|
/* vim:set ts=4 sw=4 et: */
|
||||||
|
@ -40,31 +40,34 @@ public:
|
|||||||
typedef typename std::add_pointer<T>::type pointer;
|
typedef typename std::add_pointer<T>::type pointer;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
pointer b = nullptr;
|
pointer b;
|
||||||
unsigned b_size_in_bytes = 0;
|
unsigned b_size_in_bytes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
MemBufferBase() : b(nullptr), b_size_in_bytes(0) {}
|
||||||
|
|
||||||
// NOTE: implicit conversion to underlying pointer
|
// NOTE: implicit conversion to underlying pointer
|
||||||
// NOTE: for fully bound-checked pointer use XSPAN_S from xspan.h
|
// NOTE: for fully bound-checked pointer use XSPAN_S from xspan.h
|
||||||
operator pointer() const { return b; }
|
operator pointer() const { return b; }
|
||||||
|
|
||||||
template <class U,
|
template <class U>
|
||||||
class /*Dummy*/ = typename std::enable_if<std::is_integral<U>::value, U>::type>
|
typename std::enable_if<std::is_integral<U>::value, pointer>::type operator+(U n) const {
|
||||||
pointer operator+(U n) const {
|
|
||||||
size_t bytes = mem_size(sizeof(T), n); // check mem_size
|
size_t bytes = mem_size(sizeof(T), n); // check mem_size
|
||||||
return raw_bytes(bytes) + n; // and check bytes
|
return raw_bytes(bytes) + n; // and check bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
// NOT allowed; use raw_bytes() instead
|
// NOT allowed; use raw_bytes() instead
|
||||||
template <class U,
|
template <class U>
|
||||||
class /*Dummy*/ = typename std::enable_if<std::is_integral<U>::value, U>::type>
|
typename std::enable_if<std::is_integral<U>::value, pointer>::type
|
||||||
pointer operator-(U n) const = delete;
|
operator-(U n) const DELETED_FUNCTION;
|
||||||
|
|
||||||
|
public:
|
||||||
pointer raw_bytes(size_t bytes) const {
|
pointer raw_bytes(size_t bytes) const {
|
||||||
if (bytes > 0) {
|
if (bytes > 0) {
|
||||||
if __acc_very_unlikely (b == nullptr)
|
if very_unlikely (b == nullptr)
|
||||||
throwInternalError("MemBuffer raw_bytes unexpected NULL ptr");
|
throwInternalError("MemBuffer raw_bytes unexpected NULL ptr");
|
||||||
if __acc_very_unlikely (bytes > b_size_in_bytes)
|
if very_unlikely (bytes > b_size_in_bytes)
|
||||||
throwInternalError("MemBuffer raw_bytes invalid size");
|
throwInternalError("MemBuffer raw_bytes invalid size");
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
@ -73,7 +76,7 @@ public:
|
|||||||
|
|
||||||
class MemBuffer final : public MemBufferBase<unsigned char> {
|
class MemBuffer final : public MemBufferBase<unsigned char> {
|
||||||
public:
|
public:
|
||||||
MemBuffer() = default;
|
MemBuffer() : MemBufferBase<unsigned char>() {}
|
||||||
explicit MemBuffer(upx_uint64_t size_in_bytes);
|
explicit MemBuffer(upx_uint64_t size_in_bytes);
|
||||||
~MemBuffer();
|
~MemBuffer();
|
||||||
|
|
||||||
@ -94,14 +97,14 @@ public:
|
|||||||
|
|
||||||
// util
|
// util
|
||||||
void fill(unsigned off, unsigned len, int value);
|
void fill(unsigned off, unsigned len, int value);
|
||||||
__acc_forceinline void clear(unsigned off, unsigned len) { fill(off, len, 0); }
|
forceinline void clear(unsigned off, unsigned len) { fill(off, len, 0); }
|
||||||
__acc_forceinline void clear() { fill(0, b_size_in_bytes, 0); }
|
forceinline void clear() { fill(0, b_size_in_bytes, 0); }
|
||||||
|
|
||||||
// If the entire range [skip, skip+take) is inside the buffer,
|
// If the entire range [skip, skip+take) is inside the buffer,
|
||||||
// then return &b[skip]; else throwCantPack(sprintf(errfmt, skip, take)).
|
// then return &b[skip]; else throwCantPack(sprintf(errfmt, skip, take)).
|
||||||
// This is similar to BoundedPtr, except only checks once.
|
// This is similar to BoundedPtr, except only checks once.
|
||||||
// skip == offset, take == size_in_bytes
|
// skip == offset, take == size_in_bytes
|
||||||
__acc_forceinline pointer subref(const char *errfmt, size_t skip, size_t take) {
|
forceinline pointer subref(const char *errfmt, size_t skip, size_t take) {
|
||||||
return (pointer) subref_impl(errfmt, skip, take);
|
return (pointer) subref_impl(errfmt, skip, take);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,24 +121,28 @@ private:
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
// debugging aid
|
// debugging aid
|
||||||
struct Debug {
|
struct Debug {
|
||||||
void *last_return_address_alloc = nullptr;
|
void *last_return_address_alloc;
|
||||||
void *last_return_address_dealloc = nullptr;
|
void *last_return_address_dealloc;
|
||||||
void *last_return_address_fill = nullptr;
|
void *last_return_address_fill;
|
||||||
void *last_return_address_subref = nullptr;
|
void *last_return_address_subref;
|
||||||
|
Debug() { memset(this, 0, sizeof(*this)); }
|
||||||
};
|
};
|
||||||
Debug debug;
|
Debug debug;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// disable copy, assignment and move assignment
|
// disable copy, assignment and move
|
||||||
MemBuffer(const MemBuffer &) = delete;
|
MemBuffer(const MemBuffer &) DELETED_FUNCTION;
|
||||||
MemBuffer &operator=(const MemBuffer &) = delete;
|
MemBuffer &operator=(const MemBuffer &) DELETED_FUNCTION;
|
||||||
MemBuffer &operator=(MemBuffer &&) = delete;
|
#if __cplusplus >= 201103L
|
||||||
|
MemBuffer(MemBuffer &&) DELETED_FUNCTION;
|
||||||
|
MemBuffer &operator=(MemBuffer &&) DELETED_FUNCTION;
|
||||||
|
#endif
|
||||||
// disable dynamic allocation
|
// disable dynamic allocation
|
||||||
ACC_CXX_DISABLE_NEW_DELETE
|
ACC_CXX_DISABLE_NEW_DELETE
|
||||||
|
|
||||||
// disable taking the address => force passing by reference
|
// disable taking the address => force passing by reference
|
||||||
// [I'm not too sure about this design decision, but we can always allow it if needed]
|
// [I'm not too sure about this design decision, but we can always allow it if needed]
|
||||||
MemBuffer *operator&() const = delete;
|
MemBuffer *operator&() const DELETED_FUNCTION;
|
||||||
};
|
};
|
||||||
|
|
||||||
// raw_bytes overload
|
// raw_bytes overload
|
||||||
@ -148,14 +155,14 @@ template <class T>
|
|||||||
inline typename MemBufferBase<T>::pointer raw_index_bytes(const MemBufferBase<T> &mbb, size_t index,
|
inline typename MemBufferBase<T>::pointer raw_index_bytes(const MemBufferBase<T> &mbb, size_t index,
|
||||||
size_t size_in_bytes) {
|
size_t size_in_bytes) {
|
||||||
typedef typename MemBufferBase<T>::element_type element_type;
|
typedef typename MemBufferBase<T>::element_type element_type;
|
||||||
return raw_bytes(mbb, mem_size(sizeof(element_type), index, size_in_bytes)) + index;
|
return mbb.raw_bytes(mem_size(sizeof(element_type), index, size_in_bytes)) + index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// global operators
|
// global operators
|
||||||
// rewrite "n + membuffer" to "membuffer + n" so that this will get checked above
|
// rewrite "n + membuffer" to "membuffer + n" so that this will get checked above
|
||||||
template <class T, class U,
|
template <class T, class U>
|
||||||
class /*Dummy*/ = typename std::enable_if<std::is_integral<U>::value, U>::type>
|
inline typename std::enable_if<std::is_integral<U>::value, typename MemBufferBase<T>::pointer>::type
|
||||||
inline typename MemBufferBase<T>::pointer operator+(U n, const MemBufferBase<T> &mbb) {
|
operator+(U n, const MemBufferBase<T> &mbb) {
|
||||||
return mbb + n;
|
return mbb + n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,16 +51,16 @@ ACC_COMPILE_TIME_ASSERT_HEADER(2ull * UPX_RSIZE_MAX * 9 / 8 + 16 * 1024 * 1024 <
|
|||||||
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
|
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
|
||||||
upx_uint64_t extra2) {
|
upx_uint64_t extra2) {
|
||||||
assert(element_size > 0);
|
assert(element_size > 0);
|
||||||
if __acc_very_unlikely (element_size > UPX_RSIZE_MAX)
|
if very_unlikely (element_size > UPX_RSIZE_MAX)
|
||||||
throwCantPack("mem_size 1; take care");
|
throwCantPack("mem_size 1; take care");
|
||||||
if __acc_very_unlikely (n > UPX_RSIZE_MAX)
|
if very_unlikely (n > UPX_RSIZE_MAX)
|
||||||
throwCantPack("mem_size 2; take care");
|
throwCantPack("mem_size 2; take care");
|
||||||
if __acc_very_unlikely (extra1 > UPX_RSIZE_MAX)
|
if very_unlikely (extra1 > UPX_RSIZE_MAX)
|
||||||
throwCantPack("mem_size 3; take care");
|
throwCantPack("mem_size 3; take care");
|
||||||
if __acc_very_unlikely (extra2 > UPX_RSIZE_MAX)
|
if very_unlikely (extra2 > UPX_RSIZE_MAX)
|
||||||
throwCantPack("mem_size 4; take care");
|
throwCantPack("mem_size 4; take care");
|
||||||
upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow
|
upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow
|
||||||
if __acc_very_unlikely (bytes > UPX_RSIZE_MAX)
|
if very_unlikely (bytes > UPX_RSIZE_MAX)
|
||||||
throwCantPack("mem_size 5; take care");
|
throwCantPack("mem_size 5; take care");
|
||||||
return ACC_ICONV(upx_rsize_t, bytes);
|
return ACC_ICONV(upx_rsize_t, bytes);
|
||||||
}
|
}
|
||||||
@ -68,16 +68,16 @@ upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t ext
|
|||||||
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
|
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
|
||||||
upx_uint64_t extra2) noexcept {
|
upx_uint64_t extra2) noexcept {
|
||||||
assert(element_size > 0);
|
assert(element_size > 0);
|
||||||
if __acc_very_unlikely (element_size > UPX_RSIZE_MAX)
|
if very_unlikely (element_size > UPX_RSIZE_MAX)
|
||||||
return false;
|
return false;
|
||||||
if __acc_very_unlikely (n > UPX_RSIZE_MAX)
|
if very_unlikely (n > UPX_RSIZE_MAX)
|
||||||
return false;
|
return false;
|
||||||
if __acc_very_unlikely (extra1 > UPX_RSIZE_MAX)
|
if very_unlikely (extra1 > UPX_RSIZE_MAX)
|
||||||
return false;
|
return false;
|
||||||
if __acc_very_unlikely (extra2 > UPX_RSIZE_MAX)
|
if very_unlikely (extra2 > UPX_RSIZE_MAX)
|
||||||
return false;
|
return false;
|
||||||
upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow
|
upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow
|
||||||
if __acc_very_unlikely (bytes > UPX_RSIZE_MAX)
|
if very_unlikely (bytes > UPX_RSIZE_MAX)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -98,18 +98,18 @@ TEST_CASE("mem_size") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ptr_diff_bytes(const void *a, const void *b) {
|
int ptr_diff_bytes(const void *a, const void *b) {
|
||||||
if __acc_very_unlikely (a == nullptr) {
|
if very_unlikely (a == nullptr) {
|
||||||
throwCantPack("ptr_diff_bytes null 1; take care");
|
throwCantPack("ptr_diff_bytes null 1; take care");
|
||||||
}
|
}
|
||||||
if __acc_very_unlikely (b == nullptr) {
|
if very_unlikely (b == nullptr) {
|
||||||
throwCantPack("ptr_diff_bytes null 2; take care");
|
throwCantPack("ptr_diff_bytes null 2; take care");
|
||||||
}
|
}
|
||||||
ptrdiff_t d = (const char *) a - (const char *) b;
|
ptrdiff_t d = (const char *) a - (const char *) b;
|
||||||
if (a >= b) {
|
if (a >= b) {
|
||||||
if __acc_very_unlikely (!mem_size_valid_bytes(d))
|
if very_unlikely (!mem_size_valid_bytes(d))
|
||||||
throwCantPack("ptr_diff_bytes 1; take care");
|
throwCantPack("ptr_diff_bytes 1; take care");
|
||||||
} else {
|
} else {
|
||||||
if __acc_very_unlikely (!mem_size_valid_bytes(-d))
|
if very_unlikely (!mem_size_valid_bytes(-d))
|
||||||
throwCantPack("ptr_diff_bytes 2; take care");
|
throwCantPack("ptr_diff_bytes 2; take care");
|
||||||
}
|
}
|
||||||
return ACC_ICONV(int, d);
|
return ACC_ICONV(int, d);
|
||||||
@ -117,7 +117,7 @@ int ptr_diff_bytes(const void *a, const void *b) {
|
|||||||
|
|
||||||
unsigned ptr_udiff_bytes(const void *a, const void *b) {
|
unsigned ptr_udiff_bytes(const void *a, const void *b) {
|
||||||
int d = ptr_diff_bytes(a, b);
|
int d = ptr_diff_bytes(a, b);
|
||||||
if __acc_very_unlikely (d < 0)
|
if very_unlikely (d < 0)
|
||||||
throwCantPack("ptr_udiff_bytes; take care");
|
throwCantPack("ptr_udiff_bytes; take care");
|
||||||
return ACC_ICONV(unsigned, d);
|
return ACC_ICONV(unsigned, d);
|
||||||
}
|
}
|
||||||
|
@ -40,20 +40,22 @@ inline bool mem_size_valid_bytes(upx_uint64_t bytes) noexcept { return bytes <=
|
|||||||
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0,
|
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0,
|
||||||
upx_uint64_t extra2 = 0) noexcept;
|
upx_uint64_t extra2 = 0) noexcept;
|
||||||
|
|
||||||
// "new" with asserted size; will throw on failure
|
// "new" with asserted size; will throw on invalid size
|
||||||
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
|
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
|
||||||
|
|
||||||
// will throw on invalid size
|
// will throw on invalid size
|
||||||
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
|
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
|
||||||
upx_uint64_t extra2 = 0);
|
upx_uint64_t extra2 = 0);
|
||||||
|
|
||||||
|
//
|
||||||
// inline fast paths:
|
// inline fast paths:
|
||||||
|
//
|
||||||
|
|
||||||
// will throw on invalid size
|
// will throw on invalid size
|
||||||
inline upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n) {
|
inline upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n) {
|
||||||
upx_uint64_t bytes = element_size * n;
|
upx_uint64_t bytes = element_size * n;
|
||||||
if __acc_very_unlikely (element_size == 0 || element_size > UPX_RSIZE_MAX ||
|
if very_unlikely (element_size == 0 || element_size > UPX_RSIZE_MAX || n > UPX_RSIZE_MAX ||
|
||||||
n > UPX_RSIZE_MAX || bytes > UPX_RSIZE_MAX)
|
bytes > UPX_RSIZE_MAX)
|
||||||
return mem_size(element_size, n, 0, 0); // this will throw
|
return mem_size(element_size, n, 0, 0); // this will throw
|
||||||
return ACC_ICONV(upx_rsize_t, bytes);
|
return ACC_ICONV(upx_rsize_t, bytes);
|
||||||
}
|
}
|
||||||
|
@ -33,37 +33,50 @@ XSPAN_NAMESPACE_BEGIN
|
|||||||
// debugging stats
|
// debugging stats
|
||||||
struct XSpanStats {
|
struct XSpanStats {
|
||||||
upx_std_atomic(size_t) check_range_counter;
|
upx_std_atomic(size_t) check_range_counter;
|
||||||
|
// doctest checks will set these:
|
||||||
|
upx_std_atomic(size_t) fail_nullptr;
|
||||||
|
upx_std_atomic(size_t) fail_nullbase;
|
||||||
|
upx_std_atomic(size_t) fail_not_same_base;
|
||||||
|
upx_std_atomic(size_t) fail_range_nullptr;
|
||||||
|
upx_std_atomic(size_t) fail_range_nullbase;
|
||||||
|
upx_std_atomic(size_t) fail_range_range;
|
||||||
};
|
};
|
||||||
static XSpanStats xspan_stats;
|
static XSpanStats xspan_stats;
|
||||||
|
|
||||||
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
|
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
|
||||||
__acc_noinline void xspan_fail_nullptr() {
|
noinline void xspan_fail_nullptr() {
|
||||||
|
xspan_stats.fail_nullptr += 1;
|
||||||
throwCantUnpack("xspan unexpected NULL pointer; take care!");
|
throwCantUnpack("xspan unexpected NULL pointer; take care!");
|
||||||
}
|
}
|
||||||
__acc_noinline void xspan_fail_nullbase() {
|
noinline void xspan_fail_nullbase() {
|
||||||
|
xspan_stats.fail_nullbase += 1;
|
||||||
throwCantUnpack("xspan unexpected NULL base; take care!");
|
throwCantUnpack("xspan unexpected NULL base; take care!");
|
||||||
}
|
}
|
||||||
__acc_noinline void xspan_fail_not_same_base() {
|
noinline void xspan_fail_not_same_base() {
|
||||||
|
xspan_stats.fail_not_same_base += 1;
|
||||||
throwInternalError("xspan unexpected base pointer; take care!");
|
throwInternalError("xspan unexpected base pointer; take care!");
|
||||||
}
|
}
|
||||||
|
|
||||||
__acc_noinline void xspan_fail_range_nullptr() {
|
noinline void xspan_fail_range_nullptr() {
|
||||||
|
xspan_stats.fail_range_nullptr += 1;
|
||||||
throwCantUnpack("xspan_check_range: unexpected NULL pointer; take care!");
|
throwCantUnpack("xspan_check_range: unexpected NULL pointer; take care!");
|
||||||
}
|
}
|
||||||
__acc_noinline void xspan_fail_range_nullbase() {
|
noinline void xspan_fail_range_nullbase() {
|
||||||
|
xspan_stats.fail_range_nullbase += 1;
|
||||||
throwCantUnpack("xspan_check_range: unexpected NULL base; take care!");
|
throwCantUnpack("xspan_check_range: unexpected NULL base; take care!");
|
||||||
}
|
}
|
||||||
__acc_noinline void xspan_fail_range_range() {
|
noinline void xspan_fail_range_range() {
|
||||||
|
xspan_stats.fail_range_range += 1;
|
||||||
throwCantUnpack("xspan_check_range: pointer out of range; take care!");
|
throwCantUnpack("xspan_check_range: pointer out of range; take care!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes) {
|
void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes) {
|
||||||
if __acc_very_unlikely (p == nullptr)
|
if very_unlikely (p == nullptr)
|
||||||
xspan_fail_range_nullptr();
|
xspan_fail_range_nullptr();
|
||||||
if __acc_very_unlikely (base == nullptr)
|
if very_unlikely (base == nullptr)
|
||||||
xspan_fail_range_nullbase();
|
xspan_fail_range_nullbase();
|
||||||
ptrdiff_t off = (const char *) p - (const char *) base;
|
ptrdiff_t off = (const char *) p - (const char *) base;
|
||||||
if __acc_very_unlikely (off < 0 || off > size_in_bytes)
|
if very_unlikely (off < 0 || off > size_in_bytes)
|
||||||
xspan_fail_range_range();
|
xspan_fail_range_range();
|
||||||
xspan_stats.check_range_counter += 1;
|
xspan_stats.check_range_counter += 1;
|
||||||
// fprintf(stderr, "xspan_check_range done\n");
|
// fprintf(stderr, "xspan_check_range done\n");
|
||||||
|
@ -159,4 +159,47 @@ inline R *xspan_make_helper__(R * /*dummy*/, MemBuffer &first) {
|
|||||||
#define SPAN_S_VAR XSPAN_S_VAR
|
#define SPAN_S_VAR XSPAN_S_VAR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
// raw_bytes() - get underlying memory from checked buffers/pointers.
|
||||||
|
// This is overloaded by various utility classes like BoundedPtr,
|
||||||
|
// MemBuffer and XSpan.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
typename std::enable_if<std::is_pointer<T>::value && !std_is_bounded_array<T>::value, T>::type
|
||||||
|
raw_bytes(T ptr, size_t size_in_bytes) {
|
||||||
|
if very_unlikely (size_in_bytes > 0 && ptr == nullptr)
|
||||||
|
throwInternalError("raw_bytes unexpected NULL ptr");
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default: for any regular pointer, raw_index_bytes() is just "pointer + index"
|
||||||
|
// NOTE: index == number of elements, *NOT* size in bytes!
|
||||||
|
template <class T>
|
||||||
|
inline
|
||||||
|
typename std::enable_if<std::is_pointer<T>::value && !std_is_bounded_array<T>::value, T>::type
|
||||||
|
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
|
||||||
|
if very_unlikely (ptr == nullptr)
|
||||||
|
throwInternalError("raw_index_bytes unexpected NULL ptr");
|
||||||
|
(void) mem_size(sizeof(T), index, size_in_bytes); // assert size
|
||||||
|
return ptr + index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// same for bounded arrays
|
||||||
|
template <class T, size_t N>
|
||||||
|
inline T *raw_bytes(T (&a)[N], size_t size_in_bytes) {
|
||||||
|
if very_unlikely (size_in_bytes > mem_size(sizeof(T), N))
|
||||||
|
throwInternalError("raw_bytes out of range");
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, size_t N>
|
||||||
|
inline T *raw_index_bytes(T (&a)[N], size_t index, size_t size_in_bytes) {
|
||||||
|
return raw_bytes(a, mem_size(sizeof(T), index, size_in_bytes)) + index;
|
||||||
|
}
|
||||||
|
|
||||||
/* vim:set ts=4 sw=4 et: */
|
/* vim:set ts=4 sw=4 et: */
|
||||||
|
@ -42,12 +42,12 @@
|
|||||||
XSPAN_NAMESPACE_BEGIN
|
XSPAN_NAMESPACE_BEGIN
|
||||||
|
|
||||||
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
|
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
|
||||||
__acc_noinline void xspan_fail_nullptr();
|
noinline void xspan_fail_nullptr();
|
||||||
__acc_noinline void xspan_fail_nullbase();
|
noinline void xspan_fail_nullbase();
|
||||||
__acc_noinline void xspan_fail_not_same_base();
|
noinline void xspan_fail_not_same_base();
|
||||||
__acc_noinline void xspan_fail_range_nullptr();
|
noinline void xspan_fail_range_nullptr();
|
||||||
__acc_noinline void xspan_fail_range_nullbase();
|
noinline void xspan_fail_range_nullbase();
|
||||||
__acc_noinline void xspan_fail_range_range();
|
noinline void xspan_fail_range_range();
|
||||||
void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes);
|
void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes);
|
||||||
|
|
||||||
// help constructor to distinguish between number of elements and bytes
|
// help constructor to distinguish between number of elements and bytes
|
||||||
|
@ -53,7 +53,7 @@ size_type size_in_bytes;
|
|||||||
|
|
||||||
// debug - internal sanity check; also serves as pseudo-documentation
|
// debug - internal sanity check; also serves as pseudo-documentation
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
__acc_noinline void assertInvariants() const {
|
noinline void assertInvariants() const {
|
||||||
if __acc_cte (configRequirePtr)
|
if __acc_cte (configRequirePtr)
|
||||||
assert(ptr != nullptr);
|
assert(ptr != nullptr);
|
||||||
if __acc_cte (configRequireBase)
|
if __acc_cte (configRequireBase)
|
||||||
@ -62,32 +62,32 @@ __acc_noinline void assertInvariants() const {
|
|||||||
xspan_check_range(ptr, base, size_in_bytes);
|
xspan_check_range(ptr, base, size_in_bytes);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
__acc_forceinline void assertInvariants() const {}
|
forceinline void assertInvariants() const {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static __acc_forceinline pointer makeNotNull(pointer p) {
|
static forceinline pointer makeNotNull(pointer p) {
|
||||||
if __acc_very_unlikely (p == nullptr)
|
if very_unlikely (p == nullptr)
|
||||||
xspan_fail_nullptr();
|
xspan_fail_nullptr();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
// enforce config invariants at constructor time - static functions
|
// enforce config invariants at constructor time - static functions
|
||||||
static __acc_forceinline pointer makePtr(pointer p) {
|
static forceinline pointer makePtr(pointer p) {
|
||||||
if __acc_cte (configRequirePtr && p == nullptr)
|
if __acc_cte (configRequirePtr && p == nullptr)
|
||||||
xspan_fail_nullptr();
|
xspan_fail_nullptr();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
static __acc_forceinline pointer makeBase(pointer b) {
|
static forceinline pointer makeBase(pointer b) {
|
||||||
if __acc_cte (configRequireBase && b == nullptr)
|
if __acc_cte (configRequireBase && b == nullptr)
|
||||||
xspan_fail_nullbase();
|
xspan_fail_nullbase();
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
// inverse logic for ensuring valid pointers from existing objets
|
// inverse logic for ensuring valid pointers from existing objets
|
||||||
__acc_forceinline pointer ensurePtr() const {
|
forceinline pointer ensurePtr() const {
|
||||||
if __acc_cte (!configRequirePtr && ptr == nullptr)
|
if __acc_cte (!configRequirePtr && ptr == nullptr)
|
||||||
xspan_fail_nullptr();
|
xspan_fail_nullptr();
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
__acc_forceinline pointer ensureBase() const {
|
forceinline pointer ensureBase() const {
|
||||||
if __acc_cte (!configRequireBase && base == nullptr)
|
if __acc_cte (!configRequireBase && base == nullptr)
|
||||||
xspan_fail_nullbase();
|
xspan_fail_nullbase();
|
||||||
return base;
|
return base;
|
||||||
@ -213,7 +213,7 @@ Self &assign(const Self &other) {
|
|||||||
} else {
|
} else {
|
||||||
// magic 2: assert same base (but ignore size_in_bytes !)
|
// magic 2: assert same base (but ignore size_in_bytes !)
|
||||||
if __acc_cte (configRequireBase || other.base != nullptr)
|
if __acc_cte (configRequireBase || other.base != nullptr)
|
||||||
if __acc_very_unlikely (base != other.base)
|
if very_unlikely (base != other.base)
|
||||||
xspan_fail_not_same_base();
|
xspan_fail_not_same_base();
|
||||||
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
|
if __acc_cte ((configRequirePtr || other.ptr != nullptr) &&
|
||||||
(configRequireBase || base != nullptr))
|
(configRequireBase || base != nullptr))
|
||||||
|
@ -51,11 +51,11 @@ private:
|
|||||||
pointer ptr;
|
pointer ptr;
|
||||||
|
|
||||||
// enforce config invariants at constructor time - static functions
|
// enforce config invariants at constructor time - static functions
|
||||||
static __acc_forceinline pointer makePtr(pointer p) { return p; }
|
static forceinline pointer makePtr(pointer p) { return p; }
|
||||||
// inverse logic for ensuring valid pointers from existing objets
|
// inverse logic for ensuring valid pointers from existing objets
|
||||||
__acc_forceinline pointer ensurePtr() const { return ptr; }
|
forceinline pointer ensurePtr() const { return ptr; }
|
||||||
// debug
|
// debug
|
||||||
__acc_forceinline void assertInvariants() const {}
|
forceinline void assertInvariants() const {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
|
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
|
||||||
@ -172,9 +172,9 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
__acc_forceinline pointer check_deref(pointer p) const { return p; }
|
forceinline pointer check_deref(pointer p) const { return p; }
|
||||||
__acc_forceinline pointer check_deref(pointer p, ptrdiff_t n) const { return p + n; }
|
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; }
|
forceinline pointer check_add(pointer p, ptrdiff_t n) const { return p + n; }
|
||||||
|
|
||||||
public: // raw access
|
public: // raw access
|
||||||
pointer raw_ptr() const { return ptr; }
|
pointer raw_ptr() const { return ptr; }
|
||||||
|
Reference in New Issue
Block a user