зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
1d7049a6ed
Коммит
37969b7e14
|
@ -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 *'}}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче