Coverage Report

Created: 2020-09-19 12:23

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/AST/FormatString.h
Line
Count
Source (jump to first uncovered line)
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:
35
  OptionalFlag(const char *Representation)
36
485k
      : representation(Representation), flag(false) {}
37
44.9k
  bool isSet() const { return flag; }
38
0
  void set() { flag = true; }
39
0
  void clear() { flag = false; }
40
326
  void setPosition(const char *position) {
41
326
    assert(position);
42
326
    flag = true;
43
326
    this->position = position;
44
326
  }
45
93
  const char *getPosition() const {
46
93
    assert(position);
47
93
    return position;
48
93
  }
49
63
  const char *toString() const { return representation; }
50
51
  // Overloaded operators for bool like qualities
52
219k
  explicit operator bool() const { return flag; }
53
1.03k
  OptionalFlag& operator=(const bool &rhs) {
54
1.03k
    flag = rhs;
55
1.03k
    return *this;  // Return a reference to myself.
56
1.03k
  }
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
87
  LengthModifier()
88
49.1k
    : Position(nullptr), kind(None) {}
89
  LengthModifier(const char *pos, Kind k)
90
6.32k
    : Position(pos), kind(k) {}
91
92
471
  const char *getStart() const {
93
471
    return Position;
94
471
  }
95
96
203
  unsigned getLength() const {
97
203
    switch (kind) {
98
183
      default:
99
183
        return 1;
100
14
      case AsLongLong:
101
14
      case AsChar:
102
14
        return 2;
103
6
      case AsInt32:
104
6
      case AsInt64:
105
6
        return 3;
106
0
      case None:
107
0
        return 0;
108
203
    }
109
203
  }
110
111
104k
  Kind getKind() const { return kind; }
112
1.05k
  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)
193
    : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),
194
49.1k
      kind(InvalidSpecifier) {}
195
196
  ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
197
31.4k
    : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}
198
199
525
  const char *getStart() const {
200
525
    return Position;
201
525
  }
202
203
0
  StringRef getCharacters() const {
204
0
    return StringRef(getStart(), getLength());
205
0
  }
206
207
113k
  bool consumesDataArgument() const {
208
113k
    switch (kind) {
209
33
      case PrintErrno:
210
33
        assert(IsPrintf);
211
33
        return false;
212
166
      case PercentArg:
213
166
        return false;
214
99
      case InvalidSpecifier:
215
99
        return false;
216
113k
      default:
217
113k
        return true;
218
113k
    }
219
113k
  }
220
221
219k
  Kind getKind() const { return kind; }
222
762
  void setKind(Kind k) { kind = k; }
223
151
  unsigned getLength() const {
224
139
    return EndScanList ? 
EndScanList - Position12
: 1;
225
151
  }
226
36
  void setEndScanList(const char *pos) { EndScanList = pos; }
227
228
24.5k
  bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
229
14.4k
    kind == FreeBSDrArg || 
kind == FreeBSDyArg14.4k
; }
230
14.4k
  bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
231
203
  bool isAnyIntArg() const { return kind >= IntArgBeg && 
kind <= UIntArgEnd188
; }
232
13.9k
  bool isDoubleArg() const {
233
13.9k
    return kind >= DoubleArgBeg && 
kind <= DoubleArgEnd11.9k
;
234
13.9k
  }
235
236
  const char *toString() const;
237
238
115k
  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:
282
9.64k
  ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}
283
809
  ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}
284
16.4k
  ArgType(CanQualType T) : K(SpecificTy), T(T) {}
285
286
36
  static ArgType Invalid() { return ArgType(InvalidTy); }
287
52.5k
  bool isValid() const { return K != InvalidTy; }
288
289
134
  bool isSizeT() const { return TK == TypeKind::SizeT; }
290
291
114
  bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }
292
293
  /// Create an ArgType which corresponds to the type pointer to A.
294
693
  static ArgType PtrTo(const ArgType& A) {
295
693
    assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
296
693
    ArgType Res = A;
297
693
    Res.Ptr = true;
298
693
    return Res;
299
693
  }
300
301
  /// Create an ArgType which corresponds to the size_t/ssize_t type.
302
203
  static ArgType makeSizeT(const ArgType &A) {
303
203
    ArgType Res = A;
304
203
    Res.TK = TypeKind::SizeT;
305
203
    return Res;
306
203
  }
307
308
  /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t
309
  /// type.
310
29
  static ArgType makePtrdiffT(const ArgType &A) {
311
29
    ArgType Res = A;
312
29
    Res.TK = TypeKind::PtrdiffT;
313
29
    return Res;
314
29
  }
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
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
934
  UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}
336
337
  OptionalAmount(bool valid = true)
338
  : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),
339
209k
  UsesPositionalArg(0), UsesDotPrefix(0) {}
340
341
  explicit OptionalAmount(unsigned Amount)
342
    : start(nullptr), length(0), hs(Constant), amt(Amount),
343
85
    UsesPositionalArg(false), UsesDotPrefix(false) {}
