Tweak printf format string parsing to accept 'hh' conversion specifier to accept any char, not just signed char. Fixes <rdar://problem/10303638>.

llvm-svn: 142908
This commit is contained in:
Ted Kremenek 2011-10-25 04:20:41 +00:00
parent baabbb779d
commit 74e82bd190
4 changed files with 29 additions and 7 deletions

View File

@ -199,7 +199,7 @@ protected:
class ArgTypeResult { class ArgTypeResult {
public: public:
enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
CStrTy, WCStrTy, WIntTy }; AnyCharTy, CStrTy, WCStrTy, WIntTy };
private: private:
const Kind K; const Kind K;
QualType T; QualType T;

View File

@ -183,13 +183,13 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
return false; return false;
case 'h': case 'h':
++I; ++I;
lmKind = (I != E && *I == 'h') ? lmKind = (I != E && *I == 'h') ? (++I, LengthModifier::AsChar)
++I, LengthModifier::AsChar : LengthModifier::AsShort; : LengthModifier::AsShort;
break; break;
case 'l': case 'l':
++I; ++I;
lmKind = (I != E && *I == 'l') ? lmKind = (I != E && *I == 'l') ? (++I, LengthModifier::AsLongLong)
++I, LengthModifier::AsLongLong : LengthModifier::AsLong; : LengthModifier::AsLong;
break; break;
case 'j': lmKind = LengthModifier::AsIntMax; ++I; break; case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;
case 'z': lmKind = LengthModifier::AsSizeT; ++I; break; case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;
@ -213,7 +213,21 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
case UnknownTy: case UnknownTy:
return true; return true;
case AnyCharTy: {
if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
switch (BT->getKind()) {
default:
break;
case BuiltinType::Char_S:
case BuiltinType::SChar:
case BuiltinType::UChar:
case BuiltinType::Char_U:
return true;
}
return false;
}
case SpecificTy: { case SpecificTy: {
argTy = C.getCanonicalType(argTy).getUnqualifiedType(); argTy = C.getCanonicalType(argTy).getUnqualifiedType();
if (T == argTy) if (T == argTy)
@ -314,6 +328,8 @@ QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
llvm_unreachable("No representative type for Invalid ArgTypeResult"); llvm_unreachable("No representative type for Invalid ArgTypeResult");
case UnknownTy: case UnknownTy:
return QualType(); return QualType();
case AnyCharTy:
return C.CharTy;
case SpecificTy: case SpecificTy:
return T; return T;
case CStrTy: case CStrTy:

View File

@ -297,7 +297,7 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsLongDouble: case LengthModifier::AsLongDouble:
return ArgTypeResult::Invalid(); return ArgTypeResult::Invalid();
case LengthModifier::None: return Ctx.IntTy; case LengthModifier::None: return Ctx.IntTy;
case LengthModifier::AsChar: return Ctx.SignedCharTy; case LengthModifier::AsChar: return ArgTypeResult::AnyCharTy;
case LengthModifier::AsShort: return Ctx.ShortTy; case LengthModifier::AsShort: return Ctx.ShortTy;
case LengthModifier::AsLong: return Ctx.LongTy; case LengthModifier::AsLong: return Ctx.LongTy;
case LengthModifier::AsLongLong: return Ctx.LongLongTy; case LengthModifier::AsLongLong: return Ctx.LongLongTy;

View File

@ -212,6 +212,12 @@ void test12(char *b) {
asprintf(&b, "%d", "asprintf"); // expected-warning{{conversion specifies type 'int' but the argument has type 'char *'}} asprintf(&b, "%d", "asprintf"); // expected-warning{{conversion specifies type 'int' but the argument has type 'char *'}}
} }
void test13(short x) {
char bel = 007;
printf("bel: '0%hhd'\n", bel); // no-warning
printf("x: '0%hhd'\n", x); // expected-warning {{conversion specifies type 'char' but the argument has type 'short'}}
}
typedef struct __aslclient *aslclient; typedef struct __aslclient *aslclient;
typedef struct __aslmsg *aslmsg; typedef struct __aslmsg *aslmsg;
int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5))); int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5)));