mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 12:26:52 +08:00
Fix <rdar://problem/6704086> by allowing the format string checking in Sema to
allow non-literal format strings that are variables that (a) permanently bind to a string constant and (b) whose string constants are resolvable within the same translation unit. llvm-svn: 67404
This commit is contained in:
@@ -270,7 +270,7 @@ public:
|
||||
/// from a previous declaration. Def will be set to the VarDecl that
|
||||
/// contains the initializer, and the result will be that
|
||||
/// initializer.
|
||||
const Expr *getDefinition(const VarDecl *&Def);
|
||||
const Expr *getDefinition(const VarDecl *&Def) const;
|
||||
|
||||
void setThreadSpecified(bool T) { ThreadSpecified = T; }
|
||||
bool isThreadSpecified() const {
|
||||
|
||||
@@ -281,7 +281,7 @@ bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
|
||||
(getStorageClass() == None || getStorageClass() == Static));
|
||||
}
|
||||
|
||||
const Expr *VarDecl::getDefinition(const VarDecl *&Def) {
|
||||
const Expr *VarDecl::getDefinition(const VarDecl *&Def) const {
|
||||
Def = this;
|
||||
while (Def && !Def->getInit())
|
||||
Def = Def->getPreviousDeclaration();
|
||||
|
||||
@@ -2348,12 +2348,13 @@ private:
|
||||
Action::OwningExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
|
||||
bool SemaBuiltinPrefetch(CallExpr *TheCall);
|
||||
bool SemaBuiltinObjectSize(CallExpr *TheCall);
|
||||
bool SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
|
||||
unsigned format_idx, unsigned firstDataArg);
|
||||
void CheckPrintfString(StringLiteral *FExpr, Expr *OrigFormatExpr,
|
||||
CallExpr *TheCall, bool HasVAListArg,
|
||||
bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
|
||||
bool HasVAListArg, unsigned format_idx,
|
||||
unsigned firstDataArg);
|
||||
void CheckPrintfString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
|
||||
const CallExpr *TheCall, bool HasVAListArg,
|
||||
unsigned format_idx, unsigned firstDataArg);
|
||||
void CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
|
||||
void CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
|
||||
unsigned format_idx, unsigned firstDataArg);
|
||||
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
|
||||
SourceLocation ReturnLoc);
|
||||
|
||||
@@ -423,12 +423,13 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
|
||||
}
|
||||
|
||||
// Handle i > 1 ? "x" : "y", recursivelly
|
||||
bool Sema::SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
|
||||
bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
|
||||
bool HasVAListArg,
|
||||
unsigned format_idx, unsigned firstDataArg) {
|
||||
|
||||
switch (E->getStmtClass()) {
|
||||
case Stmt::ConditionalOperatorClass: {
|
||||
ConditionalOperator *C = cast<ConditionalOperator>(E);
|
||||
const ConditionalOperator *C = cast<ConditionalOperator>(E);
|
||||
return SemaCheckStringLiteral(C->getLHS(), TheCall,
|
||||
HasVAListArg, format_idx, firstDataArg)
|
||||
&& SemaCheckStringLiteral(C->getRHS(), TheCall,
|
||||
@@ -436,26 +437,54 @@ bool Sema::SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
|
||||
}
|
||||
|
||||
case Stmt::ImplicitCastExprClass: {
|
||||
ImplicitCastExpr *Expr = dyn_cast<ImplicitCastExpr>(E);
|
||||
const ImplicitCastExpr *Expr = cast<ImplicitCastExpr>(E);
|
||||
return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
|
||||
format_idx, firstDataArg);
|
||||
}
|
||||
|
||||
case Stmt::ParenExprClass: {
|
||||
ParenExpr *Expr = dyn_cast<ParenExpr>(E);
|
||||
const ParenExpr *Expr = cast<ParenExpr>(E);
|
||||
return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
|
||||
format_idx, firstDataArg);
|
||||
}
|
||||
|
||||
case Stmt::DeclRefExprClass: {
|
||||
const DeclRefExpr *DR = cast<DeclRefExpr>(E);
|
||||
|
||||
// As an exception, do not flag errors for variables binding to
|
||||
// const string literals.
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
|
||||
bool isConstant = false;
|
||||
QualType T = DR->getType();
|
||||
|
||||
default: {
|
||||
ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E);
|
||||
StringLiteral *StrE = NULL;
|
||||
if (const ArrayType *AT = Context.getAsArrayType(T)) {
|
||||
isConstant = AT->getElementType().isConstant(Context);
|
||||
}
|
||||
else if (const PointerType *PT = T->getAsPointerType()) {
|
||||
isConstant = T.isConstant(Context) &&
|
||||
PT->getPointeeType().isConstant(Context);
|
||||
}
|
||||
|
||||
if (isConstant) {
|
||||
const VarDecl *Def = 0;
|
||||
if (const Expr *Init = VD->getDefinition(Def))
|
||||
return SemaCheckStringLiteral(Init, TheCall,
|
||||
HasVAListArg, format_idx, firstDataArg);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ObjCFExpr)
|
||||
case Stmt::ObjCStringLiteralClass:
|
||||
case Stmt::StringLiteralClass: {
|
||||
const StringLiteral *StrE = NULL;
|
||||
|
||||
if (const ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E))
|
||||
StrE = ObjCFExpr->getString();
|
||||
else
|
||||
StrE = dyn_cast<StringLiteral>(E);
|
||||
|
||||
StrE = cast<StringLiteral>(E);
|
||||
|
||||
if (StrE) {
|
||||
CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx,
|
||||
firstDataArg);
|
||||
@@ -464,6 +493,9 @@ bool Sema::SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,9 +550,9 @@ bool Sema::SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
|
||||
///
|
||||
/// For now, we ONLY do (1), (3), (5), (6), (7), and (8).
|
||||
void
|
||||
Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
|
||||
Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg,
|
||||
unsigned format_idx, unsigned firstDataArg) {
|
||||
Expr *Fn = TheCall->getCallee();
|
||||
const Expr *Fn = TheCall->getCallee();
|
||||
|
||||
// CHECK: printf-like function is called with no format string.
|
||||
if (format_idx >= TheCall->getNumArgs()) {
|
||||
@@ -529,7 +561,7 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
|
||||
return;
|
||||
}
|
||||
|
||||
Expr *OrigFormatExpr = TheCall->getArg(format_idx)->IgnoreParenCasts();
|
||||
const Expr *OrigFormatExpr = TheCall->getArg(format_idx)->IgnoreParenCasts();
|
||||
|
||||
// CHECK: format string is not a string literal.
|
||||
//
|
||||
@@ -567,22 +599,25 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
|
||||
// if the argument is a DeclRefExpr that references a parameter. We'll
|
||||
// add proper support for checking the attribute later.
|
||||
if (HasVAListArg)
|
||||
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(OrigFormatExpr))
|
||||
if (const DeclRefExpr* DR = dyn_cast<DeclRefExpr>(OrigFormatExpr))
|
||||
if (isa<ParmVarDecl>(DR->getDecl()))
|
||||
return;
|
||||
|
||||
Diag(TheCall->getArg(format_idx)->getLocStart(),
|
||||
diag::warn_printf_not_string_constant)
|
||||
<< OrigFormatExpr->getSourceRange();
|
||||
<< OrigFormatExpr->getSourceRange();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::CheckPrintfString(StringLiteral *FExpr, Expr *OrigFormatExpr,
|
||||
CallExpr *TheCall, bool HasVAListArg, unsigned format_idx,
|
||||
unsigned firstDataArg) {
|
||||
void Sema::CheckPrintfString(const StringLiteral *FExpr,
|
||||
const Expr *OrigFormatExpr,
|
||||
const CallExpr *TheCall, bool HasVAListArg,
|
||||
unsigned format_idx, unsigned firstDataArg) {
|
||||
|
||||
const ObjCStringLiteral *ObjCFExpr =
|
||||
dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
|
||||
|
||||
ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
|
||||
// CHECK: is the format string a wide literal?
|
||||
if (FExpr->isWide()) {
|
||||
Diag(FExpr->getLocStart(),
|
||||
@@ -673,7 +708,7 @@ void Sema::CheckPrintfString(StringLiteral *FExpr, Expr *OrigFormatExpr,
|
||||
}
|
||||
|
||||
// Perform type checking on width/precision specifier.
|
||||
Expr *E = TheCall->getArg(format_idx+numConversions);
|
||||
const Expr *E = TheCall->getArg(format_idx+numConversions);
|
||||
if (const BuiltinType *BT = E->getType()->getAsBuiltinType())
|
||||
if (BT->getKind() == BuiltinType::Int)
|
||||
break;
|
||||
|
||||
@@ -99,3 +99,17 @@ void __attribute__((format(printf,1,3))) myprintf(const char*, int blah, ...);
|
||||
void test_myprintf() {
|
||||
myprintf("%d", 17, 18); // okay
|
||||
}
|
||||
|
||||
void test_constant_bindings(void) {
|
||||
const char * const s1 = "hello";
|
||||
const char s2[] = "hello";
|
||||
const char *s3 = "hello";
|
||||
char * const s4 = "hello";
|
||||
extern const char s5[];
|
||||
|
||||
printf(s1); // no-warning
|
||||
printf(s2); // no-warning
|
||||
printf(s3); // expected-warning{{not a string literal}}
|
||||
printf(s4); // expected-warning{{not a string literal}}
|
||||
printf(s5); // expected-warning{{not a string literal}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user