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