1 //= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines APIs for analyzing the format strings of printf, fscanf, 10 // and friends. 11 // 12 // The structure of format strings for fprintf are described in C99 7.19.6.1. 13 // 14 // The structure of format strings for fscanf are described in C99 7.19.6.2. 15 // 16 //===----------------------------------------------------------------------===// 17 18 #ifndef LLVM_CLANG_AST_FORMATSTRING_H 19 #define LLVM_CLANG_AST_FORMATSTRING_H 20 21 #include "clang/AST/CanonicalType.h" 22 #include <optional> 23 24 namespace clang { 25 26 class TargetInfo; 27 28 //===----------------------------------------------------------------------===// 29 /// Common components of both fprintf and fscanf format strings. 30 namespace analyze_format_string { 31 32 /// Class representing optional flags with location and representation 33 /// information. 34 class OptionalFlag { 35 public: OptionalFlag(const char * Representation)36 OptionalFlag(const char *Representation) 37 : representation(Representation), flag(false) {} isSet()38 bool isSet() const { return flag; } set()39 void set() { flag = true; } clear()40 void clear() { flag = false; } setPosition(const char * position)41 void setPosition(const char *position) { 42 assert(position); 43 flag = true; 44 this->position = position; 45 } getPosition()46 const char *getPosition() const { 47 assert(position); 48 return position; 49 } toString()50 const char *toString() const { return representation; } 51 52 // Overloaded operators for bool like qualities 53 explicit operator bool() const { return flag; } 54 OptionalFlag& operator=(const bool &rhs) { 55 flag = rhs; 56 return *this; // Return a reference to myself. 57 } 58 private: 59 const char *representation; 60 const char *position; 61 bool flag; 62 }; 63 64 /// Represents the length modifier in a format string in scanf/printf. 65 class LengthModifier { 66 public: 67 enum Kind { 68 None, 69 AsChar, // 'hh' 70 AsShort, // 'h' 71 AsShortLong, // 'hl' (OpenCL float/int vector element) 72 AsLong, // 'l' 73 AsLongLong, // 'll' 74 AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types) 75 AsIntMax, // 'j' 76 AsSizeT, // 'z' 77 AsPtrDiff, // 't' 78 AsInt32, // 'I32' (MSVCRT, like __int32) 79 AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL) 80 AsInt64, // 'I64' (MSVCRT, like __int64) 81 AsLongDouble, // 'L' 82 AsAllocate, // for '%as', GNU extension to C90 scanf 83 AsMAllocate, // for '%ms', GNU extension to scanf 84 AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z 85 AsWideChar = AsLong // for '%ls', only makes sense for printf 86 }; 87 LengthModifier()88 LengthModifier() 89 : Position(nullptr), kind(None) {} LengthModifier(const char * pos,Kind k)90 LengthModifier(const char *pos, Kind k) 91 : Position(pos), kind(k) {} 92 getStart()93 const char *getStart() const { 94 return Position; 95 } 96 getLength()97 unsigned getLength() const { 98 switch (kind) { 99 default: 100 return 1; 101 case AsLongLong: 102 case AsChar: 103 return 2; 104 case AsInt32: 105 case AsInt64: 106 return 3; 107 case None: 108 return 0; 109 } 110 } 111 getKind()112 Kind getKind() const { return kind; } setKind(Kind k)113 void setKind(Kind k) { kind = k; } 114 115 const char *toString() const; 116 117 private: 118 const char *Position; 119 Kind kind; 120 }; 121 122 class ConversionSpecifier { 123 public: 124 enum Kind { 125 InvalidSpecifier = 0, 126 // C99 conversion specifiers. 127 cArg, 128 dArg, 129 DArg, // Apple extension 130 iArg, 131 // C23 conversion specifiers. 132 bArg, 133 BArg, 134 135 IntArgBeg = dArg, 136 IntArgEnd = BArg, 137 138 oArg, 139 OArg, // Apple extension 140 uArg, 141 UArg, // Apple extension 142 xArg, 143 XArg, 144 UIntArgBeg = oArg, 145 UIntArgEnd = XArg, 146 147 fArg, 148 FArg, 149 eArg, 150 EArg, 151 gArg, 152 GArg, 153 aArg, 154 AArg, 155 DoubleArgBeg = fArg, 156 DoubleArgEnd = AArg, 157 158 sArg, 159 pArg, 160 nArg, 161 PercentArg, 162 CArg, 163 SArg, 164 165 // Apple extension: P specifies to os_log that the data being pointed to is 166 // to be copied by os_log. The precision indicates the number of bytes to 167 // copy. 168 PArg, 169 170 // ** Printf-specific ** 171 172 ZArg, // MS extension 173 174 // Objective-C specific specifiers. 175 ObjCObjArg, // '@' 176 ObjCBeg = ObjCObjArg, 177 ObjCEnd = ObjCObjArg, 178 179 // FreeBSD kernel specific specifiers. 180 FreeBSDbArg, 181 FreeBSDDArg, 182 FreeBSDrArg, 183 FreeBSDyArg, 184 185 // GlibC specific specifiers. 186 PrintErrno, // 'm' 187 188 PrintfConvBeg = ObjCObjArg, 189 PrintfConvEnd = PrintErrno, 190 191 // ** Scanf-specific ** 192 ScanListArg, // '[' 193 ScanfConvBeg = ScanListArg, 194 ScanfConvEnd = ScanListArg 195 }; 196 197 ConversionSpecifier(bool isPrintf = true) IsPrintf(isPrintf)198 : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr), 199 kind(InvalidSpecifier) {} 200 ConversionSpecifier(bool isPrintf,const char * pos,Kind k)201 ConversionSpecifier(bool isPrintf, const char *pos, Kind k) 202 : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {} 203 getStart()204 const char *getStart() const { 205 return Position; 206 } 207 getCharacters()208 StringRef getCharacters() const { 209 return StringRef(getStart(), getLength()); 210 } 211 consumesDataArgument()212 bool consumesDataArgument() const { 213 switch (kind) { 214 case PrintErrno: 215 assert(IsPrintf); 216 return false; 217 case PercentArg: 218 return false; 219 case InvalidSpecifier: 220 return false; 221 default: 222 return true; 223 } 224 } 225 getKind()226 Kind getKind() const { return kind; } setKind(Kind k)227 void setKind(Kind k) { kind = k; } getLength()228 unsigned getLength() const { 229 return EndScanList ? EndScanList - Position : 1; 230 } setEndScanList(const char * pos)231 void setEndScanList(const char *pos) { EndScanList = pos; } 232 isIntArg()233 bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) || 234 kind == FreeBSDrArg || kind == FreeBSDyArg; } isUIntArg()235 bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } isAnyIntArg()236 bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; } isDoubleArg()237 bool isDoubleArg() const { 238 return kind >= DoubleArgBeg && kind <= DoubleArgEnd; 239 } 240 241 const char *toString() const; 242 isPrintfKind()243 bool isPrintfKind() const { return IsPrintf; } 244 245 std::optional<ConversionSpecifier> getStandardSpecifier() const; 246 247 protected: 248 bool IsPrintf; 249 const char *Position; 250 const char *EndScanList; 251 Kind kind; 252 }; 253 254 class ArgType { 255 public: 256 enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, 257 AnyCharTy, CStrTy, WCStrTy, WIntTy }; 258 259 /// How well a given conversion specifier matches its argument. 260 enum MatchKind { 261 /// The conversion specifier and the argument types are incompatible. For 262 /// instance, "%d" and float. 263 NoMatch = 0, 264 /// The conversion specifier and the argument type are compatible. For 265 /// instance, "%d" and int. 266 Match = 1, 267 /// The conversion specifier and the argument type are compatible because of 268 /// default argument promotions. For instance, "%hhd" and int. 269 MatchPromotion, 270 /// The conversion specifier and the argument type are compatible but still 271 /// seems likely to be an error. For instanace, "%hhd" and short. 272 NoMatchPromotionTypeConfusion, 273 /// The conversion specifier and the argument type are disallowed by the C 274 /// standard, but are in practice harmless. For instance, "%p" and int*. 275 NoMatchPedantic, 276 /// The conversion specifier and the argument type are compatible, but still 277 /// seems likely to be an error. For instance, "%hd" and _Bool. 278 NoMatchTypeConfusion, 279 }; 280 281 private: 282 const Kind K; 283 QualType T; 284 const char *Name = nullptr; 285 bool Ptr = false; 286 287 /// The TypeKind identifies certain well-known types like size_t and 288 /// ptrdiff_t. 289 enum class TypeKind { DontCare, SizeT, PtrdiffT }; 290 TypeKind TK = TypeKind::DontCare; 291 292 public: K(K)293 ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {} K(SpecificTy)294 ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {} ArgType(CanQualType T)295 ArgType(CanQualType T) : K(SpecificTy), T(T) {} 296 Invalid()297 static ArgType Invalid() { return ArgType(InvalidTy); } isValid()298 bool isValid() const { return K != InvalidTy; } 299 isSizeT()300 bool isSizeT() const { return TK == TypeKind::SizeT; } 301 isPtrdiffT()302 bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; } 303 304 /// Create an ArgType which corresponds to the type pointer to A. PtrTo(const ArgType & A)305 static ArgType PtrTo(const ArgType& A) { 306 assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); 307 ArgType Res = A; 308 Res.Ptr = true; 309 return Res; 310 } 311 312 /// Create an ArgType which corresponds to the size_t/ssize_t type. makeSizeT(const ArgType & A)313 static ArgType makeSizeT(const ArgType &A) { 314 ArgType Res = A; 315 Res.TK = TypeKind::SizeT; 316 return Res; 317 } 318 319 /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t 320 /// type. makePtrdiffT(const ArgType & A)321 static ArgType makePtrdiffT(const ArgType &A) { 322 ArgType Res = A; 323 Res.TK = TypeKind::PtrdiffT; 324 return Res; 325 } 326 327 MatchKind matchesType(ASTContext &C, QualType argTy) const; 328 329 QualType getRepresentativeType(ASTContext &C) const; 330 331 ArgType makeVectorType(ASTContext &C, unsigned NumElts) const; 332 333 std::string getRepresentativeTypeName(ASTContext &C) const; 334 }; 335 336 class OptionalAmount { 337 public: 338 enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; 339 OptionalAmount(HowSpecified howSpecified,unsigned amount,const char * amountStart,unsigned amountLength,bool usesPositionalArg)340 OptionalAmount(HowSpecified howSpecified, 341 unsigned amount, 342 const char *amountStart, 343 unsigned amountLength, 344 bool usesPositionalArg) 345 : start(amountStart), length(amountLength), hs(howSpecified), amt(amount), 346 UsesPositionalArg(usesPositionalArg), UsesDotPrefix(false) {} 347 348 OptionalAmount(bool valid = true) start(nullptr)349 : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0), 350 UsesPositionalArg(false), UsesDotPrefix(false) {} 351 OptionalAmount(unsigned Amount)352 explicit OptionalAmount(unsigned Amount) 353 : start(nullptr), length(0), hs(Constant), amt(Amount), 354 UsesPositionalArg(false), UsesDotPrefix(false) {} 355 isInvalid()356 bool isInvalid() const { 357 return hs == Invalid; 358 } 359 getHowSpecified()360 HowSpecified getHowSpecified() const { return hs; } setHowSpecified(HowSpecified h)361 void setHowSpecified(HowSpecified h) { hs = h; } 362 hasDataArgument()363 bool hasDataArgument() const { return hs == Arg; } 364 getArgIndex()365 unsigned getArgIndex() const { 366 assert(hasDataArgument()); 367 return amt; 368 } 369 getConstantAmount()370 unsigned getConstantAmount() const { 371 assert(hs == Constant); 372 return amt; 373 } 374 getStart()375 const char *getStart() const { 376 // We include the . character if it is given. 377 return start - UsesDotPrefix; 378 } 379 getConstantLength()380 unsigned getConstantLength() const { 381 assert(hs == Constant); 382 return length + UsesDotPrefix; 383 } 384 385 ArgType getArgType(ASTContext &Ctx) const; 386 387 void toString(raw_ostream &os) const; 388 usesPositionalArg()389 bool usesPositionalArg() const { return (bool) UsesPositionalArg; } getPositionalArgIndex()390 unsigned getPositionalArgIndex() const { 391 assert(hasDataArgument()); 392 return amt + 1; 393 } 394 usesDotPrefix()395 bool usesDotPrefix() const { return UsesDotPrefix; } setUsesDotPrefix()396 void setUsesDotPrefix() { UsesDotPrefix = true; } 397 398 private: 399 const char *start; 400 unsigned length; 401 HowSpecified hs; 402 unsigned amt; 403 bool UsesPositionalArg : 1; 404 bool UsesDotPrefix; 405 }; 406 407 408 class FormatSpecifier { 409 protected: 410 LengthModifier LM; 411 OptionalAmount FieldWidth; 412 ConversionSpecifier CS; 413 OptionalAmount VectorNumElts; 414 415 /// Positional arguments, an IEEE extension: 416 /// IEEE Std 1003.1, 2004 Edition 417 /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html 418 bool UsesPositionalArg; 419 unsigned argIndex; 420 public: FormatSpecifier(bool isPrintf)421 FormatSpecifier(bool isPrintf) 422 : CS(isPrintf), VectorNumElts(false), 423 UsesPositionalArg(false), argIndex(0) {} 424 setLengthModifier(LengthModifier lm)425 void setLengthModifier(LengthModifier lm) { 426 LM = lm; 427 } 428 setUsesPositionalArg()429 void setUsesPositionalArg() { UsesPositionalArg = true; } 430 setArgIndex(unsigned i)431 void setArgIndex(unsigned i) { 432 argIndex = i; 433 } 434 getArgIndex()435 unsigned getArgIndex() const { 436 return argIndex; 437 } 438 getPositionalArgIndex()439 unsigned getPositionalArgIndex() const { 440 return argIndex + 1; 441 } 442 getLengthModifier()443 const LengthModifier &getLengthModifier() const { 444 return LM; 445 } 446 getFieldWidth()447 const OptionalAmount &getFieldWidth() const { 448 return FieldWidth; 449 } 450 setVectorNumElts(const OptionalAmount & Amt)451 void setVectorNumElts(const OptionalAmount &Amt) { 452 VectorNumElts = Amt; 453 } 454 getVectorNumElts()455 const OptionalAmount &getVectorNumElts() const { 456 return VectorNumElts; 457 } 458 setFieldWidth(const OptionalAmount & Amt)459 void setFieldWidth(const OptionalAmount &Amt) { 460 FieldWidth = Amt; 461 } 462 usesPositionalArg()463 bool usesPositionalArg() const { return UsesPositionalArg; } 464 465 bool hasValidLengthModifier(const TargetInfo &Target, 466 const LangOptions &LO) const; 467 468 bool hasStandardLengthModifier() const; 469 470 std::optional<LengthModifier> getCorrectedLengthModifier() const; 471 472 bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; 473 474 bool hasStandardLengthConversionCombination() const; 475 476 /// For a TypedefType QT, if it is a named integer type such as size_t, 477 /// assign the appropriate value to LM and return true. 478 static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM); 479 }; 480 481 } // end analyze_format_string namespace 482 483 //===----------------------------------------------------------------------===// 484 /// Pieces specific to fprintf format strings. 485 486 namespace analyze_printf { 487 488 class PrintfConversionSpecifier : 489 public analyze_format_string::ConversionSpecifier { 490 public: PrintfConversionSpecifier()491 PrintfConversionSpecifier() 492 : ConversionSpecifier(true, nullptr, InvalidSpecifier) {} 493 PrintfConversionSpecifier(const char * pos,Kind k)494 PrintfConversionSpecifier(const char *pos, Kind k) 495 : ConversionSpecifier(true, pos, k) {} 496 isObjCArg()497 bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } isDoubleArg()498 bool isDoubleArg() const { return kind >= DoubleArgBeg && 499 kind <= DoubleArgEnd; } 500 classof(const analyze_format_string::ConversionSpecifier * CS)501 static bool classof(const analyze_format_string::ConversionSpecifier *CS) { 502 return CS->isPrintfKind(); 503 } 504 }; 505 506 using analyze_format_string::ArgType; 507 using analyze_format_string::LengthModifier; 508 using analyze_format_string::OptionalAmount; 509 using analyze_format_string::OptionalFlag; 510 511 class PrintfSpecifier : public analyze_format_string::FormatSpecifier { 512 OptionalFlag HasThousandsGrouping; // ''', POSIX extension. 513 OptionalFlag IsLeftJustified; // '-' 514 OptionalFlag HasPlusPrefix; // '+' 515 OptionalFlag HasSpacePrefix; // ' ' 516 OptionalFlag HasAlternativeForm; // '#' 517 OptionalFlag HasLeadingZeroes; // '0' 518 OptionalFlag HasObjCTechnicalTerm; // '[tt]' 519 OptionalFlag IsPrivate; // '{private}' 520 OptionalFlag IsPublic; // '{public}' 521 OptionalFlag IsSensitive; // '{sensitive}' 522 OptionalAmount Precision; 523 StringRef MaskType; 524 525 ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const; 526 527 public: PrintfSpecifier()528 PrintfSpecifier() 529 : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"), 530 IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "), 531 HasAlternativeForm("#"), HasLeadingZeroes("0"), 532 HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"), 533 IsSensitive("sensitive") {} 534 535 static PrintfSpecifier Parse(const char *beg, const char *end); 536 537 // Methods for incrementally constructing the PrintfSpecifier. setConversionSpecifier(const PrintfConversionSpecifier & cs)538 void setConversionSpecifier(const PrintfConversionSpecifier &cs) { 539 CS = cs; 540 } setHasThousandsGrouping(const char * position)541 void setHasThousandsGrouping(const char *position) { 542 HasThousandsGrouping.setPosition(position); 543 } setIsLeftJustified(const char * position)544 void setIsLeftJustified(const char *position) { 545 IsLeftJustified.setPosition(position); 546 } setHasPlusPrefix(const char * position)547 void setHasPlusPrefix(const char *position) { 548 HasPlusPrefix.setPosition(position); 549 } setHasSpacePrefix(const char * position)550 void setHasSpacePrefix(const char *position) { 551 HasSpacePrefix.setPosition(position); 552 } setHasAlternativeForm(const char * position)553 void setHasAlternativeForm(const char *position) { 554 HasAlternativeForm.setPosition(position); 555 } setHasLeadingZeros(const char * position)556 void setHasLeadingZeros(const char *position) { 557 HasLeadingZeroes.setPosition(position); 558 } setHasObjCTechnicalTerm(const char * position)559 void setHasObjCTechnicalTerm(const char *position) { 560 HasObjCTechnicalTerm.setPosition(position); 561 } setIsPrivate(const char * position)562 void setIsPrivate(const char *position) { IsPrivate.setPosition(position); } setIsPublic(const char * position)563 void setIsPublic(const char *position) { IsPublic.setPosition(position); } setIsSensitive(const char * position)564 void setIsSensitive(const char *position) { 565 IsSensitive.setPosition(position); 566 } setUsesPositionalArg()567 void setUsesPositionalArg() { UsesPositionalArg = true; } 568 569 // Methods for querying the format specifier. 570 getConversionSpecifier()571 const PrintfConversionSpecifier &getConversionSpecifier() const { 572 return cast<PrintfConversionSpecifier>(CS); 573 } 574 setPrecision(const OptionalAmount & Amt)575 void setPrecision(const OptionalAmount &Amt) { 576 Precision = Amt; 577 Precision.setUsesDotPrefix(); 578 } 579 getPrecision()580 const OptionalAmount &getPrecision() const { 581 return Precision; 582 } 583 consumesDataArgument()584 bool consumesDataArgument() const { 585 return getConversionSpecifier().consumesDataArgument(); 586 } 587 588 /// Returns the builtin type that a data argument 589 /// paired with this format specifier should have. This method 590 /// will return null if the format specifier does not have 591 /// a matching data argument or the matching argument matches 592 /// more than one type. 593 ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; 594 hasThousandsGrouping()595 const OptionalFlag &hasThousandsGrouping() const { 596 return HasThousandsGrouping; 597 } isLeftJustified()598 const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } hasPlusPrefix()599 const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } hasAlternativeForm()600 const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } hasLeadingZeros()601 const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; } hasSpacePrefix()602 const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } hasObjCTechnicalTerm()603 const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; } isPrivate()604 const OptionalFlag &isPrivate() const { return IsPrivate; } isPublic()605 const OptionalFlag &isPublic() const { return IsPublic; } isSensitive()606 const OptionalFlag &isSensitive() const { return IsSensitive; } usesPositionalArg()607 bool usesPositionalArg() const { return UsesPositionalArg; } 608 getMaskType()609 StringRef getMaskType() const { return MaskType; } setMaskType(StringRef S)610 void setMaskType(StringRef S) { MaskType = S; } 611 612 /// Changes the specifier and length according to a QualType, retaining any 613 /// flags or options. Returns true on success, or false when a conversion 614 /// was not successful. 615 bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, 616 bool IsObjCLiteral); 617 618 void toString(raw_ostream &os) const; 619 620 // Validation methods - to check if any element results in undefined behavior 621 bool hasValidPlusPrefix() const; 622 bool hasValidAlternativeForm() const; 623 bool hasValidLeadingZeros() const; 624 bool hasValidSpacePrefix() const; 625 bool hasValidLeftJustified() const; 626 bool hasValidThousandsGroupingPrefix() const; 627 628 bool hasValidPrecision() const; 629 bool hasValidFieldWidth() const; 630 }; 631 } // end analyze_printf namespace 632 633 //===----------------------------------------------------------------------===// 634 /// Pieces specific to fscanf format strings. 635 636 namespace analyze_scanf { 637 638 class ScanfConversionSpecifier : 639 public analyze_format_string::ConversionSpecifier { 640 public: ScanfConversionSpecifier()641 ScanfConversionSpecifier() 642 : ConversionSpecifier(false, nullptr, InvalidSpecifier) {} 643 ScanfConversionSpecifier(const char * pos,Kind k)644 ScanfConversionSpecifier(const char *pos, Kind k) 645 : ConversionSpecifier(false, pos, k) {} 646 classof(const analyze_format_string::ConversionSpecifier * CS)647 static bool classof(const analyze_format_string::ConversionSpecifier *CS) { 648 return !CS->isPrintfKind(); 649 } 650 }; 651 652 using analyze_format_string::ArgType; 653 using analyze_format_string::LengthModifier; 654 using analyze_format_string::OptionalAmount; 655 using analyze_format_string::OptionalFlag; 656 657 class ScanfSpecifier : public analyze_format_string::FormatSpecifier { 658 OptionalFlag SuppressAssignment; // '*' 659 public: ScanfSpecifier()660 ScanfSpecifier() : 661 FormatSpecifier(/* isPrintf = */ false), 662 SuppressAssignment("*") {} 663 setSuppressAssignment(const char * position)664 void setSuppressAssignment(const char *position) { 665 SuppressAssignment.setPosition(position); 666 } 667 getSuppressAssignment()668 const OptionalFlag &getSuppressAssignment() const { 669 return SuppressAssignment; 670 } 671 setConversionSpecifier(const ScanfConversionSpecifier & cs)672 void setConversionSpecifier(const ScanfConversionSpecifier &cs) { 673 CS = cs; 674 } 675 getConversionSpecifier()676 const ScanfConversionSpecifier &getConversionSpecifier() const { 677 return cast<ScanfConversionSpecifier>(CS); 678 } 679 consumesDataArgument()680 bool consumesDataArgument() const { 681 return CS.consumesDataArgument() && !SuppressAssignment; 682 } 683 684 ArgType getArgType(ASTContext &Ctx) const; 685 686 bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt, 687 ASTContext &Ctx); 688 689 void toString(raw_ostream &os) const; 690 691 static ScanfSpecifier Parse(const char *beg, const char *end); 692 }; 693 694 } // end analyze_scanf namespace 695 696 //===----------------------------------------------------------------------===// 697 // Parsing and processing of format strings (both fprintf and fscanf). 698 699 namespace analyze_format_string { 700 701 enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; 702 703 class FormatStringHandler { 704 public: FormatStringHandler()705 FormatStringHandler() {} 706 virtual ~FormatStringHandler(); 707 HandleNullChar(const char * nullCharacter)708 virtual void HandleNullChar(const char *nullCharacter) {} 709 HandlePosition(const char * startPos,unsigned posLen)710 virtual void HandlePosition(const char *startPos, unsigned posLen) {} 711 HandleInvalidPosition(const char * startPos,unsigned posLen,PositionContext p)712 virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, 713 PositionContext p) {} 714 HandleZeroPosition(const char * startPos,unsigned posLen)715 virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {} 716 HandleIncompleteSpecifier(const char * startSpecifier,unsigned specifierLen)717 virtual void HandleIncompleteSpecifier(const char *startSpecifier, 718 unsigned specifierLen) {} 719 HandleEmptyObjCModifierFlag(const char * startFlags,unsigned flagsLen)720 virtual void HandleEmptyObjCModifierFlag(const char *startFlags, 721 unsigned flagsLen) {} 722 HandleInvalidObjCModifierFlag(const char * startFlag,unsigned flagLen)723 virtual void HandleInvalidObjCModifierFlag(const char *startFlag, 724 unsigned flagLen) {} 725 HandleObjCFlagsWithNonObjCConversion(const char * flagsStart,const char * flagsEnd,const char * conversionPosition)726 virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, 727 const char *flagsEnd, 728 const char *conversionPosition) {} 729 // Printf-specific handlers. 730 HandleInvalidPrintfConversionSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)731 virtual bool HandleInvalidPrintfConversionSpecifier( 732 const analyze_printf::PrintfSpecifier &FS, 733 const char *startSpecifier, 734 unsigned specifierLen) { 735 return true; 736 } 737 HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen,const TargetInfo & Target)738 virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, 739 const char *startSpecifier, 740 unsigned specifierLen, 741 const TargetInfo &Target) { 742 return true; 743 } 744 745 /// Handle mask types whose sizes are not between one and eight bytes. handleInvalidMaskType(StringRef MaskType)746 virtual void handleInvalidMaskType(StringRef MaskType) {} 747 748 // Scanf-specific handlers. 749 HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)750 virtual bool HandleInvalidScanfConversionSpecifier( 751 const analyze_scanf::ScanfSpecifier &FS, 752 const char *startSpecifier, 753 unsigned specifierLen) { 754 return true; 755 } 756 HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)757 virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, 758 const char *startSpecifier, 759 unsigned specifierLen) { 760 return true; 761 } 762 HandleIncompleteScanList(const char * start,const char * end)763 virtual void HandleIncompleteScanList(const char *start, const char *end) {} 764 }; 765 766 bool ParsePrintfString(FormatStringHandler &H, 767 const char *beg, const char *end, const LangOptions &LO, 768 const TargetInfo &Target, bool isFreeBSDKPrintf); 769 770 bool ParseFormatStringHasSArg(const char *beg, const char *end, 771 const LangOptions &LO, const TargetInfo &Target); 772 773 bool ParseScanfString(FormatStringHandler &H, 774 const char *beg, const char *end, const LangOptions &LO, 775 const TargetInfo &Target); 776 777 /// Return true if the given string has at least one formatting specifier. 778 bool parseFormatStringHasFormattingSpecifiers(const char *Begin, 779 const char *End, 780 const LangOptions &LO, 781 const TargetInfo &Target); 782 783 } // end analyze_format_string namespace 784 } // end clang namespace 785 #endif 786