Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- 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 checker improves modeling of a few simple library functions.
10
// It does not generate warnings.
11
//
12
// This checker provides a specification format - `FunctionSummaryTy' - and
13
// contains descriptions of some library functions in this format. Each
14
// specification contains a list of branches for splitting the program state
15
// upon call, and range constraints on argument and return-value symbols that
16
// are satisfied on each branch. This spec can be expanded to include more
17
// items, like external effects of the function.
18
//
19
// The main difference between this approach and the body farms technique is
20
// in more explicit control over how many branches are produced. For example,
21
// consider standard C function `ispunct(int x)', which returns a non-zero value
22
// iff `x' is a punctuation character, that is, when `x' is in range
23
//   ['!', '/']   [':', '@']  U  ['[', '\`']  U  ['{', '~'].
24
// `FunctionSummaryTy' provides only two branches for this function. However,
25
// any attempt to describe this range with if-statements in the body farm
26
// would result in many more branches. Because each branch needs to be analyzed
27
// independently, this significantly reduces performance. Additionally,
28
// once we consider a branch on which `x' is in range, say, ['!', '/'],
29
// we assume that such branch is an important separate path through the program,
30
// which may lead to false positives because considering this particular path
31
// was not consciously intended, and therefore it might have been unreachable.
32
//
33
// This checker uses eval::Call for modeling "pure" functions, for which
34
// their `FunctionSummaryTy' is a precise model. This avoids unnecessary
35
// invalidation passes. Conflicts with other checkers are unlikely because
36
// if the function has no other effects, other checkers would probably never
37
// want to improve upon the modeling done by this checker.
38
//
39
// Non-"pure" functions, for which only partial improvement over the default
40
// behavior is expected, are modeled via check::PostCall, non-intrusively.
41
//
42
// The following standard C functions are currently supported:
43
//
44
//   fgetc      getline   isdigit   isupper
45
//   fread      isalnum   isgraph   isxdigit
46
//   fwrite     isalpha   islower   read
47
//   getc       isascii   isprint   write
48
//   getchar    isblank   ispunct
49
//   getdelim   iscntrl   isspace
50
//
51
//===----------------------------------------------------------------------===//
52
53
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
54
#include "clang/StaticAnalyzer/Core/Checker.h"
55
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
56
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
57
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
58
59
using namespace clang;
60
using namespace clang::ento;
61
62
namespace {
63
class StdLibraryFunctionsChecker : public Checker<check::PostCall, eval::Call> {
64
  /// Below is a series of typedefs necessary to define function specs.
65
  /// We avoid nesting types here because each additional qualifier
66
  /// would need to be repeated in every function spec.
67
  struct FunctionSummaryTy;
68
69
  /// Specify how much the analyzer engine should entrust modeling this function
70
  /// to us. If he doesn't, he performs additional invalidations.
71
  enum InvalidationKindTy { NoEvalCall, EvalCallAsPure };
72
73
  /// A pair of ValueRangeKindTy and IntRangeVectorTy would describe a range
74
  /// imposed on a particular argument or return value symbol.
75
  ///
76
  /// Given a range, should the argument stay inside or outside this range?
77
  /// The special `ComparesToArgument' value indicates that we should
78
  /// impose a constraint that involves other argument or return value symbols.
79
  enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument };
80
81
  // The universal integral type to use in value range descriptions.
82
  // Unsigned to make sure overflows are well-defined.
83
  typedef uint64_t RangeIntTy;
84
85
  /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
86
  /// a non-negative integer, which less than 5 and not equal to 2. For
87
  /// `ComparesToArgument', holds information about how exactly to compare to
88
  /// the argument.
89
  typedef std::vector<std::pair<RangeIntTy, RangeIntTy>> IntRangeVectorTy;
90
91
  /// A reference to an argument or return value by its number.
92
  /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
93
  /// obviously uint32_t should be enough for all practical purposes.
94
  typedef uint32_t ArgNoTy;
95
  static const ArgNoTy Ret = std::numeric_limits<ArgNoTy>::max();
96
97
  /// Incapsulates a single range on a single symbol within a branch.
98
  class ValueRange {
99
    ArgNoTy ArgNo; // Argument to which we apply the range.
100
    ValueRangeKindTy Kind; // Kind of range definition.
101
    IntRangeVectorTy Args; // Polymorphic arguments.
102
103
  public:
104
    ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind,
105
               const IntRangeVectorTy &Args)
106
1.07k
        : ArgNo(ArgNo), Kind(Kind), Args(Args) {}
107
108
1.78k
    ArgNoTy getArgNo() const { return ArgNo; }
109
0
    ValueRangeKindTy getKind() const { return Kind; }
110
111
25
    BinaryOperator::Opcode getOpcode() const {
112
25
      assert(Kind == ComparesToArgument);
113
25
      assert(Args.size() == 1);
114
25
      BinaryOperator::Opcode Op =
115
25
          static_cast<BinaryOperator::Opcode>(Args[0].first);
116
25
      assert(BinaryOperator::isComparisonOp(Op) &&
117
25
             "Only comparison ops are supported for ComparesToArgument");
118
25
      return Op;
119
25
    }
120
121
25
    ArgNoTy getOtherArgNo() const {
122
25
      assert(Kind == ComparesToArgument);
123
25
      assert(Args.size() == 1);
124
25
      return static_cast<ArgNoTy>(Args[0].second);
125
25
    }
126
127
867
    const IntRangeVectorTy &getRanges() const {
128
867
      assert(Kind != ComparesToArgument);
129
867
      return Args;
130
867
    }
131
132
    // We avoid creating a virtual apply() method because
133
    // it makes initializer lists harder to write.
134
  private:
135
    ProgramStateRef
136
    applyAsOutOfRange(ProgramStateRef State, const CallEvent &Call,
137
                      const FunctionSummaryTy &Summary) const;
138
    ProgramStateRef
139
    applyAsWithinRange(ProgramStateRef State, const CallEvent &Call,
140
                       const FunctionSummaryTy &Summary) const;
141
    ProgramStateRef
142
    applyAsComparesToArgument(ProgramStateRef State, const CallEvent &Call,
143
                              const FunctionSummaryTy &Summary) const;
144
145
  public:
146
    ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
147
892
                          const FunctionSummaryTy &Summary) const {
148
892
      switch (Kind) {
149
892
      case OutOfRange:
150
346
        return applyAsOutOfRange(State, Call, Summary);
151
892
      case WithinRange:
152
521
        return applyAsWithinRange(State, Call, Summary);
153
892
      case ComparesToArgument:
154
25
        return applyAsComparesToArgument(State, Call, Summary);
155
0
      }
156
0
      llvm_unreachable("Unknown ValueRange kind!");
157
0
    }
