[ubsan_minimal] Allow UBSan handler from Minimal runtime to accept arguments (#152192)
+ Changed type_mismatch minimal handler to accept and print pointer. This will allow to distinguish null pointer use, misallignment and incorrect object size. The change increases binary size by ~1% and has almost no performance impact. Fixes #149943
This commit is contained in:
parent
266a1a819a
commit
a1209d8686
@ -3789,33 +3789,50 @@ void CodeGenFunction::EmitCheck(
|
||||
Branch->setMetadata(llvm::LLVMContext::MD_prof, Node);
|
||||
EmitBlock(Handlers);
|
||||
|
||||
// Clear arguments for the MinimalRuntime handler.
|
||||
if (CGM.getCodeGenOpts().SanitizeMinimalRuntime) {
|
||||
switch (CheckHandler) {
|
||||
case SanitizerHandler::TypeMismatch:
|
||||
// Pass value pointer only. It adds minimal overhead.
|
||||
StaticArgs = {};
|
||||
assert(DynamicArgs.size() == 1);
|
||||
break;
|
||||
default:
|
||||
// No arguments for other checks.
|
||||
StaticArgs = {};
|
||||
DynamicArgs = {};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handler functions take an i8* pointing to the (handler-specific) static
|
||||
// information block, followed by a sequence of intptr_t arguments
|
||||
// representing operand values.
|
||||
SmallVector<llvm::Value *, 4> Args;
|
||||
SmallVector<llvm::Type *, 4> ArgTypes;
|
||||
if (!CGM.getCodeGenOpts().SanitizeMinimalRuntime) {
|
||||
Args.reserve(DynamicArgs.size() + 1);
|
||||
ArgTypes.reserve(DynamicArgs.size() + 1);
|
||||
|
||||
// Emit handler arguments and create handler function type.
|
||||
if (!StaticArgs.empty()) {
|
||||
llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
|
||||
auto *InfoPtr = new llvm::GlobalVariable(
|
||||
CGM.getModule(), Info->getType(), false,
|
||||
llvm::GlobalVariable::PrivateLinkage, Info, "", nullptr,
|
||||
llvm::GlobalVariable::NotThreadLocal,
|
||||
CGM.getDataLayout().getDefaultGlobalsAddressSpace());
|
||||
InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
||||
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
|
||||
Args.push_back(InfoPtr);
|
||||
ArgTypes.push_back(Args.back()->getType());
|
||||
}
|
||||
Args.reserve(DynamicArgs.size() + 1);
|
||||
ArgTypes.reserve(DynamicArgs.size() + 1);
|
||||
|
||||
for (llvm::Value *DynamicArg : DynamicArgs) {
|
||||
Args.push_back(EmitCheckValue(DynamicArg));
|
||||
ArgTypes.push_back(IntPtrTy);
|
||||
}
|
||||
// Emit handler arguments and create handler function type.
|
||||
if (!StaticArgs.empty()) {
|
||||
llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
|
||||
auto *InfoPtr = new llvm::GlobalVariable(
|
||||
CGM.getModule(), Info->getType(),
|
||||
// Non-constant global is used in a handler to deduplicate reports.
|
||||
// TODO: change deduplication logic and make it constant.
|
||||
/*isConstant=*/false, llvm::GlobalVariable::PrivateLinkage, Info, "",
|
||||
nullptr, llvm::GlobalVariable::NotThreadLocal,
|
||||
CGM.getDataLayout().getDefaultGlobalsAddressSpace());
|
||||
InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
||||
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
|
||||
Args.push_back(InfoPtr);
|
||||
ArgTypes.push_back(Args.back()->getType());
|
||||
}
|
||||
|
||||
for (llvm::Value *DynamicArg : DynamicArgs) {
|
||||
Args.push_back(EmitCheckValue(DynamicArg));
|
||||
ArgTypes.push_back(IntPtrTy);
|
||||
}
|
||||
|
||||
llvm::FunctionType *FnType =
|
||||
|
@ -34,12 +34,16 @@ static char *append_hex(uintptr_t d, char *buf, const char *end) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void format_msg(const char *kind, uintptr_t caller, char *buf,
|
||||
const char *end) {
|
||||
static void format_msg(const char *kind, uintptr_t caller,
|
||||
const uintptr_t *address, char *buf, const char *end) {
|
||||
buf = append_str("ubsan: ", buf, end);
|
||||
buf = append_str(kind, buf, end);
|
||||
buf = append_str(" by 0x", buf, end);
|
||||
buf = append_hex(caller, buf, end);
|
||||
if (address) {
|
||||
buf = append_str(" address 0x", buf, end);
|
||||
buf = append_hex(*address, buf, end);
|
||||
}
|
||||
buf = append_str("\n", buf, end);
|
||||
if (buf == end)
|
||||
--buf; // Make sure we don't cause a buffer overflow.
|
||||
@ -47,7 +51,7 @@ static void format_msg(const char *kind, uintptr_t caller, char *buf,
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind,
|
||||
uintptr_t caller) {
|
||||
uintptr_t caller, const uintptr_t *address) {
|
||||
if (caller == 0)
|
||||
return;
|
||||
while (true) {
|
||||
@ -80,15 +84,15 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind,
|
||||
__sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller);
|
||||
|
||||
char msg_buf[128];
|
||||
format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf));
|
||||
format_msg(kind, caller, address, msg_buf, msg_buf + sizeof(msg_buf));
|
||||
message(msg_buf);
|
||||
}
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_fatal, const char *kind,
|
||||
uintptr_t caller) {
|
||||
uintptr_t caller, const uintptr_t *address) {
|
||||
// Use another handlers, in case it's already overriden.
|
||||
__ubsan_report_error(kind, caller);
|
||||
__ubsan_report_error(kind, caller, address);
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
@ -121,13 +125,13 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
|
||||
|
||||
#define HANDLER_RECOVER(name, kind) \
|
||||
INTERFACE void __ubsan_handle_##name##_minimal() { \
|
||||
__ubsan_report_error(kind, GET_CALLER_PC()); \
|
||||
__ubsan_report_error(kind, GET_CALLER_PC(), nullptr); \
|
||||
}
|
||||
|
||||
#define HANDLER_NORECOVER(name, kind) \
|
||||
INTERFACE void __ubsan_handle_##name##_minimal_abort() { \
|
||||
uintptr_t caller = GET_CALLER_PC(); \
|
||||
__ubsan_report_error_fatal(kind, caller); \
|
||||
__ubsan_report_error_fatal(kind, caller, nullptr); \
|
||||
abort_with_message(kind, caller); \
|
||||
}
|
||||
|
||||
@ -135,7 +139,25 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
|
||||
HANDLER_RECOVER(name, kind) \
|
||||
HANDLER_NORECOVER(name, kind)
|
||||
|
||||
HANDLER(type_mismatch, "type-mismatch")
|
||||
#define HANDLER_RECOVER_PTR(name, kind) \
|
||||
INTERFACE void __ubsan_handle_##name##_minimal(const uintptr_t address) { \
|
||||
__ubsan_report_error(kind, GET_CALLER_PC(), &address); \
|
||||
}
|
||||
|
||||
#define HANDLER_NORECOVER_PTR(name, kind) \
|
||||
INTERFACE void __ubsan_handle_##name##_minimal_abort( \
|
||||
const uintptr_t address) { \
|
||||
uintptr_t caller = GET_CALLER_PC(); \
|
||||
__ubsan_report_error_fatal(kind, caller, &address); \
|
||||
abort_with_message(kind, caller); \
|
||||
}
|
||||
|
||||
// A version of a handler that takes a pointer to a value.
|
||||
#define HANDLER_PTR(name, kind) \
|
||||
HANDLER_RECOVER_PTR(name, kind) \
|
||||
HANDLER_NORECOVER_PTR(name, kind)
|
||||
|
||||
HANDLER_PTR(type_mismatch, "type-mismatch")
|
||||
HANDLER(alignment_assumption, "alignment-assumption")
|
||||
HANDLER(add_overflow, "add-overflow")
|
||||
HANDLER(sub_overflow, "sub-overflow")
|
||||
|
13
compiler-rt/test/ubsan_minimal/TestCases/misalignment.cpp
Normal file
13
compiler-rt/test/ubsan_minimal/TestCases/misalignment.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
// RUN: %clang_min_runtime -fsanitize=alignment %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK
|
||||
|
||||
void f(int &n) {}
|
||||
|
||||
int *t;
|
||||
|
||||
int main() {
|
||||
int r;
|
||||
t = (int *)(((char *)&r) + 1);
|
||||
// CHECK: ubsan: type-mismatch by 0x{{[[:xdigit:]]+}} address 0x{{[[:xdigit:]]+$}}
|
||||
// CHECK-NOT: type-mismatch
|
||||
f(*t);
|
||||
}
|
11
compiler-rt/test/ubsan_minimal/TestCases/null.cpp
Normal file
11
compiler-rt/test/ubsan_minimal/TestCases/null.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
// RUN: %clang_min_runtime -fsanitize=null %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK
|
||||
|
||||
void f(int &n) {}
|
||||
|
||||
int *t;
|
||||
|
||||
int main() {
|
||||
// CHECK: ubsan: type-mismatch by 0x{{[[:xdigit:]]+}} address 0x{{[[:xdigit:]]+$}}
|
||||
// CHECK-NOT: type-mismatch
|
||||
f(*t);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user