
# What This PR renames the newly-introduced llvm attribute `sanitize_realtime_unsafe` to `sanitize_realtime_blocking`. Likewise, sibling variables such as `SanitizeRealtimeUnsafe` are renamed to `SanitizeRealtimeBlocking` respectively. There are no other functional changes. # Why? - There are a number of problems that can cause a function to be real-time "unsafe", - we wish to communicate what problems rtsan detects and *why* they're unsafe, and - a generic "unsafe" attribute is, in our opinion, too broad a net - which may lead to future implementations that need extra contextual information passed through them in order to communicate meaningful reasons to users. - We want to avoid this situation and make the runtime library boundary API/ABI as simple as possible, and - we believe that restricting the scope of attributes to names like `sanitize_realtime_blocking` is an effective means of doing so. We also feel that the symmetry between `[[clang::blocking]]` and `sanitize_realtime_blocking` is easier to follow as a developer. # Concerns - I'm aware that the LLVM attribute `sanitize_realtime_unsafe` has been part of the tree for a few weeks now (introduced here: https://github.com/llvm/llvm-project/pull/106754). Given that it hasn't been released in version 20 yet, am I correct in considering this to not be a breaking change?
92 lines
3.4 KiB
C++
92 lines
3.4 KiB
C++
//===- RealtimeSanitizer.cpp - RealtimeSanitizer instrumentation *- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file is a part of the RealtimeSanitizer, an LLVM transformation for
|
|
// detecting and reporting realtime safety violations.
|
|
//
|
|
// See also: llvm-project/compiler-rt/lib/rtsan/
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/IR/Analysis.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/IR/InstIterator.h"
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/Demangle/Demangle.h"
|
|
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
|
|
|
|
using namespace llvm;
|
|
|
|
static SmallVector<Type *> getArgTypes(ArrayRef<Value *> FunctionArgs) {
|
|
SmallVector<Type *> Types;
|
|
for (Value *Arg : FunctionArgs)
|
|
Types.push_back(Arg->getType());
|
|
return Types;
|
|
}
|
|
|
|
static void insertCallBeforeInstruction(Function &Fn, Instruction &Instruction,
|
|
const char *FunctionName,
|
|
ArrayRef<Value *> FunctionArgs) {
|
|
LLVMContext &Context = Fn.getContext();
|
|
FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context),
|
|
getArgTypes(FunctionArgs), false);
|
|
FunctionCallee Func =
|
|
Fn.getParent()->getOrInsertFunction(FunctionName, FuncType);
|
|
IRBuilder<> Builder{&Instruction};
|
|
Builder.CreateCall(Func, FunctionArgs);
|
|
}
|
|
|
|
static void insertCallAtFunctionEntryPoint(Function &Fn,
|
|
const char *InsertFnName,
|
|
ArrayRef<Value *> FunctionArgs) {
|
|
insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName,
|
|
FunctionArgs);
|
|
}
|
|
|
|
static void insertCallAtAllFunctionExitPoints(Function &Fn,
|
|
const char *InsertFnName,
|
|
ArrayRef<Value *> FunctionArgs) {
|
|
for (auto &I : instructions(Fn))
|
|
if (isa<ReturnInst>(&I))
|
|
insertCallBeforeInstruction(Fn, I, InsertFnName, FunctionArgs);
|
|
}
|
|
|
|
static PreservedAnalyses rtsanPreservedCFGAnalyses() {
|
|
PreservedAnalyses PA;
|
|
PA.preserveSet<CFGAnalyses>();
|
|
return PA;
|
|
}
|
|
|
|
static PreservedAnalyses runSanitizeRealtime(Function &Fn) {
|
|
insertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter", {});
|
|
insertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit", {});
|
|
return rtsanPreservedCFGAnalyses();
|
|
}
|
|
|
|
static PreservedAnalyses runSanitizeRealtimeBlocking(Function &Fn) {
|
|
IRBuilder<> Builder(&Fn.front().front());
|
|
Value *Name = Builder.CreateGlobalString(demangle(Fn.getName()));
|
|
insertCallAtFunctionEntryPoint(Fn, "__rtsan_notify_blocking_call", {Name});
|
|
return rtsanPreservedCFGAnalyses();
|
|
}
|
|
|
|
RealtimeSanitizerPass::RealtimeSanitizerPass(
|
|
const RealtimeSanitizerOptions &Options) {}
|
|
|
|
PreservedAnalyses RealtimeSanitizerPass::run(Function &Fn,
|
|
AnalysisManager<Function> &AM) {
|
|
if (Fn.hasFnAttribute(Attribute::SanitizeRealtime))
|
|
return runSanitizeRealtime(Fn);
|
|
|
|
if (Fn.hasFnAttribute(Attribute::SanitizeRealtimeBlocking))
|
|
return runSanitizeRealtimeBlocking(Fn);
|
|
|
|
return PreservedAnalyses::all();
|
|
}
|