1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
//===--- BugReducerTester.cpp ---------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// This pass is a testing pass for sil-bug-reducer. It asserts when it visits a
/// function that calls a function specified by an llvm::cl::opt.
///
//===----------------------------------------------------------------------===//
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/ApplySite.h"
#include "swift/SIL/SILLocation.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "llvm/Support/CommandLine.h"
using namespace swift;
static llvm::cl::opt<std::string> FunctionTarget(
"bug-reducer-tester-target-func",
llvm::cl::desc("Function that when called by an apply should cause "
"BugReducerTester to blow up or miscompile if the pass "
"visits the apply"));
namespace {
enum class FailureKind {
OptimizerCrasher,
RuntimeMiscompile,
RuntimeCrasher,
None
};
} // end anonymous namespace
static llvm::cl::opt<FailureKind> TargetFailureKind(
"bug-reducer-tester-failure-kind",
llvm::cl::desc("The type of failure to perform"),
llvm::cl::values(
clEnumValN(FailureKind::OptimizerCrasher, "opt-crasher",
"Crash the optimizer when we see the specified apply"),
clEnumValN(FailureKind::RuntimeMiscompile, "miscompile",
"Delete the target function call to cause a runtime "
"miscompile that is not a crasher"),
clEnumValN(FailureKind::RuntimeCrasher, "runtime-crasher",
"Delete the target function call to cause a runtime "
"miscompile that is not a crasher")),
llvm::cl::init(FailureKind::None));
LLVM_ATTRIBUTE_NOINLINE
void THIS_TEST_IS_EXPECTED_TO_CRASH_HERE() {
llvm_unreachable("Found the target!");
}
namespace {
class BugReducerTester : public SILFunctionTransform {
// We only want to cause 1 miscompile.
bool CausedError = false;
StringRef RuntimeCrasherFunctionName = "bug_reducer_runtime_crasher_func";
SILFunction *getRuntimeCrasherFunction() {
assert(TargetFailureKind == FailureKind::RuntimeCrasher);
llvm::SmallVector<SILResultInfo, 1> ResultInfoArray;
auto EmptyTupleCanType = getFunction()
->getModule()
.Types.getEmptyTupleType()
.getASTType();
ResultInfoArray.push_back(
SILResultInfo(EmptyTupleCanType, ResultConvention::Unowned));
auto FuncType = SILFunctionType::get(
nullptr, SILFunctionType::ExtInfo::getThin(), SILCoroutineKind::None,
ParameterConvention::Direct_Unowned, ArrayRef<SILParameterInfo>(),
ArrayRef<SILYieldInfo>(), ResultInfoArray, std::nullopt,
SubstitutionMap(), SubstitutionMap(),
getFunction()->getModule().getASTContext());
SILOptFunctionBuilder FunctionBuilder(*this);
SILFunction *F = FunctionBuilder.getOrCreateSharedFunction(
RegularLocation::getAutoGeneratedLocation(), RuntimeCrasherFunctionName,
FuncType, IsBare, IsNotTransparent, IsSerialized, ProfileCounter(),
IsNotThunk, IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible);
if (F->isDefinition())
return F;
// Create a new block.
SILBasicBlock *BB = F->createBasicBlock();
// Insert a builtin int trap. Then return F.
SILBuilder B(BB);
B.createUnconditionalFail(RegularLocation::getAutoGeneratedLocation(),
"bug reducer crash");
B.createUnreachable(ArtificialUnreachableLocation());
return F;
}
void run() override {
// If we don't have a target function or we already caused a miscompile,
// just return.
if (FunctionTarget.empty() || CausedError)
return;
assert(TargetFailureKind != FailureKind::None);
for (auto &BB : *getFunction()) {
for (auto II = BB.begin(), IE = BB.end(); II != IE;) {
// Skip try_apply. We do not support them for now.
if (isa<TryApplyInst>(&*II)) {
++II;
continue;
}
auto FAS = FullApplySite::isa(&*II);
if (!FAS) {
++II;
continue;
}
auto *FRI = dyn_cast<FunctionRefInst>(FAS.getCallee());
if (!FRI || !FRI->getReferencedFunction()->getName().equals(
FunctionTarget)) {
++II;
continue;
}
// Ok, we found the Apply that we want! If we are asked to crash, crash
// here.
if (TargetFailureKind == FailureKind::OptimizerCrasher)
THIS_TEST_IS_EXPECTED_TO_CRASH_HERE();
// Otherwise, if we are asked to perform a runtime time miscompile,
// delete the apply target.
if (TargetFailureKind == FailureKind::RuntimeMiscompile) {
// Ok, we need to insert a runtime miscompile. Move II to
// the next instruction and then replace its current value
// with undef.
auto *Inst = cast<SingleValueInstruction>(&*II);
Inst->replaceAllUsesWith(SILUndef::get(Inst));
Inst->eraseFromParent();
// Mark that we found the miscompile and return so we do not try to
// visit any more instructions in this function.
CausedError = true;
return;
}
assert(TargetFailureKind == FailureKind::RuntimeCrasher);
// Finally, if we reach this point we are being asked to replace the
// given apply with a new apply that calls the crasher func.
auto Loc = RegularLocation::getAutoGeneratedLocation();
SILFunction *RuntimeCrasherFunc = getRuntimeCrasherFunction();
llvm::dbgs() << "Runtime Crasher Func!\n";
RuntimeCrasherFunc->dump();
SILBuilder B(II);
B.createApply(Loc, B.createFunctionRef(Loc, RuntimeCrasherFunc),
SubstitutionMap(),
ArrayRef<SILValue>());
auto *Inst = cast<SingleValueInstruction>(&*II);
++II;
Inst->replaceAllUsesWith(SILUndef::get(Inst));
Inst->eraseFromParent();
CausedError = true;
return;
}
}
}
};
} // end anonymous namespace
SILTransform *swift::createBugReducerTester() { return new BugReducerTester(); }
|