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
This commit is contained in:
parent
b08cf1cfd2
commit
1ba2d78b9a
|
@ -698,6 +698,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
|
|||
std::pair<llvm::Value*, unsigned> Dest =
|
||||
EmitPointerWithAlignment(E->getArg(0));
|
||||
Value *SizeVal = EmitScalarExpr(E->getArg(1));
|
||||
EmitNonNullArgCheck(RValue::get(Dest.first), E->getArg(0)->getType(),
|
||||
E->getArg(0)->getExprLoc(), FD, 0);
|
||||
Builder.CreateMemSet(Dest.first, Builder.getInt8(0), SizeVal,
|
||||
Dest.second, false);
|
||||
return RValue::get(Dest.first);
|
||||
|
@ -710,6 +712,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
|
|||
EmitPointerWithAlignment(E->getArg(1));
|
||||
Value *SizeVal = EmitScalarExpr(E->getArg(2));
|
||||
unsigned Align = std::min(Dest.second, Src.second);
|
||||
EmitNonNullArgCheck(RValue::get(Dest.first), E->getArg(0)->getType(),
|
||||
E->getArg(0)->getExprLoc(), FD, 0);
|
||||
EmitNonNullArgCheck(RValue::get(Src.first), E->getArg(1)->getType(),
|
||||
E->getArg(1)->getExprLoc(), FD, 1);
|
||||
Builder.CreateMemCpy(Dest.first, Src.first, SizeVal, Align, false);
|
||||
return RValue::get(Dest.first);
|
||||
}
|
||||
|
@ -767,6 +773,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
|
|||
EmitPointerWithAlignment(E->getArg(1));
|
||||
Value *SizeVal = EmitScalarExpr(E->getArg(2));
|
||||
unsigned Align = std::min(Dest.second, Src.second);
|
||||
EmitNonNullArgCheck(RValue::get(Dest.first), E->getArg(0)->getType(),
|
||||
E->getArg(0)->getExprLoc(), FD, 0);
|
||||
EmitNonNullArgCheck(RValue::get(Src.first), E->getArg(1)->getType(),
|
||||
E->getArg(1)->getExprLoc(), FD, 1);
|
||||
Builder.CreateMemMove(Dest.first, Src.first, SizeVal, Align, false);
|
||||
return RValue::get(Dest.first);
|
||||
}
|
||||
|
@ -777,6 +787,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
|
|||
Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)),
|
||||
Builder.getInt8Ty());
|
||||
Value *SizeVal = EmitScalarExpr(E->getArg(2));
|
||||
EmitNonNullArgCheck(RValue::get(Dest.first), E->getArg(0)->getType(),
|
||||
E->getArg(0)->getExprLoc(), FD, 0);
|
||||
Builder.CreateMemSet(Dest.first, ByteVal, SizeVal, Dest.second, false);
|
||||
return RValue::get(Dest.first);
|
||||
}
|
||||
|
|
|
@ -2719,27 +2719,28 @@ void CallArgList::freeArgumentMemory(CodeGenFunction &CGF) const {
|
|||
}
|
||||
}
|
||||
|
||||
static void emitNonNullArgCheck(CodeGenFunction &CGF, RValue RV,
|
||||
QualType ArgType, SourceLocation ArgLoc,
|
||||
const FunctionDecl *FD, unsigned ParmNum) {
|
||||
if (!CGF.SanOpts.has(SanitizerKind::NonnullAttribute) || !FD)
|
||||
void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
|
||||
SourceLocation ArgLoc,
|
||||
const FunctionDecl *FD,
|
||||
unsigned ParmNum) {
|
||||
if (!SanOpts.has(SanitizerKind::NonnullAttribute) || !FD)
|
||||
return;
|
||||
auto PVD = ParmNum < FD->getNumParams() ? FD->getParamDecl(ParmNum) : nullptr;
|
||||
unsigned ArgNo = PVD ? PVD->getFunctionScopeIndex() : ParmNum;
|
||||
auto NNAttr = getNonNullAttr(FD, PVD, ArgType, ArgNo);
|
||||
if (!NNAttr)
|
||||
return;
|
||||
CodeGenFunction::SanitizerScope SanScope(&CGF);
|
||||
SanitizerScope SanScope(this);
|
||||
assert(RV.isScalar());
|
||||
llvm::Value *V = RV.getScalarVal();
|
||||
llvm::Value *Cond =
|
||||
CGF.Builder.CreateICmpNE(V, llvm::Constant::getNullValue(V->getType()));
|
||||
Builder.CreateICmpNE(V, llvm::Constant::getNullValue(V->getType()));
|
||||
llvm::Constant *StaticData[] = {
|
||||
CGF.EmitCheckSourceLocation(ArgLoc),
|
||||
CGF.EmitCheckSourceLocation(NNAttr->getLocation()),
|
||||
llvm::ConstantInt::get(CGF.Int32Ty, ArgNo + 1),
|
||||
EmitCheckSourceLocation(ArgLoc),
|
||||
EmitCheckSourceLocation(NNAttr->getLocation()),
|
||||
llvm::ConstantInt::get(Int32Ty, ArgNo + 1),
|
||||
};
|
||||
CGF.EmitCheck(std::make_pair(Cond, SanitizerKind::NonnullAttribute),
|
||||
EmitCheck(std::make_pair(Cond, SanitizerKind::NonnullAttribute),
|
||||
"nonnull_arg", StaticData, None);
|
||||
}
|
||||
|
||||
|
@ -2767,7 +2768,7 @@ void CodeGenFunction::EmitCallArgs(CallArgList &Args,
|
|||
for (int I = ArgTypes.size() - 1; I >= 0; --I) {
|
||||
CallExpr::const_arg_iterator Arg = ArgBeg + I;
|
||||
EmitCallArg(Args, *Arg, ArgTypes[I]);
|
||||
emitNonNullArgCheck(*this, Args.back().RV, ArgTypes[I], Arg->getExprLoc(),
|
||||
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], Arg->getExprLoc(),
|
||||
CalleeDecl, ParamsToSkip + I);
|
||||
}
|
||||
|
||||
|
@ -2781,7 +2782,7 @@ void CodeGenFunction::EmitCallArgs(CallArgList &Args,
|
|||
CallExpr::const_arg_iterator Arg = ArgBeg + I;
|
||||
assert(Arg != ArgEnd);
|
||||
EmitCallArg(Args, *Arg, ArgTypes[I]);
|
||||
emitNonNullArgCheck(*this, Args.back().RV, ArgTypes[I], Arg->getExprLoc(),
|
||||
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], Arg->getExprLoc(),
|
||||
CalleeDecl, ParamsToSkip + I);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2836,6 +2836,11 @@ public:
|
|||
/// conditional branch to it, for the -ftrapv checks.
|
||||
void EmitTrapCheck(llvm::Value *Checked);
|
||||
|
||||
/// \brief Create a check for a function parameter that may potentially be
|
||||
/// declared as non-null.
|
||||
void EmitNonNullArgCheck(RValue RV, QualType ArgType, SourceLocation ArgLoc,
|
||||
const FunctionDecl *FD, unsigned ParmNum);
|
||||
|
||||
/// EmitCallArg - Emit a single call argument.
|
||||
void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
|
||||
|
||||
|
|
|
@ -371,6 +371,34 @@ void call_decl_nonnull(int *a) {
|
|||
decl_nonnull(a);
|
||||
}
|
||||
|
||||
extern void *memcpy (void *, const void *, unsigned) __attribute__((nonnull(1, 2)));
|
||||
|
||||
// CHECK-COMMON-LABEL: @call_memcpy_nonnull
|
||||
void call_memcpy_nonnull(void *p, void *q, int sz) {
|
||||
// CHECK-COMMON: icmp ne i8* {{.*}}, null
|
||||
// CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
|
||||
// CHECK-TRAP: call void @llvm.trap()
|
||||
|
||||
// CHECK-COMMON: icmp ne i8* {{.*}}, null
|
||||
// CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
|
||||
// CHECK-TRAP: call void @llvm.trap()
|
||||
memcpy(p, q, sz);
|
||||
}
|
||||
|
||||
extern void *memmove (void *, const void *, unsigned) __attribute__((nonnull(1, 2)));
|
||||
|
||||
// CHECK-COMMON-LABEL: @call_memmove_nonnull
|
||||
void call_memmove_nonnull(void *p, void *q, int sz) {
|
||||
// CHECK-COMMON: icmp ne i8* {{.*}}, null
|
||||
// CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
|
||||
// CHECK-TRAP: call void @llvm.trap()
|
||||
|
||||
// CHECK-COMMON: icmp ne i8* {{.*}}, null
|
||||
// CHECK-UBSAN: call void @__ubsan_handle_nonnull_arg
|
||||
// CHECK-TRAP: call void @llvm.trap()
|
||||
memmove(p, q, sz);
|
||||
}
|
||||
|
||||
// CHECK-COMMON-LABEL: @call_nonnull_variadic
|
||||
__attribute__((nonnull)) void nonnull_variadic(int a, ...);
|
||||
void call_nonnull_variadic(int a, int *b) {
|
||||
|
|
Loading…
Reference in New Issue