diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3543c7a..03259ec 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -254,3 +254,94 @@ jobs: - name: ccache stats run: ccache -s + + sanitizer: + runs-on: ubuntu-latest + permissions: + contents: read + + env: + CXX: clang++ + ASAN_OPTIONS: strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:detect_leaks=1 + UBSAN_OPTIONS: print_stacktrace=1 + + strategy: + fail-fast: false + matrix: + release: [stable, HEAD] + + steps: + - uses: actions/checkout@v6 + + - name: Setup Git User for Applying Patches + run: | + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ccache + + - name: Generate cache key + shell: cmake -P {0} + run: | + string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC) + file(APPEND "$ENV{GITHUB_ENV}" "CACHE_KEY=sanitizer_${{ matrix.release }}\n") + file(APPEND "$ENV{GITHUB_ENV}" "CACHE_TIMESTAMP=${current_date}\n") + + - name: Update the cache (ccache) + uses: actions/cache@v5 + with: + path: "${{ github.workspace }}/ccache" + key: ${{ env.CACHE_KEY }}_ccache_${{ env.CACHE_TIMESTAMP }} + restore-keys: | + ${{ env.CACHE_KEY }}_ccache_ + + - name: Setup ccache + working-directory: "${{ github.workspace }}" + shell: cmake -P {0} + run: | + file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ccache") + file(APPEND "$ENV{GITHUB_ENV}" "CCACHE_BASEDIR=${CMAKE_CURRENT_SOURCE_DIR}\n") + file(APPEND "$ENV{GITHUB_ENV}" "CCACHE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/ccache\n") + file(APPEND "$ENV{GITHUB_ENV}" "CCACHE_COMPRESS=true\n") + file(APPEND "$ENV{GITHUB_ENV}" "CCACHE_COMPRESSLEVEL=10\n") + file(APPEND "$ENV{GITHUB_ENV}" "CCACHE_MAXSIZE=400M\n") + file(APPEND "$ENV{GITHUB_ENV}" "CMAKE_CXX_COMPILER_LAUNCHER=ccache\n") + file(APPEND "$ENV{GITHUB_ENV}" "CMAKE_C_COMPILER_LAUNCHER=ccache\n") + execute_process(COMMAND ccache -z) + + - name: Configure the project + run: cmake --preset=ci-sanitize + -Dsleigh_RELEASE_TYPE=${{ matrix.release }} + -Dsleigh_BUILD_DOCUMENTATION=OFF + + - name: Build the project + run: cmake + --build build/sanitize + -j 4 + -v + + - name: Test the project + working-directory: build/sanitize + run: ctest -VV + + - name: Run the example + run: cmake + --build build/sanitize + -j 4 + --target sleigh_example_runner + + - name: Run the install target + run: cmake --install build/sanitize + --prefix install + + - name: Smoketest sleigh lift + run: | + ./install/bin/sleigh-lift --version + ./install/bin/sleigh-lift disassemble x86-64.sla 4881ecc00f0000 + ./install/bin/sleigh-lift pcode x86-64.sla 4881ecc00f0000 + + - name: ccache stats + run: ccache -s diff --git a/src/patches/HEAD/0008-Fix-UBSAN-signed-left-shift-errors.patch b/src/patches/HEAD/0008-Fix-UBSAN-signed-left-shift-errors.patch new file mode 100644 index 0000000..d269a2b --- /dev/null +++ b/src/patches/HEAD/0008-Fix-UBSAN-signed-left-shift-errors.patch @@ -0,0 +1,57 @@ +From 8afa7d89a368b358a5493b87804985ed9ac70a2f Mon Sep 17 00:00:00 2001 +From: "github-actions[bot]" + <41898282+github-actions[bot]@users.noreply.github.com> +Date: Wed, 25 Feb 2026 20:41:10 +0000 +Subject: [PATCH] Fix UBSAN signed left shift errors + +Cast signed values to unsigned before left shifting to avoid undefined +behavior when the signed value is negative or when the result cannot be +represented in the signed type. + +Fixes runtime errors detected by UndefinedBehaviorSanitizer: +- address.hh sign_extend(): left shift of negative value +- address.hh sign_extend(): left shift cannot be represented in type 'intb' +- slghpatexpress.cc LeftShiftExpression: left shift of negative value +--- + Ghidra/Features/Decompiler/src/decompile/cpp/address.hh | 2 +- + .../Features/Decompiler/src/decompile/cpp/slghpatexpress.cc | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh +index 45144daf3..0e75c68b8 100644 +--- a/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh ++++ b/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh +@@ -544,7 +544,7 @@ inline intb sign_extend(intb val,int4 bit) + + { + int4 sa = 8*sizeof(intb) - (bit+1); +- val = (val << sa) >> sa; ++ val = static_cast(static_cast(val) << sa) >> sa; + return val; + } + +diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc +index 941097859..93cce378a 100644 +--- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc ++++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc +@@ -969,7 +969,7 @@ intb LeftShiftExpression::getValue(ParserWalker &walker) const + { + intb leftval = getLeft()->getValue(walker); + intb rightval = getRight()->getValue(walker); +- return leftval << rightval; ++ return static_cast(static_cast(leftval) << rightval); + } + + intb LeftShiftExpression::getSubValue(const vector &replace,int4 &listpos) const +@@ -977,7 +977,7 @@ intb LeftShiftExpression::getSubValue(const vector &replace,int4 &listpos) + { + intb leftval = getLeft()->getSubValue(replace,listpos); // Must be left first + intb rightval = getRight()->getSubValue(replace,listpos); +- return leftval << rightval; ++ return static_cast(static_cast(leftval) << rightval); + } + + void LeftShiftExpression::encode(Encoder &encoder) const +-- +2.51.1 + diff --git a/src/patches/stable/0006-Fix-UBSAN-signed-left-shift-errors.patch b/src/patches/stable/0006-Fix-UBSAN-signed-left-shift-errors.patch new file mode 100644 index 0000000..91b4d8c --- /dev/null +++ b/src/patches/stable/0006-Fix-UBSAN-signed-left-shift-errors.patch @@ -0,0 +1,57 @@ +From 8afa7d89a368b358a5493b87804985ed9ac70a2f Mon Sep 17 00:00:00 2001 +From: "github-actions[bot]" + <41898282+github-actions[bot]@users.noreply.github.com> +Date: Wed, 25 Feb 2026 20:41:10 +0000 +Subject: [PATCH] Fix UBSAN signed left shift errors + +Cast signed values to unsigned before left shifting to avoid undefined +behavior when the signed value is negative or when the result cannot be +represented in the signed type. + +Fixes runtime errors detected by UndefinedBehaviorSanitizer: +- address.hh sign_extend(): left shift of negative value +- address.hh sign_extend(): left shift cannot be represented in type 'intb' +- slghpatexpress.cc LeftShiftExpression: left shift of negative value +--- + Ghidra/Features/Decompiler/src/decompile/cpp/address.hh | 2 +- + .../Features/Decompiler/src/decompile/cpp/slghpatexpress.cc | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh +index 45144daf3..0e75c68b8 100644 +--- a/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh ++++ b/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh +@@ -544,7 +544,7 @@ inline intb sign_extend(intb val,int4 bit) + + { + int4 sa = 8*sizeof(intb) - (bit+1); +- val = (val << sa) >> sa; ++ val = static_cast(static_cast(val) << sa) >> sa; + return val; + } + +diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc +index 941097859..93cce378a 100644 +--- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc ++++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc +@@ -969,7 +969,7 @@ intb LeftShiftExpression::getValue(ParserWalker &walker) const + { + intb leftval = getLeft()->getValue(walker); + intb rightval = getRight()->getValue(walker); +- return leftval << rightval; ++ return static_cast(static_cast(leftval) << rightval); + } + + intb LeftShiftExpression::getSubValue(const vector &replace,int4 &listpos) const +@@ -977,7 +977,7 @@ intb LeftShiftExpression::getSubValue(const vector &replace,int4 &listpos) + { + intb leftval = getLeft()->getSubValue(replace,listpos); // Must be left first + intb rightval = getRight()->getSubValue(replace,listpos); +- return leftval << rightval; ++ return static_cast(static_cast(leftval) << rightval); + } + + void LeftShiftExpression::encode(Encoder &encoder) const +-- +2.51.1 + diff --git a/src/setup-ghidra-source.cmake b/src/setup-ghidra-source.cmake index 5dcd98d..cc1e2ac 100644 --- a/src/setup-ghidra-source.cmake +++ b/src/setup-ghidra-source.cmake @@ -43,6 +43,7 @@ set(ghidra_patches "${CMAKE_CURRENT_LIST_DIR}/patches/stable/0003-Ignore-floating-point-test-due-to-compilation-differ.patch" "${CMAKE_CURRENT_LIST_DIR}/patches/stable/0004-Allow-positive-or-negative-NAN-in-decompiler-floatin.patch" "${CMAKE_CURRENT_LIST_DIR}/patches/stable/0005-decompiler-Fix-strict-weak-ordering-TypePartialEnum.patch" + "${CMAKE_CURRENT_LIST_DIR}/patches/stable/0006-Fix-UBSAN-signed-left-shift-errors.patch" ) # Ghidra pinned commits used for pinning last known working HEAD commit @@ -65,6 +66,7 @@ if("${sleigh_RELEASE_TYPE}" STREQUAL "HEAD") "${CMAKE_CURRENT_LIST_DIR}/patches/HEAD/0005-decompiler-Fix-strict-weak-ordering-TypePartialEnum.patch" "${CMAKE_CURRENT_LIST_DIR}/patches/HEAD/0006-decompiler-Fix-strict-weak-ordering-PullRecord.patch" "${CMAKE_CURRENT_LIST_DIR}/patches/HEAD/0007-decompiler-Fix-strict-weak-ordering-compareFinalOrde.patch" + "${CMAKE_CURRENT_LIST_DIR}/patches/HEAD/0008-Fix-UBSAN-signed-left-shift-errors.patch" ) string(SUBSTRING "${ghidra_git_tag}" 0 7 ghidra_short_commit) else()