aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-01-30 00:49:51 +0000
committerTed Kremenek <kremenek@apple.com>2010-01-30 00:49:51 +0000
commitd635c5fcc45c952b75743dd2f4c86d6950e4954e (patch)
tree29dacdd5dcf27bf7e16b51272e597c0e0ba68336 /lib/Sema/SemaChecking.cpp
parent31f8e32788adb299acad455363eb7fd244642c82 (diff)
Add basic type checking of format string conversion specifiers and their arguments. Thanks to Cristian Draghici for his help with this patch!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94864 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r--lib/Sema/SemaChecking.cpp69
1 files changed, 63 insertions, 6 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index f10c8a17fc..1e7641690d 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -1081,6 +1081,8 @@ private:
unsigned MissingArgDiag, unsigned BadTypeDiag,
const char *startSpecifier, unsigned specifierLen);
+ bool MatchType(QualType A, QualType B, bool ignoreSign);
+
const Expr *getDataArg(unsigned i) const;
};
}
@@ -1132,6 +1134,47 @@ const Expr *CheckPrintfHandler::getDataArg(unsigned i) const {
return TheCall->getArg(FormatIdx + i);
}
+bool CheckPrintfHandler::MatchType(QualType A, QualType B, bool ignoreSign) {
+ A = S.Context.getCanonicalType(A).getUnqualifiedType();
+ B = S.Context.getCanonicalType(B).getUnqualifiedType();
+
+ if (A == B)
+ return true;
+
+ if (ignoreSign) {
+ if (const BuiltinType *BT = B->getAs<BuiltinType>()) {
+ switch (BT->getKind()) {
+ default:
+ return false;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ return A == S.Context.UnsignedCharTy;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ return A == S.Context.SignedCharTy;
+ case BuiltinType::Short:
+ return A == S.Context.UnsignedShortTy;
+ case BuiltinType::UShort:
+ return A == S.Context.ShortTy;
+ case BuiltinType::Int:
+ return A == S.Context.UnsignedIntTy;
+ case BuiltinType::UInt:
+ return A == S.Context.IntTy;
+ case BuiltinType::Long:
+ return A == S.Context.UnsignedLongTy;
+ case BuiltinType::ULong:
+ return A == S.Context.LongTy;
+ case BuiltinType::LongLong:
+ return A == S.Context.UnsignedLongLongTy;
+ case BuiltinType::ULongLong:
+ return A == S.Context.LongLongTy;
+ }
+ return A == B;
+ }
+ }
+ return false;
+}
+
bool
CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt,
unsigned MissingArgDiag,
@@ -1156,13 +1199,11 @@ CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt,
// doesn't emit a warning for that case.
const Expr *Arg = getDataArg(NumConversions);
QualType T = Arg->getType();
- const BuiltinType *BT = T->getAs<BuiltinType>();
- if (!BT || (BT->getKind() != BuiltinType::Int &&
- BT->getKind() != BuiltinType::UInt)) {
+ if (!MatchType(T, S.Context.IntTy, true)) {
S.Diag(getLocationOfByte(Amt.getStart()), BadTypeDiag)
- << T
- << getFormatSpecifierRange(startSpecifier, specifierLen)
- << Arg->getSourceRange();
+ << S.Context.IntTy << T
+ << getFormatSpecifierRange(startSpecifier, specifierLen)
+ << Arg->getSourceRange();
// Don't do any more checking. We will just emit
// spurious errors.
return false;
@@ -1234,6 +1275,22 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
// Don't do any more checking.
return false;
}
+
+ // Now type check the data expression that matches the
+ // format specifier.
+ const Expr *Ex = getDataArg(NumConversions);
+ const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context);
+
+ if (const QualType *T = ATR.getSpecificType()) {
+ if (!MatchType(*T, Ex->getType(), true)) {
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_conversion_argument_type_mismatch)
+ << *T << Ex->getType()
+ << getFormatSpecifierRange(startSpecifier, specifierLen)
+ << Ex->getSourceRange();
+ }
+ return true;
+ }
return true;
}