diff --git a/clang/include/clang/Analysis/Analyses/FormatString.h b/clang/include/clang/Analysis/Analyses/FormatString.h index f3fe32474c76..ce66fcf2123f 100644 --- a/clang/include/clang/Analysis/Analyses/FormatString.h +++ b/clang/include/clang/Analysis/Analyses/FormatString.h @@ -66,7 +66,8 @@ public: AsChar, // 'hh' AsShort, // 'h' AsLong, // 'l' - AsLongLong, // 'll', 'q' (BSD, deprecated) + AsLongLong, // 'll' + AsQuad, // 'q' (BSD, deprecated, same as 'll') AsIntMax, // 'j' AsSizeT, // 'z' AsPtrDiff, // 't' diff --git a/clang/lib/Analysis/FormatString.cpp b/clang/lib/Analysis/FormatString.cpp index 1c911c45c3b5..fcc293bf30d2 100644 --- a/clang/lib/Analysis/FormatString.cpp +++ b/clang/lib/Analysis/FormatString.cpp @@ -198,7 +198,7 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, case 'z': lmKind = LengthModifier::AsSizeT; ++I; break; case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break; case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break; - case 'q': lmKind = LengthModifier::AsLongLong; ++I; break; + case 'q': lmKind = LengthModifier::AsQuad; ++I; break; case 'a': if (IsScanf && !LO.C99 && !LO.CPlusPlus0x) { // For scanf in C90, look at the next character to see if this should @@ -417,6 +417,8 @@ analyze_format_string::LengthModifier::toString() const { return "l"; case AsLongLong: return "ll"; + case AsQuad: + return "q"; case AsIntMax: return "j"; case AsSizeT: @@ -506,10 +508,11 @@ bool FormatSpecifier::hasValidLengthModifier() const { case LengthModifier::None: return true; - // Handle most integer flags + // Handle most integer flags case LengthModifier::AsChar: case LengthModifier::AsShort: case LengthModifier::AsLongLong: + case LengthModifier::AsQuad: case LengthModifier::AsIntMax: case LengthModifier::AsSizeT: case LengthModifier::AsPtrDiff: @@ -526,7 +529,7 @@ bool FormatSpecifier::hasValidLengthModifier() const { return false; } - // Handle 'l' flag + // Handle 'l' flag case LengthModifier::AsLong: switch (CS.getKind()) { case ConversionSpecifier::dArg: diff --git a/clang/lib/Analysis/PrintfFormatString.cpp b/clang/lib/Analysis/PrintfFormatString.cpp index ff0174e3c3e5..e1049b3c685b 100644 --- a/clang/lib/Analysis/PrintfFormatString.cpp +++ b/clang/lib/Analysis/PrintfFormatString.cpp @@ -266,7 +266,9 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx, case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy; case LengthModifier::AsShort: return Ctx.ShortTy; case LengthModifier::AsLong: return Ctx.LongTy; - case LengthModifier::AsLongLong: return Ctx.LongLongTy; + case LengthModifier::AsLongLong: + case LengthModifier::AsQuad: + return Ctx.LongLongTy; case LengthModifier::AsIntMax: return ArgTypeResult(Ctx.getIntMaxType(), "intmax_t"); case LengthModifier::AsSizeT: @@ -288,7 +290,9 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx, case LengthModifier::AsChar: return Ctx.UnsignedCharTy; case LengthModifier::AsShort: return Ctx.UnsignedShortTy; case LengthModifier::AsLong: return Ctx.UnsignedLongTy; - case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy; + case LengthModifier::AsLongLong: + case LengthModifier::AsQuad: + return Ctx.UnsignedLongLongTy; case LengthModifier::AsIntMax: return ArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t"); case LengthModifier::AsSizeT: diff --git a/clang/lib/Analysis/ScanfFormatString.cpp b/clang/lib/Analysis/ScanfFormatString.cpp index 5990a56c35c6..6bc4adb4f3c6 100644 --- a/clang/lib/Analysis/ScanfFormatString.cpp +++ b/clang/lib/Analysis/ScanfFormatString.cpp @@ -210,7 +210,9 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const { return ArgTypeResult(ArgTypeResult::AnyCharTy); case LengthModifier::AsShort: return ArgTypeResult(Ctx.ShortTy); case LengthModifier::AsLong: return ArgTypeResult(Ctx.LongTy); - case LengthModifier::AsLongLong: return ArgTypeResult(Ctx.LongLongTy); + case LengthModifier::AsLongLong: + case LengthModifier::AsQuad: + return ArgTypeResult(Ctx.LongLongTy); case LengthModifier::AsIntMax: return ScanfArgTypeResult(Ctx.getIntMaxType(), "intmax_t *"); case LengthModifier::AsSizeT: @@ -236,6 +238,7 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsShort: return ArgTypeResult(Ctx.UnsignedShortTy); case LengthModifier::AsLong: return ArgTypeResult(Ctx.UnsignedLongTy); case LengthModifier::AsLongLong: + case LengthModifier::AsQuad: return ArgTypeResult(Ctx.UnsignedLongLongTy); case LengthModifier::AsIntMax: return ScanfArgTypeResult(Ctx.getUIntMaxType(), "uintmax_t *"); diff --git a/clang/test/Sema/format-strings-scanf.c b/clang/test/Sema/format-strings-scanf.c index c97da3fd9219..e94af5acb11c 100644 --- a/clang/test/Sema/format-strings-scanf.c +++ b/clang/test/Sema/format-strings-scanf.c @@ -117,3 +117,7 @@ void test_longlong(long long *x, unsigned long long *y) { scanf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}} } +void test_quad(int *x, long long *llx) { + scanf("%qd", x); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}} + scanf("%qd", llx); // no-warning +} diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c index a7b40f8a55fa..e6ce6e3c4ab8 100644 --- a/clang/test/Sema/format-strings.c +++ b/clang/test/Sema/format-strings.c @@ -167,7 +167,9 @@ void test10(int x, float f, int i, long long lli) { printf("%.d", x); // no-warning printf("%.", x); // expected-warning{{incomplete format specifier}} printf("%f", 4); // expected-warning{{format specifies type 'double' but the argument has type 'int'}} - printf("%qd", lli); + printf("%qd", lli); // no-warning + printf("%qd", x); // expected-warning{{format specifies type 'long long' but the argument has type 'int'}} + printf("%qp", (void *)0); // expected-warning{{length modifier 'q' results in undefined behavior or no effect with 'p' conversion specifier}} printf("hhX %hhX", (unsigned char)10); // no-warning printf("llX %llX", (long long) 10); // no-warning // This is fine, because there is an implicit conversion to an int.