Skip to content

Commit 1ba2d78

Browse files
committed
ubsan: Check for null pointers given to certain builtins, such
as memcpy, memset, memmove, and bzero. Reviewed by: Richard Smith Differential Revision: http://reviews.llvm.org/D9673 llvm-svn: 238657
1 parent b08cf1c commit 1ba2d78

File tree

4 files changed

+58
-12
lines changed

4 files changed

+58
-12
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
698698
std::pair<llvm::Value*, unsigned> Dest =
699699
EmitPointerWithAlignment(E->getArg(0));
700700
Value *SizeVal = EmitScalarExpr(E->getArg(1));
701+
EmitNonNullArgCheck(RValue::get(Dest.first), E->getArg(0)->getType(),
702+
E->getArg(0)->getExprLoc(), FD, 0);
701703
Builder.CreateMemSet(Dest.first, Builder.getInt8(0), SizeVal,
702704
Dest.second, false);
703705
return RValue::get(Dest.first);
@@ -710,6 +712,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
710712
EmitPointerWithAlignment(E->getArg(1));
711713
Value *SizeVal = EmitScalarExpr(E->getArg(2));
712714
unsigned Align = std::min(Dest.second, Src.second);
715+
EmitNonNullArgCheck(RValue::get(Dest.first), E->getArg(0)->getType(),
716+
E->getArg(0)->getExprLoc(), FD, 0);
717+
EmitNonNullArgCheck(RValue::get(Src.first), E->getArg(1)->getType(),
718+
E->getArg(1)->getExprLoc(), FD, 1);
713719
Builder.CreateMemCpy(Dest.first, Src.first, SizeVal, Align, false);
714720
return RValue::get(Dest.first);
715721
}
@@ -767,6 +773,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
767773
EmitPointerWithAlignment(E->getArg(1));
768774
Value *SizeVal = EmitScalarExpr(E->getArg(2));
769775
unsigned Align = std::min(Dest.second, Src.second);
776+
EmitNonNullArgCheck(RValue::get(Dest.first), E->getArg(0)->getType(),
777+
E->getArg(0)->getExprLoc(), FD, 0);
778+
EmitNonNullArgCheck(RValue::get(Src.first), E->getArg(1)->getType(),
779+
E->getArg(1)->getExprLoc(), FD, 1);
770780
Builder.CreateMemMove(Dest.first, Src.first, SizeVal, Align, false);
771781
return RValue::get(Dest.first);
772782
}
@@ -777,6 +787,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
777787
Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
778788
Builder.getInt8Ty());
779789
Value *SizeVal = EmitScalarExpr(E->getArg(2));
790+
EmitNonNullArgCheck(RValue::get(Dest.first), E->getArg(0)->getType(),
791+
E->getArg(0)->getExprLoc(), FD, 0);
780792
Builder.CreateMemSet(Dest.first, ByteVal, SizeVal, Dest.second, false);
781793
return RValue::get(Dest.first);
782794
}

clang/lib/CodeGen/CGCall.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2719,27 +2719,28 @@ void CallArgList::freeArgumentMemory(CodeGenFunction &CGF) const {
27192719
}
27202720
}
27212721