158
  };
159
160
  /// The complete list of ranges that defines a single branch.
161
  typedef std::vector<ValueRange> ValueRangeSet;
162
163
  /// Includes information about function prototype (which is necessary to
164
  /// ensure we're modeling the right function and casting values properly),
165
  /// approach to invalidation, and a list of branches - essentially, a list
166
  /// of list of ranges - essentially, a list of lists of lists of segments.
167
  struct FunctionSummaryTy {
168
    const std::vector<QualType> ArgTypes;
169
    const QualType RetType;
170
    const InvalidationKindTy InvalidationKind;
171
    const std::vector<ValueRangeSet> Ranges;
172
173
  private:
174
1.32k
    static void assertTypeSuitableForSummary(QualType T) {
175
1.32k
      assert(!T->isVoidType() &&
176
1.32k
             "We should have had no significant void types in the spec");
177
1.32k
      assert(T.isCanonical() &&
178
1.32k
             "We should only have canonical types in the spec");
179
1.32k
      // FIXME: lift this assert (but not the ones above!)
180
1.32k
      assert(T->isIntegralOrEnumerationType() &&
181
1.32k
             "We only support integral ranges in the spec");
182
1.32k
    }
183
184
  public:
185
892
    QualType getArgType(ArgNoTy ArgNo) const {
186
892
      QualType T = (ArgNo == Ret) ? 
RetType420
:
ArgTypes[ArgNo]472
;
187
892
      assertTypeSuitableForSummary(T);
188
892
      return T;
189
892
    }
190
191
    /// Try our best to figure out if the call expression is the call of
192
    /// *the* library function to which this specification applies.
193
    bool matchesCall(const CallExpr *CE) const;
194
  };
195
196
  // The same function (as in, function identifier) may have different
197
  // summaries assigned to it, with different argument and return value types.
198
  // We call these "variants" of the function. This can be useful for handling
199
  // C++ function overloads, and also it can be used when the same function
200
  // may have different definitions on different platforms.
201
  typedef std::vector<FunctionSummaryTy> FunctionVariantsTy;
202
203
  // The map of all functions supported by the checker. It is initialized
204
  // lazily, and it doesn't change after initialization.
205
  typedef llvm::StringMap<FunctionVariantsTy> FunctionSummaryMapTy;
206
  mutable FunctionSummaryMapTy FunctionSummaryMap;
207
208
  // Auxiliary functions to support ArgNoTy within all structures
209
  // in a unified manner.
210
892
  static QualType getArgType(const FunctionSummaryTy &Summary, ArgNoTy ArgNo) {
211
892
    return Summary.getArgType(ArgNo);
212
892
  }
213
25
  static QualType getArgType(const CallEvent &Call, ArgNoTy ArgNo) {
214
25
    return ArgNo == Ret ? 
Call.getResultType().getCanonicalType()0
215
25
                        : Call.getArgExpr(ArgNo)->getType().getCanonicalType();
216
25
  }
217
432
  static QualType getArgType(const CallExpr *CE, ArgNoTy ArgNo) {
218
432
    return ArgNo == Ret ? 
CE->getType().getCanonicalType()0
219
432
                        : CE->getArg(ArgNo)->getType().getCanonicalType();
220
432
  }
221
917
  static SVal getArgSVal(const CallEvent &Call, ArgNoTy ArgNo) {
222
917
    return ArgNo == Ret ? 
Call.getReturnValue()420
:
Call.getArgSVal(ArgNo)497
;
223
917
  }
224
225
public:
226
  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
227
  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
228
229
private:
230
  Optional<FunctionSummaryTy> findFunctionSummary(const FunctionDecl *FD,
231
                                          const CallExpr *CE,
232
                                          CheckerContext &C) const;
233
234
  void initFunctionSummaries(BasicValueFactory &BVF) const;
235
};
236
} // end of anonymous namespace
237
238
ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
239
    ProgramStateRef State, const CallEvent &Call,
240
346
    const FunctionSummaryTy &Summary) const {
241
346
242
346
  ProgramStateManager &Mgr = State->getStateManager();
243
346
  SValBuilder &SVB = Mgr.getSValBuilder();
244
346
  BasicValueFactory &BVF = SVB.getBasicValueFactory();
245
346
  ConstraintManager &CM = Mgr.getConstraintManager();
246
346
  QualType T = getArgType(Summary, getArgNo());
247
346
  SVal V = getArgSVal(Call, getArgNo());
248
346
249
346
  if (auto N = V.getAs<NonLoc>()) {
250
346
    const IntRangeVectorTy &R = getRanges();
251
346
    size_t E = R.size();
252
762
    for (size_t I = 0; I != E; 
++I416
) {
253
506
      const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
254
506
      const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
255
506
      assert(Min <= Max);
256
506
      State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
257
506
      if (!State)
258
90
        break;
259
506
    }
260
346
  }
261
346
262
346
  return State;
263
346
}
264
265
ProgramStateRef
266
StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
267
    ProgramStateRef State, const CallEvent &Call,
