[cfe-commits] r67404 - in /cfe/trunk: include/clang/AST/Decl.h lib/AST/Decl.cpp lib/Sema/Sema.h lib/Sema/SemaChecking.cpp test/Sema/format-strings.c
Ted Kremenek
kremenek at apple.com
Fri Mar 20 14:35:28 PDT 2009
Author: kremenek
Date: Fri Mar 20 16:35:28 2009
New Revision: 67404
URL: http://llvm.org/viewvc/llvm-project?rev=67404&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/test/Sema/format-strings.c
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=67404&r1=67403&r2=67404&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Fri Mar 20 16:35:28 2009
@@ -270,7 +270,7 @@
/// 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 {
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=67404&r1=67403&r2=67404&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Fri Mar 20 16:35:28 2009
@@ -281,7 +281,7 @@
(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();
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=67404&r1=67403&r2=67404&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Mar 20 16:35:28 2009
@@ -2348,12 +2348,13 @@
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);
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=67404&r1=67403&r2=67404&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Mar 20 16:35:28 2009
@@ -423,12 +423,13 @@
}
// 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 @@
}
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 @@
return false;
}
+
+ default:
+ return false;
}
}
@@ -518,9 +550,9 @@
///
/// 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 @@
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 @@
// 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 @@
}
// 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;
Modified: cfe/trunk/test/Sema/format-strings.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings.c?rev=67404&r1=67403&r2=67404&view=diff
==============================================================================
--- cfe/trunk/test/Sema/format-strings.c (original)
+++ cfe/trunk/test/Sema/format-strings.c Fri Mar 20 16:35:28 2009
@@ -99,3 +99,17 @@
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}}
+}
More information about the cfe-commits
mailing list