Improve support of GNU mempcpy

- Lower to the memcpy intrinsic
- Raise warnings when size/bounds are known

Differential Revision: https://reviews.llvm.org/D71374
This commit is contained in:
serge-sans-paille 2019-12-11 21:30:10 +01:00
parent d27a15fed7
commit cee4a1c957
6 changed files with 39 additions and 4 deletions

View File

@ -984,6 +984,7 @@ LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(alloca, "v*z", "f", "stdlib.h", ALL_GNU_LANGUAGES)
// POSIX string.h
LIBBUILTIN(memccpy, "v*v*vC*iz", "f", "string.h", ALL_GNU_LANGUAGES)
LIBBUILTIN(mempcpy, "v*v*vC*z", "f", "string.h", ALL_GNU_LANGUAGES)
LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h", ALL_GNU_LANGUAGES)
LIBBUILTIN(stpncpy, "c*c*cC*z", "f", "string.h", ALL_GNU_LANGUAGES)
LIBBUILTIN(strdup, "c*cC*", "f", "string.h", ALL_GNU_LANGUAGES)

View File

@ -3879,6 +3879,11 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
case Builtin::BImemcpy:
return Builtin::BImemcpy;
case Builtin::BI__builtin_mempcpy:
case Builtin::BI__builtin___mempcpy_chk:
case Builtin::BImempcpy:
return Builtin::BImempcpy;
case Builtin::BI__builtin_memmove:
case Builtin::BI__builtin___memmove_chk:
case Builtin::BImemmove:
@ -3936,6 +3941,8 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
return Builtin::BImemset;
else if (FnInfo->isStr("memcpy"))
return Builtin::BImemcpy;
else if (FnInfo->isStr("mempcpy"))
return Builtin::BImempcpy;
else if (FnInfo->isStr("memmove"))
return Builtin::BImemmove;
else if (FnInfo->isStr("memcmp"))

View File

@ -2500,7 +2500,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(nullptr);
}
case Builtin::BImemcpy:
case Builtin::BI__builtin_memcpy: {
case Builtin::BI__builtin_memcpy:
case Builtin::BImempcpy:
case Builtin::BI__builtin_mempcpy: {
Address Dest = EmitPointerWithAlignment(E->getArg(0));
Address Src = EmitPointerWithAlignment(E->getArg(1));
Value *SizeVal = EmitScalarExpr(E->getArg(2));
@ -2509,7 +2511,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(1)->getType(),
E->getArg(1)->getExprLoc(), FD, 1);
Builder.CreateMemCpy(Dest, Src, SizeVal, false);
return RValue::get(Dest.getPointer());
if (BuiltinID == Builtin::BImempcpy ||
BuiltinID == Builtin::BI__builtin_mempcpy)
return RValue::get(Builder.CreateInBoundsGEP(Dest.getPointer(), SizeVal));
else
return RValue::get(Dest.getPointer());
}
case Builtin::BI__builtin_char_memchr:

View File

@ -340,7 +340,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
case Builtin::BI__builtin___strncat_chk:
case Builtin::BI__builtin___strncpy_chk:
case Builtin::BI__builtin___stpncpy_chk:
case Builtin::BI__builtin___memccpy_chk: {
case Builtin::BI__builtin___memccpy_chk:
case Builtin::BI__builtin___mempcpy_chk: {
DiagID = diag::warn_builtin_chk_overflow;
IsChkVariant = true;
SizeIndex = TheCall->getNumArgs() - 2;
@ -379,7 +380,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
case Builtin::BImemmove:
case Builtin::BI__builtin_memmove:
case Builtin::BImemset:
case Builtin::BI__builtin_memset: {
case Builtin::BI__builtin_memset:
case Builtin::BImempcpy:
case Builtin::BI__builtin_mempcpy: {
DiagID = diag::warn_fortify_source_overflow;
SizeIndex = TheCall->getNumArgs() - 1;
ObjectIndex = 0;

View File

@ -222,6 +222,9 @@ void mempcpy2 () {
char dst[1];
mempcpy(dst, src, 4); // expected-warning{{Memory copy function overflows destination buffer}}
#ifndef VARIANT
// expected-warning@-2{{'mempcpy' will always overflow; destination buffer has size 1, but size argument is 4}}
#endif
}
void mempcpy3 () {
@ -243,6 +246,9 @@ void mempcpy5() {
char dst[3];
mempcpy(dst+2, src+2, 2); // expected-warning{{Memory copy function overflows destination buffer}}
#ifndef VARIANT
// expected-warning@-2{{'mempcpy' will always overflow; destination buffer has size 1, but size argument is 2}}
#endif
}
void mempcpy6() {

View File

@ -0,0 +1,12 @@
// RUN: %clang_cc1 -emit-llvm < %s| FileCheck %s
typedef __SIZE_TYPE__ size_t;
void *mempcpy(void *, void const *, size_t);
char *test(char *d, char *s, size_t n) {
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}} %[[REG1:[^ ]+]], i8* {{.*}} %1, i64 %[[REG2:[^ ]+]], i1 false)
// CHECK-NEXT: %[[REGr:[^ ]+]] = getelementptr inbounds i8, i8* %[[REG1]], i64 %[[REG2]]
// CHECK-NEXT: ret i8* %[[REGr]]
return mempcpy(d, s, n);
}