268
521
    const FunctionSummaryTy &Summary) const {
269
521
270
521
  ProgramStateManager &Mgr = State->getStateManager();
271
521
  SValBuilder &SVB = Mgr.getSValBuilder();
272
521
  BasicValueFactory &BVF = SVB.getBasicValueFactory();
273
521
  ConstraintManager &CM = Mgr.getConstraintManager();
274
521
  QualType T = getArgType(Summary, getArgNo());
275
521
  SVal V = getArgSVal(Call, getArgNo());
276
521
277
521
  // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
278
521
  // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
279
521
  // and then cut away all holes in R one by one.
280
521
  if (auto N = V.getAs<NonLoc>()) {
281
521
    const IntRangeVectorTy &R = getRanges();
282
521
    size_t E = R.size();
283
521
284
521
    const llvm::APSInt &MinusInf = BVF.getMinValue(T);
285
521
    const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
286
521
287
521
    const llvm::APSInt &Left = BVF.getValue(R[0].first - 1ULL, T);
288
521
    if (Left != PlusInf) {
289
521
      assert(MinusInf <= Left);
290
521
      State = CM.assumeInclusiveRange(State, *N, MinusInf, Left, false);
291
521
      if (!State)
292
70
        return nullptr;
293
451
    }
294
451
295
451
    const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1ULL, T);
296
451
    if (Right != MinusInf) {
297
421
      assert(Right <= PlusInf);
298
421
      State = CM.assumeInclusiveRange(State, *N, Right, PlusInf, false);
299
421
      if (!State)
300
11
        return nullptr;
301
440
    }
302
440
303
560
    
for (size_t I = 1; 440
I != E;
++I120
) {
304
135
      const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, T);
305
135
      const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, T);
306
135
      assert(Min <= Max);
307
135
      State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
308
135
      if (!State)
309
15
        return nullptr;
310
135
    }
311
440
  }
312
521
313
521
  
return State425
;
314
521
}
315
316
ProgramStateRef
317
StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument(
318
    ProgramStateRef State, const CallEvent &Call,
319
25
    const FunctionSummaryTy &Summary) const {
320
25
321
25
  ProgramStateManager &Mgr = State->getStateManager();
322
25
  SValBuilder &SVB = Mgr.getSValBuilder();
323
25
  QualType CondT = SVB.getConditionType();
324
25
  QualType T = getArgType(Summary, getArgNo());
325
25
  SVal V = getArgSVal(Call, getArgNo());
326
25
327
25
  BinaryOperator::Opcode Op = getOpcode();
328
25
  ArgNoTy OtherArg = getOtherArgNo();
329
25
  SVal OtherV = getArgSVal(Call, OtherArg);
330
25
  QualType OtherT = getArgType(Call, OtherArg);
331
25
  // Note: we avoid integral promotion for comparison.
332
25
  OtherV = SVB.evalCast(OtherV, T, OtherT);
333
25
  if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
334
25
                       .getAs<DefinedOrUnknownSVal>())
335
25
    State = State->assume(*CompV, true);
336
25
  return State;
337
25
}
338
339
void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
340
731
                                               CheckerContext &C) const {
341
731
  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
342
731
  if (!FD)
343
0
    return;
344
731
345
731
  const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
346
731
  if (!CE)
347
2
    return;
348
729
349
729
  Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
350
729
  if (!FoundSummary)
351
384
    return;
352
345
353
345
  // Now apply ranges.
354
345
  const FunctionSummaryTy &Summary = *FoundSummary;
355
345
  ProgramStateRef State = C.getState();
356
345
357
611
  for (const auto &VRS: Summary.Ranges) {
358
611
    ProgramStateRef NewState = State;
359
892
    for (const auto &VR: VRS) {
360
892
      NewState = VR.apply(NewState, Call, Summary);
361
892
      if (!NewState)
362
186
        break;
363
892
    }
364
611
365
611
    if (NewState && 
NewState != State425
)
366
420
      C.addTransition(NewState);
367
611
  }
368
345
}
369
370
bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
371
729
                                          CheckerContext &C) const {
372
729
  const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
373
729
  if (!FD)
374
0
    return false;
375
729
376
729
  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
377
729
  if (!CE)
378
0
    return false;
379
729
380
729
  Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
381
729
  if (!FoundSummary)
382
384
    return false;
383
345
384
345
  const FunctionSummaryTy &Summary = *FoundSummary;
385
345
  switch (Summary.InvalidationKind) {
386
345
  case EvalCallAsPure: {
387
191
    ProgramStateRef State = C.getState();
388
191
    const LocationContext *LC = C.getLocationContext();
389
191
    SVal V = C.getSValBuilder().conjureSymbolVal(
390
191
        CE, LC, CE->getType().getCanonicalType(), C.blockCount());
391
191
    State = State->BindExpr(CE, LC, V);
392
191
    C.addTransition(State);
393
191
    return true;
394
345
  }
395
345
  case NoEvalCall:
396
154
    // Summary tells us to avoid performing eval::Call. The function is possibly
397
154
    // evaluated by another checker, or evaluated conservatively.
398
154
    return false;
399
0
  }
400
0
  llvm_unreachable("Unknown invalidation kind!");
401
0
}
402
403
bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall(
404
752
    const CallExpr *CE) const {
405
752
  // Check number of arguments:
406
752
  if (CE->getNumArgs() != ArgTypes.size())
407
0
    return false;
408
752
409
752
  // Check return type if relevant:
410
752
  if (!RetType.isNull() && RetType != CE->getType().getCanonicalType())
411
62
    return false;
412
690
413
690
  // Check argument types when relevant:
414
1.58k
  
for (size_t I = 0, E = ArgTypes.size(); 690
I != E;
++I890
) {
415
890
    QualType FormalT = ArgTypes[I];
416
890
    // Null type marks irrelevant arguments.
417
890
    if (FormalT.isNull())
418
458
      continue;
419
432
420
432
    assertTypeSuitableForSummary(FormalT);
421
432
422
432
    QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I);
423
432
    assert(ActualT.isCanonical());
424
432
    if (ActualT != FormalT)
425
0
      return false;
426
432
  }
