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 /// How well a given conversion specifier matches its argument. 255 enum MatchKind { 256 /// The conversion specifier and the argument types are incompatible. For 257 /// instance, "%d" and float. 258 NoMatch = 0, 259 /// The conversion specifier and the argument type are compatible. For 260 /// instance, "%d" and _Bool. 261 Match = 1, 262 /// The conversion specifier and the argument type are disallowed by the C 263 /// standard, but are in practice harmless. For instance, "%p" and int*. 264 NoMatchPedantic, 265 /// The conversion specifier and the argument type are compatible, but still 266 /// seems likely to be an error. For instance, "%hd" and _Bool. 267 NoMatchTypeConfusion, 268 }; 269 270 private: 271 const Kind K; 272 QualType T; 273 const char *Name = nullptr; 274 bool Ptr = false; 275 276 /// The TypeKind identifies certain well-known types like size_t and 277 /// ptrdiff_t. 278 enum class TypeKind { DontCare, SizeT, PtrdiffT }; 279 TypeKind TK = TypeKind::DontCare; 280 281 public: K(K)282 ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {} K(SpecificTy)283 ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {} ArgType(CanQualType T)284 ArgType(CanQualType T) : K(SpecificTy), T(T) {} 285 Invalid()286 static ArgType Invalid() { return ArgType(InvalidTy); } isValid()287 bool isValid() const { return K != InvalidTy; } 288 isSizeT()289 bool isSizeT() const { return TK == TypeKind::SizeT; } 290 isPtrdiffT()291 bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; } 292 293 /// Create an ArgType which corresponds to the type pointer to A. PtrTo(const ArgType & A)294 static ArgType PtrTo(const ArgType& A) { 295 assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); 296 ArgType Res = A; 297 Res.Ptr = true; 298 return Res; 299 } 300 301 /// Create an ArgType which corresponds to the size_t/ssize_t type. makeSizeT(const ArgType & A)302 static ArgType makeSizeT(const ArgType &A) { 303 ArgType Res = A; 304 Res.TK = TypeKind::SizeT; 305 return Res; 306 } 307 308 /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t 309 /// type. makePtrdiffT(const ArgType & A)310 static ArgType makePtrdiffT(const ArgType &A) { 311 ArgType Res = A; 312 Res.TK = TypeKind::PtrdiffT; 313 return Res; 314 } 315 316 MatchKind matchesType(ASTContext &C, QualType argTy) const; 317 318 QualType getRepresentativeType(ASTContext &C) const; 319 320 ArgType makeVectorType(ASTContext &C, unsigned NumElts) const; 321 322 std::string getRepresentativeTypeName(ASTContext &C) const; 323 }; 324 325 class OptionalAmount { 326 public: 327 enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; 328 OptionalAmount(HowSpecified howSpecified,unsigned amount,const char * amountStart,unsigned amountLength,bool usesPositionalArg)329 OptionalAmount(HowSpecified howSpecified, 330 unsigned amount, 331 const char *amountStart, 332 unsigned amountLength, 333 bool usesPositionalArg) 334 : start(amountStart), length(amountLength), hs(howSpecified), amt(amount), 335 UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {} 336 337 OptionalAmount(bool valid = true) start(nullptr)338 : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0), 339 UsesPositionalArg(0), UsesDotPrefix(0) {} 340 OptionalAmount(unsigned Amount)341 explicit OptionalAmount(unsigned Amount) 342 : start(nullptr), length(0), hs(Constant), amt(Amount), 343 UsesPositionalArg(false), UsesDotPrefix(false) {} 344 isInvalid()345 bool isInvalid() const { 346 return hs == Invalid; 347 } 348 getHowSpecified()349 HowSpecified getHowSpecified() const { return hs; } setHowSpecified(HowSpecified h)350 void setHowSpecified(HowSpecified h) { hs = h; } 351 hasDataArgument()352 bool hasDataArgument() const { return hs == Arg; } 353 getArgIndex()354 unsigned getArgIndex() const { 355 assert(hasDataArgument()); 356 return amt; 357 } 358 getConstantAmount()359 unsigned getConstantAmount() const { 360 assert(hs == Constant); 361 return amt; 362 } 363 getStart()364 const char *getStart() const { 365 // We include the . character if it is given. 366 return start - UsesDotPrefix; 367 } 368 getConstantLength()369 unsigned getConstantLength() const { 370 assert(hs == Constant); 371 return length + UsesDotPrefix; 372 } 373 374 ArgType getArgType(ASTContext &Ctx) const; 375 376 void toString(raw_ostream &os) const; 377 usesPositionalArg()378 bool usesPositionalArg() const { return (bool) UsesPositionalArg; } getPositionalArgIndex()379 unsigned getPositionalArgIndex() const { 380 assert(hasDataArgument()); 381 return amt + 1; 382 } 383 usesDotPrefix()384 bool usesDotPrefix() const { return UsesDotPrefix; } setUsesDotPrefix()385 void setUsesDotPrefix() { UsesDotPrefix = true; } 386 387 private: 388 const char *start; 389 unsigned length; 390 HowSpecified hs; 391 unsigned amt; 392 bool UsesPositionalArg : 1; 393 bool UsesDotPrefix; 394 }; 395 396 397 class FormatSpecifier { 398 protected: 399 LengthModifier LM; 400 OptionalAmount FieldWidth; 401 ConversionSpecifier CS; 402 OptionalAmount VectorNumElts; 403 404 /// Positional arguments, an IEEE extension: 405 /// IEEE Std 1003.1, 2004 Edition 406 /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html 407 bool UsesPositionalArg; 408 unsigned argIndex; 409 public: FormatSpecifier(bool isPrintf)410 FormatSpecifier(bool isPrintf) 411 : CS(isPrintf), VectorNumElts(false), 412 UsesPositionalArg(false), argIndex(0) {} 413 setLengthModifier(LengthModifier lm)414 void setLengthModifier(LengthModifier lm) { 415 LM = lm; 416 } 417 setUsesPositionalArg()418 void setUsesPositionalArg() { UsesPositionalArg = true; } 419 setArgIndex(unsigned i)420 void setArgIndex(unsigned i) { 421 argIndex = i; 422 } 423 getArgIndex()424 unsigned getArgIndex() const { 425 return argIndex; 426 } 427 getPositionalArgIndex()428 unsigned getPositionalArgIndex() const { 429 return argIndex + 1; 430 } 431 getLengthModifier()432 const LengthModifier &getLengthModifier() const { 433 return LM; 434 } 435 getFieldWidth()436 const OptionalAmount &getFieldWidth() const { 437 return FieldWidth; 438 } 439 setVectorNumElts(const OptionalAmount & Amt)440 void setVectorNumElts(const OptionalAmount &Amt) { 441 VectorNumElts = Amt; 442 } 443 getVectorNumElts()444 const OptionalAmount &getVectorNumElts() const { 445 return VectorNumElts; 446 } 447 setFieldWidth(const OptionalAmount & Amt)448 void setFieldWidth(const OptionalAmount &Amt) { 449 FieldWidth = Amt; 450 } 451 usesPositionalArg()452 bool usesPositionalArg() const { return UsesPositionalArg; } 453 454 bool hasValidLengthModifier(const TargetInfo &Target, 455 const LangOptions &LO) const; 456 457 bool hasStandardLengthModifier() const; 458 459 Optional<LengthModifier> getCorrectedLengthModifier() const; 460 461 bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; 462 463 bool hasStandardLengthConversionCombination() const; 464 465 /// For a TypedefType QT, if it is a named integer type such as size_t, 466 /// assign the appropriate value to LM and return true. 467 static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM); 468 }; 469 470 } // end analyze_format_string namespace 471 472 //===----------------------------------------------------------------------===// 473 /// Pieces specific to fprintf format strings. 474 475 namespace analyze_printf { 476 477 class PrintfConversionSpecifier : 478 public analyze_format_string::ConversionSpecifier { 479 public: PrintfConversionSpecifier()480 PrintfConversionSpecifier() 481 : ConversionSpecifier(true, nullptr, InvalidSpecifier) {} 482 PrintfConversionSpecifier(const char * pos,Kind k)483 PrintfConversionSpecifier(const char *pos, Kind k) 484 : ConversionSpecifier(true, pos, k) {} 485 isObjCArg()486 bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } isDoubleArg()487 bool isDoubleArg() const { return kind >= DoubleArgBeg && 488 kind <= DoubleArgEnd; } 489 classof(const analyze_format_string::ConversionSpecifier * CS)490 static bool classof(const analyze_format_string::ConversionSpecifier *CS) { 491 return CS->isPrintfKind(); 492 } 493 }; 494 495 using analyze_format_string::ArgType; 496 using analyze_format_string::LengthModifier; 497 using analyze_format_string::OptionalAmount; 498 using analyze_format_string::OptionalFlag; 499 500 class PrintfSpecifier : public analyze_format_string::FormatSpecifier { 501 OptionalFlag HasThousandsGrouping; // ''', POSIX extension. 502 OptionalFlag IsLeftJustified; // '-' 503 OptionalFlag HasPlusPrefix; // '+' 504 OptionalFlag HasSpacePrefix; // ' ' 505 OptionalFlag HasAlternativeForm; // '#' 506 OptionalFlag HasLeadingZeroes; // '0' 507 OptionalFlag HasObjCTechnicalTerm; // '[tt]' 508 OptionalFlag IsPrivate; // '{private}' 509 OptionalFlag IsPublic; // '{public}' 510 OptionalFlag IsSensitive; // '{sensitive}' 511 OptionalAmount Precision; 512 StringRef MaskType; 513 514 ArgType getScalarArgType(ASTContext &Ctx, bool IsObjCLiteral) const; 515 516 public: PrintfSpecifier()517 PrintfSpecifier() 518 : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"), 519 IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "), 520 HasAlternativeForm("#"), HasLeadingZeroes("0"), 521 HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"), 522 IsSensitive("sensitive") {} 523 524 static PrintfSpecifier Parse(const char *beg, const char *end); 525 526 // Methods for incrementally constructing the PrintfSpecifier. setConversionSpecifier(const PrintfConversionSpecifier & cs)527 void setConversionSpecifier(const PrintfConversionSpecifier &cs) { 528 CS = cs; 529 } setHasThousandsGrouping(const char * position)530 void setHasThousandsGrouping(const char *position) { 531 HasThousandsGrouping.setPosition(position); 532 } setIsLeftJustified(const char * position)533 void setIsLeftJustified(const char *position) { 534 IsLeftJustified.setPosition(position); 535 } setHasPlusPrefix(const char * position)536 void setHasPlusPrefix(const char *position) { 537 HasPlusPrefix.setPosition(position); 538 } setHasSpacePrefix(const char * position)539 void setHasSpacePrefix(const char *position) { 540 HasSpacePrefix.setPosition(position); 541 } setHasAlternativeForm(const char * position)542 void setHasAlternativeForm(const char *position) { 543 HasAlternativeForm.setPosition(position); 544 } setHasLeadingZeros(const char * position)545 void setHasLeadingZeros(const char *position) { 546 HasLeadingZeroes.setPosition(position); 547 } setHasObjCTechnicalTerm(const char * position)548 void setHasObjCTechnicalTerm(const char *position) { 549 HasObjCTechnicalTerm.setPosition(position); 550 } setIsPrivate(const char * position)551 void setIsPrivate(const char *position) { IsPrivate.setPosition(position); } setIsPublic(const char * position)552 void setIsPublic(const char *position) { IsPublic.setPosition(position); } setIsSensitive(const char * position)553 void setIsSensitive(const char *position) { 554 IsSensitive.setPosition(position); 555 } setUsesPositionalArg()556 void setUsesPositionalArg() { UsesPositionalArg = true; } 557 558 // Methods for querying the format specifier. 559 getConversionSpecifier()560 const PrintfConversionSpecifier &getConversionSpecifier() const { 561 return cast<PrintfConversionSpecifier>(CS); 562 } 563 setPrecision(const OptionalAmount & Amt)564 void setPrecision(const OptionalAmount &Amt) { 565 Precision = Amt; 566 Precision.setUsesDotPrefix(); 567 } 568 getPrecision()569 const OptionalAmount &getPrecision() const { 570 return Precision; 571 } 572 consumesDataArgument()573 bool consumesDataArgument() const { 574 return getConversionSpecifier().consumesDataArgument(); 575 } 576 577 /// Returns the builtin type that a data argument 578 /// paired with this format specifier should have. This method 579 /// will return null if the format specifier does not have 580 /// a matching data argument or the matching argument matches 581 /// more than one type. 582 ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; 583 hasThousandsGrouping()584 const OptionalFlag &hasThousandsGrouping() const { 585 return HasThousandsGrouping; 586 } isLeftJustified()587 const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } hasPlusPrefix()588 const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } hasAlternativeForm()589 const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } hasLeadingZeros()590 const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; } hasSpacePrefix()591 const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } hasObjCTechnicalTerm()592 const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; } isPrivate()593 const OptionalFlag &isPrivate() const { return IsPrivate; } isPublic()594 const OptionalFlag &isPublic() const { return IsPublic; } isSensitive()595 const OptionalFlag &isSensitive() const { return IsSensitive; } usesPositionalArg()596 bool usesPositionalArg() const { return UsesPositionalArg; } 597 getMaskType()598 StringRef getMaskType() const { return MaskType; } setMaskType(StringRef S)599 void setMaskType(StringRef S) { MaskType = S; } 600 601 /// Changes the specifier and length according to a QualType, retaining any 602 /// flags or options. Returns true on success, or false when a conversion 603 /// was not successful. 604 bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, 605 bool IsObjCLiteral); 606 607 void toString(raw_ostream &os) const; 608 609 // Validation methods - to check if any element results in undefined behavior 610 bool hasValidPlusPrefix() const; 611 bool hasValidAlternativeForm() const; 612 bool hasValidLeadingZeros() const; 613 bool hasValidSpacePrefix() const; 614 bool hasValidLeftJustified() const; 615 bool hasValidThousandsGroupingPrefix() const; 616 617 bool hasValidPrecision() const; 618 bool hasValidFieldWidth() const; 619 }; 620 } // end analyze_printf namespace 621 622 //===----------------------------------------------------------------------===// 623 /// Pieces specific to fscanf format strings. 624 625 namespace analyze_scanf { 626 627 class ScanfConversionSpecifier : 628 public analyze_format_string::ConversionSpecifier { 629 public: ScanfConversionSpecifier()630 ScanfConversionSpecifier() 631 : ConversionSpecifier(false, nullptr, InvalidSpecifier) {} 632 ScanfConversionSpecifier(const char * pos,Kind k)633 ScanfConversionSpecifier(const char *pos, Kind k) 634 : ConversionSpecifier(false, pos, k) {} 635 classof(const analyze_format_string::ConversionSpecifier * CS)636 static bool classof(const analyze_format_string::ConversionSpecifier *CS) { 637 return !CS->isPrintfKind(); 638 } 639 }; 640 641 using analyze_format_string::ArgType; 642 using analyze_format_string::LengthModifier; 643 using analyze_format_string::OptionalAmount; 644 using analyze_format_string::OptionalFlag; 645 646 class ScanfSpecifier : public analyze_format_string::FormatSpecifier { 647 OptionalFlag SuppressAssignment; // '*' 648 public: ScanfSpecifier()649 ScanfSpecifier() : 650 FormatSpecifier(/* isPrintf = */ false), 651 SuppressAssignment("*") {} 652 setSuppressAssignment(const char * position)653 void setSuppressAssignment(const char *position) { 654 SuppressAssignment.setPosition(position); 655 } 656 getSuppressAssignment()657 const OptionalFlag &getSuppressAssignment() const { 658 return SuppressAssignment; 659 } 660 setConversionSpecifier(const ScanfConversionSpecifier & cs)661 void setConversionSpecifier(const ScanfConversionSpecifier &cs) { 662 CS = cs; 663 } 664 getConversionSpecifier()665 const ScanfConversionSpecifier &getConversionSpecifier() const { 666 return cast<ScanfConversionSpecifier>(CS); 667 } 668 consumesDataArgument()669 bool consumesDataArgument() const { 670 return CS.consumesDataArgument() && !SuppressAssignment; 671 } 672 673 ArgType getArgType(ASTContext &Ctx) const; 674 675 bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt, 676 ASTContext &Ctx); 677 678 void toString(raw_ostream &os) const; 679 680 static ScanfSpecifier Parse(const char *beg, const char *end); 681 }; 682 683 } // end analyze_scanf namespace 684 685 //===----------------------------------------------------------------------===// 686 // Parsing and processing of format strings (both fprintf and fscanf). 687 688 namespace analyze_format_string { 689 690 enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; 691 692 class FormatStringHandler { 693 public: FormatStringHandler()694 FormatStringHandler() {} 695 virtual ~FormatStringHandler(); 696 HandleNullChar(const char * nullCharacter)697 virtual void HandleNullChar(const char *nullCharacter) {} 698 HandlePosition(const char * startPos,unsigned posLen)699 virtual void HandlePosition(const char *startPos, unsigned posLen) {} 700 HandleInvalidPosition(const char * startPos,unsigned posLen,PositionContext p)701 virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, 702 PositionContext p) {} 703 HandleZeroPosition(const char * startPos,unsigned posLen)704 virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {} 705 HandleIncompleteSpecifier(const char * startSpecifier,unsigned specifierLen)706 virtual void HandleIncompleteSpecifier(const char *startSpecifier, 707 unsigned specifierLen) {} 708 HandleEmptyObjCModifierFlag(const char * startFlags,unsigned flagsLen)709 virtual void HandleEmptyObjCModifierFlag(const char *startFlags, 710 unsigned flagsLen) {} 711 HandleInvalidObjCModifierFlag(const char * startFlag,unsigned flagLen)712 virtual void HandleInvalidObjCModifierFlag(const char *startFlag, 713 unsigned flagLen) {} 714 HandleObjCFlagsWithNonObjCConversion(const char * flagsStart,const char * flagsEnd,const char * conversionPosition)715 virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, 716 const char *flagsEnd, 717 const char *conversionPosition) {} 718 // Printf-specific handlers. 719 HandleInvalidPrintfConversionSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)720 virtual bool HandleInvalidPrintfConversionSpecifier( 721 const analyze_printf::PrintfSpecifier &FS, 722 const char *startSpecifier, 723 unsigned specifierLen) { 724 return true; 725 } 726 HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)727 virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, 728 const char *startSpecifier, 729 unsigned specifierLen) { 730 return true; 731 } 732 733 /// Handle mask types whose sizes are not between one and eight bytes. handleInvalidMaskType(StringRef MaskType)734 virtual void handleInvalidMaskType(StringRef MaskType) {} 735 736 // Scanf-specific handlers. 737 HandleInvalidScanfConversionSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)738 virtual bool HandleInvalidScanfConversionSpecifier( 739 const analyze_scanf::ScanfSpecifier &FS, 740 const char *startSpecifier, 741 unsigned specifierLen) { 742 return true; 743 } 744 HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier & FS,const char * startSpecifier,unsigned specifierLen)745 virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, 746 const char *startSpecifier, 747 unsigned specifierLen) { 748 return true; 749 } 750 HandleIncompleteScanList(const char * start,const char * end)751 virtual void HandleIncompleteScanList(const char *start, const char *end) {} 752 }; 753 754 bool ParsePrintfString(FormatStringHandler &H, 755 const char *beg, const char *end, const LangOptions &LO, 756 const TargetInfo &Target, bool isFreeBSDKPrintf); 757 758 bool ParseFormatStringHasSArg(const char *beg, const char *end, 759 const LangOptions &LO, const TargetInfo &Target); 760 761 bool ParseScanfString(FormatStringHandler &H, 762 const char *beg, const char *end, const LangOptions &LO, 763 const TargetInfo &Target); 764 765 /// Return true if the given string has at least one formatting specifier. 766 bool parseFormatStringHasFormattingSpecifiers(const char *Begin, 767 const char *End, 768 const LangOptions &LO, 769 const TargetInfo &Target); 770 771 } // end analyze_format_string namespace 772 } // end clang namespace 773 #endif 774