344
345
28.7k
  bool isInvalid() const {
346
28.7k
    return hs == Invalid;
347
28.7k
  }
348
349
85.2k
  HowSpecified getHowSpecified() const { return hs; }
350
84
  void setHowSpecified(HowSpecified h) { hs = h; }
351
352
56.4k
  bool hasDataArgument() const { return hs == Arg; }
353
354
90
  unsigned getArgIndex() const {
355
90
    assert(hasDataArgument());
356
90
    return amt;
357
90
  }
358
359
549
  unsigned getConstantAmount() const {
360
549
    assert(hs == Constant);
361
549
    return amt;
362
549
  }
363
364
78
  const char *getStart() const {
365
      // We include the . character if it is given.
366
78
    return start - UsesDotPrefix;
367
78
  }
368
369
25
  unsigned getConstantLength() const {
370
25
    assert(hs == Constant);
371
25
    return length + UsesDotPrefix;
372
25
  }
373
374
  ArgType getArgType(ASTContext &Ctx) const;
375
376
  void toString(raw_ostream &os) const;
377
378
4
  bool usesPositionalArg() const { return (bool) UsesPositionalArg; }
379
2
  unsigned getPositionalArgIndex() const {
380
2
    assert(hasDataArgument());
381
2
    return amt + 1;
382
2
  }
383
384
0
  bool usesDotPrefix() const { return UsesDotPrefix; }
385
217
  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:
410
  FormatSpecifier(bool isPrintf)
411
    : CS(isPrintf), VectorNumElts(false),
412
49.1k
      UsesPositionalArg(false), argIndex(0) {}
413
414
6.32k
  void setLengthModifier(LengthModifier lm) {
415
6.32k
    LM = lm;
416
6.32k
  }
417
418
63
  void setUsesPositionalArg() { UsesPositionalArg = true; }
419
420
31.2k
  void setArgIndex(unsigned i) {
421
31.2k
    argIndex = i;
422
31.2k
  }
423
424
36.3k
  unsigned getArgIndex() const {
425
36.3k
    return argIndex;
426
36.3k
  }
427
428
7
  unsigned getPositionalArgIndex() const {
429
7
    return argIndex + 1;
430
7
  }
431
432
203
  const LengthModifier &getLengthModifier() const {
433
203
    return LM;
434
203
  }
435
436
29.4k
  const OptionalAmount &getFieldWidth() const {
437
29.4k
    return FieldWidth;
438
29.4k
  }
439
440
156
  void setVectorNumElts(const OptionalAmount &Amt) {
441
156
    VectorNumElts = Amt;
442
156
  }
443
444
0
  const OptionalAmount &getVectorNumElts() const {
445
0
    return VectorNumElts;
446
0
  }
447
448
30.9k
  void setFieldWidth(const OptionalAmount &Amt) {
449
30.9k
    FieldWidth = Amt;
450
30.9k
  }
451
452
1.30k
  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:
480
  PrintfConversionSpecifier()
481
0
    : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}
482
483
  PrintfConversionSpecifier(const char *pos, Kind k)
484
30.8k
    : ConversionSpecifier(true, pos, k) {}
485
486
20.5k
  bool isObjCArg() const { return kind >= ObjCBeg && 
kind <= ObjCEnd41
; }
487
0
  bool isDoubleArg() const { return kind >= DoubleArgBeg &&
488
0
                                    kind <= DoubleArgEnd; }
489
490
114k
  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
491
114k
    return CS->isPrintfKind();
492
114k
  }
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:
517
  PrintfSpecifier()
518
      : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),
519
        IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),
520
        HasAlternativeForm("#"), HasLeadingZeroes("0"),
521
        HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public"),
522
48.4k
        IsSensitive("sensitive") {}
523
524
  static PrintfSpecifier Parse(const char *beg, const char *end);
525
526
    // Methods for incrementally constructing the PrintfSpecifier.
527
30.8k
  void setConversionSpecifier(const PrintfConversionSpecifier &cs) {
528
30.8k
    CS = cs;
529
30.8k
  }
530
14
  void setHasThousandsGrouping(const char *position) {
531
14
    HasThousandsGrouping.setPosition(position);
532
14
  }
533
20
  void setIsLeftJustified(const char *position) {
534
20
    IsLeftJustified.setPosition(position);
535
20
  }
536
83
  void setHasPlusPrefix(const char *position) {
537
83
    HasPlusPrefix.setPosition(position);
538
83
  }
539
43
  void setHasSpacePrefix(const char *position) {
540
43
    HasSpacePrefix.setPosition(position);
541
43
  }
542
51
  void setHasAlternativeForm(const char *position) {
543
51
    HasAlternativeForm.setPosition(position);
544
51
  }
545
43
  void setHasLeadingZeros(const char *position) {
546
43
    HasLeadingZeroes.setPosition(position);
547
43
  }
548
13
  void setHasObjCTechnicalTerm(const char *position) {
549
13
    HasObjCTechnicalTerm.setPosition(position);
550
13
  }