427
690
428
690
  return true;
429
690
}
430
431
Optional<StdLibraryFunctionsChecker::FunctionSummaryTy>
432
StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
433
                                                const CallExpr *CE,
434
1.45k
                                                CheckerContext &C) const {
435
1.45k
  // Note: we cannot always obtain FD from CE
436
1.45k
  // (eg. virtual call, or call by pointer).
437
1.45k
  assert(CE);
438
1.45k
439
1.45k
  if (!FD)
440
0
    return None;
441
1.45k
442
1.45k
  SValBuilder &SVB = C.getSValBuilder();
443
1.45k
  BasicValueFactory &BVF = SVB.getBasicValueFactory();
444
1.45k
  initFunctionSummaries(BVF);
445
1.45k
446
1.45k
  IdentifierInfo *II = FD->getIdentifier();
447
1.45k
  if (!II)
448
0
    return None;
449
1.45k
  StringRef Name = II->getName();
450
1.45k
  if (Name.empty() || !C.isCLibraryFunction(FD, Name))
451
0
    return None;
452
1.45k
453
1.45k
  auto FSMI = FunctionSummaryMap.find(Name);
454
1.45k
  if (FSMI == FunctionSummaryMap.end())
455
766
    return None;
456
692
457
692
  // Verify that function signature matches the spec in advance.
458
692
  // Otherwise we might be modeling the wrong function.
459
692
  // Strict checking is important because we will be conducting
460
692
  // very integral-type-sensitive operations on arguments and
461
692
  // return values.
462
692
  const FunctionVariantsTy &SpecVariants = FSMI->second;
463
692
  for (const FunctionSummaryTy &Spec : SpecVariants)
464
752
    if (Spec.matchesCall(CE))
465
690
      return Spec;
466
692
467
692
  
return None2
;
468
692
}
469
470
void StdLibraryFunctionsChecker::initFunctionSummaries(
471
1.45k
    BasicValueFactory &BVF) const {
472
1.45k
  if (!FunctionSummaryMap.empty())
473
1.44k
    return;
474
13
475
13
  ASTContext &ACtx = BVF.getContext();
476
13
477
13
  // These types are useful for writing specifications quickly,
478
13
  // New specifications should probably introduce more types.
479
13
  // Some types are hard to obtain from the AST, eg. "ssize_t".
480
13
  // In such cases it should be possible to provide multiple variants
481
13
  // of function summary for common cases (eg. ssize_t could be int or long
482
13
  // or long long, so three summary variants would be enough).
483
13
  // Of course, function variants are also useful for C++ overloads.
484
13
  QualType Irrelevant; // A placeholder, whenever we do not care about the type.
485
13
  QualType IntTy = ACtx.IntTy;
486
13
  QualType LongTy = ACtx.LongTy;
487
13
  QualType LongLongTy = ACtx.LongLongTy;
488
13
  QualType SizeTy = ACtx.getSizeType();
489
13
490
13
  RangeIntTy IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
491
13
  RangeIntTy LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
492
13
  RangeIntTy LongLongMax = BVF.getMaxValue(LongLongTy).getLimitedValue();
493
13
494
13
  // We are finally ready to define specifications for all supported functions.
495
13
  //
496
13
  // The signature needs to have the correct number of arguments.
497
13
  // However, we insert `Irrelevant' when the type is insignificant.
498
13
  //
499
13
  // Argument ranges should always cover all variants. If return value
500
13
  // is completely unknown, omit it from the respective range set.
501
13
  //
502
13
  // All types in the spec need to be canonical.
503
13
  //
504
13
  // Every item in the list of range sets represents a particular
505
13
  // execution path the analyzer would need to explore once
506
13
  // the call is modeled - a new program state is constructed
507
13
  // for every range set, and each range line in the range set
508
13
  // corresponds to a specific constraint within this state.
509
13
  //
510
13
  // Upon comparing to another argument, the other argument is casted
511
13
  // to the current argument's type. This avoids proper promotion but
512
13
  // seems useful. For example, read() receives size_t argument,
513
13
  // and its return value, which is of type ssize_t, cannot be greater
514
13
  // than this argument. If we made a promotion, and the size argument
515
13
  // is equal to, say, 10, then we'd impose a range of [0, 10] on the
516
13
  // return value, however the correct range is [-1, 10].
517
13
  //
518
13
  // Please update the list of functions in the header after editing!
519
13
  //
520
13
  // The format is as follows:
521
13
  //
522
13
  //{ "function name",
523
13
  //  { spec:
524
13
  //    { argument types list, ... },
525
13
  //    return type, purity, { range set list:
526
13
  //      { range list:
527
13
  //        { argument index, within or out of, {{from, to}, ...} },
528
13
  //        { argument index, compares to argument, {{how, which}} },
529
13
  //        ...
530
13
  //      }
531
13
  //    }
532
13
  //  }
533
13
  //}
534
13
535
52
#define SUMMARY_WITH_VARIANTS(identifier) {#identifier, {
536
52
#define END_SUMMARY_WITH_VARIANTS }},
537
13
#define VARIANT(argument_types, return_type, invalidation_approach)            \
538
156
  { argument_types, return_type, invalidation_approach, {
539
156
#define END_VARIANT } },
540
13
#define SUMMARY(identifier, argument_types, return_type,                       \
541
13
                invalidation_approach)                                         \
542
234
  { #identifier, { { argument_types, return_type, invalidation_approach, {
543
234
#define END_SUMMARY } } } },
544
13
#define ARGUMENT_TYPES(...) { __VA_ARGS__ }
545
13
#define RETURN_TYPE(x) x
546
13
#define INVALIDATION_APPROACH(x) x
547
637
#define CASE {
548
637
#define END_CASE },
549
13
#define ARGUMENT_CONDITION(argument_number, condition_kind)                    \
550
429
  { argument_number, condition_kind, {
551
429
#define END_ARGUMENT_CONDITION }},
552
13
#define RETURN_VALUE_CONDITION(condition_kind)                                 \
553
650
  { Ret, condition_kind, {
554
650
#define END_RETURN_VALUE_CONDITION }},
555
13
#define ARG_NO(x) x##U
556
1.39k
#define RANGE(x, y) { x, y },
557
533
#define SINGLE_VALUE(x) RANGE(x, x)
558
104
#define IS_LESS_THAN(arg) { BO_LE, arg }
559
13
560
13
  FunctionSummaryMap = {
561
13
    // The isascii() family of functions.
562
13
    SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
563
13
            INVALIDATION_APPROACH(EvalCallAsPure))
564
13
      CASE // Boils down to isupper() or islower() or isdigit()
565
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
566
13
          RANGE('0', '9')
567
13
          RANGE('A', 'Z')
568
13
          RANGE('a', 'z')
569
13
        END_ARGUMENT_CONDITION
570
13
        RETURN_VALUE_CONDITION(OutOfRange)
571
13
          SINGLE_VALUE(0)
572
13
        END_RETURN_VALUE_CONDITION
573
13
      END_CASE
574
13
      CASE // The locale-specific range.
575
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
576
13
          RANGE(128, 255)
577
13
        END_ARGUMENT_CONDITION
578
13
        // No post-condition. We are completely unaware of
579
13
        // locale-specific return values.
580
13
      END_CASE
581
13
      CASE
582
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
583
13
          RANGE('0', '9')
584
13
          RANGE('A', 'Z')
585
13
          RANGE('a', 'z')
586
13
          RANGE(128, 255)
587
13
        END_ARGUMENT_CONDITION
588
13
        RETURN_VALUE_CONDITION(WithinRange)
589
13
          SINGLE_VALUE(0)
590
13
        END_RETURN_VALUE_CONDITION
591
13
      END_CASE
592
13
    END_SUMMARY
593
13
    SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
594
13
            INVALIDATION_APPROACH(EvalCallAsPure))
595
13
      CASE // isupper() or islower(). Note that 'Z' is less than 'a'.
596
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
597
13
          RANGE('A', 'Z')
598
13
          RANGE('a', 'z')
599
13
        END_ARGUMENT_CONDITION
600
13
        RETURN_VALUE_CONDITION(OutOfRange)
601
13
          SINGLE_VALUE(0)
602
13
        END_RETURN_VALUE_CONDITION
603
13
      END_CASE
604
13
      CASE // The locale-specific range.
605
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
606
13
          RANGE(128, 255)
607
13
        END_ARGUMENT_CONDITION
608
13
      END_CASE
609
13
      CASE // Other.
610
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
611
13
          RANGE('A', 'Z')
612
13
          RANGE('a', 'z')
613
13
          RANGE(128, 255)
614
13
        END_ARGUMENT_CONDITION
615
13
        RETURN_VALUE_CONDITION(WithinRange)
616
13
          SINGLE_VALUE(0)
617
13
        END_RETURN_VALUE_CONDITION
618
13
      END_CASE
619
13
    END_SUMMARY
620
13
    SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
621
13
            INVALIDATION_APPROACH(EvalCallAsPure))
622
13
      CASE // Is ASCII.
623
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
624
13
          RANGE(0, 127)
625
13
        END_ARGUMENT_CONDITION
626
13
        RETURN_VALUE_CONDITION(OutOfRange)
627
13
          SINGLE_VALUE(0)
628
13
        END_RETURN_VALUE_CONDITION
629
13
      END_CASE
630
13
      CASE
631
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
632
13
          RANGE(0, 127)
633
13
        END_ARGUMENT_CONDITION
634
13
        RETURN_VALUE_CONDITION(WithinRange)
635
13
          SINGLE_VALUE(0)
636
13
        END_RETURN_VALUE_CONDITION
637
13
      END_CASE
638
13
    END_SUMMARY
639
13
    SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
640
13
            INVALIDATION_APPROACH(EvalCallAsPure))
641
13
      CASE
642
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
643
13
          SINGLE_VALUE('\t')
644
13
          SINGLE_VALUE(' ')
645
13
        END_ARGUMENT_CONDITION
646
13
        RETURN_VALUE_CONDITION(OutOfRange)
647
13
          SINGLE_VALUE(0)
648
13
        END_RETURN_VALUE_CONDITION
649
13
      END_CASE
650
13
      CASE
651
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
652
13
          SINGLE_VALUE('\t')
653
13
          SINGLE_VALUE(' ')
654
13
        END_ARGUMENT_CONDITION
655
13
        RETURN_VALUE_CONDITION(WithinRange)
656
13
          SINGLE_VALUE(0)
657
13
        END_RETURN_VALUE_CONDITION
658
13
      END_CASE
659
13
    END_SUMMARY
660
13
    SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
661
13
            INVALIDATION_APPROACH(EvalCallAsPure))
662
13
      CASE // 0..31 or 127
663
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
664
13
          RANGE(0, 32)
665
13
          SINGLE_VALUE(127)
666
13
        END_ARGUMENT_CONDITION
667
13
        RETURN_VALUE_CONDITION(OutOfRange)
668
13
          SINGLE_VALUE(0)
669
13
        END_RETURN_VALUE_CONDITION
670
13
      END_CASE
671
13
      CASE
672
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
673
13
          RANGE(0, 32)
674
13
          SINGLE_VALUE(127)
675
13
        END_ARGUMENT_CONDITION
676
13
        RETURN_VALUE_CONDITION(WithinRange)
677
13
          SINGLE_VALUE(0)
678
13
        END_RETURN_VALUE_CONDITION
679
13
      END_CASE
680
13
    END_SUMMARY
681
13
    SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
682
13
            INVALIDATION_APPROACH(EvalCallAsPure))
683
13
      CASE // Is a digit.
684
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
685
13
          RANGE('0', '9')
686
13
        END_ARGUMENT_CONDITION
687
13
        RETURN_VALUE_CONDITION(OutOfRange)
688
13
          SINGLE_VALUE(0)
689
13
        END_RETURN_VALUE_CONDITION
690
13
      END_CASE
691
13
      CASE
692
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
693
13
          RANGE('0', '9')
694
13
        END_ARGUMENT_CONDITION
695
13
        RETURN_VALUE_CONDITION(WithinRange)
696
13
          SINGLE_VALUE(0)
697
13
        END_RETURN_VALUE_CONDITION
698
13
      END_CASE
699
13
    END_SUMMARY
700
13
    SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
701
13
            INVALIDATION_APPROACH(EvalCallAsPure))
702
13
      CASE
703
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
704
13
          RANGE(33, 126)
705
13
        END_ARGUMENT_CONDITION
706
13
        RETURN_VALUE_CONDITION(OutOfRange)
707
13
          SINGLE_VALUE(0)
708
13
        END_RETURN_VALUE_CONDITION
709
13
      END_CASE
710
13
      CASE
711
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
712
13
          RANGE(33, 126)
713
13
        END_ARGUMENT_CONDITION
714
13
        RETURN_VALUE_CONDITION(WithinRange)
715
13
          SINGLE_VALUE(0)
716
13
        END_RETURN_VALUE_CONDITION
717
13
      END_CASE
718
13
    END_SUMMARY
719
13
    SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
720
13
            INVALIDATION_APPROACH(EvalCallAsPure))
