Skip to content

Commit f826728

Browse files
MSan: handle callbr instructions
Summary: Handling callbr is very similar to handling an inline assembly call: MSan must checks the instruction's inputs. callbr doesn't (yet) have outputs, so there's nothing to unpoison, and conservative assembly handling doesn't apply either. Fixes PR42479. Reviewers: eugenis Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D64072 llvm-svn: 365008
1 parent e6020f5 commit f826728

File tree

2 files changed

+52
-21
lines changed

2 files changed

+52
-21
lines changed

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3233,21 +3233,21 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
32333233
void visitCallSite(CallSite CS) {
32343234
Instruction &I = *CS.getInstruction();
32353235
assert(!I.getMetadata("nosanitize"));
3236-
assert((CS.isCall() || CS.isInvoke()) && "Unknown type of CallSite");
3236+
assert((CS.isCall() || CS.isInvoke() || CS.isCallBr()) &&
3237+
"Unknown type of CallSite");
3238+
if (CS.isCallBr() || (CS.isCall() && cast<CallInst>(&I)->isInlineAsm())) {
3239+
// For inline asm (either a call to asm function, or callbr instruction),
3240+
// do the usual thing: check argument shadow and mark all outputs as
3241+
// clean. Note that any side effects of the inline asm that are not
3242+
// immediately visible in its constraints are not handled.
3243+
if (ClHandleAsmConservative && MS.CompileKernel)
3244+
visitAsmInstruction(I);
3245+
else
3246+
visitInstruction(I);
3247+
return;
3248+
}
32373249
if (CS.isCall()) {
32383250
CallInst *Call = cast<CallInst>(&I);
3239-
3240-
// For inline asm, do the usual thing: check argument shadow and mark all
3241-
// outputs as clean. Note that any side effects of the inline asm that are
3242-
// not immediately visible in its constraints are not handled.
3243-
if (Call->isInlineAsm()) {
3244-
if (ClHandleAsmConservative && MS.CompileKernel)
3245-
visitAsmInstruction(I);
3246-
else
3247-
visitInstruction(I);
3248-
return;
3249-
}
3250-
32513251
assert(!isa<IntrinsicInst>(&I) && "intrinsics are handled elsewhere");
32523252

32533253
// We are going to insert code that relies on the fact that the callee
@@ -3624,10 +3624,10 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
36243624
}
36253625

36263626
/// Get the number of output arguments returned by pointers.
3627-
int getNumOutputArgs(InlineAsm *IA, CallInst *CI) {
3627+
int getNumOutputArgs(InlineAsm *IA, CallBase *CB) {
36283628
int NumRetOutputs = 0;
36293629
int NumOutputs = 0;
3630-
Type *RetTy = dyn_cast<Value>(CI)->getType();
3630+
Type *RetTy = dyn_cast<Value>(CB)->getType();
36313631
if (!RetTy->isVoidTy()) {
36323632
// Register outputs are returned via the CallInst return value.
36333633
StructType *ST = dyn_cast_or_null<StructType>(RetTy);
@@ -3667,24 +3667,24 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
36673667
// corresponding CallInst has nO+nI+1 operands (the last operand is the
36683668
// function to be called).
36693669
const DataLayout &DL = F.getParent()->getDataLayout();
3670-
CallInst *CI = dyn_cast<CallInst>(&I);
3670+
CallBase *CB = dyn_cast<CallBase>(&I);
36713671
IRBuilder<> IRB(&I);
3672-
InlineAsm *IA = cast<InlineAsm>(CI->getCalledValue());
3673-
int OutputArgs = getNumOutputArgs(IA, CI);
3672+
InlineAsm *IA = cast<InlineAsm>(CB->getCalledValue());
3673+
int OutputArgs = getNumOutputArgs(IA, CB);
36743674
// The last operand of a CallInst is the function itself.
3675-
int NumOperands = CI->getNumOperands() - 1;
3675+
int NumOperands = CB->getNumOperands() - 1;
36763676

36773677
// Check input arguments. Doing so before unpoisoning output arguments, so
36783678
// that we won't overwrite uninit values before checking them.
36793679
for (int i = OutputArgs; i < NumOperands; i++) {
3680-
Value *Operand = CI->getOperand(i);
3680+
Value *Operand = CB->getOperand(i);
36813681
instrumentAsmArgument(Operand, I, IRB, DL, /*isOutput*/ false);
36823682
}
36833683
// Unpoison output arguments. This must happen before the actual InlineAsm
36843684
// call, so that the shadow for memory published in the asm() statement
36853685
// remains valid.
36863686
for (int i = 0; i < OutputArgs; i++) {
3687-
Value *Operand = CI->getOperand(i);
3687+
Value *Operand = CB->getOperand(i);
36883688
instrumentAsmArgument(Operand, I, IRB, DL, /*isOutput*/ true);
36893689
}
36903690

llvm/test/Instrumentation/MemorySanitizer/msan_asm_conservative.ll

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,34 @@ entry:
264264
; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@c2{{.*}}, i64 1)
265265
; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@memcpy_d1{{.*}}, i64 8)
266266
; CHECK: call void asm "", "=*m,=*m,=*m,*m,*m,*m,~{dirflag},~{fpsr},~{flags}"(%struct.pair* @pair2, i8* @c2, i8* (i8*, i8*, i32)** @memcpy_d1, %struct.pair* @pair1, i8* @c1, i8* (i8*, i8*, i32)** @memcpy_s1)
267+
268+
269+
; A simple asm goto construct to check that callbr is handled correctly:
270+
; int asm_goto(int n) {
271+
; int v = 1;
272+
; asm goto("cmp %0, %1; jnz %l2;" :: "r"(n), "r"(v)::skip_label);
273+
; return 0;
274+
; skip_label:
275+
; return 1;
276+
; }
277+
; asm goto statements can't have outputs, so just make sure we check the input
278+
; and the compiler doesn't crash.
279+
define dso_local i32 @asm_goto(i32 %n) sanitize_memory {
280+
entry:
281+
callbr void asm sideeffect "cmp $0, $1; jnz ${2:l}", "r,r,X,~{dirflag},~{fpsr},~{flags}"(i32 %n, i32 1, i8* blockaddress(@asm_goto, %skip_label))
282+
to label %cleanup [label %skip_label]
283+
284+
skip_label: ; preds = %entry
285+
br label %cleanup
286+
287+
cleanup: ; preds = %entry, %skip_label
288+
%retval.0 = phi i32 [ 2, %skip_label ], [ 1, %entry ]
289+
ret i32 %retval.0
290+
}
291+
292+
; CHECK-LABEL: @asm_goto
293+
; CHECK: [[LOAD_ARG:%.*]] = load {{.*}} %_msarg
294+
; CHECK: [[CMP:%.*]] = icmp ne {{.*}} [[LOAD_ARG]], 0
295+
; CHECK: br {{.*}} [[CMP]], label %[[LABEL:.*]], label
296+
; CHECK: [[LABEL]]:
297+
; CHECK-NEXT: call void @__msan_warning

0 commit comments

Comments
 (0)