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