From: Ted Kremenek Date: Fri, 16 Jul 2010 02:11:15 +0000 (+0000) Subject: Add builtin definition for scanf, including extending the builtin encoding to X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bee05c1206dcd525e0a1f066d166ad3e972a500e;p=clang 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 --- 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()) + 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