721
13
      CASE // Is certainly lowercase.
722
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
723
13
          RANGE('a', 'z')
724
13
        END_ARGUMENT_CONDITION
725
13
        RETURN_VALUE_CONDITION(OutOfRange)
726
13
          SINGLE_VALUE(0)
727
13
        END_RETURN_VALUE_CONDITION
728
13
      END_CASE
729
13
      CASE // Is ascii but not lowercase.
730
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
731
13
          RANGE(0, 127)
732
13
        END_ARGUMENT_CONDITION
733
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
734
13
          RANGE('a', 'z')
735
13
        END_ARGUMENT_CONDITION
736
13
        RETURN_VALUE_CONDITION(WithinRange)
737
13
          SINGLE_VALUE(0)
738
13
        END_RETURN_VALUE_CONDITION
739
13
      END_CASE
740
13
      CASE // The locale-specific range.
741
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
742
13
          RANGE(128, 255)
743
13
        END_ARGUMENT_CONDITION
744
13
      END_CASE
745
13
      CASE // Is not an unsigned char.
746
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
747
13
          RANGE(0, 255)
748
13
        END_ARGUMENT_CONDITION
749
13
        RETURN_VALUE_CONDITION(WithinRange)
750
13
          SINGLE_VALUE(0)
751
13
        END_RETURN_VALUE_CONDITION
