зеркало из 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'
|
AsSizeT, // 'z'
|
||||||
AsPtrDiff, // 't'
|
AsPtrDiff, // 't'
|
||||||
AsLongDouble, // 'L'
|
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
|
AsWideChar = AsLong // for '%ls', only makes sense for printf
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -212,6 +212,13 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
|
||||||
--I;
|
--I;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
case 'm':
|
||||||
|
if (IsScanf) {
|
||||||
|
lmKind = LengthModifier::AsMAllocate;
|
||||||
|
++I;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
LengthModifier lm(lmPosition, lmKind);
|
LengthModifier lm(lmPosition, lmKind);
|
||||||
FS.setLengthModifier(lm);
|
FS.setLengthModifier(lm);
|
||||||
|
@ -409,6 +416,8 @@ analyze_format_string::LengthModifier::toString() const {
|
||||||
return "L";
|
return "L";
|
||||||
case AsAllocate:
|
case AsAllocate:
|
||||||
return "a";
|
return "a";
|
||||||
|
case AsMAllocate:
|
||||||
|
return "m";
|
||||||
case None:
|
case None:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -555,6 +564,18 @@ bool FormatSpecifier::hasValidLengthModifier() const {
|
||||||
default:
|
default:
|
||||||
return false;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,6 +273,7 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
|
||||||
case LengthModifier::AsPtrDiff:
|
case LengthModifier::AsPtrDiff:
|
||||||
return ArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t");
|
return ArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t");
|
||||||
case LengthModifier::AsAllocate:
|
case LengthModifier::AsAllocate:
|
||||||
|
case LengthModifier::AsMAllocate:
|
||||||
return ArgTypeResult::Invalid();
|
return ArgTypeResult::Invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,6 +295,7 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
|
||||||
// version of ptrdiff_t?
|
// version of ptrdiff_t?
|
||||||
return ArgTypeResult();
|
return ArgTypeResult();
|
||||||
case LengthModifier::AsAllocate:
|
case LengthModifier::AsAllocate:
|
||||||
|
case LengthModifier::AsMAllocate:
|
||||||
return ArgTypeResult::Invalid();
|
return ArgTypeResult::Invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,6 +220,7 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
||||||
return ScanfArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t *");
|
return ScanfArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t *");
|
||||||
case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
|
case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
|
||||||
case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
|
case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
|
||||||
|
case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsigned int.
|
// Unsigned int.
|
||||||
|
@ -243,6 +244,7 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
||||||
return ScanfArgTypeResult();
|
return ScanfArgTypeResult();
|
||||||
case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
|
case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid();
|
||||||
case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
|
case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid();
|
||||||
|
case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Float.
|
// Float.
|
||||||
|
@ -271,15 +273,24 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const {
|
||||||
case LengthModifier::None: return ScanfArgTypeResult::CStrTy;
|
case LengthModifier::None: return ScanfArgTypeResult::CStrTy;
|
||||||
case LengthModifier::AsLong:
|
case LengthModifier::AsLong:
|
||||||
return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
|
return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
|
||||||
|
case LengthModifier::AsAllocate:
|
||||||
|
case LengthModifier::AsMAllocate:
|
||||||
|
return ScanfArgTypeResult(ArgTypeResult::CStrTy);
|
||||||
default:
|
default:
|
||||||
return ScanfArgTypeResult::Invalid();
|
return ScanfArgTypeResult::Invalid();
|
||||||
}
|
}
|
||||||
case ConversionSpecifier::CArg:
|
case ConversionSpecifier::CArg:
|
||||||
case ConversionSpecifier::SArg:
|
case ConversionSpecifier::SArg:
|
||||||
// FIXME: Mac OS X specific?
|
// FIXME: Mac OS X specific?
|
||||||
if (LM.getKind() == LengthModifier::None)
|
switch (LM.getKind()) {
|
||||||
return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
|
case LengthModifier::None:
|
||||||
return ScanfArgTypeResult::Invalid();
|
return ScanfArgTypeResult(ScanfArgTypeResult::WCStrTy, "wchar_t *");
|
||||||
|
case LengthModifier::AsAllocate:
|
||||||
|
case LengthModifier::AsMAllocate:
|
||||||
|
return ScanfArgTypeResult(ArgTypeResult::WCStrTy, "wchar_t **");
|
||||||
|
default:
|
||||||
|
return ScanfArgTypeResult::Invalid();
|
||||||
|
}
|
||||||
|
|
||||||
// Pointer.
|
// Pointer.
|
||||||
case ConversionSpecifier::pArg:
|
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, ...);
|
int scanf(const char * restrict, ...);
|
||||||
|
@ -19,4 +19,9 @@ void foo(char **sp, float *fp, int *ip) {
|
||||||
printf("%afoo", 1.0);
|
printf("%afoo", 1.0);
|
||||||
|
|
||||||
scanf("%da", ip);
|
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>
|
#include <stdarg.h>
|
||||||
typedef __typeof(sizeof(int)) size_t;
|
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}}
|
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,
|
/* 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
|
* even when followed by an 's', 'S' or '[', which would cause it to be
|
||||||
* parsed as a length modifier in C90. */
|
* parsed as a length modifier in C90. */
|
||||||
scanf("%as", sp); // expected-warning{{conversion specifies type 'float *' but the argument has type 'char **'}}
|
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("%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 **'}}
|
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 *'}}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче