Extend -Wno-sizeof-array-argument to strncpy and friends.

This finds 2 bugs in chromium and 1 in hunspell, with 0 false positives.

llvm-svn: 141902
This commit is contained in:
Nico Weber 2011-10-13 22:30:23 +00:00
parent 834bd602e6
commit 39bfed8ad6
3 changed files with 74 additions and 5 deletions

View File

@ -6113,7 +6113,12 @@ private:
CMF_Memset,
CMF_Memcpy,
CMF_Memmove,
CMF_Memcmp
CMF_Memcmp,
CMF_Strncpy,
CMF_Strncmp,
CMF_Strncasecmp,
CMF_Strncat,
CMF_Strndup
};
void CheckMemaccessArguments(const CallExpr *Call, CheckedMemoryFunction CMF,

View File

@ -390,6 +390,30 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
CMF = CMF_Memcmp;
break;
case Builtin::BI__builtin_strncpy:
case Builtin::BI__builtin___strncpy_chk:
case Builtin::BIstrncpy:
CMF = CMF_Strncpy;
break;
case Builtin::BI__builtin_strncmp:
CMF = CMF_Strncmp;
break;
case Builtin::BI__builtin_strncasecmp:
CMF = CMF_Strncasecmp;
break;
case Builtin::BI__builtin_strncat:
case Builtin::BIstrncat:
CMF = CMF_Strncat;
break;
case Builtin::BI__builtin_strndup:
case Builtin::BIstrndup:
CMF = CMF_Strndup;
break;
default:
if (FDecl->getLinkage() == ExternalLinkage &&
(!getLangOptions().CPlusPlus || FDecl->isExternC())) {
@ -401,6 +425,16 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
CMF = CMF_Memmove;
else if (FnInfo->isStr("memcmp"))
CMF = CMF_Memcmp;
else if (FnInfo->isStr("strncpy"))
CMF = CMF_Strncpy;
else if (FnInfo->isStr("strncmp"))
CMF = CMF_Strncmp;
else if (FnInfo->isStr("strncasecmp"))
CMF = CMF_Strncasecmp;
else if (FnInfo->isStr("strncat"))
CMF = CMF_Strncat;
else if (FnInfo->isStr("strndup"))
CMF = CMF_Strndup;
}
break;
}
@ -2124,11 +2158,13 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
IdentifierInfo *FnName) {
// It is possible to have a non-standard definition of memset. Validate
// we have enough arguments, and if not, abort further checking.
if (Call->getNumArgs() < 3)
unsigned ExpectedNumArgs = (CMF == CMF_Strndup ? 2 : 3);
if (Call->getNumArgs() < ExpectedNumArgs)
return;
unsigned LastArg = (CMF == CMF_Memset? 1 : 2);
const Expr *LenExpr = Call->getArg(2)->IgnoreParenImpCasts();
unsigned LastArg = (CMF == CMF_Memset || CMF == CMF_Strndup ? 1 : 2);
unsigned LenArg = (CMF == CMF_Strndup ? 1 : 2);
const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts();
// We have special checking when the length is a sizeof expression.
QualType SizeOfArgTy = getSizeOfArgType(LenExpr);
@ -2162,6 +2198,8 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
llvm::FoldingSetNodeID DestID;
Dest->Profile(DestID, Context, true);
if (DestID == SizeOfArgID) {
// TODO: For strncpy() and friends, this could suggest sizeof(dst)
// over sizeof(src) as well.
unsigned ActionIdx = 0; // Default is to suggest dereferencing.
if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
if (UnaryOp->getOpcode() == UO_AddrOf)
@ -2169,9 +2207,10 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
ActionIdx = 2; // If the pointee's size is sizeof(char),
// suggest an explicit length.
unsigned DestSrcSelect = (CMF == CMF_Strndup ? 1 : ArgIdx);
DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest,
PDiag(diag::warn_sizeof_pointer_expr_memaccess)
<< FnName << ArgIdx << ActionIdx
<< FnName << DestSrcSelect << ActionIdx
<< Dest->getSourceRange()
<< SizeOfArg->getSourceRange());
break;

View File

@ -112,3 +112,28 @@ void f(int* i) {
memset(i, 0, sizeof(i));
}
}
extern "C" int strncmp(const char *s1, const char *s2, unsigned n);
extern "C" int strncasecmp(const char *s1, const char *s2, unsigned n);
extern "C" char *strncpy(char *det, const char *src, unsigned n);
extern "C" char *strncat(char *dst, const char *src, unsigned n);
extern "C" char *strndup(const char *src, unsigned n);
void strcpy_and_friends() {
const char* FOO = "<- should be an array instead";
const char* BAR = "<- this, too";
strncmp(FOO, BAR, sizeof(FOO)); // \
// expected-warning {{argument to 'sizeof' in 'strncmp' call is the same expression as the destination}}
strncasecmp(FOO, BAR, sizeof(FOO)); // \
// expected-warning {{argument to 'sizeof' in 'strncasecmp' call is the same expression as the destination}}
char buff[80];
strncpy(buff, BAR, sizeof(BAR)); // \
// expected-warning {{argument to 'sizeof' in 'strncpy' call is the same expression as the source}}
strncat(buff, BAR, sizeof(BAR)); // \
// expected-warning {{argument to 'sizeof' in 'strncat' call is the same expression as the source}}
strndup(FOO, sizeof(FOO)); // \
// expected-warning {{argument to 'sizeof' in 'strndup' call is the same expression as the source}}
}