752
13
      END_CASE
753
13
    END_SUMMARY
754
13
    SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
755
13
            INVALIDATION_APPROACH(EvalCallAsPure))
756
13
      CASE
757
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
758
13
          RANGE(32, 126)
759
13
        END_ARGUMENT_CONDITION
760
13
        RETURN_VALUE_CONDITION(OutOfRange)
761
13
          SINGLE_VALUE(0)
762
13
        END_RETURN_VALUE_CONDITION
763
13
      END_CASE
764
13
      CASE
765
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
766
13
          RANGE(32, 126)
767
13
        END_ARGUMENT_CONDITION
768
13
        RETURN_VALUE_CONDITION(WithinRange)
769
13
          SINGLE_VALUE(0)
770
13
        END_RETURN_VALUE_CONDITION
771
13
      END_CASE
772
13
    END_SUMMARY
773
13
    SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
774
13
            INVALIDATION_APPROACH(EvalCallAsPure))
775
13
      CASE
776
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
777
13
          RANGE('!', '/')
778
13
          RANGE(':', '@')
779
13
          RANGE('[', '`')
780
13
          RANGE('{', '~')
781
13
        END_ARGUMENT_CONDITION
782
13
        RETURN_VALUE_CONDITION(OutOfRange)
783
13
          SINGLE_VALUE(0)
784
13
        END_RETURN_VALUE_CONDITION
785
13
      END_CASE
786
13
      CASE
787
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
788
13
          RANGE('!', '/')
789
13
          RANGE(':', '@')
790
13
          RANGE('[', '`')
791
13
          RANGE('{', '~')
792
13
        END_ARGUMENT_CONDITION
793
13
        RETURN_VALUE_CONDITION(WithinRange)
794
13
          SINGLE_VALUE(0)
795
13
        END_RETURN_VALUE_CONDITION
796
13
      END_CASE
797
13
    END_SUMMARY
798
13
    SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
799
13
            INVALIDATION_APPROACH(EvalCallAsPure))
800
13
      CASE // Space, '\f', '\n', '\r', '\t', '\v'.
801
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
802
13
          RANGE(9, 13)
