1
0
mirror of https://github.com/upx/upx.git synced 2025-08-11 22:52:30 +08:00

all: cleanups

This commit is contained in:
Markus F.X.J. Oberhumer
2023-01-14 08:37:22 +01:00
parent 58de07629e
commit cc994326a0
21 changed files with 1030 additions and 868 deletions

View File

@ -131,7 +131,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 ld bug; supposed to be fixed in 14.1 # { 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, testsuite: true } - { os: macos-12, testsuite: true }
steps: steps:
- name: 'Install brew packages' - name: 'Install brew packages'
@ -245,10 +245,12 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- { name: amd64-win64-msvc-14.2, os: windows-2019, C: msvc-14.2-x64, A: x64 } # Visual Studio 2019 - { name: amd64-win64-vs2019, os: windows-2019, C: msvc-14.2-x64, arch: amd64 }
- { name: amd64-win64-msvc-14.3, os: windows-2022, C: msvc-14.3-x64, A: x64 } # Visual Studio 2022 - { name: amd64-win64-vs2022, os: windows-2022, C: msvc-14.3-x64, arch: amd64 }
- { name: i386-win32-msvc-14.2, os: windows-2019, C: msvc-14.2-x86, A: x86 } # Visual Studio 2019 - { name: arm64-win64-vs2019, os: windows-2019, C: msvc-14.2-x64, arch: amd64_arm64 }
- { name: i386-win32-msvc-14.3, os: windows-2022, C: msvc-14.3-x86, A: x86 } # Visual Studio 2022 - { name: arm64-win64-vs2022, os: windows-2022, C: msvc-14.3-x64, arch: amd64_arm64 }
- { name: i386-win32-vs2019, os: windows-2019, C: msvc-14.2-x86, arch: amd64_x86 }
- { name: i386-win32-vs2022, os: windows-2022, C: msvc-14.3-x86, arch: amd64_x86 }
steps: steps:
- name: 'Check out code' - name: 'Check out code'
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -263,7 +265,7 @@ jobs:
- name: 'Set up Developer Command Prompt' - name: 'Set up Developer Command Prompt'
uses: ilammy/msvc-dev-cmd@v1 uses: ilammy/msvc-dev-cmd@v1
with: with:
arch: ${{ matrix.A }} arch: ${{ matrix.arch }}
- name: 'Build' - name: 'Build'
shell: cmd shell: cmd
run: | run: |
@ -291,7 +293,7 @@ jobs:
set s=%H%\src set s=%H%\src
cat .GITREV.txt cat .GITREV.txt
set /p GITREV=<.GITREV.txt set /p GITREV=<.GITREV.txt
cl -std:c++17 -Zc:__cplusplus -EHsc -J -O2 -W4 -WX -DUPX_VERSION_GITREV="""%GITREV%""" -DWITH_ZSTD %DEFS% -I%H%\vendor -I%H%\vendor\boost-pfr\include -Feupx.exe %s%\*.cpp %s%\util\*.cpp %BDIR%\ucl\ucl.lib %BDIR%\zlib\zlib.lib %BDIR%\zstd\zstd.lib /link setargv.obj cl -std:c++17 -Zc:__cplusplus -EHsc -J -O2 -W4 -WX -DUPX_VERSION_GITREV="""%GITREV%""" -DWITH_ZSTD %DEFS% -I%H%\vendor -I%H%\vendor\boost-pfr\include -Feupx.exe %s%\*.cpp %s%\check\*.cpp %s%\util\*.cpp %BDIR%\ucl\ucl.lib %BDIR%\zlib\zlib.lib %BDIR%\zstd\zstd.lib /link setargv.obj
- name: 'Make artifact' - name: 'Make artifact'
shell: bash shell: bash
run: | run: |
@ -306,6 +308,7 @@ jobs:
name: ${{ env.artifact_name }} name: ${{ env.artifact_name }}
path: tmp/artifact path: tmp/artifact
- name: 'Run basic tests' - name: 'Run basic tests'
if: ${{ matrix.arch != 'amd64_arm64' }}
run: | run: |
$ErrorActionPreference = 'stop' $ErrorActionPreference = 'stop'
$ErrorView = 'NormalView' $ErrorView = 'NormalView'
@ -318,6 +321,7 @@ jobs:
.\upx.exe -t upx_packed.exe .\upx.exe -t upx_packed.exe
.\upx_packed.exe --version .\upx_packed.exe --version
- name: 'Run test suite' - name: 'Run test suite'
if: ${{ matrix.arch != 'amd64_arm64' }}
shell: bash shell: bash
run: | run: |
export upx_testsuite_SRCDIR="$(readlink -en ../deps/upx-testsuite)" export upx_testsuite_SRCDIR="$(readlink -en ../deps/upx-testsuite)"

View File

@ -1,11 +1,11 @@
name: "CodeQL" name: "CodeQL"
on: on:
push: # push:
branches: [ "devel", "devel4", "devel5", "master" ] # branches: [ "devel", "devel4", "devel5", "master" ]
pull_request: # pull_request:
# The branches below must be a subset of the branches above # # The branches below must be a subset of the branches above
branches: [ "devel", "devel4", "devel5" ] # branches: [ "devel", "devel4", "devel5" ]
schedule: schedule:
- cron: '20 1 * * 3' - cron: '20 1 * * 3'
workflow_dispatch: workflow_dispatch:

View File

