]> granicus.if.org Git - clang/commitdiff
Add builtin definition for scanf, including extending the builtin encoding to
authorTed Kremenek <kremenek@apple.com>
Fri, 16 Jul 2010 02:11:15 +0000 (02:11 +0000)
committerTed Kremenek <kremenek@apple.com>
Fri, 16 Jul 2010 02:11:15 +0000 (02:11 +0000)
represent builtins that have the "scanf" attribution (via the format attribute) just
like we do with printf functions.  Follow-up work is needed to add similar support
for fscanf et al.

This is to support format-string checking for scanf functions.

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

include/clang/Basic/Builtins.def
include/clang/Basic/Builtins.h
lib/Basic/Builtins.cpp
lib/Sema/SemaDecl.cpp

index 44b7f117d44d146a328f38ae28cb77d2199db25d..6457f9935ad67584127a6feab83041dd53edb7dc 100644 (file)
 //  P:N: -> similar to the p:N: attribute, but the function is like vprintf
 //          in that it accepts its arguments as a va_list rather than
 //          through an ellipsis
+//  s:N: -> this is a scanf-like function whose Nth argument is the format
+//          string.
+//  S:N: -> similar to the s:N: attribute, but the function is like vscanf
+//          in that it accepts its arguments as a va_list rather than
+//          through an ellipsis
 //  e -> const, but only when -fmath-errno=0
 //  FIXME: gcc has nonnull
 
@@ -516,6 +521,7 @@ LIBBUILTIN(vprintf, "icC*a",      "fP:0:", "stdio.h")
 LIBBUILTIN(vfprintf, "i.",        "fP:1:", "stdio.h")
 LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h")
 LIBBUILTIN(vsprintf, "ic*cC*a",   "fP:1:", "stdio.h")
+LIBBUILTIN(scanf, "icC*.",       "fs:0:", "stdio.h")
 // C99
 LIBBUILTIN(longjmp, "vJi",        "fr",    "setjmp.h")
 
index 07f091a58a4e26f297694f007fdbd7b44b829fe0..94d5e6955a245cd333be90cae181b43b5c628fd1 100644 (file)
@@ -119,6 +119,11 @@ public:
   /// argument and whether this function as a va_list argument.
   bool isPrintfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg);
 
+  /// \brief Determine whether this builtin is like scanf in its
+  /// formatting rules and, if so, set the index to the format string
+  /// argument and whether this function as a va_list argument.
+  bool isScanfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg);
+
   /// hasVAListUse - Return true of the specified builtin uses __builtin_va_list
   /// as an operand or return type.
   bool hasVAListUse(unsigned ID) const {
index 1a3293775ed615f8d53e9458764ba4ce9a28923f..040cdb5d55f3746a7adbd01b240a990e7375ca4c 100644 (file)
@@ -93,3 +93,23 @@ Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
   return true;
 }
 
+// FIXME: Refactor with isPrintfLike.
+bool
+Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,
+                              bool &HasVAListArg) {
+  const char *Scanf = strpbrk(GetRecord(ID).Attributes, "sS");
+  if (!Scanf)
+    return false;
+
+  HasVAListArg = (*Scanf == 'S');
+
+  ++Scanf;
+  assert(*Scanf == ':' && "s or S specifier must have be followed by a ':'");
+  ++Scanf;
+
+  assert(strchr(Scanf, ':') && "printf specifier must end with a ':'");
+  FormatIdx = strtol(Scanf, 0, 10);
+  return true;
+}
+
+
index c1c898fac5f9e61fccd7e75387107c9c0f144e50..76cb90565b384853bae6635d70bba1b295921cae 100644 (file)
@@ -4905,6 +4905,12 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
         FD->addAttr(::new (Context) FormatAttr(Context, "printf", FormatIdx+1,
                                                HasVAListArg ? 0 : FormatIdx+2));
     }
+    if (Context.BuiltinInfo.isScanfLike(BuiltinID, FormatIdx,
+                                             HasVAListArg)) {
+     if (!FD->getAttr<FormatAttr>())
+       FD->addAttr(::new (Context) FormatAttr(Context, "scanf", FormatIdx+1,
+                                              HasVAListArg ? 0 : FormatIdx+2));
+    }
 
     // Mark const if we don't care about errno and that is the only
     // thing preventing the function from being const. This allows