803
13
          SINGLE_VALUE(' ')
804
13
        END_ARGUMENT_CONDITION
805
13
        RETURN_VALUE_CONDITION(OutOfRange)
806
13
          SINGLE_VALUE(0)
807
13
        END_RETURN_VALUE_CONDITION
808
13
      END_CASE
809
13
      CASE // The locale-specific range.
810
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
811
13
          RANGE(128, 255)
812
13
        END_ARGUMENT_CONDITION
813
13
      END_CASE
814
13
      CASE
815
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
816
13
          RANGE(9, 13)
817
13
          SINGLE_VALUE(' ')
818
13
          RANGE(128, 255)
819
13
        END_ARGUMENT_CONDITION
820
13
        RETURN_VALUE_CONDITION(WithinRange)
821
13
          SINGLE_VALUE(0)
822
13
        END_RETURN_VALUE_CONDITION
823
13
      END_CASE
824
13
    END_SUMMARY
825
13
    SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy),
826
13
            INVALIDATION_APPROACH(EvalCallAsPure))
827
13
      CASE // Is certainly uppercase.
828
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
829
13
          RANGE('A', 'Z')
830
13
        END_ARGUMENT_CONDITION
831
13
        RETURN_VALUE_CONDITION(OutOfRange)
832
13
          SINGLE_VALUE(0)
833
13
        END_RETURN_VALUE_CONDITION
834
13
      END_CASE
835
13
      CASE // The locale-specific range.
836
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
837
13
          RANGE(128, 255)
838
13
        END_ARGUMENT_CONDITION
839
13
      END_CASE
840
13
      CASE // Other.
841
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
842
13
          RANGE('A', 'Z') RANGE(128, 255)
843
13
        END_ARGUMENT_CONDITION
844
13
        RETURN_VALUE_CONDITION(WithinRange)
845
13
          SINGLE_VALUE(0)
846
13
        END_RETURN_VALUE_CONDITION
847
13
      END_CASE
848
13
    END_SUMMARY
849
13
    SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
850
13
            INVALIDATION_APPROACH(EvalCallAsPure))
851
13
      CASE
852
13
        ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
853
13
          RANGE('0', '9')
854
13
          RANGE('A', 'F')
855
13
          RANGE('a', 'f')
856
13
        END_ARGUMENT_CONDITION
857
13
        RETURN_VALUE_CONDITION(OutOfRange)
858
13
          SINGLE_VALUE(0)
859
13
        END_RETURN_VALUE_CONDITION
860
13
      END_CASE
861
13
      CASE
862
13
        ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
863
13
          RANGE('0', '9')
864
13
          RANGE('A', 'F')
865
13
          RANGE('a', 'f')
866
13
        END_ARGUMENT_CONDITION
867
13
        RETURN_VALUE_CONDITION(WithinRange)
868
13
          SINGLE_VALUE(0)
869
13
        END_RETURN_VALUE_CONDITION
870
13
      END_CASE
871
13
    END_SUMMARY
872
13
873
13
    // The getc() family of functions that returns either a char or an EOF.
874
13
    SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
875
13
            INVALIDATION_APPROACH(NoEvalCall))
876
13
      CASE // FIXME: EOF is assumed to be defined as -1.
877
13
        RETURN_VALUE_CONDITION(WithinRange)
878
13
          RANGE(-1, 255)
879
13
        END_RETURN_VALUE_CONDITION
880
13
      END_CASE
881
13
    END_SUMMARY
882
13
    SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
883
13
            INVALIDATION_APPROACH(NoEvalCall))
884
13
      CASE // FIXME: EOF is assumed to be defined as -1.
885
13
        RETURN_VALUE_CONDITION(WithinRange)
886
13
          RANGE(-1, 255)
887
13
        END_RETURN_VALUE_CONDITION
888
13
      END_CASE
889
13
    END_SUMMARY
890
13
    SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy),
891
13
            INVALIDATION_APPROACH(NoEvalCall))
892
13
      CASE // FIXME: EOF is assumed to be defined as -1.
893
13
        RETURN_VALUE_CONDITION(WithinRange)
894
13
          RANGE(-1, 255)
895
13
        END_RETURN_VALUE_CONDITION
896
13
      END_CASE
897
13
    END_SUMMARY
898
13
899
13
    // read()-like functions that never return more than buffer size.
900
13
    // We are not sure how ssize_t is defined on every platform, so we provide
901
13
    // three variants that should cover common cases.
902
13
    SUMMARY_WITH_VARIANTS(read)
903
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
904
13
              RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
905
13
        CASE
906
13
          RETURN_VALUE_CONDITION(ComparesToArgument)
907
13
            IS_LESS_THAN(ARG_NO(2))
908
13
          END_RETURN_VALUE_CONDITION
909
13
          RETURN_VALUE_CONDITION(WithinRange)
910
13
            RANGE(-1, IntMax)
911
13
          END_RETURN_VALUE_CONDITION
912
13
        END_CASE
913
13
      END_VARIANT
914
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
915
13
              RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
916
13
        CASE
917
13
          RETURN_VALUE_CONDITION(ComparesToArgument)
918
13
            IS_LESS_THAN(ARG_NO(2))
919
13
          END_RETURN_VALUE_CONDITION
920
13
          RETURN_VALUE_CONDITION(WithinRange)
921
13
            RANGE(-1, LongMax)
922
13
          END_RETURN_VALUE_CONDITION
923
13
        END_CASE
924
13
      END_VARIANT
925
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
926
13
              RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
927
13
        CASE
928
13
          RETURN_VALUE_CONDITION(ComparesToArgument)
929
13
            IS_LESS_THAN(ARG_NO(2))
930
13
          END_RETURN_VALUE_CONDITION
931
13
          RETURN_VALUE_CONDITION(WithinRange)