2722-
static void emitNonNullArgCheck(CodeGenFunction &CGF, RValue RV,
2723-
QualType ArgType, SourceLocation ArgLoc,
2724-
const FunctionDecl *FD, unsigned ParmNum) {
2725-
if (!CGF.SanOpts.has(SanitizerKind::NonnullAttribute) || !FD)
2722+
void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
2723+
SourceLocation ArgLoc,
2724+
const FunctionDecl *FD,
2725+
unsigned ParmNum) {
2726+
if (!SanOpts.has(SanitizerKind::NonnullAttribute) || !FD)
27262727
return;
27272728
auto PVD = ParmNum < FD->getNumParams() ? FD->getParamDecl(ParmNum) : nullptr;
27282729
unsigned ArgNo = PVD ? PVD->getFunctionScopeIndex() : ParmNum;
27292730
auto NNAttr = getNonNullAttr(FD, PVD, ArgType, ArgNo);
27302731
if (!NNAttr)
27312732
return;
2732-
CodeGenFunction::SanitizerScope SanScope(&CGF);
2733+
SanitizerScope SanScope(this);
27332734
assert(RV.isScalar());
27342735
llvm::Value *V = RV.getScalarVal();
27352736
llvm::Value *Cond =
2736-
CGF.Builder.CreateICmpNE(V, llvm::Constant::getNullValue(V->getType()));
2737+
Builder.CreateICmpNE(V, llvm::Constant::getNullValue(V->getType()));
27372738
llvm::Constant *StaticData[] = {
2738-
CGF.EmitCheckSourceLocation(ArgLoc),
2739-
CGF.EmitCheckSourceLocation(NNAttr->getLocation()),
2740-
llvm::ConstantInt::get(CGF.Int32Ty, ArgNo + 1),
2739+
EmitCheckSourceLocation(ArgLoc),
2740+
EmitCheckSourceLocation(NNAttr->getLocation()),
2741+
llvm::ConstantInt::get(Int32Ty, ArgNo + 1),
27412742
};
2742-
CGF.EmitCheck(std::make_pair(Cond, SanitizerKind::NonnullAttribute),
2743+
EmitCheck(std::make_pair(Cond, SanitizerKind::NonnullAttribute),
27432744
"nonnull_arg", StaticData, None);
27442745
}
27452746

@@ -2767,7 +2768,7 @@ void CodeGenFunction::EmitCallArgs(CallArgList &Args,
27672768
for (int I = ArgTypes.size() - 1; I >= 0; --I) {
27682769
CallExpr::const_arg_iterator Arg = ArgBeg + I;
27692770
EmitCallArg(Args, *Arg, ArgTypes[I]);
2770-
emitNonNullArgCheck(*this, Args.back().RV, ArgTypes[I], Arg->getExprLoc(),
2771+
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], Arg->getExprLoc(),
27712772
CalleeDecl, ParamsToSkip + I);
27722773
}
27732774

@@ -2781,7 +2782,7 @@ void CodeGenFunction::EmitCallArgs(CallArgList &Args,
27812782
CallExpr::const_arg_iterator Arg = ArgBeg + I;
27822783
assert(Arg != ArgEnd);
27832784
EmitCallArg(Args, *Arg, ArgTypes[I]);
2784-
emitNonNullArgCheck(*this, Args.back().RV, ArgTypes[I], Arg->getExprLoc(),
2785+
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], Arg->getExprLoc(),
27852786
CalleeDecl, ParamsToSkip + I);
27862787
}
27872788
}

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2836,6 +2836,11 @@ class CodeGenFunction : public CodeGenTypeCache {
28362836
/// conditional branch to it, for the -ftrapv checks.
28372837
void EmitTrapCheck(llvm::Value *Checked);
28382838

2839+
/// \brief Create a check for a function parameter that may potentially be
2840+
/// declared as non-null.
2841+
void EmitNonNullArgCheck(RValue RV, QualType ArgType, SourceLocation ArgLoc,
2842+
const FunctionDecl *FD, unsigned ParmNum);
2843+
28392844
/// EmitCallArg - Emit a single call argument.
28402845
void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
28412846

clang/test/CodeGen/catch-undef-behavior.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,34 @@ void call_decl_nonnull(int *a) {
371371
decl_nonnull(a);
372372
}
373373

374+
extern void *memcpy (void *, const void *, unsigned) __attribute__((nonnull(1, 2)));
375+
376+
// CHECK-COMMON-LABEL: @call_memcpy_nonnull
377+
void call_memcpy_nonnull(void *p, void *q, int sz) {
378+
// CHECK-COMMON: icmp ne i8* {{.*}}, null
379+
// CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
380+
// CHECK-TRAP: call void @llvm.trap()
381+
382+
// CHECK-COMMON: icmp ne i8* {{.*}}, null
383+
// CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
384+
// CHECK-TRAP: call void @llvm.trap()
385+
memcpy(p, q, sz);
386+
}
387+
388+
extern void *memmove (void *, const void *, unsigned) __attribute__((nonnull(1, 2)));
389+
390+
// CHECK-COMMON-LABEL: @call_memmove_nonnull
391+
void call_memmove_nonnull(void *p, void *q, int sz) {
392+
// CHECK-COMMON: icmp ne i8* {{.*}}, null
393+
// CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
394+
// CHECK-TRAP: call void @llvm.trap()
395+
396+
// CHECK-COMMON: icmp ne i8* {{.*}}, null
397+
// CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
398+
// CHECK-TRAP: call void @llvm.trap()
399+
memmove(p, q, sz);
400+
}
401+
374402
// CHECK-COMMON-LABEL: @call_nonnull_variadic
375403
__attribute__((nonnull)) void nonnull_variadic(int a, ...);
376404
void call_nonnull_variadic(int a, int *b) {

0 commit comments

Comments
 (0)