[cfe-commits] r94761 - in /cfe/trunk/lib/Sema: Sema.h SemaChecking.cpp

Ted Kremenek kremenek at apple.com
Thu Jan 28 15:39:18 PST 2010


Author: kremenek
Date: Thu Jan 28 17:39:18 2010
New Revision: 94761

URL: http://llvm.org/viewvc/llvm-project?rev=94761&view=rev
Log:
Start fleshing out Sema::AlternateCheckPrintfString():
- Add an anonymous class 'CheckPrintfHandler' which will do the
  checking of specific format specifiers
- Add checking for using the '@' conversion specifier outside
  an ObjC string literal
- Add checking for null characters within the string

Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaChecking.cpp

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=94761&r1=94760&r2=94761&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Jan 28 17:39:18 2010
@@ -4020,12 +4020,15 @@
   
   //===--------------------------------------------------------------------===//
   // Extra semantic analysis beyond the C type system
+
+public:
+  SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
+                                                unsigned ByteNo) const;
+
 private:
   bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
   bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall);
 
-  SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
-                                                unsigned ByteNo) const;
   bool CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall);
   bool CheckObjCString(Expr *Arg);
 

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=94761&r1=94760&r2=94761&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Jan 28 17:39:18 2010
@@ -15,6 +15,7 @@
 #include "Sema.h"
 #include "clang/Analysis/CFG.h"
 #include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Analyses/PrintfFormatString.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
@@ -1279,13 +1280,106 @@
   }
 }
 
+
+namespace {
+class CheckPrintfHandler : public analyze_printf::FormatStringHandler {
+  Sema &S;
+  const StringLiteral *FExpr;
+  const Expr *OrigFormatExpr;
+  unsigned NumConversions;
+  const unsigned NumDataArgs;
+  const bool IsObjCLiteral;
+  const char *Beg; // Start of format string.
+public:  
+  CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
+                     const Expr *origFormatExpr,
+                     unsigned numDataArgs, bool isObjCLiteral,
+                     const char *beg)
+    : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
+      NumConversions(0), NumDataArgs(numDataArgs),
+      IsObjCLiteral(isObjCLiteral), Beg(beg) {}
+    
+  void HandleNullChar(const char *nullCharacter);
+  
+  bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
+                             const char *startSpecifier,
+                             unsigned specifierLen);
+private:
+  SourceRange getFormatRange();
+  SourceLocation getLocationOfByte(const char *x);
+};
+}
+
+SourceRange CheckPrintfHandler::getFormatRange() {
+  return OrigFormatExpr->getSourceRange();
+}
+
+SourceLocation CheckPrintfHandler::getLocationOfByte(const char *x) {
+  return S.getLocationOfStringLiteralByte(FExpr, x - Beg);  
+}
+
+void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) {
+  // The presence of a null character is likely an error.
+  S.Diag(getLocationOfByte(nullCharacter),
+         diag::warn_printf_format_string_contains_null_char)
+    << getFormatRange();
+}
+
+bool
+CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
+                                          const char *startSpecifier,
+                                          unsigned specifierLen) {
+
+  using namespace analyze_printf;
+  const ConversionSpecifier &CS = FS.getConversionSpecifier();
+
+  // Check for using an Objective-C specific conversion specifier
+  // in a non-ObjC literal.
+  if (!IsObjCLiteral && CS.isObjCArg()) {
+    SourceLocation Loc = getLocationOfByte(CS.getConversionStart());
+    S.Diag(Loc, diag::warn_printf_invalid_conversion)
+      << llvm::StringRef(startSpecifier, specifierLen)
+      << getFormatRange();
+    
+    // Continue checking the other format specifiers.
+    return true;
+  }
+
+  return true;
+}
+
+
 void
 Sema::AlternateCheckPrintfString(const StringLiteral *FExpr,
                                  const Expr *OrigFormatExpr,
                                  const CallExpr *TheCall, bool HasVAListArg,
                                  unsigned format_idx, unsigned firstDataArg) {
   
+  // CHECK: is the format string a wide literal?
+  if (FExpr->isWide()) {
+    Diag(FExpr->getLocStart(),
+         diag::warn_printf_format_string_is_wide_literal)
+    << OrigFormatExpr->getSourceRange();
+    return;
+  }
+  
+  // Str - The format string.  NOTE: this is NOT null-terminated!
+  const char *Str = FExpr->getStrData();
+  
+  // CHECK: empty format string?
+  unsigned StrLen = FExpr->getByteLength();
+  
+  if (StrLen == 0) {
+    Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string)
+    << OrigFormatExpr->getSourceRange();
+    return;
+  }
   
+  CheckPrintfHandler H(*this, FExpr, OrigFormatExpr,
+                       TheCall->getNumArgs() - firstDataArg,
+                       isa<ObjCStringLiteral>(OrigFormatExpr), Str);
+
+  analyze_printf::ParseFormatString(H, Str, Str + StrLen);
 }
 
 //===--- CHECK: Return Address of Stack Variable --------------------------===//





More information about the cfe-commits mailing list