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.

llvm-svn: 108499
This commit is contained in:
Ted Kremenek 2010-07-16 02:11:15 +00:00
parent 103c4ebea5
commit 5932c35138
4 changed files with 37 additions and 0 deletions

View File

@ -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")

View 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 {

View 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;
}

View 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