]> granicus.if.org Git - clang/commitdiff
Introduce preliminary support for NSString format-string checking.
authorTed Kremenek <kremenek@apple.com>
Mon, 16 Jun 2008 18:00:42 +0000 (18:00 +0000)
committerTed Kremenek <kremenek@apple.com>
Mon, 16 Jun 2008 18:00:42 +0000 (18:00 +0000)
Patch by Nikita Zhuk!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52336 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/ParseAST.cpp
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaChecking.cpp

index 67b6546637fd83aea676c166c976dd3011ff8ac9..dce577bc4c21a9cb6e67c74fe7bec5be7573dc47 100644 (file)
@@ -39,6 +39,8 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, bool PrintStats) {
                      PP.getIdentifierTable(), PP.getSelectorTable());
   
   TranslationUnit TU(Context);
+  TU.SetOwnsDecls(false);
+  
 
   Sema S(PP, Context, *Consumer);
   Parser P(PP, S);
index 3861d04bf0a8e8d8c408b58bcd39108e8d134ba9..78cc5d85af5f0d4eab58c9d828f3abc6f6853a6b 100644 (file)
@@ -85,6 +85,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
   KnownFunctionIDs[id_sprintf]   = &IT.get("sprintf");
   KnownFunctionIDs[id_snprintf]  = &IT.get("snprintf");
   KnownFunctionIDs[id_asprintf]  = &IT.get("asprintf");
+  KnownFunctionIDs[id_NSLog]     = &IT.get("NSLog");
   KnownFunctionIDs[id_vsnprintf] = &IT.get("vsnprintf");
   KnownFunctionIDs[id_vasprintf] = &IT.get("vasprintf");
   KnownFunctionIDs[id_vfprintf]  = &IT.get("vfprintf");
index a86bc6b62b575f5489a4b08b75efd70957ef2ec3..64ab91173300eba8c2e2aa18e10d747fa7d76406 100644 (file)
@@ -124,6 +124,7 @@ class Sema : public Action {
     id_sprintf,
     id_snprintf,
     id_asprintf,
+    id_NSLog,
     id_vsnprintf,
     id_vasprintf,
     id_vfprintf,
index 63c1635ef2b0a1e1715f6f2364187d44e116cb50..7c0ff47a60542ca2f9a5bad9b4bb6c340aa535f3 100644 (file)
@@ -17,6 +17,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/LiteralSupport.h"
 #include "clang/Basic/SourceManager.h"
@@ -86,6 +87,7 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCallRaw) {
     case id_sprintf:   format_idx = 1; break;
     case id_snprintf:  format_idx = 2; break;
     case id_asprintf:  format_idx = 1; break;
+    case id_NSLog:     format_idx = 0; break;
     case id_vsnprintf: format_idx = 2; HasVAListArg = true; break;
     case id_vasprintf: format_idx = 1; HasVAListArg = true; break;
     case id_vfprintf:  format_idx = 1; HasVAListArg = true; break;
@@ -361,7 +363,19 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
   // are string literals: (1) permits the checking of format strings by
   // the compiler and thereby (2) can practically remove the source of
   // many format string exploits.
-  StringLiteral *FExpr = dyn_cast<StringLiteral>(OrigFormatExpr);
+
+  // Format string can be either ObjC string (e.g. @"%d") or 
+  // C string (e.g. "%d")
+  // ObjC string uses the same format specifiers as C string, so we can use 
+  // the same format string checking logic for both ObjC and C strings.
+  ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
+  StringLiteral *FExpr = NULL;
+
+  if(ObjCFExpr != NULL) 
+    FExpr = ObjCFExpr->getString();
+  else
+    FExpr = dyn_cast<StringLiteral>(OrigFormatExpr);
+
   if (FExpr == NULL) {
     // For vprintf* functions (i.e., HasVAListArg==true), we add a
     // special check to see if the format string is a function parameter
@@ -540,7 +554,25 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
       Diag(Loc, diag::warn_printf_write_back, Fn->getSourceRange());
       break;
     }
-                  
+             
+    // Handle "%@"
+    case '@':
+      // %@ is allowed in ObjC format strings only.
+      if(ObjCFExpr != NULL)
+        CurrentState = state_OrdChr; 
+      else {
+        // Issue a warning: invalid format conversion.
+        SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(),
+                                                    LastConversionIdx+1);
+    
+        Diag(Loc, diag::warn_printf_invalid_conversion, 
+          std::string(Str+LastConversionIdx, 
+          Str+std::min(LastConversionIdx+2, StrLen)),
+          Fn->getSourceRange());
+      }
+      ++numConversions;
+      break;
+    
     // Handle "%%"
     case '%':
       // Sanity check: Was the first "%" character the previous one?