aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-07-16 02:11:15 +0000
committerTed Kremenek <kremenek@apple.com>2010-07-16 02:11:15 +0000
commitbee05c1206dcd525e0a1f066d166ad3e972a500e (patch)
treec2fc54c7b3cd70cf93f13ae3ac126ca00b4111eb
parent6d7cfd7ef82e42ff30ee1dafd2883fd94e9f8294 (diff)
Add builtin definition for scanf, including extending the builtin encoding to
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
-rw-r--r--include/clang/Basic/Builtins.def6
-rw-r--r--include/clang/Basic/Builtins.h5
-rw-r--r--lib/Basic/Builtins.cpp20
-rw-r--r--lib/Sema/SemaDecl.cpp6
4 files changed, 37 insertions, 0 deletions
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 44b7f117d4..6457f9935a 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -66,6 +66,11 @@
// 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")
diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h
index 07f091a58a..94d5e6955a 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -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 {
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index 1a3293775e..040cdb5d55 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -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;
+}
+
+
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c1c898fac5..76cb90565b 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -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