Skip to content

Commit a1209d8

Browse files
authored
[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
1 parent 266a1a8 commit a1209d8

File tree

4 files changed

+93
-30
lines changed

4 files changed

+93
-30
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3789,33 +3789,50 @@ void CodeGenFunction::EmitCheck(
37893789
Branch->setMetadata(llvm::LLVMContext::MD_prof, Node);
37903790
EmitBlock(Handlers);
37913791

3792+
// Clear arguments for the MinimalRuntime handler.
3793+
if (CGM.getCodeGenOpts().SanitizeMinimalRuntime) {
3794+
switch (CheckHandler) {
3795+
case SanitizerHandler::TypeMismatch:
3796+
// Pass value pointer only. It adds minimal overhead.
3797+
StaticArgs = {};
3798+
assert(DynamicArgs.size() == 1);
3799+
break;
3800+
default:
3801+
// No arguments for other checks.
3802+
StaticArgs = {};
3803+
DynamicArgs = {};
3804+
break;
3805+
}
3806+
}
3807+
37923808
// Handler functions take an i8* pointing to the (handler-specific) static
37933809
// information block, followed by a sequence of intptr_t arguments
37943810
// representing operand values.
37953811
SmallVector<llvm::Value *, 4> Args;
37963812
SmallVector<llvm::Type *, 4> ArgTypes;
3797-
if (!CGM.getCodeGenOpts().SanitizeMinimalRuntime) {
3798-
Args.reserve(DynamicArgs.size() + 1);
3799-
ArgTypes.reserve(DynamicArgs.size() + 1);
3800-
3801-
// Emit handler arguments and create handler function type.
3802-
if (!StaticArgs.empty()) {
3803-
llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
3804-
auto *InfoPtr = new llvm::GlobalVariable(
3805-
CGM.getModule(), Info->getType(), false,
3806-
llvm::GlobalVariable::PrivateLinkage, Info, "", nullptr,
3807-
llvm::GlobalVariable::NotThreadLocal,
3808-
CGM.getDataLayout().getDefaultGlobalsAddressSpace());
3809-
InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
3810-
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
3811-
Args.push_back(InfoPtr);
3812-
ArgTypes.push_back(Args.back()->getType());
3813-
}
38143813

3815-
for (llvm::Value *DynamicArg : DynamicArgs) {
3816-
Args.push_back(EmitCheckValue(DynamicArg));
3817-
ArgTypes.push_back(IntPtrTy);
3818-
}
3814+
Args.reserve(DynamicArgs.size() + 1);
3815+
ArgTypes.reserve(DynamicArgs.size() + 1);
3816+
3817+
// Emit handler arguments and create handler function type.
3818+
if (!StaticArgs.empty()) {
3819+
llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
3820+
auto *InfoPtr = new llvm::GlobalVariable(
3821+
CGM.getModule(), Info->getType(),
3822+
// Non-constant global is used in a handler to deduplicate reports.
3823+
// TODO: change deduplication logic and make it constant.
3824+
/*isConstant=*/false, llvm::GlobalVariable::PrivateLinkage, Info, "",
3825+
nullptr, llvm::GlobalVariable::NotThreadLocal,
3826+
CGM.getDataLayout().getDefaultGlobalsAddressSpace());
3827+
InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
3828+
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
3829+
Args.push_back(InfoPtr);
3830+
ArgTypes.push_back(Args.back()->getType());
3831+
}
3832+
3833+
for (llvm::Value *DynamicArg : DynamicArgs) {
3834+
Args.push_back(EmitCheckValue(DynamicArg));
3835+
ArgTypes.push_back(IntPtrTy);
38193836
}
38203837

38213838
llvm::FunctionType *FnType =

compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,24 @@ static char *append_hex(uintptr_t d, char *buf, const char *end) {
3434
return buf;
3535
}
3636

37-
static void format_msg(const char *kind, uintptr_t caller, char *buf,
38-
const char *end) {
37+
static void format_msg(const char *kind, uintptr_t caller,
38+
const uintptr_t *address, char *buf, const char *end) {
3939
buf = append_str("ubsan: ", buf, end);
4040
buf = append_str(kind, buf, end);
4141
buf = append_str(" by 0x", buf, end);
4242
buf = append_hex(caller, buf, end);
43+
if (address) {
44+
buf = append_str(" address 0x", buf, end);
45+
buf = append_hex(*address, buf, end);
46+
}
4347
buf = append_str("\n", buf, end);
4448
if (buf == end)
4549
--buf; // Make sure we don't cause a buffer overflow.
4650
*buf = '\0';
4751
}
4852

4953
SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind,
50-
uintptr_t caller) {
54+
uintptr_t caller, const uintptr_t *address) {
5155
if (caller == 0)
5256
return;
5357
while (true) {
@@ -80,15 +84,15 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind,
8084
__sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller);
8185

8286
char msg_buf[128];
83-
format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf));
87+
format_msg(kind, caller, address, msg_buf, msg_buf + sizeof(msg_buf));
8488
message(msg_buf);
8589
}
8690
}
8791