932
13
            RANGE(-1, LongLongMax)
933
13
          END_RETURN_VALUE_CONDITION
934
13
        END_CASE
935
13
      END_VARIANT
936
13
    END_SUMMARY_WITH_VARIANTS
937
13
    SUMMARY_WITH_VARIANTS(write)
938
13
      // Again, due to elusive nature of ssize_t, we have duplicate
939
13
      // our summaries to cover different variants.
940
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
941
13
              RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
942
13
        CASE
943
13
          RETURN_VALUE_CONDITION(ComparesToArgument)
944
13
            IS_LESS_THAN(ARG_NO(2))
945
13
          END_RETURN_VALUE_CONDITION
946
13
          RETURN_VALUE_CONDITION(WithinRange)
947
13
            RANGE(-1, IntMax)
948
13
          END_RETURN_VALUE_CONDITION
949
13
        END_CASE
950
13
      END_VARIANT
951
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
952
13
              RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
953
13
        CASE
954
13
          RETURN_VALUE_CONDITION(ComparesToArgument)
955
13
            IS_LESS_THAN(ARG_NO(2))
956
13
          END_RETURN_VALUE_CONDITION
957
13
          RETURN_VALUE_CONDITION(WithinRange)
958
13
            RANGE(-1, LongMax)
959
13
          END_RETURN_VALUE_CONDITION
960
13
        END_CASE
961
13
      END_VARIANT
962
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
963
13
              RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
964
13
        CASE
965
13
          RETURN_VALUE_CONDITION(ComparesToArgument)
966
13
            IS_LESS_THAN(ARG_NO(2))
967
13
          END_RETURN_VALUE_CONDITION
968
13
          RETURN_VALUE_CONDITION(WithinRange)
969
13
            RANGE(-1, LongLongMax)
970
13
          END_RETURN_VALUE_CONDITION
971
13
        END_CASE
972
13
      END_VARIANT
973
13
    END_SUMMARY_WITH_VARIANTS
974
13
    SUMMARY(fread,
975
13
            ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
976
13
            RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
977
13
      CASE
978
13
        RETURN_VALUE_CONDITION(ComparesToArgument)
979
13
          IS_LESS_THAN(ARG_NO(2))
980
13
        END_RETURN_VALUE_CONDITION
981
13
      END_CASE
982
13
    END_SUMMARY
983
13
    SUMMARY(fwrite,
984
13
            ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
985
13
            RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
986
13
      CASE
987
13
        RETURN_VALUE_CONDITION(ComparesToArgument)
988
13
          IS_LESS_THAN(ARG_NO(2))
989
13
        END_RETURN_VALUE_CONDITION
990
13
      END_CASE
991
13
    END_SUMMARY
992
13
993
13
    // getline()-like functions either fail or read at least the delimiter.
994
13
    SUMMARY_WITH_VARIANTS(getline)
995
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
996
13
              RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
997
13
        CASE
998
13
          RETURN_VALUE_CONDITION(WithinRange)
999
13
            SINGLE_VALUE(-1)
1000
13
            RANGE(1, IntMax)
1001
13
          END_RETURN_VALUE_CONDITION
1002
13
        END_CASE
1003
13
      END_VARIANT
1004
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
1005
13
              RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
1006
13
        CASE
1007
13
          RETURN_VALUE_CONDITION(WithinRange)
1008
13
            SINGLE_VALUE(-1)
1009
13
            RANGE(1, LongMax)
1010
13
          END_RETURN_VALUE_CONDITION
1011
13
        END_CASE
1012
13
      END_VARIANT
1013
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
1014
13
              RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
1015
13
        CASE
1016
13
          RETURN_VALUE_CONDITION(WithinRange)
1017
13
            SINGLE_VALUE(-1)
1018
13
            RANGE(1, LongLongMax)
1019
13
          END_RETURN_VALUE_CONDITION
1020
13
        END_CASE
1021
13
      END_VARIANT
1022
13
    END_SUMMARY_WITH_VARIANTS
1023
13
    SUMMARY_WITH_VARIANTS(getdelim)
1024
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1025
13
            RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
1026
13
        CASE
1027
13
          RETURN_VALUE_CONDITION(WithinRange)
1028
13
            SINGLE_VALUE(-1)
1029
13
            RANGE(1, IntMax)
1030
13
          END_RETURN_VALUE_CONDITION
1031
13
        END_CASE
1032
13
      END_VARIANT
1033
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1034
13
            RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
1035
13
        CASE
1036
13
          RETURN_VALUE_CONDITION(WithinRange)
1037
13
            SINGLE_VALUE(-1)
1038
13
            RANGE(1, LongMax)
1039
13
          END_RETURN_VALUE_CONDITION
1040
13
        END_CASE
1041
13
      END_VARIANT
1042
13
      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
1043
13
            RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
1044
13
        CASE
1045
13
          RETURN_VALUE_CONDITION(WithinRange)
1046
13
            SINGLE_VALUE(-1)
1047
13
            RANGE(1, LongLongMax)
1048
13
          END_RETURN_VALUE_CONDITION
1049
13
        END_CASE
1050
13
      END_VARIANT
1051
13
    END_SUMMARY_WITH_VARIANTS
1052
13
  };
1053
13
}
1054
1055
21
void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
1056
21
  // If this checker grows large enough to support C++, Objective-C, or other
1057
21
  // standard libraries, we could use multiple register...Checker() functions,
1058
21
  // which would register various checkers with the help of the same Checker
1059
21
  // class, turning on different function summaries.
1060
21
  mgr.registerChecker<StdLibraryFunctionsChecker>();
1061
21
}
1062
1063
21
bool ento::shouldRegisterStdCLibraryFunctionsChecker(const LangOptions &LO) {
1064
21
  return true;
1065
21
}