551
25
  void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }
552
20
  void setIsPublic(const char *position) { IsPublic.setPosition(position); }
553
8
  void setIsSensitive(const char *position) {
554
8
    IsSensitive.setPosition(position);
555
8
  }
556
0
  void setUsesPositionalArg() { UsesPositionalArg = true; }
557
558
    // Methods for querying the format specifier.
559
560
114k
  const PrintfConversionSpecifier &getConversionSpecifier() const {
561
114k
    return cast<PrintfConversionSpecifier>(CS);
562
114k
  }
563
564
217
  void setPrecision(const OptionalAmount &Amt) {
565
217
    Precision = Amt;
566
217
    Precision.setUsesDotPrefix();
567
217
  }
568
569
28.8k
  const OptionalAmount &getPrecision() const {
570
28.8k
    return Precision;
571
28.8k
  }
572
573
28.6k
  bool consumesDataArgument() const {
574
28.6k
    return getConversionSpecifier().consumesDataArgument();
575
28.6k
  }
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
584
2
  const OptionalFlag &hasThousandsGrouping() const {
585
2
      return HasThousandsGrouping;
586
2
  }
587
55
  const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
588
327
  const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
589
295
  const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
590
25.4k
  const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }
591
25.7k
  const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }
592
0
  const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }
593
25.4k
  const OptionalFlag &isPrivate() const { return IsPrivate; }
594
25.4k
  const OptionalFlag &isPublic() const { return IsPublic; }
595
3.00k
  const OptionalFlag &isSensitive() const { return IsSensitive; }
596
88.2k
  bool usesPositionalArg() const { return UsesPositionalArg; }
597
598
3.00k
  StringRef getMaskType() const { return MaskType; }
599
17
  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:
630
  ScanfConversionSpecifier()
631
0
    : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}
632
633
  ScanfConversionSpecifier(const char *pos, Kind k)
634
605
    : ConversionSpecifier(false, pos, k) {}
635
636
1.22k
  static bool classof(const analyze_format_string::ConversionSpecifier *CS) {
637
1.22k
    return !CS->isPrintfKind();
638
1.22k
  }
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:
649
  ScanfSpecifier() :
650
    FormatSpecifier(/* isPrintf = */ false),
651
672
    SuppressAssignment("*") {}
652
653
6
  void setSuppressAssignment(const char *position) {
654
6
    SuppressAssignment.setPosition(position);
655
6
  }
656
657
575
  const OptionalFlag &getSuppressAssignment() const {
658
575
    return SuppressAssignment;
659
575
  }
660
661
597
  void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
662
597
    CS = cs;
663
597
  }
664
665
1.22k
  const ScanfConversionSpecifier &getConversionSpecifier() const {
666
1.22k
    return cast<ScanfConversionSpecifier>(CS);
667
1.22k
  }
668
669
1.16k
  bool consumesDataArgument() const {
670
1.16k
    return CS.consumesDataArgument() && 
!SuppressAssignment1.15k
;
671
1.16k
  }
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:
694
22.0k
  FormatStringHandler() {}
695
  virtual ~FormatStringHandler();
696
697
0
  virtual void HandleNullChar(const char *nullCharacter) {}
698
699
4
  virtual void HandlePosition(const char *startPos, unsigned posLen) {}
700
701
  virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,
702
0
                                     PositionContext p) {}
703
704
0
  virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}
705
706
  virtual void HandleIncompleteSpecifier(const char *startSpecifier,
707
8
                                         unsigned specifierLen) {}
708
709
  virtual void HandleEmptyObjCModifierFlag(const char *startFlags,
710
0
                                           unsigned flagsLen) {}
711
712
  virtual void HandleInvalidObjCModifierFlag(const char *startFlag,
713
0
                                             unsigned flagLen) {}
714
715
  virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
716
                                            const char *flagsEnd,
717
1
                                            const char *conversionPosition) {}
718
  // Printf-specific handlers.
719
720
  virtual bool HandleInvalidPrintfConversionSpecifier(
721
                                      const analyze_printf::PrintfSpecifier &FS,
722
                                      const char *startSpecifier,
723
13
                                      unsigned specifierLen) {
724
13
    return true;
725
13
  }
726
727
  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
728
                                     const char *startSpecifier,
729
0
                                     unsigned specifierLen) {
730
0
    return true;
731
0
  }
732
733
  /// Handle mask types whose sizes are not between one and eight bytes.
734
0
  virtual void handleInvalidMaskType(StringRef MaskType) {}
735
736
    // Scanf-specific handlers.
737
738
  virtual bool HandleInvalidScanfConversionSpecifier(
739
                                        const analyze_scanf::ScanfSpecifier &FS,
740
                                        const char *startSpecifier,
741
0
                                        unsigned specifierLen) {
742
0
    return true;
743
0
  }
744
745
  virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
746
                                    const char *startSpecifier,
747
0
                                    unsigned specifierLen) {
748
0
    return true;
749
0
  }
750
751
0
  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