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