[llvm] Add pass to turn function into Unreachable and script to find UB. (PR #118034)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 28 13:30:37 PST 2024
https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/118034
This adds a pass to replace function bodies with 'unreachable' and a script that checks if the result still verifies.
This can be used to find functions in llvm-lit tests that have unconditional UB using
llvm-lit -j4 -sv -Dopt=~/find-ub-in-test.sh
Examples of found & fixed UB:
* b8d728a098b1
* 684a82fbc543
Differential Revision: https://reviews.llvm.org/D127607
>From c537f563330e2cf5a98d6bf9f4e4375e5a45ea10 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 11 Jun 2022 23:17:53 +0100
Subject: [PATCH] Add pass to turn function into Unreachable and script to find
UB.
This adds a pass to replace function bodies with 'unreachable' and a
script that checks if the result still verifies.
This can be used to find functions in llvm-lit tests that have
unconditional UB using
llvm-lit -j4 -sv -Dopt=~/find-ub-in-test.sh
Examples of found & fixed UB:
* b8d728a098b1
* 684a82fbc543
Differential Revision: https://reviews.llvm.org/D127607
---
.../llvm/Transforms/Scalar/ToUnreachable.h | 22 ++++++++
llvm/lib/Passes/PassBuilder.cpp | 1 +
llvm/lib/Passes/PassRegistry.def | 1 +
llvm/lib/Transforms/Scalar/CMakeLists.txt | 1 +
llvm/lib/Transforms/Scalar/ToUnreachable.cpp | 34 ++++++++++++
llvm/utils/find-ub-in-test.sh | 52 +++++++++++++++++++
6 files changed, 111 insertions(+)
create mode 100644 llvm/include/llvm/Transforms/Scalar/ToUnreachable.h
create mode 100644 llvm/lib/Transforms/Scalar/ToUnreachable.cpp
create mode 100755 llvm/utils/find-ub-in-test.sh
diff --git a/llvm/include/llvm/Transforms/Scalar/ToUnreachable.h b/llvm/include/llvm/Transforms/Scalar/ToUnreachable.h
new file mode 100644
index 00000000000000..251afe24997c04
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Scalar/ToUnreachable.h
@@ -0,0 +1,22 @@
+//===- ToUnreachable.h - Turn function into unreachable. --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_TOUNREACHABLE_H
+#define LLVM_TRANSFORMS_SCALAR_TOUNREACHABLE_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+struct ToUnreachablePass : public PassInfoMixin<ToUnreachablePass> {
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+};
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index cf7ceed63607a6..9300c9ff145fec 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -299,6 +299,7 @@
#include "llvm/Transforms/Scalar/StraightLineStrengthReduce.h"
#include "llvm/Transforms/Scalar/StructurizeCFG.h"
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
+#include "llvm/Transforms/Scalar/ToUnreachable.h"
#include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
#include "llvm/Transforms/Utils/AddDiscriminators.h"
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 7c3798f6462a46..adf601f0c832d5 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -495,6 +495,7 @@ FUNCTION_PASS("view-dom-only", DomOnlyViewer())
FUNCTION_PASS("view-post-dom", PostDomViewer())
FUNCTION_PASS("view-post-dom-only", PostDomOnlyViewer())
FUNCTION_PASS("wasm-eh-prepare", WasmEHPreparePass())
+FUNCTION_PASS("to-unreachable", ToUnreachablePass())
#undef FUNCTION_PASS
#ifndef FUNCTION_PASS_WITH_PARAMS
diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt
index 84a5b02043d012..d4dadf86c3ffd9 100644
--- a/llvm/lib/Transforms/Scalar/CMakeLists.txt
+++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt
@@ -78,6 +78,7 @@ add_llvm_component_library(LLVMScalarOpts
StraightLineStrengthReduce.cpp
StructurizeCFG.cpp
TailRecursionElimination.cpp
+ ToUnreachable.cpp
WarnMissedTransforms.cpp
ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/Transforms/Scalar/ToUnreachable.cpp b/llvm/lib/Transforms/Scalar/ToUnreachable.cpp
new file mode 100644
index 00000000000000..541099c13026b3
--- /dev/null
+++ b/llvm/lib/Transforms/Scalar/ToUnreachable.cpp
@@ -0,0 +1,34 @@
+//===- ToUnreachable.cpp - Turn function into unreachable. ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/ToUnreachable.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+
+using namespace llvm;
+
+PreservedAnalyses ToUnreachablePass::run(Function &F,
+ FunctionAnalysisManager &AM) {
+ SmallVector<BasicBlock *> AllBlocks;
+ for (BasicBlock &BB : F) {
+ AllBlocks.push_back(&BB);
+ BB.dropAllReferences();
+ }
+
+ for (unsigned I = 1; I < AllBlocks.size(); ++I)
+ AllBlocks[I]->eraseFromParent();
+
+ for (Instruction &I : make_early_inc_range(*AllBlocks[0]))
+ I.eraseFromParent();
+
+ new UnreachableInst(F.getContext(), AllBlocks[0]);
+ return PreservedAnalyses::none();
+}
diff --git a/llvm/utils/find-ub-in-test.sh b/llvm/utils/find-ub-in-test.sh
new file mode 100755
index 00000000000000..15dab0a797aa63
--- /dev/null
+++ b/llvm/utils/find-ub-in-test.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+FILE=""
+S_OPT=""
+ORIG_ARGS="$@"
+for arg in $@; do
+ shift
+ if [[ $arg == *".ll" ]]; then
+ FILE="${arg}"
+ fi
+done
+
+if [[ "$OSTYPE" == "darwin"* ]]; then
+ # Mac
+ TV_SHAREDLIB=tv.dylib
+else
+ # Linux, Cygwin/Msys, or Win32?
+ TV_SHAREDLIB=tv.so
+fi
+
+TV_REPORT_DIR=""
+TIMEOUT=""
+TV_SMT_TO=""
+TV_SMT_STATS=""
+TV_REPORT_DIR=-tv-report-dir=alive2/build/logs
+TIMEOUT=""
+TV_SMT_TO="-tv-smt-to=100000"
+TV_SMT_STATS=-tv-smt-stats
+
+NPM_PLUGIN="-load-pass-plugin=alive2/build/tv/$TV_SHAREDLIB"
+
+# Write input to temporary file so it can be passed to multiple opt calls, even
+# if read from stdin. Run opt with original args, save output.
+OUT=$(mktemp)
+if [[ $FILE == "" ]]; then
+ FILE="$(mktemp)"
+ bin/opt > $FILE
+ bin/opt $ORIG_ARGS $FILE > $OUT
+else
+ bin/opt $ORIG_ARGS > $OUT
+fi
+
+# Check if replacing all input functions with unreachable still verifies. If it does, the input has likely unconditional UB.
+bin/opt -load=live2/build/tv/$TV_SHAREDLIB $NPM_PLUGIN -tv-exit-on-error -passes="tv,to-unreachable,tv" -disable-output $FILE $TV_SMT_TO $TV_REPORT_DIR $TV_SMT_STATS 2> /dev/null
+ret=$?
+
+cat $OUT
+
+if [ $ret -ne 0 ]; then
+ exit 0
+fi
+exit 1
More information about the llvm-commits
mailing list