From 56eee94851292f86ee48c6b258393f110ee6470d Mon Sep 17 00:00:00 2001 From: William Tan <1284324+Ninja3047@users.noreply.github.com> Date: Tue, 31 Mar 2026 10:12:41 -0400 Subject: [PATCH] fix control-flow decoding and restore smoketests Handle the synthetic fallthrough sentinel in Sleigh control-flow analysis without indexing past the end of the pcode ops vector. Also fix the aarch32 smoketest flag spelling in CI and keep Nix checks enabled on Darwin so the smoketests run consistently across environments. --- .github/workflows/build.yml | 8 ++---- flake.nix | 2 +- lib/Arch/Sleigh/ControlFlowStructuring.cpp | 30 +++++++++++++++++----- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb96c316..8f67831d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -80,7 +80,7 @@ jobs: run: | install/bin/remill-lift-${{ matrix.llvm }} --arch amd64 --ir_out /dev/stdout --bytes c704ba01000000 install/bin/remill-lift-${{ matrix.llvm }} --arch aarch64 --ir_out /dev/stdout --address 0x400544 --bytes FD7BBFA90000009000601891FD030091B7FFFF97E0031F2AFD7BC1A8C0035FD6 - install/bin/remill-lift-${{ matrix.llvm }} --arch aarch32 -ir_out /dev/stderr --bytes 0cd04de208008de504108de500208de508309de504009de500109de5903122e0c20fa0e110109fe5001091e5002081e5040081e50cd08de21eff2fe14000000000000000 + install/bin/remill-lift-${{ matrix.llvm }} --arch aarch32 --ir_out /dev/stderr --bytes 0cd04de208008de504108de500208de508309de504009de500109de5903122e0c20fa0e110109fe5001091e5002081e5040081e50cd08de21eff2fe14000000000000000 - name: Test remill run: | @@ -117,11 +117,7 @@ jobs: run: | ./result/bin/remill-lift-${{ matrix.llvm }} --arch amd64 --ir_out /dev/stdout --bytes c704ba01000000 ./result/bin/remill-lift-${{ matrix.llvm }} --arch aarch64 --ir_out /dev/stdout --address 0x400544 --bytes FD7BBFA90000009000601891FD030091B7FFFF97E0031F2AFD7BC1A8C0035FD6 - - - name: Smoketests (aarch32) - if: ${{ runner.os != 'macOS' }} - run: | - ./result/bin/remill-lift-${{ matrix.llvm }} --arch aarch32 -ir_out /dev/stderr --bytes 0cd04de208008de504108de500208de508309de504009de500109de5903122e0c20fa0e110109fe5001091e5002081e5040081e50cd08de21eff2fe14000000000000000 + ./result/bin/remill-lift-${{ matrix.llvm }} --arch aarch32 --ir_out /dev/stderr --bytes 0cd04de208008de504108de500208de508309de504009de500109de5903122e0c20fa0e110109fe5001091e5002081e5040081e50cd08de21eff2fe14000000000000000 macos: # Skip building pull requests from the same repository diff --git a/flake.nix b/flake.nix index a9cb5a94..58989910 100644 --- a/flake.nix +++ b/flake.nix @@ -136,7 +136,7 @@ "-DGIT_FAIL_IF_NONZERO_EXIT=FALSE" ]; - doCheck = !pkgs.stdenv.hostPlatform.isDarwin; + doCheck = true; checkPhase = '' runHook preCheck diff --git a/lib/Arch/Sleigh/ControlFlowStructuring.cpp b/lib/Arch/Sleigh/ControlFlowStructuring.cpp index f771dc27..5de579b5 100644 --- a/lib/Arch/Sleigh/ControlFlowStructuring.cpp +++ b/lib/Arch/Sleigh/ControlFlowStructuring.cpp @@ -255,13 +255,22 @@ static ControlFlowStructureAnalysis::SleighDecodingResult ExtractNonConditionalCategory( const std::vector &flows, const std::vector &ops, std::function( - const Flow &, const RemillPcodeOp &)> + const Flow &, + std::optional>)> compute_single_flow_category) { // So here the requirement to make this cateogry work is that all flows target the same abnormal (or are all returns), and all decoding contexts are equal std::vector cats; - for (auto flow : flows) { - if (auto cat = compute_single_flow_category(flow, ops[flow.pcode_index])) { + for (const auto &flow : flows) { + std::optional> op; + if (flow.pcode_index < ops.size()) { + op = std::cref(ops[flow.pcode_index]); + } else if (flow.pcode_index != ops.size()) { + DLOG(ERROR) << "Flow index out of range"; + return std::nullopt; + } + + if (auto cat = compute_single_flow_category(flow, op)) { cats.push_back(*cat); } else { DLOG(ERROR) << "Missing flow cat"; @@ -291,11 +300,12 @@ ExtractNonConditionalCategory( static ControlFlowStructureAnalysis::SleighDecodingResult ExtractNormal(const std::vector &flows, const std::vector &ops) { - // So we already know the op fallsthrough return ExtractNonConditionalCategory( flows, ops, - [](const Flow &flow, const RemillPcodeOp &op) + [](const Flow &flow, + std::optional> op) -> std::optional { + (void) op; if (flow.context) { Instruction::NormalInsn norm( Instruction::FallthroughFlow(*flow.context)); @@ -312,9 +322,15 @@ ExtractAbnormal(const std::vector &flows, const std::vector &ops) { return ExtractNonConditionalCategory( flows, ops, - [](const Flow &flow, const RemillPcodeOp &op) + [](const Flow &flow, + std::optional> op) -> std::optional { - auto res = AbnormalCategoryOfFlow(flow, op); + if (!op) { + DLOG(ERROR) << "Abnormal flow requires backing pcode op"; + return std::nullopt; + } + + auto res = AbnormalCategoryOfFlow(flow, op->get()); if (res) { return variant_cast(*res); }