8892
SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_fatal, const char *kind,
89-
uintptr_t caller) {
93+
uintptr_t caller, const uintptr_t *address) {
9094
// Use another handlers, in case it's already overriden.
91-
__ubsan_report_error(kind, caller);
95+
__ubsan_report_error(kind, caller, address);
9296
}
9397

9498
#if defined(__ANDROID__)
@@ -121,21 +125,39 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
121125

122126
#define HANDLER_RECOVER(name, kind) \
123127
INTERFACE void __ubsan_handle_##name##_minimal() { \
124-
__ubsan_report_error(kind, GET_CALLER_PC()); \
128+
__ubsan_report_error(kind, GET_CALLER_PC(), nullptr); \
125129
}
126130

127131
#define HANDLER_NORECOVER(name, kind) \
128132
INTERFACE void __ubsan_handle_##name##_minimal_abort() { \
129133
uintptr_t caller = GET_CALLER_PC(); \
130-
__ubsan_report_error_fatal(kind, caller); \
134+
__ubsan_report_error_fatal(kind, caller, nullptr); \
131135
abort_with_message(kind, caller); \
132136
}
133137

134138
#define HANDLER(name, kind) \
135139
HANDLER_RECOVER(name, kind) \
136140
HANDLER_NORECOVER(name, kind)
137141

138-
HANDLER(type_mismatch, "type-mismatch")
142+
#define HANDLER_RECOVER_PTR(name, kind) \
143+
INTERFACE void __ubsan_handle_##name##_minimal(const uintptr_t address) { \
144+
__ubsan_report_error(kind, GET_CALLER_PC(), &address); \
145+
}
146+
147+
#define HANDLER_NORECOVER_PTR(name, kind) \
148+
INTERFACE void __ubsan_handle_##name##_minimal_abort( \
149+
const uintptr_t address) { \
150+
uintptr_t caller = GET_CALLER_PC(); \
151+
__ubsan_report_error_fatal(kind, caller, &address); \
152+
abort_with_message(kind, caller); \
153+
}
154+
155+
// A version of a handler that takes a pointer to a value.
156+
#define HANDLER_PTR(name, kind) \
157+
HANDLER_RECOVER_PTR(name, kind) \
158+
HANDLER_NORECOVER_PTR(name, kind)
159+
160+
HANDLER_PTR(type_mismatch, "type-mismatch")
139161
HANDLER(alignment_assumption, "alignment-assumption")
140162
HANDLER(add_overflow, "add-overflow")
141163
HANDLER(sub_overflow, "sub-overflow")
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_min_runtime -fsanitize=alignment %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK
2+
3+
void f(int &n) {}
4+
5+
int *t;
6+
7+
int main() {
8+
int r;
9+
t = (int *)(((char *)&r) + 1);
10+
// CHECK: ubsan: type-mismatch by 0x{{[[:xdigit:]]+}} address 0x{{[[:xdigit:]]+$}}
11+
// CHECK-NOT: type-mismatch
12+
f(*t);
13+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %clang_min_runtime -fsanitize=null %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK
2+
3+
void f(int &n) {}
4+
5+
int *t;
6+
7+
int main() {
8+
// CHECK: ubsan: type-mismatch by 0x{{[[:xdigit:]]+}} address 0x{{[[:xdigit:]]+$}}
9+
// CHECK-NOT: type-mismatch
10+
f(*t);
11+
}

0 commit comments

Comments
 (0)