@ -6,14 +6,12 @@ if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git")
option(UPX_CONFIG_DISABLE_GITREV "Do not compile with default Git version info." ON) option(UPX_CONFIG_DISABLE_GITREV "Do not compile with default Git version info." ON)
option(UPX_CONFIG_DISABLE_SANITIZE "Do not compile with default sanitize options." ON) option(UPX_CONFIG_DISABLE_SANITIZE "Do not compile with default sanitize options." ON)
option(UPX_CONFIG_DISABLE_WERROR "Do not compile with default -Werror option." ON) option(UPX_CONFIG_DISABLE_WERROR "Do not compile with default -Werror option." ON)
option(UPX_CONFIG_DISABLE_ZSTD "Do not compile with zstd; NOTE: zstd is WIP." ON)
else() else()
# strict config defaults for devel builds # strict config defaults for devel builds
message(STATUS "upx info: strict config defaults enabled") message(STATUS "upx info: strict config defaults enabled")
option(UPX_CONFIG_DISABLE_GITREV "Do not compile with default Git version info." OFF) option(UPX_CONFIG_DISABLE_GITREV "Do not compile with default Git version info." OFF)
option(UPX_CONFIG_DISABLE_SANITIZE "Do not compile with default sanitize options." OFF) option(UPX_CONFIG_DISABLE_SANITIZE "Do not compile with default sanitize options." OFF)
option(UPX_CONFIG_DISABLE_WERROR "Do not compile with default -Werror option." OFF) option(UPX_CONFIG_DISABLE_WERROR "Do not compile with default -Werror option." OFF)
option(UPX_CONFIG_DISABLE_ZSTD "Do not compile with zstd; NOTE: zstd is WIP." OFF)
endif() endif()
# test config options (see below) # test config options (see below)
@ -42,7 +40,7 @@ set(GITREV_SHORT "")
set(GITREV_PLUS "") set(GITREV_PLUS "")
set(GIT_DESCRIBE "") set(GIT_DESCRIBE "")
find_package(Git) find_package(Git)
if(GIT_FOUND AND NOT UPX_CONFIG_DISABLE_GITREV) if(Git_FOUND AND NOT UPX_CONFIG_DISABLE_GITREV)
execute_process( execute_process(
COMMAND "${GIT_EXECUTABLE}" rev-parse --short=12 HEAD COMMAND "${GIT_EXECUTABLE}" rev-parse --short=12 HEAD
RESULT_VARIABLE result ERROR_QUIET RESULT_VARIABLE result ERROR_QUIET
@ -101,6 +99,10 @@ endif()
# targets and compilation flags # targets and compilation flags
#*********************************************************************** #***********************************************************************
#find_package(Threads)
set(UPX_CONFIG_DISABLE_ZSTD ON) # zstd is currently not used; maybe in UPX version 5
file(GLOB ucl_SOURCES "vendor/ucl/src/*.c") file(GLOB ucl_SOURCES "vendor/ucl/src/*.c")
list(SORT ucl_SOURCES) list(SORT ucl_SOURCES)
add_library(upx_vendor_ucl STATIC ${ucl_SOURCES}) add_library(upx_vendor_ucl STATIC ${ucl_SOURCES})
@ -118,7 +120,7 @@ add_library(upx_vendor_zstd STATIC ${zstd_SOURCES})
set_property(TARGET upx_vendor_zstd PROPERTY C_STANDARD 11) set_property(TARGET upx_vendor_zstd PROPERTY C_STANDARD 11)
endif() endif()
file(GLOB upx_SOURCES "src/*.cpp" "src/util/*.cpp") file(GLOB upx_SOURCES "src/*.cpp" "src/check/*.cpp" "src/util/*.cpp")
list(SORT upx_SOURCES) list(SORT upx_SOURCES)
add_executable(upx ${upx_SOURCES}) add_executable(upx ${upx_SOURCES})
#target_compile_features(upx PRIVATE cxx_std_17) #target_compile_features(upx PRIVATE cxx_std_17)
@ -223,6 +225,10 @@ if(NOT UPX_CONFIG_DISABLE_ZSTD)
target_compile_definitions(${t} PRIVATE WITH_ZSTD=1) target_compile_definitions(${t} PRIVATE WITH_ZSTD=1)
target_link_libraries(upx upx_vendor_zstd) target_link_libraries(upx upx_vendor_zstd)
endif() endif()
if(Threads_FOUND AND 0)
# for RANGELESS_FN_ENABLE_PARALLEL multithreading test
target_link_libraries(upx Threads::Threads)
endif()
#*********************************************************************** #***********************************************************************
# "make test" # "make test"

View File

@ -141,6 +141,9 @@ endif
ifeq ($(wildcard ./vendor/lzma-sdk/C/.),) ifeq ($(wildcard ./vendor/lzma-sdk/C/.),)
$(error ERROR: missing git submodule; run 'git submodule update --init') $(error ERROR: missing git submodule; run 'git submodule update --init')
endif endif
ifeq ($(wildcard ./vendor/rangeless/include/.),)
$(error ERROR: missing git submodule; run 'git submodule update --init')
endif
ifeq ($(wildcard ./vendor/ucl/include/.),) ifeq ($(wildcard ./vendor/ucl/include/.),)
$(error ERROR: missing git submodule; run 'git submodule update --init') $(error ERROR: missing git submodule; run 'git submodule update --init')
endif endif

View File

@ -6,10 +6,10 @@ argv0=$0; argv0abs="$(readlink -fn "$argv0")"; argv0dir="$(dirname "$argv0abs")"
# create the image from Dockerfile # create the image from Dockerfile
# using a rootless Podman container # using a rootless Podman container
# NOTE: this image is based on rebuild-stubs-with-upx/upx-stubtools-20221212-v2, # NOTE: this image is based on rebuild-stubs-with-upx/upx-stubtools-20221212-v3,
# so you have to create that image first # so you have to create that image first
# WARNING: we install many packages, so the resulting image needs A LOT of disk space! # WARNING: we install many packages, so the resulting image needs A LOT of disk space!
image=upx-cross-compile-20221212-v2 image=upx-cross-compile-20230115-v1
podman build -t "$image" -f "$argv0dir/Dockerfile" "$argv0dir" podman build -t "$image" -f "$argv0dir/Dockerfile" "$argv0dir"

View File

@ -6,7 +6,7 @@ argv0=$0; argv0abs="$(readlink -fn "$argv0")"; argv0dir="$(dirname "$argv0abs")"
# run an interactive shell in the image # run an interactive shell in the image
# using a rootless Podman container # using a rootless Podman container
image=upx-cross-compile-20221212-v2 image=upx-cross-compile-20230115-v1
flags=( -ti --read-only --rm ) flags=( -ti --read-only --rm )
flags+=( --cap-drop=all ) # drop all capabilities flags+=( --cap-drop=all ) # drop all capabilities

View File

@ -1,8 +1,8 @@
# NOTE: this image is based on rebuild-stubs-with-upx/upx-stubtools-20221212-v2, # NOTE: this image is based on rebuild-stubs-with-upx/upx-stubtools-20221212-v3,
# so you have to create that image first # so you have to create that image first
# WARNING: we install many packages, so the resulting image needs A LOT of disk space! # WARNING: we install many packages, so the resulting image needs A LOT of disk space!
FROM localhost/upx-stubtools-20221212-v2 FROM localhost/upx-stubtools-20221212-v3
ENV UPX_CONTAINER_IMAGE_NAME=upx-cross-compile-20221212-v2 ENV UPX_CONTAINER_IMAGE_NAME=upx-cross-compile-20230115-v1
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
USER root USER root

View File

@ -6,7 +6,7 @@ argv0=$0; argv0abs="$(readlink -fn "$argv0")"; argv0dir="$(dirname "$argv0abs")"
# create the image from Dockerfile # create the image from Dockerfile
# using a rootless Podman container # using a rootless Podman container
image=upx-stubtools-20221212-v2 image=upx-stubtools-20221212-v3
podman build -t "$image" -f "$argv0dir/Dockerfile" "$argv0dir" podman build -t "$image" -f "$argv0dir/Dockerfile" "$argv0dir"

View File

@ -6,7 +6,7 @@ argv0=$0; argv0abs="$(readlink -fn "$argv0")"; argv0dir="$(dirname "$argv0abs")"
# run an interactive shell in the image # run an interactive shell in the image
# using a rootless Podman container # using a rootless Podman container
image=upx-stubtools-20221212-v2 image=upx-stubtools-20221212-v3
flags=( -ti --read-only --rm ) flags=( -ti --read-only --rm )
flags+=( --cap-drop=all ) # drop all capabilities flags+=( --cap-drop=all ) # drop all capabilities

View File

@ -1,5 +1,5 @@
FROM docker.io/library/ubuntu:22.04 FROM docker.io/library/ubuntu:22.04
ENV UPX_CONTAINER_IMAGE_NAME=upx-stubtools-20221212-v2 ENV UPX_CONTAINER_IMAGE_NAME=upx-stubtools-20221212-v3
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
ENV LANG=C.UTF-8 ENV LANG=C.UTF-8
@ -13,8 +13,9 @@ RUN dpkg --add-architecture i386 \
# the following packages are not required for rebuilding the stubs, but # the following packages are not required for rebuilding the stubs, but
# they do make the image much more convenient and also allow building # they do make the image much more convenient and also allow building
# the full UPX binary inside the container via CMake: # the full UPX binary inside the container via CMake:
7zip bzip2 cmake elfutils file g++ gdb htop libzstd-dev lzip lzop ninja-build \ 7zip bfs bzip2 cmake elfutils fd-find file fzf g++ gdb htop hyperfine \
p7zip patch patchelf pax-utils rsync screen unzip vim zip zlib1g-dev zsh zstd \ libzstd-dev lzip lzop ninja-build p7zip patch patchelf pax-utils ripgrep \
rsync screen universal-ctags unzip vim zip zlib1g-dev zsh zstd \
# extra packages for compiling with "gcc -m32" and and "gcc -mx32": # extra packages for compiling with "gcc -m32" and and "gcc -mx32":
gcc-multilib g++-multilib \ gcc-multilib g++-multilib \
&& true && true

View File

@ -79,7 +79,7 @@ CLANG_FORMAT_EXCLUDE_FILES += conf.h miniacc.h version.h
CLANG_FORMAT_EXCLUDE_FILES += compress.cpp compress.h filter.cpp filter.h filteri.cpp help.cpp CLANG_FORMAT_EXCLUDE_FILES += compress.cpp compress.h filter.cpp filter.h filteri.cpp help.cpp
CLANG_FORMAT_EXCLUDE_FILES += p_elf.h p_elf_enum.h p_lx_% p_mach% p_unix% p_vmli% CLANG_FORMAT_EXCLUDE_FILES += p_elf.h p_elf_enum.h p_lx_% p_mach% p_unix% p_vmli%
CLANG_FORMAT_EXCLUDE_FILES += p_w32pe.cpp p_w64pep.cpp packer_c.cpp packer_f.cpp pefile% CLANG_FORMAT_EXCLUDE_FILES += p_w32pe.cpp p_w64pep.cpp packer_c.cpp packer_f.cpp pefile%
CLANG_FORMAT_FILES := $(sort $(wildcard *.[ch]* ../maint/src/*.[ch]* util/*.[ch]*)) CLANG_FORMAT_FILES := $(sort $(wildcard *.[ch]* ../maint/src/*.[ch]* check/*.[ch]* util/*.[ch]*))
CLANG_FORMAT_FILES := $(filter-out $(CLANG_FORMAT_EXCLUDE_FILES),$(CLANG_FORMAT_FILES)) CLANG_FORMAT_FILES := $(filter-out $(CLANG_FORMAT_EXCLUDE_FILES),$(CLANG_FORMAT_FILES))
clang-format: PHONY $(CLANG_FORMAT_FILES) clang-format: PHONY $(CLANG_FORMAT_FILES)
@echo "running upx-clang-format" @echo "running upx-clang-format"

View File

@ -3,7 +3,6 @@
This file is part of the UPX executable compressor. This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2023 Laszlo Molnar
All Rights Reserved. All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them UPX and the UCL library are free software; you can redistribute them
@ -21,15 +20,10 @@
If not, write to the Free Software Foundation, Inc., If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar Markus F.X.J. Oberhumer
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com>
*/ */
#if DEBUG || 1
#ifndef WITH_BOOST_PFR
#define WITH_BOOST_PFR 1
#endif
#endif
#include "../conf.h" #include "../conf.h"
/************************************************************************* /*************************************************************************
@ -138,8 +132,13 @@ namespace {
template <class T> template <class T>
struct TestBELE { struct TestBELE {
__acc_static_noinline bool test(void) { __acc_static_noinline bool test(void) {
COMPILE_TIME_ASSERT_ALIGNED1(T) // POD checks
// COMPILE_TIME_ASSERT(std::is_pod<T>::value); // deprecated in C++20
COMPILE_TIME_ASSERT(std::is_standard_layout<T>::value);
COMPILE_TIME_ASSERT(std::is_trivial<T>::value);
// alignment checks
{ {
COMPILE_TIME_ASSERT_ALIGNED1(T)
struct alignas(1) test1_t { struct alignas(1) test1_t {
char a; char a;
T b; T b;
@ -160,6 +159,7 @@ struct TestBELE {
UNUSED(t2); UNUSED(t2);
} }
#if 1 #if 1
// arithmetic checks
{ {
T allbits; T allbits;
allbits = 0; allbits = 0;
@ -453,33 +453,4 @@ TEST_CASE("libc snprintf") {
CHECK_EQ(strcmp(buf, "-7.0.0.0.0.0.0.0.7.0xffffffffffffffff"), 0); CHECK_EQ(strcmp(buf, "-7.0.0.0.0.0.0.0.7.0xffffffffffffffff"), 0);
} }
#if WITH_BOOST_PFR
TEST_CASE("Boost.PFR") {
int i = -1;
CHECK_EQ(strcmp(pfr_str(i), "-1"), 0);
BE32 b32;
b32 = 1;
LE32 l32;
l32 = 2;
CHECK_EQ(strcmp(pfr_str(b32), "1"), 0);
CHECK_EQ(strcmp(pfr_str(l32), "2"), 0);
struct Foo {
BE16 b16;
BE32 b32;
BE64 b64;
LE16 l16;
LE32 l32;
LE64 l64;
};
Foo foo;
foo.b16 = 1;
foo.b32 = 2;
foo.b64 = 3;
foo.l16 = 4;
foo.l32 = 5;
foo.l64 = 6;
CHECK_EQ(strcmp(pfr_str("foo", "=", foo), "foo = {1, 2, 3, 4, 5, 6}"), 0);
}
#endif // WITH_BOOST_PFR
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -3,7 +3,6 @@
This file is part of the UPX executable compressor. This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2023 Laszlo Molnar
All Rights Reserved. All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them UPX and the UCL library are free software; you can redistribute them
@ -21,8 +20,8 @@
If not, write to the Free Software Foundation, Inc., If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar Markus F.X.J. Oberhumer
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com>
*/ */
/************************************************************************* /*************************************************************************

752
src/check/dt_xspan.cpp Normal file
View File

@ -0,0 +1,752 @@
/* xspan -- a minimally invasive checked memory smart pointer
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 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>
*/
// lots of tests (and probably quite a number of redundant tests)
#include "../conf.h"
/*************************************************************************
// basic
**************************************************************************/
TEST_CASE("basic xspan usage") {
char buf[4] = {0, 1, 2, 3};
SUBCASE("SPAN_x") {
SPAN_0(char) a0 = nullptr;
SPAN_0(char) b0 = buf;
SPAN_P(char) bp = buf;
SPAN_0(char) c0 = SPAN_0_MAKE(char, buf);
SPAN_P(char) cp = SPAN_P_MAKE(char, buf);
SPAN_S(char) cs = SPAN_S_MAKE(char, buf, sizeof(buf));
SPAN_0(const char) const x0 = SPAN_0_MAKE(const char, buf);
SPAN_P(const char) const xp = SPAN_P_MAKE(const char, buf);
SPAN_S(const char) const xs = SPAN_S_MAKE(const char, buf, sizeof(buf));
SPAN_P(const char) const yp = xs;
SPAN_0(const char) const z0p = yp;
SPAN_0(const char) const z0s = xs;
CHECK((a0 == nullptr));
CHECK(c0 == b0);
CHECK(cp == bp);
CHECK(cs == bp);
CHECK(x0 == z0p);
CHECK(xp == z0s);
CHECK(raw_bytes(c0, 4) == buf);
CHECK(raw_index_bytes(c0, 1, 3) == buf + 1);
CHECK(raw_bytes(cp, 4) == buf);
CHECK(raw_index_bytes(cp, 1, 3) == buf + 1);
CHECK(raw_bytes(cs, 4) == buf);
CHECK(raw_index_bytes(cs, 1, 3) == buf + 1);
CHECK_THROWS(raw_bytes(cs, 5));
CHECK_THROWS(raw_index_bytes(cs, 1, 4));
}
SUBCASE("SPAN_x_VAR") {
SPAN_0_VAR(char, a0, nullptr);
SPAN_0_VAR(char, b0, buf);
SPAN_P_VAR(char, bp, buf);
SPAN_0_VAR(char, c0, buf, sizeof(buf));
SPAN_P_VAR(char, cp, buf, sizeof(buf));
SPAN_S_VAR(char, cs, buf, sizeof(buf));
SPAN_0_VAR(char, d0, buf + 1, sizeof(buf), buf);
SPAN_P_VAR(char, dp, buf + 1, sizeof(buf), buf);
SPAN_S_VAR(char, ds, buf + 1, sizeof(buf), buf);
SPAN_0_VAR(const char, const x0, buf, sizeof(buf));
SPAN_P_VAR(const char, const xp, buf, sizeof(buf));
SPAN_S_VAR(const char, const xs, buf, sizeof(buf));
SPAN_P_VAR(const char, const yp, xs);
SPAN_0_VAR(const char, const z0p, yp);
SPAN_0_VAR(const char, const z0s, xs);
CHECK((a0 == nullptr));
CHECK(c0 == b0);
CHECK(cp == bp);
CHECK(cs == bp);
CHECK(d0 == dp);
CHECK(d0 == ds);
CHECK(x0 == z0p);
CHECK(xp == z0s);
CHECK(raw_bytes(c0, 4) == buf);
CHECK(raw_index_bytes(c0, 1, 3) == buf + 1);
CHECK(raw_bytes(cp, 4) == buf);
CHECK(raw_index_bytes(cp, 1, 3) == buf + 1);
CHECK(raw_bytes(cs, 4) == buf);
CHECK(raw_index_bytes(cs, 1, 3) == buf + 1);
CHECK_THROWS(raw_bytes(cs, 5));
CHECK_THROWS(raw_index_bytes(cs, 1, 4));
}
SUBCASE("xspan in class") {
struct MyType {
SPAN_0(char) s0;
SPAN_P(char) sp;
SPAN_S(char) ss;
#if __cplusplus >= 201103L
SPAN_0(char) x0 = nullptr;
#endif
#if WITH_SPAN >= 2
// much nicer syntax when using fully checked xspan:
MyType(char *b, size_t n, bool) : s0(b, n), sp(b, n), ss(b, n) {}
#endif
MyType(char *b, size_t n)
: s0(SPAN_0_MAKE(char, b, n)), sp(SPAN_P_MAKE(char, b, n)),
ss(SPAN_S_MAKE(char, b, n)) {
UNUSED(n);
}
};
MyType x(buf, sizeof(buf));
MyType y = MyType(buf, sizeof(buf));
CHECK(x.s0 == y.sp);
}
}
/*************************************************************************
//
**************************************************************************/
#if (WITH_SPAN >= 2) && DEBUG
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;
// v0 nullptr, b0 base, b1 base + 1
const Span0 v0_v0(nullptr);
const Span0 v0_b0(nullptr, 4, base_buf);
const Span0 v0_b1(nullptr, 3, base_buf + 1);
const Span0 b0_v0(base_buf);
const Span0 b0_b0(base_buf, 4, base_buf);
CHECK_THROWS(SPAN_0_MAKE(char, base_buf, 3, base_buf + 1)); // b0_b1
const Span0 b1_v0(base_buf + 1);
const Span0 b1_b0(base_buf + 1, 4, base_buf);
const Span0 b1_b1(base_buf + 1, 3, base_buf + 1);
CHECK_THROWS(ss_with_base = v0_v0); // nullptr assignment
CHECK_THROWS(ss_with_base = v0_b0); // nullptr assignment
CHECK_THROWS(ss_with_base = v0_b1); // nullptr assignment
CHECK_NOTHROW(ss_with_base = b0_v0);
CHECK_NOTHROW(ss_with_base = b0_b0);
CHECK_NOTHROW(ss_with_base = b1_v0);
CHECK_NOTHROW(ss_with_base = b1_b0);
CHECK_THROWS(ss_with_base = b1_b1); // different base
CHECK_THROWS(SPAN_S_MAKE(char, v0_v0));
CHECK_THROWS(SPAN_S_MAKE(char, v0_b0));
CHECK_THROWS(SPAN_S_MAKE(char, v0_b1));
CHECK_THROWS(SPAN_S_MAKE(char, b0_v0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b0_b0));
CHECK_THROWS(SPAN_S_MAKE(char, b1_v0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b1_b0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b1_b1));
//
CHECK((SPAN_S_MAKE(char, b0_b0).raw_base() == base_buf));
CHECK((SPAN_S_MAKE(char, b1_b0).raw_base() == base_buf));
CHECK((SPAN_S_MAKE(char, b1_b1).raw_base() == base_buf + 1));
}
{
typedef PtrOrSpan<char> SpanP;
// v0 nullptr, b0 base, b1 base + 1
const SpanP b0_v0(base_buf);
const SpanP b0_b0(base_buf, 4, base_buf);
CHECK_THROWS(SPAN_P_MAKE(char, base_buf, 3, base_buf + 1)); // b0_b1
const SpanP b1_v0(base_buf + 1);
const SpanP b1_b0(base_buf + 1, 4, base_buf);
const SpanP b1_b1(base_buf + 1, 3, base_buf + 1);
CHECK_NOTHROW(ss_with_base = b0_v0);
CHECK_NOTHROW(ss_with_base = b0_b0);
CHECK_NOTHROW(ss_with_base = b1_v0);
CHECK_NOTHROW(ss_with_base = b1_b0);
CHECK_THROWS(ss_with_base = b1_b1); // different base
CHECK_THROWS(SPAN_S_MAKE(char, b0_v0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b0_b0));
CHECK_THROWS(SPAN_S_MAKE(char, b1_v0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b1_b0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b1_b1));
//
CHECK((SPAN_S_MAKE(char, b0_b0).raw_base() == base_buf));
CHECK((SPAN_S_MAKE(char, b1_b0).raw_base() == base_buf));
CHECK((SPAN_S_MAKE(char, b1_b1).raw_base() == base_buf + 1));
}
#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);
}
/*************************************************************************
//
**************************************************************************/
#if !defined(DOCTEST_CONFIG_DISABLE)
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
#endif
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: */

View File

@ -0,0 +1,82 @@
/* dtx_.cpp -- DocTest eXtra checks
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 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>
*/
#if DEBUG
#ifndef WITH_BOOST_PFR
#define WITH_BOOST_PFR 1
#endif
#endif
#include "../conf.h"
/*************************************************************************
//
**************************************************************************/
#if WITH_BOOST_PFR
TEST_CASE("boost::pfr") {
struct Foo {
BE16 b16;
BE32 b32;
BE64 b64;
LE16 l16;
LE32 l32;
LE64 l64;
};
{
int i = -1;
CHECK_EQ(strcmp(pfr_str(i), "-1"), 0);
BE32 b32;
b32 = 1;
LE32 l32;
l32 = 2;
CHECK_EQ(strcmp(pfr_str(b32), "1"), 0);
CHECK_EQ(strcmp(pfr_str(l32), "2"), 0);
}
{
Foo foo;
foo.b16 = 1;
foo.b32 = 2;
foo.b64 = 3;
foo.l16 = 4;
foo.l32 = 5;
foo.l64 = 6;
CHECK_EQ(strcmp(pfr_str("foo", "=", foo), "foo = {1, 2, 3, 4, 5, 6}"), 0);
}
{
#if (ACC_ABI_BIG_ENDIAN)
#else
constexpr Foo foo{{1}, {1}, {1}, {1}, {1}, {1}};
CHECK_EQ(strcmp(pfr_str(foo), "{256, 16777216, 72057594037927936, 1, 1, 1}"), 0);
#endif
}
}
#endif // WITH_BOOST_PFR
/* vim:set ts=4 sw=4 et: */

View File

@ -0,0 +1,64 @@
/* dtx_.cpp -- DocTest eXtra checks
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 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>
*/
#if DEBUG && 0
#ifndef WITH_RANGELESS_FN
#define WITH_RANGELESS_FN 1
#endif
#endif
#if WITH_RANGELESS_FN
#define RANGELESS_FN_ENABLE_RUN_TESTS 1
#if defined(__i386__) && defined(__MSDOS__) && defined(__DJGPP__) && defined(__GNUC__)
#define RANGELESS_FN_ENABLE_PARALLEL 0
#elif defined(__m68k__) && defined(__atarist__) && defined(__GNUC__)
#define RANGELESS_FN_ENABLE_PARALLEL 0
#else
// disable multithreading for now; needs CMake find_package(Threads)
#define RANGELESS_FN_ENABLE_PARALLEL 0
#endif
#endif // WITH_RANGELESS_FN
#include "../conf.h"
/*************************************************************************
//
**************************************************************************/
#if WITH_RANGELESS_FN && RANGELESS_FN_ENABLE_RUN_TESTS
TEST_CASE("rangeless::fn") { CHECK_NOTHROW(rangeless::fn::impl::run_tests()); }
#if RANGELESS_FN_ENABLE_PARALLEL
TEST_CASE("rangeless::fn parallel") {
// CHECK_NOTHROW(rangeless::mt::impl::run_tests());
ACC_UNUSED_FUNC(rangeless::mt::impl::run_tests);
}
#endif
#endif // WITH_RANGELESS_FN
/* vim:set ts=4 sw=4 et: */

View File

@ -83,10 +83,10 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
// don't enable before gcc-10 because of gcc bug #78010 // don't enable before gcc-10 because of gcc bug #78010
# pragma GCC diagnostic error "-Wsuggest-override" # pragma GCC diagnostic error "-Wsuggest-override"
#endif #endif
// Some non-GLIBC toolchains do not use 'nullptr' everywhere when C++: // Some non-GLIBC toolchains do not use 'nullptr' everywhere when C++:
// openwrt-sdk-x86-64_gcc-11.2.0_musl.Linux-x86_64/staging_dir/ // openwrt-sdk-x86-64_gcc-11.2.0_musl.Linux-x86_64/staging_dir/
// toolchain-x86_64_gcc-11.2.0_musl/include/fortify/stdlib.h: // toolchain-x86_64_gcc-11.2.0_musl/include/fortify/stdlib.h:
// 51:32: error: zero as null pointer constant // 51:32: error: zero as null pointer constant
#if (ACC_CC_CLANG >= 0x050000) #if (ACC_CC_CLANG >= 0x050000)
# pragma clang diagnostic error "-Wzero-as-null-pointer-constant" # pragma clang diagnostic error "-Wzero-as-null-pointer-constant"
#elif (ACC_CC_GNUC >= 0x040700) && defined(__GLIBC__) #elif (ACC_CC_GNUC >= 0x040700) && defined(__GLIBC__)
@ -115,7 +115,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
# include <intrin.h> # include <intrin.h>
#endif #endif
// C++ headers // C++ system headers
#include <exception> #include <exception>
#include <new> #include <new>
#include <type_traits> #include <type_traits>
@ -128,11 +128,21 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
#include <atomic> #include <atomic>
#define upx_std_atomic(Type) std::atomic<Type> #define upx_std_atomic(Type) std::atomic<Type>
#endif #endif
//#define DOCTEST_CONFIG_DISABLE 1
// C++ submodule headers
#include <doctest/doctest/parts/doctest_fwd.h> #include <doctest/doctest/parts/doctest_fwd.h>
#if WITH_BOOST_PFR #if WITH_BOOST_PFR
#include <sstream> # include <sstream>
#include <boost/pfr/io.hpp> # include <boost/pfr/io.hpp>
#endif
#if WITH_RANGELESS_FN
# include <rangeless/include/fn.hpp>
#endif
#ifndef WITH_VALGRIND
#define WITH_VALGRIND 1
#endif
#if (WITH_VALGRIND) && defined(__GNUC__) && !defined(__SANITIZE_ADDRESS__)
# include <valgrind/include/valgrind/memcheck.h>
#endif #endif
// IMPORTANT: unconditionally enable assertions // IMPORTANT: unconditionally enable assertions
@ -141,56 +151,9 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
/************************************************************************* /*************************************************************************
// // core
**************************************************************************/ **************************************************************************/
#if defined(__linux__) && !defined(__unix__)
# define __unix__ 1
#endif
// just in case
#undef _
#undef __
#undef ___
#undef dos
#undef linux
#undef small
#undef tos
#undef unix
#if (ACC_OS_DOS32) && defined(__DJGPP__)
# undef sopen
# undef __unix__
# undef __unix
#endif
#define WITH_LZMA 0x443
#define WITH_UCL 1
#define WITH_ZLIB 1
#if (WITH_UCL)
# define ucl_compress_config_t REAL_ucl_compress_config_t
# include <ucl/include/ucl/uclconf.h>
# include <ucl/include/ucl/ucl.h>
# undef ucl_compress_config_t
# undef ucl_compress_config_p
#endif
// malloc debuggers
#ifndef WITH_VALGRIND
# define WITH_VALGRIND 1
#endif
#if (WITH_VALGRIND) && defined(__GNUC__) && !defined(__SANITIZE_ADDRESS__)
# include <valgrind/include/valgrind/memcheck.h>
#endif
#if !defined(VALGRIND_MAKE_MEM_DEFINED)
# define VALGRIND_MAKE_MEM_DEFINED(addr,len) 0
#endif
#if !defined(VALGRIND_MAKE_MEM_NOACCESS)
# define VALGRIND_MAKE_MEM_NOACCESS(addr,len) 0
#endif
#if !defined(VALGRIND_MAKE_MEM_UNDEFINED)
# define VALGRIND_MAKE_MEM_UNDEFINED(addr,len) 0
#endif
// intergral types // intergral types
typedef acc_int8_t upx_int8_t; typedef acc_int8_t upx_int8_t;
typedef acc_uint8_t upx_uint8_t; typedef acc_uint8_t upx_uint8_t;
@ -227,6 +190,24 @@ typedef upx_int64_t upx_off_t;
// portab // portab
**************************************************************************/ **************************************************************************/
// just in case
#undef _
#undef __
#undef ___
#undef dos
#undef linux
#undef small
#undef tos
#undef unix
#if defined(__linux__) && !defined(__unix__)
# define __unix__ 1
#endif
#if (ACC_OS_DOS32) && defined(__DJGPP__)
# undef sopen
# undef __unix__
# undef __unix
#endif
#ifndef STDIN_FILENO #ifndef STDIN_FILENO
# define STDIN_FILENO (fileno(stdin)) # define STDIN_FILENO (fileno(stdin))
#endif #endif
@ -307,11 +288,22 @@ typedef upx_int64_t upx_off_t;
/************************************************************************* /*************************************************************************
// // util
**************************************************************************/ **************************************************************************/
#define CLANG_FORMAT_DUMMY_STATEMENT /*empty*/ #define CLANG_FORMAT_DUMMY_STATEMENT /*empty*/
// malloc debuggers
#if !defined(VALGRIND_MAKE_MEM_DEFINED)
# define VALGRIND_MAKE_MEM_DEFINED(addr,len) 0
#endif
#if !defined(VALGRIND_MAKE_MEM_NOACCESS)
# define VALGRIND_MAKE_MEM_NOACCESS(addr,len) 0
#endif
#if !defined(VALGRIND_MAKE_MEM_UNDEFINED)
# define VALGRIND_MAKE_MEM_UNDEFINED(addr,len) 0
#endif
#if defined(_WIN32) && defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__) #if defined(_WIN32) && defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)
# define attribute_format(a,b) __attribute__((__format__(__gnu_printf__,a,b))) # define attribute_format(a,b) __attribute__((__format__(__gnu_printf__,a,b)))
#elif (ACC_CC_CLANG || ACC_CC_GNUC) #elif (ACC_CC_CLANG || ACC_CC_GNUC)
@ -488,14 +480,14 @@ constexpr bool string_ge(const char *a, const char *b) {
#define UPX_F_DOS_EXE 3 #define UPX_F_DOS_EXE 3
#define UPX_F_DJGPP2_COFF 4 #define UPX_F_DJGPP2_COFF 4
#define UPX_F_WATCOM_LE 5 #define UPX_F_WATCOM_LE 5
#define UPX_F_VXD_LE 6 // NOT IMPLEMENTED //#define UPX_F_VXD_LE 6 // NOT IMPLEMENTED
#define UPX_F_DOS_EXEH 7 // OBSOLETE #define UPX_F_DOS_EXEH 7 // OBSOLETE
#define UPX_F_TMT_ADAM 8 #define UPX_F_TMT_ADAM 8
#define UPX_F_WIN32_PE 9 #define UPX_F_WIN32_PE 9
#define UPX_F_LINUX_i386 10 #define UPX_F_LINUX_i386 10
#define UPX_F_WIN16_NE 11 // NOT IMPLEMENTED //#define UPX_F_WIN16_NE 11 // NOT IMPLEMENTED
#define UPX_F_LINUX_ELF_i386 12 #define UPX_F_LINUX_ELF_i386 12
#define UPX_F_LINUX_SEP_i386 13 // NOT IMPLEMENTED //#define UPX_F_LINUX_SEP_i386 13 // NOT IMPLEMENTED
#define UPX_F_LINUX_SH_i386 14 #define UPX_F_LINUX_SH_i386 14
#define UPX_F_VMLINUZ_i386 15 #define UPX_F_VMLINUZ_i386 15
#define UPX_F_BVMLINUZ_i386 16 #define UPX_F_BVMLINUZ_i386 16
@ -533,7 +525,7 @@ constexpr bool string_ge(const char *a, const char *b) {
#define UPX_F_LINUX_ELF64_ARM 42 #define UPX_F_LINUX_ELF64_ARM 42
#define UPX_F_ATARI_TOS 129 #define UPX_F_ATARI_TOS 129
#define UPX_F_SOLARIS_SPARC 130 // NOT IMPLEMENTED //#define UPX_F_SOLARIS_SPARC 130 // NOT IMPLEMENTED
#define UPX_F_MACH_PPC32 131 #define UPX_F_MACH_PPC32 131
#define UPX_F_LINUX_ELFPPC32 132 #define UPX_F_LINUX_ELFPPC32 132
#define UPX_F_LINUX_ELF32_ARMEB 133 #define UPX_F_LINUX_ELF32_ARMEB 133
@ -562,7 +554,7 @@ constexpr bool string_ge(const char *a, const char *b) {
//#define M_CL1B_8 12 //#define M_CL1B_8 12
//#define M_CL1B_LE16 13 //#define M_CL1B_LE16 13
#define M_LZMA 14 #define M_LZMA 14
#define M_DEFLATE 15 /* zlib */ #define M_DEFLATE 15 // zlib
#define M_ZSTD 16 #define M_ZSTD 16
// compression methods internal usage // compression methods internal usage
#define M_ALL (-1) #define M_ALL (-1)
@ -588,9 +580,20 @@ constexpr bool string_ge(const char *a, const char *b) {
/************************************************************************* /*************************************************************************
// compression - callback_t // compression - setup and callback_t
**************************************************************************/ **************************************************************************/
#define WITH_LZMA 0x443
#define WITH_UCL 1
#define WITH_ZLIB 1
#if (WITH_UCL)
# define ucl_compress_config_t REAL_ucl_compress_config_t
# include <ucl/include/ucl/uclconf.h>
# include <ucl/include/ucl/ucl.h>
# undef ucl_compress_config_t
# undef ucl_compress_config_p
#endif
struct upx_callback_t; struct upx_callback_t;
typedef upx_callback_t *upx_callback_p; typedef upx_callback_t *upx_callback_p;
typedef void (__acc_cdecl *upx_progress_func_t) typedef void (__acc_cdecl *upx_progress_func_t)

View File

@ -31,6 +31,15 @@
// UPX version of string functions, with assertions and sane limits // UPX version of string functions, with assertions and sane limits
**************************************************************************/ **************************************************************************/
upx_rsize_t upx_safe_strlen(const char *s) {
#undef strlen
assert(s != nullptr);
size_t len = strlen(s);
assert(len < UPX_RSIZE_MAX_STR);
return len;
#define strlen upx_safe_strlen
}
int upx_safe_vsnprintf(char *str, upx_rsize_t max_size, const char *format, va_list ap) { int upx_safe_vsnprintf(char *str, upx_rsize_t max_size, const char *format, va_list ap) {
#undef vsnprintf #undef vsnprintf
size_t size; size_t size;
@ -114,13 +123,4 @@ char *upx_safe_xprintf(const char *format, ...) {
return ptr; return ptr;
} }
upx_rsize_t upx_safe_strlen(const char *s) {
#undef strlen
assert(s != nullptr);
size_t len = strlen(s);
assert(len < UPX_RSIZE_MAX_STR);
return len;
#define strlen upx_safe_strlen
}
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -49,6 +49,9 @@ char *upx_safe_xprintf(const char *format, ...) attribute_format(1, 2);
upx_rsize_t upx_safe_strlen(const char *); upx_rsize_t upx_safe_strlen(const char *);
// globally redirect some functions // globally redirect some functions
#undef strlen
#define strlen upx_safe_strlen
#undef snprintf #undef snprintf
#undef sprintf #undef sprintf
#undef vsnprintf #undef vsnprintf
@ -56,9 +59,6 @@ upx_rsize_t upx_safe_strlen(const char *);
#define sprintf ERROR_sprintf_IS_DANGEROUS_USE_snprintf #define sprintf ERROR_sprintf_IS_DANGEROUS_USE_snprintf
#define vsnprintf upx_safe_vsnprintf #define vsnprintf upx_safe_vsnprintf
#undef strlen
#define strlen upx_safe_strlen
/************************************************************************* /*************************************************************************
// some unsigned char string support functions to avoid casts // some unsigned char string support functions to avoid casts
**************************************************************************/ **************************************************************************/

View File

@ -69,727 +69,4 @@ SPAN_NAMESPACE_END
#endif // WITH_SPAN #endif // WITH_SPAN
// lots of tests (and probably quite a number of redundant tests)
/*************************************************************************
//
**************************************************************************/
TEST_CASE("basic xspan usage") {
char buf[4] = {0, 1, 2, 3};
SUBCASE("SPAN_x") {
SPAN_0(char) a0 = nullptr;
SPAN_0(char) b0 = buf;
SPAN_P(char) bp = buf;
SPAN_0(char) c0 = SPAN_0_MAKE(char, buf);
SPAN_P(char) cp = SPAN_P_MAKE(char, buf);
SPAN_S(char) cs = SPAN_S_MAKE(char, buf, sizeof(buf));
SPAN_0(const char) const x0 = SPAN_0_MAKE(const char, buf);
SPAN_P(const char) const xp = SPAN_P_MAKE(const char, buf);
SPAN_S(const char) const xs = SPAN_S_MAKE(const char, buf, sizeof(buf));
SPAN_P(const char) const yp = xs;
SPAN_0(const char) const z0p = yp;
SPAN_0(const char) const z0s = xs;
CHECK((a0 == nullptr));
CHECK(c0 == b0);
CHECK(cp == bp);
CHECK(cs == bp);
CHECK(x0 == z0p);
CHECK(xp == z0s);
CHECK(raw_bytes(c0, 4) == buf);
CHECK(raw_index_bytes(c0, 1, 3) == buf + 1);
CHECK(raw_bytes(cp, 4) == buf);
CHECK(raw_index_bytes(cp, 1, 3) == buf + 1);
CHECK(raw_bytes(cs, 4) == buf);
CHECK(raw_index_bytes(cs, 1, 3) == buf + 1);
CHECK_THROWS(raw_bytes(cs, 5));
CHECK_THROWS(raw_index_bytes(cs, 1, 4));
}
SUBCASE("SPAN_x_VAR") {
SPAN_0_VAR(char, a0, nullptr);
SPAN_0_VAR(char, b0, buf);
SPAN_P_VAR(char, bp, buf);
SPAN_0_VAR(char, c0, buf, sizeof(buf));
SPAN_P_VAR(char, cp, buf, sizeof(buf));
SPAN_S_VAR(char, cs, buf, sizeof(buf));
SPAN_0_VAR(char, d0, buf + 1, sizeof(buf), buf);
SPAN_P_VAR(char, dp, buf + 1, sizeof(buf), buf);
SPAN_S_VAR(char, ds, buf + 1, sizeof(buf), buf);
SPAN_0_VAR(const char, const x0, buf, sizeof(buf));
SPAN_P_VAR(const char, const xp, buf, sizeof(buf));
SPAN_S_VAR(const char, const xs, buf, sizeof(buf));
SPAN_P_VAR(const char, const yp, xs);
SPAN_0_VAR(const char, const z0p, yp);
SPAN_0_VAR(const char, const z0s, xs);
CHECK((a0 == nullptr));
CHECK(c0 == b0);
CHECK(cp == bp);
CHECK(cs == bp);
CHECK(d0 == dp);
CHECK(d0 == ds);
CHECK(x0 == z0p);
CHECK(xp == z0s);
CHECK(raw_bytes(c0, 4) == buf);
CHECK(raw_index_bytes(c0, 1, 3) == buf + 1);
CHECK(raw_bytes(cp, 4) == buf);
CHECK(raw_index_bytes(cp, 1, 3) == buf + 1);
CHECK(raw_bytes(cs, 4) == buf);
CHECK(raw_index_bytes(cs, 1, 3) == buf + 1);
CHECK_THROWS(raw_bytes(cs, 5));
CHECK_THROWS(raw_index_bytes(cs, 1, 4));
}
SUBCASE("xspan in class") {
struct MyType {
SPAN_0(char) s0;
SPAN_P(char) sp;
SPAN_S(char) ss;
#if __cplusplus >= 201103L
SPAN_0(char) x0 = nullptr;
#endif
#if WITH_SPAN >= 2
// much nicer syntax when using fully checked xspan:
MyType(char *b, size_t n, bool) : s0(b, n), sp(b, n), ss(b, n) {}
#endif
MyType(char *b, size_t n)
: s0(SPAN_0_MAKE(char, b, n)), sp(SPAN_P_MAKE(char, b, n)),
ss(SPAN_S_MAKE(char, b, n)) {
UNUSED(n);
}
};
MyType x(buf, sizeof(buf));
MyType y = MyType(buf, sizeof(buf));
CHECK(x.s0 == y.sp);
}
}
/*************************************************************************
//
**************************************************************************/
#if WITH_SPAN >= 2
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;
// v0 nullptr, b0 base, b1 base + 1
const Span0 v0_v0(nullptr);
const Span0 v0_b0(nullptr, 4, base_buf);
const Span0 v0_b1(nullptr, 3, base_buf + 1);
const Span0 b0_v0(base_buf);
const Span0 b0_b0(base_buf, 4, base_buf);
CHECK_THROWS(SPAN_0_MAKE(char, base_buf, 3, base_buf + 1)); // b0_b1
const Span0 b1_v0(base_buf + 1);
const Span0 b1_b0(base_buf + 1, 4, base_buf);
const Span0 b1_b1(base_buf + 1, 3, base_buf + 1);
CHECK_THROWS(ss_with_base = v0_v0); // nullptr assignment
CHECK_THROWS(ss_with_base = v0_b0); // nullptr assignment
CHECK_THROWS(ss_with_base = v0_b1); // nullptr assignment
CHECK_NOTHROW(ss_with_base = b0_v0);
CHECK_NOTHROW(ss_with_base = b0_b0);
CHECK_NOTHROW(ss_with_base = b1_v0);
CHECK_NOTHROW(ss_with_base = b1_b0);
CHECK_THROWS(ss_with_base = b1_b1); // different base
CHECK_THROWS(SPAN_S_MAKE(char, v0_v0));
CHECK_THROWS(SPAN_S_MAKE(char, v0_b0));
CHECK_THROWS(SPAN_S_MAKE(char, v0_b1));
CHECK_THROWS(SPAN_S_MAKE(char, b0_v0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b0_b0));
CHECK_THROWS(SPAN_S_MAKE(char, b1_v0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b1_b0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b1_b1));
//
CHECK((SPAN_S_MAKE(char, b0_b0).raw_base() == base_buf));
CHECK((SPAN_S_MAKE(char, b1_b0).raw_base() == base_buf));
CHECK((SPAN_S_MAKE(char, b1_b1).raw_base() == base_buf + 1));
}
{
typedef PtrOrSpan<char> SpanP;
// v0 nullptr, b0 base, b1 base + 1
const SpanP b0_v0(base_buf);
const SpanP b0_b0(base_buf, 4, base_buf);
CHECK_THROWS(SPAN_P_MAKE(char, base_buf, 3, base_buf + 1)); // b0_b1
const SpanP b1_v0(base_buf + 1);
const SpanP b1_b0(base_buf + 1, 4, base_buf);
const SpanP b1_b1(base_buf + 1, 3, base_buf + 1);
CHECK_NOTHROW(ss_with_base = b0_v0);
CHECK_NOTHROW(ss_with_base = b0_b0);
CHECK_NOTHROW(ss_with_base = b1_v0);
CHECK_NOTHROW(ss_with_base = b1_b0);
CHECK_THROWS(ss_with_base = b1_b1); // different base
CHECK_THROWS(SPAN_S_MAKE(char, b0_v0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b0_b0));
CHECK_THROWS(SPAN_S_MAKE(char, b1_v0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b1_b0));
CHECK_NOTHROW(SPAN_S_MAKE(char, b1_b1));
//
CHECK((SPAN_S_MAKE(char, b0_b0).raw_base() == base_buf));
CHECK((SPAN_S_MAKE(char, b1_b0).raw_base() == base_buf));
CHECK((SPAN_S_MAKE(char, b1_b1).raw_base() == base_buf + 1));
}
#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);
}
/*************************************************************************
//
**************************************************************************/
#if !defined(DOCTEST_CONFIG_DISABLE)
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
#endif
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: */ /* vim:set ts=4 sw=4 et: */

View File

@ -52,7 +52,7 @@ pointer base;
size_type size_in_bytes; 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 || 1 #if DEBUG
__acc_noinline void assertInvariants() const { __acc_noinline void assertInvariants() const {
if __acc_cte (configRequirePtr) if __acc_cte (configRequirePtr)
assert(ptr != nullptr); assert(ptr != nullptr);