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