forked from OSchip/llvm-project
Properly check length modfiers for %n in format strings.
llvm-svn: 161408
This commit is contained in:
parent
b1ab2a84f0
commit
abc1e22d65
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 *'}}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue