scanf: parse the 'm' length modifier, and check that the right arguments

are used with that and the 'a' length modifier.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148029 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Hans Wennborg 2012-01-12 17:11:12 +00:00
Родитель 1d7049a6ed
Коммит 37969b7e14
6 изменённых файлов: 63 добавлений и 7 удалений

Просмотреть файл

@ -71,7 +71,8 @@ public:
AsSizeT, // 'z'
AsPtrDiff, // 't'
AsLongDouble, // 'L'
AsAllocate, // for '%as', GNU extension to C90 scanf
AsAllocate, // for '%as', GNU extension to C90 scanf
AsMAllocate, // for '%ms', GNU extension to scanf
AsWideChar = AsLong // for '%ls', only makes sense for printf
};

Просмотреть файл

@ -212,6 +212,13 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
--I;
}
return false;
case 'm':
if (IsScanf) {
lmKind = LengthModifier::AsMAllocate;
++I;
break;
}
return false;
}
LengthModifier lm(lmPosition, lmKind);
FS.setLengthModifier(lm);
@ -409,6 +416,8 @@ analyze_format_string::LengthModifier::toString() const {
return "L";
case AsAllocate:
return "a";
case AsMAllocate:
return "m";
case None:
return "";
}
@ -555,6 +564,18 @@ bool FormatSpecifier::hasValidLengthModifier() const {
default:
return false;
}
case LengthModifier::AsMAllocate:
switch (CS.getKind()) {
case ConversionSpecifier::cArg:
case ConversionSpecifier::CArg:
case ConversionSpecifier::sArg:
case ConversionSpecifier::SArg:
case ConversionSpecifier::ScanListArg:
return true;
default:
return false;
}
}
return false;
}

Просмотреть файл

@ -273,6 +273,7 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsPtrDiff:
return ArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t");
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
return ArgTypeResult::Invalid();
}
@ -294,6 +295,7 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
// version of ptrdiff_t?
return ArgTypeResult();
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
return ArgTypeResult::Invalid();
}

Просмотреть файл

@ -220,6 +220,7 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
return ScanfArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t *");
case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid();
}
// Unsigned int.
@ -243,6 +244,7 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
return ScanfArgTypeResult();
case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid();
}
// Float.
@ -271,15 +273,24 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::None: return ScanfArgTypeResult::CStrTy;
case LengthModifier::AsLong:
return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
return ScanfArgTypeResult(ArgTypeResult::CStrTy);
default:
return ScanfArgTypeResult::Invalid();
}
case ConversionSpecifier::CArg:
case ConversionSpecifier::SArg:
// FIXME: Mac OS X specific?
if (LM.getKind() == LengthModifier::None)
return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
return ScanfArgTypeResult::Invalid();
switch (LM.getKind()) {
case LengthModifier::None:
return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
case LengthModifier::AsAllocate:
case LengthModifier::AsMAllocate:
return ScanfArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t **");
default:
return ScanfArgTypeResult::Invalid();
}
// Pointer.
case ConversionSpecifier::pArg:

Просмотреть файл

@ -1,4 +1,4 @@
/* RUN: %clang_cc1 -fsyntax-only -verify -pedantic -std=c89 %s
/* RUN: %clang_cc1 -fsyntax-only -verify -triple i386-apple-darwin9 -pedantic -std=c89 %s
*/
int scanf(const char * restrict, ...);
@ -19,4 +19,9 @@ void foo(char **sp, float *fp, int *ip) {
printf("%afoo", 1.0);
scanf("%da", ip);
/* Test argument type check for the 'a' length modifier. */
scanf("%as", fp); /* expected-warning{{conversion specifies type 'char **' but the argument has type 'float *'}} */
scanf("%aS", fp); /* expected-warning{{conversion specifies type 'wchar_t **' (aka 'int **') but the argument has type 'float *'}} */
scanf("%a[abc]", fp); /* expected-warning{{conversion specifies type 'char **' but the argument has type 'float *'}} */
}

Просмотреть файл

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral %s
// RUN: %clang_cc1 -fsyntax-only -verify -triple i386-apple-darwin9 -Wformat-nonliteral %s
#include <stdarg.h>
typedef __typeof(sizeof(int)) size_t;
@ -73,11 +73,27 @@ void test_scanlist(int *ip, char *sp) {
scanf("%h[abc]", sp); // expected-warning{{length modifier 'h' results in undefined behavior or no effect with '[' conversion specifier}}
}
void test_alloc_extension(char **sp, wchar_t **lsp) {
void test_alloc_extension(char **sp, wchar_t **lsp, float *fp) {
/* Make sure "%a" gets parsed as a conversion specifier for float,
* even when followed by an 's', 'S' or '[', which would cause it to be
* parsed as a length modifier in C90. */
scanf("%as", sp); // expected-warning{{conversion specifies type 'float *' but the argument has type 'char **'}}
scanf("%aS", lsp); // expected-warning{{conversion specifies type 'float *' but the argument has type 'wchar_t **'}}
scanf("%a[bcd]", sp); // expected-warning{{conversion specifies type 'float *' but the argument has type 'char **'}}
// Test that the 'm' length modifier is only allowed with s, S, c, C or [.
// TODO: Warn that 'm' is an extension.
scanf("%ms", sp); // No warning.
scanf("%mS", lsp); // No warning.
scanf("%mc", sp); // No warning.
scanf("%mC", lsp); // No warning.
scanf("%m[abc]", sp); // No warning.
scanf("%md", sp); // expected-warning{{length modifier 'm' results in undefined behavior or no effect with 'd' conversion specifier}}
// Test argument type check for the 'm' length modifier.
scanf("%ms", fp); // expected-warning{{conversion specifies type 'char **' but the argument has type 'float *'}}
scanf("%mS", fp); // expected-warning{{conversion specifies type 'wchar_t **' (aka 'int **') but the argument has type 'float *'}}
scanf("%mc", fp); // expected-warning{{conversion specifies type 'char **' but the argument has type 'float *'}}
scanf("%mC", fp); // expected-warning{{conversion specifies type 'wchar_t **' (aka 'int **') but the argument has type 'float *'}}
scanf("%m[abc]", fp); // expected-warning{{conversion specifies type 'char **' but the argument has type 'float *'}}
}