aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Analysis/Analyses/FormatString.h4
-rw-r--r--lib/Analysis/FormatString.cpp34
-rw-r--r--lib/Analysis/PrintfFormatString.cpp17
-rw-r--r--lib/Analysis/ScanfFormatString.cpp17
-rw-r--r--test/Sema/format-strings-fixit.c34
5 files changed, 76 insertions, 30 deletions
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index f99b97a189..1fb05d7486 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -355,6 +355,10 @@ public:
bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
bool hasStandardLengthConversionCombination() const;
+
+ /// For a TypedefType QT, if it is a named integer type such as size_t,
+ /// assign the appropriate value to LM and return true.
+ static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
};
} // end analyze_format_string namespace
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index caceeac113..a68b9bb324 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -681,3 +681,37 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const {
}
return true;
}
+
+bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
+ LengthModifier &LM) {
+ assert(isa<TypedefType>(QT) && "Expected a TypedefType");
+ const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
+
+ for (;;) {
+ const IdentifierInfo *Identifier = Typedef->getIdentifier();
+ if (Identifier->getName() == "size_t") {
+ LM.setKind(LengthModifier::AsSizeT);
+ return true;
+ } else if (Identifier->getName() == "ssize_t") {
+ // Not C99, but common in Unix.
+ LM.setKind(LengthModifier::AsSizeT);
+ return true;
+ } else if (Identifier->getName() == "intmax_t") {
+ LM.setKind(LengthModifier::AsIntMax);
+ return true;
+ } else if (Identifier->getName() == "uintmax_t") {
+ LM.setKind(LengthModifier::AsIntMax);
+ return true;
+ } else if (Identifier->getName() == "ptrdiff_t") {
+ LM.setKind(LengthModifier::AsPtrDiff);
+ return true;
+ }
+
+ QualType T = Typedef->getUnderlyingType();
+ if (!isa<TypedefType>(T))
+ break;
+
+ Typedef = cast<TypedefType>(T)->getDecl();
+ }
+ return false;
+}
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index aa6d7424c0..2a9644a353 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -447,21 +447,8 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) {
- const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier();
- if (Identifier->getName() == "size_t") {
- LM.setKind(LengthModifier::AsSizeT);
- } else if (Identifier->getName() == "ssize_t") {
- // Not C99, but common in Unix.
- LM.setKind(LengthModifier::AsSizeT);
- } else if (Identifier->getName() == "intmax_t") {
- LM.setKind(LengthModifier::AsIntMax);
- } else if (Identifier->getName() == "uintmax_t") {
- LM.setKind(LengthModifier::AsIntMax);
- } else if (Identifier->getName() == "ptrdiff_t") {
- LM.setKind(LengthModifier::AsPtrDiff);
- }
- }
+ if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x))
+ namedTypeToLengthModifier(QT, LM);
// If fixing the length modifier was enough, we are done.
const analyze_printf::ArgTypeResult &ATR = getArgType(Ctx, IsObjCLiteral);
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 066d5d6fa1..5c7e6ef8f2 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -382,21 +382,8 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) {
- const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier();
- if (Identifier->getName() == "size_t") {
- LM.setKind(LengthModifier::AsSizeT);
- } else if (Identifier->getName() == "ssize_t") {
- // Not C99, but common in Unix.
- LM.setKind(LengthModifier::AsSizeT);
- } else if (Identifier->getName() == "intmax_t") {
- LM.setKind(LengthModifier::AsIntMax);
- } else if (Identifier->getName() == "uintmax_t") {
- LM.setKind(LengthModifier::AsIntMax);
- } else if (Identifier->getName() == "ptrdiff_t") {
- LM.setKind(LengthModifier::AsPtrDiff);
- }
- }
+ if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x))
+ namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
const analyze_scanf::ScanfArgTypeResult &ATR = getArgType(Ctx);
diff --git a/test/Sema/format-strings-fixit.c b/test/Sema/format-strings-fixit.c
index 800691ecc8..15ac713428 100644
--- a/test/Sema/format-strings-fixit.c
+++ b/test/Sema/format-strings-fixit.c
@@ -64,6 +64,18 @@ void test() {
printf("%f", (uintmax_t) 42);
printf("%f", (ptrdiff_t) 42);
+ // Look beyond the first typedef.
+ typedef size_t my_size_type;
+ typedef intmax_t my_intmax_type;
+ typedef uintmax_t my_uintmax_type;
+ typedef ptrdiff_t my_ptrdiff_type;
+ typedef int my_int_type;
+ printf("%f", (my_size_type) 42);
+ printf("%f", (my_intmax_type) 42);
+ printf("%f", (my_uintmax_type) 42);
+ printf("%f", (my_ptrdiff_type) 42);
+ printf("%f", (my_int_type) 42);
+
// string
printf("%ld", "foo");
@@ -122,6 +134,18 @@ void test2() {
scanf("%f", &uIntmaxVar);
scanf("%f", &ptrdiffVar);
+ // Look beyond the first typedef for named integer types.
+ typedef size_t my_size_type;
+ typedef intmax_t my_intmax_type;
+ typedef uintmax_t my_uintmax_type;
+ typedef ptrdiff_t my_ptrdiff_type;
+ typedef int my_int_type;
+ scanf("%f", (my_size_type*)&sizeVar);
+ scanf("%f", (my_intmax_type*)&intmaxVar);
+ scanf("%f", (my_uintmax_type*)&uIntmaxVar);
+ scanf("%f", (my_ptrdiff_type*)&ptrdiffVar);
+ scanf("%f", (my_int_type*)&intVar);
+
// Preserve the original formatting.
scanf("%o", &longVar);
scanf("%u", &longVar);
@@ -162,6 +186,11 @@ void test2() {
// CHECK: printf("%jd", (intmax_t) 42);
// CHECK: printf("%ju", (uintmax_t) 42);
// CHECK: printf("%td", (ptrdiff_t) 42);
+// CHECK: printf("%zu", (my_size_type) 42);
+// CHECK: printf("%jd", (my_intmax_type) 42);
+// CHECK: printf("%ju", (my_uintmax_type) 42);
+// CHECK: printf("%td", (my_ptrdiff_type) 42);
+// CHECK: printf("%d", (my_int_type) 42);
// CHECK: printf("%s", "foo");
// CHECK: printf("%lo", (long) 42);
// CHECK: printf("%lu", (long) 42);
@@ -193,6 +222,11 @@ void test2() {
// CHECK: scanf("%jd", &intmaxVar);
// CHECK: scanf("%ju", &uIntmaxVar);
// CHECK: scanf("%td", &ptrdiffVar);
+// CHECK: scanf("%zu", (my_size_type*)&sizeVar);
+// CHECK: scanf("%jd", (my_intmax_type*)&intmaxVar);
+// CHECK: scanf("%ju", (my_uintmax_type*)&uIntmaxVar);
+// CHECK: scanf("%td", (my_ptrdiff_type*)&ptrdiffVar);
+// CHECK: scanf("%d", (my_int_type*)&intVar);
// CHECK: scanf("%lo", &longVar);
// CHECK: scanf("%lu", &longVar);
// CHECK: scanf("%lx", &longVar);