From 9d24c2cbd9cf1b7c165ccb13221f2efb2f4b49b0 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 24 Jan 2012 21:29:54 +0000 Subject: [PATCH] Teach scanf/printf checking about '%Ld' and friends (a GNU extension). Fixes PR 9466. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148859 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/FormatString.cpp | 8 ++++++++ lib/Analysis/PrintfFormatString.cpp | 6 ++++-- lib/Analysis/ScanfFormatString.cpp | 8 ++++++-- test/Sema/format-strings-scanf.c | 10 ++++++++++ test/Sema/format-strings.c | 11 +++++++++++ 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp index fb52742bb0..a4d97fd90a 100644 --- a/lib/Analysis/FormatString.cpp +++ b/lib/Analysis/FormatString.cpp @@ -548,6 +548,14 @@ bool FormatSpecifier::hasValidLengthModifier() const { case ConversionSpecifier::gArg: case ConversionSpecifier::GArg: return true; + // GNU extension. + case ConversionSpecifier::dArg: + case ConversionSpecifier::iArg: + case ConversionSpecifier::oArg: + case ConversionSpecifier::uArg: + case ConversionSpecifier::xArg: + case ConversionSpecifier::XArg: + return true; default: return false; } diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index bc2b356934..dbe73c8f83 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -259,7 +259,8 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { if (CS.isIntArg()) switch (LM.getKind()) { case LengthModifier::AsLongDouble: - return ArgTypeResult::Invalid(); + // GNU extension. + return Ctx.LongLongTy; case LengthModifier::None: return Ctx.IntTy; case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy; case LengthModifier::AsShort: return Ctx.ShortTy; @@ -280,7 +281,8 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { if (CS.isUIntArg()) switch (LM.getKind()) { case LengthModifier::AsLongDouble: - return ArgTypeResult::Invalid(); + // GNU extension. + return Ctx.UnsignedLongLongTy; case LengthModifier::None: return Ctx.UnsignedIntTy; case LengthModifier::AsChar: return Ctx.UnsignedCharTy; case LengthModifier::AsShort: return Ctx.UnsignedShortTy; diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp index 38afd615c1..c1cdef8632 100644 --- a/lib/Analysis/ScanfFormatString.cpp +++ b/lib/Analysis/ScanfFormatString.cpp @@ -218,7 +218,9 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const { return ScanfArgTypeResult(); case LengthModifier::AsPtrDiff: return ScanfArgTypeResult(Ctx.getPointerDiffType(), "ptrdiff_t *"); - case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid(); + case LengthModifier::AsLongDouble: + // GNU extension. + return ArgTypeResult(Ctx.LongLongTy); case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid(); case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid(); } @@ -242,7 +244,9 @@ ScanfArgTypeResult ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsPtrDiff: // FIXME: Unsigned version of ptrdiff_t? return ScanfArgTypeResult(); - case LengthModifier::AsLongDouble: return ScanfArgTypeResult::Invalid(); + case LengthModifier::AsLongDouble: + // GNU extension. + return ArgTypeResult(Ctx.UnsignedLongLongTy); case LengthModifier::AsAllocate: return ScanfArgTypeResult::Invalid(); case LengthModifier::AsMAllocate: return ScanfArgTypeResult::Invalid(); } diff --git a/test/Sema/format-strings-scanf.c b/test/Sema/format-strings-scanf.c index 6962a97611..d89dbc494b 100644 --- a/test/Sema/format-strings-scanf.c +++ b/test/Sema/format-strings-scanf.c @@ -103,3 +103,13 @@ void test_alloc_extension(char **sp, wchar_t **lsp, float *fp) { scanf("%m[abc]", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}} } +void test_longlong(long long *x, unsigned long long *y) { + scanf("%Ld", y); // no-warning + scanf("%Lu", y); // no-warning + scanf("%Lx", y); // no-warning + scanf("%Ld", x); // no-warning + scanf("%Lu", x); // no-warning + scanf("%Lx", x); // no-warning + scanf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}} +} + diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c index e32ad245e3..9daaf3b0a5 100644 --- a/test/Sema/format-strings.c +++ b/test/Sema/format-strings.c @@ -469,3 +469,14 @@ void pr9751() { // when the original string is within the argument expression. printf(1 ? "yes %d" : "no %d"); // expected-warning 2{{more '%' conversions than data arguments}} } + +// PR 9466: clang: doesn't know about %Lu, %Ld, and %Lx +void printf_longlong(long long x, unsigned long long y) { + printf("%Ld", y); // no-warning + printf("%Lu", y); // no-warning + printf("%Lx", y); // no-warning + printf("%Ld", x); // no-warning + printf("%Lu", x); // no-warning + printf("%Lx", x); // no-warning + printf("%Ls", "hello"); // expected-warning {{length modifier 'L' results in undefined behavior or no effect with 's' conversion specifier}} +} -- 2.40.0