diff options
author | Hans Wennborg <hans@hanshq.net> | 2012-08-07 09:13:19 +0000 |
---|---|---|
committer | Hans Wennborg <hans@hanshq.net> | 2012-08-07 09:13:19 +0000 |
commit | abc1e22d659e735af4946bc70762ece5391e4472 (patch) | |
tree | 5d23e66ddb30fc5f212abe17c1ff72794c843a72 /clang | |
parent | b1ab2a84f0eac4954e2769ace9c1c73ebce983e5 (diff) | |
download | bcm5719-llvm-abc1e22d659e735af4946bc70762ece5391e4472.tar.gz bcm5719-llvm-abc1e22d659e735af4946bc70762ece5391e4472.zip |
Properly check length modfiers for %n in format strings.
llvm-svn: 161408
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Analysis/PrintfFormatString.cpp | 29 | ||||
-rw-r--r-- | clang/lib/Analysis/ScanfFormatString.cpp | 25 | ||||
-rw-r--r-- | clang/test/Sema/format-strings-scanf.c | 26 | ||||
-rw-r--r-- | clang/test/Sema/format-strings-size_t.c | 13 | ||||
-rw-r--r-- | clang/test/Sema/format-strings.c | 27 |
5 files changed, 117 insertions, 3 deletions
diff --git a/clang/lib/Analysis/PrintfFormatString.cpp b/clang/lib/Analysis/PrintfFormatString.cpp index 0a30328b12b..9e4c0fec4c0 100644 --- a/clang/lib/Analysis/PrintfFormatString.cpp +++ b/clang/lib/Analysis/PrintfFormatString.cpp @@ -312,6 +312,33 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, return Ctx.DoubleTy; } + if (CS.getKind() == ConversionSpecifier::nArg) { + switch (LM.getKind()) { + case LengthModifier::None: + return ArgType::PtrTo(Ctx.IntTy); + case LengthModifier::AsChar: + return ArgType::PtrTo(Ctx.SignedCharTy); + case LengthModifier::AsShort: + return ArgType::PtrTo(Ctx.ShortTy); + case LengthModifier::AsLong: + return ArgType::PtrTo(Ctx.LongTy); + case LengthModifier::AsLongLong: + case LengthModifier::AsQuad: + return ArgType::PtrTo(Ctx.LongLongTy); + case LengthModifier::AsIntMax: + return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); + case LengthModifier::AsSizeT: + return ArgType(); // FIXME: ssize_t + case LengthModifier::AsPtrDiff: + return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); + case LengthModifier::AsLongDouble: + return ArgType(); // FIXME: Is this a known extension? + case LengthModifier::AsAllocate: + case LengthModifier::AsMAllocate: + return ArgType::Invalid(); + } + } + switch (CS.getKind()) { case ConversionSpecifier::sArg: if (LM.getKind() == LengthModifier::AsWideChar) { @@ -330,8 +357,6 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, return ArgType(Ctx.WCharTy, "wchar_t"); case ConversionSpecifier::pArg: return ArgType::CPointerTy; - case ConversionSpecifier::nArg: - return ArgType::PtrTo(Ctx.IntTy); case ConversionSpecifier::ObjCObjArg: return ArgType::ObjCPointerTy; default: diff --git a/clang/lib/Analysis/ScanfFormatString.cpp b/clang/lib/Analysis/ScanfFormatString.cpp index 80deb37fad2..2942400621d 100644 --- a/clang/lib/Analysis/ScanfFormatString.cpp +++ b/clang/lib/Analysis/ScanfFormatString.cpp @@ -318,7 +318,30 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { // Write-back. case ConversionSpecifier::nArg: - return ArgType::PtrTo(Ctx.IntTy); + switch (LM.getKind()) { + case LengthModifier::None: + return ArgType::PtrTo(Ctx.IntTy); + case LengthModifier::AsChar: + return ArgType::PtrTo(Ctx.SignedCharTy); + case LengthModifier::AsShort: + return ArgType::PtrTo(Ctx.ShortTy); + case LengthModifier::AsLong: + return ArgType::PtrTo(Ctx.LongTy); + case LengthModifier::AsLongLong: + case LengthModifier::AsQuad: + return ArgType::PtrTo(Ctx.LongLongTy); + case LengthModifier::AsIntMax: + return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); + case LengthModifier::AsSizeT: + return ArgType(); // FIXME: ssize_t + case LengthModifier::AsPtrDiff: + return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); + case LengthModifier::AsLongDouble: + return ArgType(); // FIXME: Is this a known extension? + case LengthModifier::AsAllocate: + case LengthModifier::AsMAllocate: + return ArgType::Invalid(); + } default: break; diff --git a/clang/test/Sema/format-strings-scanf.c b/clang/test/Sema/format-strings-scanf.c index 49c97149a77..235ac11faa1 100644 --- a/clang/test/Sema/format-strings-scanf.c +++ b/clang/test/Sema/format-strings-scanf.c @@ -131,6 +131,32 @@ void test_quad(int *x, long long *llx) { void test_writeback(int *x) { scanf("%n", (void*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'void *'}} scanf("%n %c", x, x); // expected-warning{{format specifies type 'char *' but the argument has type 'int *'}} + + scanf("%hhn", (signed char*)0); // no-warning + scanf("%hhn", (char*)0); // no-warning + scanf("%hhn", (unsigned char*)0); // no-warning + scanf("%hhn", (int*)0); // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}} + + scanf("%hn", (short*)0); // no-warning + scanf("%hn", (unsigned short*)0); // no-warning + scanf("%hn", (int*)0); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}} + + scanf("%n", (int*)0); // no-warning + scanf("%n", (unsigned int*)0); // no-warning + scanf("%n", (char*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}} + + scanf("%ln", (long*)0); // no-warning + scanf("%ln", (unsigned long*)0); // no-warning + scanf("%ln", (int*)0); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}} + + scanf("%lln", (long long*)0); // no-warning + scanf("%lln", (unsigned long long*)0); // no-warning + scanf("%lln", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}} + + scanf("%qn", (long long*)0); // no-warning + scanf("%qn", (unsigned long long*)0); // no-warning + scanf("%qn", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}} + } void test_qualifiers(const int *cip, volatile int* vip, diff --git a/clang/test/Sema/format-strings-size_t.c b/clang/test/Sema/format-strings-size_t.c index 7f88ff38c30..5058a762183 100644 --- a/clang/test/Sema/format-strings-size_t.c +++ b/clang/test/Sema/format-strings-size_t.c @@ -13,3 +13,16 @@ void test(void) { // ptrdiff_t printf("%td", (double)42); // expected-warning {{format specifies type 'ptrdiff_t' (aka 'long') but the argument has type 'double'}} } + +void test_writeback(void) { + printf("%jn", (long*)0); // no-warning + printf("%jn", (unsigned long*)0); // no-warning + printf("%jn", (int*)0); // expected-warning{{format specifies type 'intmax_t *' (aka 'long *') but the argument has type 'int *'}} + + printf("%zn", (long*)0); // no-warning + // FIXME: Warn about %zn with non-ssize_t argument. + + printf("%tn", (long*)0); // no-warning + printf("%tn", (unsigned long*)0); // no-warning + printf("%tn", (int*)0); // expected-warning{{format specifies type 'ptrdiff_t *' (aka 'long *') but the argument has type 'int *'}} +} diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c index aff996fed3e..86b9296108c 100644 --- a/clang/test/Sema/format-strings.c +++ b/clang/test/Sema/format-strings.c @@ -90,6 +90,33 @@ void check_writeback_specifier() char *b; printf("%n", b); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}} printf("%n", &x); // no-warning + + printf("%hhn", (signed char*)0); // no-warning + printf("%hhn", (char*)0); // no-warning + printf("%hhn", (unsigned char*)0); // no-warning + printf("%hhn", (int*)0); // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}} + + printf("%hn", (short*)0); // no-warning + printf("%hn", (unsigned short*)0); // no-warning + printf("%hn", (int*)0); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}} + + printf("%n", (int*)0); // no-warning + printf("%n", (unsigned int*)0); // no-warning + printf("%n", (char*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}} + + printf("%ln", (long*)0); // no-warning + printf("%ln", (unsigned long*)0); // no-warning + printf("%ln", (int*)0); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}} + + printf("%lln", (long long*)0); // no-warning + printf("%lln", (unsigned long long*)0); // no-warning + printf("%lln", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}} + + printf("%qn", (long long*)0); // no-warning + printf("%qn", (unsigned long long*)0); // no-warning + printf("%qn", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}} + + printf("%Ln", 0); // expected-warning{{length modifier 'L' results in undefined behavior or no effect with 'n' conversion specifier}} } void check_invalid_specifier(FILE* fp, char *buf) |