blob: 8e77be54274c617bf1acd6660335f2306a37945a [file] [log] [blame]
Artem Dergachevbba497f2016-10-24 09:41:38 +00001//=== 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
60using namespace clang;
61using namespace clang::ento;
62
63namespace {
64class 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 /// Normally, describes a single range constraint, eg. {{0, 1}, {3, 4}} is
83 /// a non-negative integer, which less than 5 and not equal to 2. For
84 /// `ComparesToArgument', holds information about how exactly to compare to
85 /// the argument.
86 typedef std::vector<std::pair<int64_t, int64_t>> IntRangeVectorTy;
87
88 /// A reference to an argument or return value by its number.
89 /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
90 /// obviously uint32_t should be enough for all practical purposes.
91 typedef uint32_t ArgNoTy;
92 static const ArgNoTy Ret = std::numeric_limits<ArgNoTy>::max();
93
94 /// Incapsulates a single range on a single symbol within a branch.
95 class ValueRange {
96 ArgNoTy ArgNo; // Argument to which we apply the range.
97 ValueRangeKindTy Kind; // Kind of range definition.
98 IntRangeVectorTy Args; // Polymorphic arguments.
99
100 public:
101 ValueRange(ArgNoTy ArgNo, ValueRangeKindTy Kind,
102 const IntRangeVectorTy &Args)
103 : ArgNo(ArgNo), Kind(Kind), Args(Args) {}
104
105 ArgNoTy getArgNo() const { return ArgNo; }
106 ValueRangeKindTy getKind() const { return Kind; }
107
108 BinaryOperator::Opcode getOpcode() const {
109 assert(Kind == ComparesToArgument);
110 assert(Args.size() == 1);
111 BinaryOperator::Opcode Op =
112 static_cast<BinaryOperator::Opcode>(Args[0].first);
113 assert(BinaryOperator::isComparisonOp(Op) &&
114 "Only comparison ops are supported for ComparesToArgument");
115 return Op;
116 }
117
118 ArgNoTy getOtherArgNo() const {
119 assert(Kind == ComparesToArgument);
120 assert(Args.size() == 1);
121 return static_cast<ArgNoTy>(Args[0].second);
122 }
123
124 const IntRangeVectorTy &getRanges() const {
125 assert(Kind != ComparesToArgument);
126 return Args;
127 }
128
129 // We avoid creating a virtual apply() method because
130 // it makes initializer lists harder to write.
131 private:
132 ProgramStateRef
133 applyAsOutOfRange(ProgramStateRef State, const CallEvent &Call,
134 const FunctionSummaryTy &Summary) const;
135 ProgramStateRef
136 applyAsWithinRange(ProgramStateRef State, const CallEvent &Call,
137 const FunctionSummaryTy &Summary) const;
138 ProgramStateRef
139 applyAsComparesToArgument(ProgramStateRef State, const CallEvent &Call,
140 const FunctionSummaryTy &Summary) const;
141
142 public:
143 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
144 const FunctionSummaryTy &Summary) const {
145 switch (Kind) {
146 case OutOfRange:
147 return applyAsOutOfRange(State, Call, Summary);
148 case WithinRange:
149 return applyAsWithinRange(State, Call, Summary);
150 case ComparesToArgument:
151 return applyAsComparesToArgument(State, Call, Summary);
152 }
153 llvm_unreachable("Unknown ValueRange kind!");
154 }
155 };
156
157 /// The complete list of ranges that defines a single branch.
158 typedef std::vector<ValueRange> ValueRangeSet;
159
160 /// Includes information about function prototype (which is necessary to
161 /// ensure we're modeling the right function and casting values properly),
162 /// approach to invalidation, and a list of branches - essentially, a list
163 /// of list of ranges - essentially, a list of lists of lists of segments.
164 struct FunctionSummaryTy {
165 const std::vector<QualType> ArgTypes;
166 const QualType RetType;
167 const InvalidationKindTy InvalidationKind;
168 const std::vector<ValueRangeSet> Ranges;
169
170 private:
171 static void assertTypeSuitableForSummary(QualType T) {
172 assert(!T->isVoidType() &&
173 "We should have had no significant void types in the spec");
174 assert(T.isCanonical() &&
175 "We should only have canonical types in the spec");
176 // FIXME: lift this assert (but not the ones above!)
177 assert(T->isIntegralOrEnumerationType() &&
178 "We only support integral ranges in the spec");
179 }
180
181 public:
182 QualType getArgType(ArgNoTy ArgNo) const {
183 QualType T = (ArgNo == Ret) ? RetType : ArgTypes[ArgNo];
184 assertTypeSuitableForSummary(T);
185 return T;
186 }
187
188 /// Try our best to figure out if the call expression is the call of
189 /// *the* library function to which this specification applies.
190 bool matchesCall(const CallExpr *CE) const;
191 };
192
193 // The map of all functions supported by the checker. It is initialized
194 // lazily, and it doesn't change after initialization.
195 typedef llvm::StringMap<FunctionSummaryTy> FunctionSummaryMapTy;
196 mutable FunctionSummaryMapTy FunctionSummaryMap;
197
198 // Auxiliary functions to support ArgNoTy within all structures
199 // in a unified manner.
200 static QualType getArgType(const FunctionSummaryTy &Summary, ArgNoTy ArgNo) {
201 return Summary.getArgType(ArgNo);
202 }
203 static QualType getArgType(const CallEvent &Call, ArgNoTy ArgNo) {
204 return ArgNo == Ret ? Call.getResultType().getCanonicalType()
205 : Call.getArgExpr(ArgNo)->getType().getCanonicalType();
206 }
207 static QualType getArgType(const CallExpr *CE, ArgNoTy ArgNo) {
208 return ArgNo == Ret ? CE->getType().getCanonicalType()
209 : CE->getArg(ArgNo)->getType().getCanonicalType();
210 }
211 static SVal getArgSVal(const CallEvent &Call, ArgNoTy ArgNo) {
212 return ArgNo == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgNo);
213 }
214
215public:
216 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
217 bool evalCall(const CallExpr *CE, CheckerContext &C) const;
218
219private:
220 Optional<FunctionSummaryTy> findFunctionSummary(const FunctionDecl *FD,
221 const CallExpr *CE,
222 CheckerContext &C) const;
223
224 void initFunctionSummaries(BasicValueFactory &BVF) const;
225};
226} // end of anonymous namespace
227
228ProgramStateRef StdLibraryFunctionsChecker::ValueRange::applyAsOutOfRange(
229 ProgramStateRef State, const CallEvent &Call,
230 const FunctionSummaryTy &Summary) const {
231
232 ProgramStateManager &Mgr = State->getStateManager();
233 SValBuilder &SVB = Mgr.getSValBuilder();
234 BasicValueFactory &BVF = SVB.getBasicValueFactory();
235 ConstraintManager &CM = Mgr.getConstraintManager();
236 QualType T = getArgType(Summary, getArgNo());
237 SVal V = getArgSVal(Call, getArgNo());
238
239 if (auto N = V.getAs<NonLoc>()) {
240 const IntRangeVectorTy &R = getRanges();
241 size_t E = R.size();
242 for (size_t I = 0; I != E; ++I) {
243 const llvm::APSInt &Min = BVF.getValue(R[I].first, T);
244 const llvm::APSInt &Max = BVF.getValue(R[I].second, T);
245 assert(Min <= Max);
246 State = CM.assumeWithinInclusiveRange(State, *N, Min, Max, false);
247 if (!State)
248 break;
249 }
250 }
251
252 return State;
253}
254
255ProgramStateRef
256StdLibraryFunctionsChecker::ValueRange::applyAsWithinRange(
257 ProgramStateRef State, const CallEvent &Call,
258 const FunctionSummaryTy &Summary) const {
259
260 ProgramStateManager &Mgr = State->getStateManager();
261 SValBuilder &SVB = Mgr.getSValBuilder();
262 BasicValueFactory &BVF = SVB.getBasicValueFactory();
263 ConstraintManager &CM = Mgr.getConstraintManager();
264 QualType T = getArgType(Summary, getArgNo());
265 SVal V = getArgSVal(Call, getArgNo());
266
267 // "WithinRange R" is treated as "outside [T_MIN, T_MAX] \ R".
268 // We cut off [T_MIN, min(R) - 1] and [max(R) + 1, T_MAX] if necessary,
269 // and then cut away all holes in R one by one.
270 if (auto N = V.getAs<NonLoc>()) {
271 const IntRangeVectorTy &R = getRanges();
272 size_t E = R.size();
273
274 const llvm::APSInt &MinusInf = BVF.getMinValue(T);
275 const llvm::APSInt &PlusInf = BVF.getMaxValue(T);
276
277 const llvm::APSInt &Left = BVF.getValue(R[0].first - 1, T);
278 if (Left != PlusInf) {
279 assert(MinusInf <= Left);
280 State = CM.assumeWithinInclusiveRange(State, *N, MinusInf, Left, false);
281 if (!State)
282 return nullptr;
283 }
284
285 const llvm::APSInt &Right = BVF.getValue(R[E - 1].second + 1, T);
286 if (Right != MinusInf) {
287 assert(Right <= PlusInf);
288 State = CM.assumeWithinInclusiveRange(State, *N, Right, PlusInf, false);
289 if (!State)
290 return nullptr;
291 }
292
293 for (size_t I = 1; I != E; ++I) {
294 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1, T);
295 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1, T);
296 assert(Min <= Max);
297 State = CM.assumeWithinInclusiveRange(State, *N, Min, Max, false);
298 if (!State)
299 return nullptr;
300 }
301 }
302
303 return State;
304}
305
306ProgramStateRef
307StdLibraryFunctionsChecker::ValueRange::applyAsComparesToArgument(
308 ProgramStateRef State, const CallEvent &Call,
309 const FunctionSummaryTy &Summary) const {
310
311 ProgramStateManager &Mgr = State->getStateManager();
312 SValBuilder &SVB = Mgr.getSValBuilder();
313 QualType CondT = SVB.getConditionType();
314 QualType T = getArgType(Summary, getArgNo());
315 SVal V = getArgSVal(Call, getArgNo());
316
317 BinaryOperator::Opcode Op = getOpcode();
318 ArgNoTy OtherArg = getOtherArgNo();
319 SVal OtherV = getArgSVal(Call, OtherArg);
320 QualType OtherT = getArgType(Call, OtherArg);
321 // Note: we avoid integral promotion for comparison.
322 OtherV = SVB.evalCast(OtherV, T, OtherT);
323 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
324 .getAs<DefinedOrUnknownSVal>())
325 State = State->assume(*CompV, true);
326 return State;
327}
328
329void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
330 CheckerContext &C) const {
331 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
332 if (!FD)
333 return;
334
335 const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
336 if (!CE)
337 return;
338
339 Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
340 if (!FoundSummary)
341 return;
342
343 // Now apply ranges.
344 const FunctionSummaryTy &Summary = *FoundSummary;
345 ProgramStateRef State = C.getState();
346
347 for (const auto &VRS: Summary.Ranges) {
348 ProgramStateRef NewState = State;
349 for (const auto &VR: VRS) {
350 NewState = VR.apply(NewState, Call, Summary);
351 if (!NewState)
352 break;
353 }
354
355 if (NewState && NewState != State)
356 C.addTransition(NewState);
357 }
358}
359
360bool StdLibraryFunctionsChecker::evalCall(const CallExpr *CE,
361 CheckerContext &C) const {
362 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl());
363 if (!FD)
364 return false;
365
366 Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
367 if (!FoundSummary)
368 return false;
369
370 const FunctionSummaryTy &Summary = *FoundSummary;
371 switch (Summary.InvalidationKind) {
372 case EvalCallAsPure: {
373 ProgramStateRef State = C.getState();
374 const LocationContext *LC = C.getLocationContext();
375 SVal V = C.getSValBuilder().conjureSymbolVal(
376 CE, LC, CE->getType().getCanonicalType(), C.blockCount());
377 State = State->BindExpr(CE, LC, V);
378 C.addTransition(State);
379 return true;
380 }
381 case NoEvalCall:
382 // Summary tells us to avoid performing eval::Call. The function is possibly
383 // evaluated by another checker, or evaluated conservatively.
384 return false;
385 }
386 llvm_unreachable("Unknown invalidation kind!");
387}
388
389bool StdLibraryFunctionsChecker::FunctionSummaryTy::matchesCall(
390 const CallExpr *CE) const {
391 // Check number of arguments:
392 if (CE->getNumArgs() != ArgTypes.size())
393 return false;
394
395 // Check return type if relevant:
396 if (!RetType.isNull() && RetType != CE->getType().getCanonicalType())
397 return false;
398
399 // Check argument types when relevant:
400 for (size_t I = 0, E = ArgTypes.size(); I != E; ++I) {
401 QualType FormalT = ArgTypes[I];
402 // Null type marks irrelevant arguments.
403 if (FormalT.isNull())
404 continue;
405
406 assertTypeSuitableForSummary(FormalT);
407
408 QualType ActualT = StdLibraryFunctionsChecker::getArgType(CE, I);
409 assert(ActualT.isCanonical());
410 if (ActualT != FormalT)
411 return false;
412 }
413
414 return true;
415}
416
417Optional<StdLibraryFunctionsChecker::FunctionSummaryTy>
418StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
419 const CallExpr *CE,
420 CheckerContext &C) const {
421 // Note: we cannot always obtain FD from CE
422 // (eg. virtual call, or call by pointer).
423 assert(CE);
424
425 if (!FD)
426 return None;
427
428 SValBuilder &SVB = C.getSValBuilder();
429 BasicValueFactory &BVF = SVB.getBasicValueFactory();
430 initFunctionSummaries(BVF);
431
432 std::string Name = FD->getQualifiedNameAsString();
433 if (Name.empty() || !C.isCLibraryFunction(FD, Name))
434 return None;
435
436 auto FSMI = FunctionSummaryMap.find(Name);
437 if (FSMI == FunctionSummaryMap.end())
438 return None;
439
440 // Verify that function signature matches the spec in advance.
441 // Otherwise we might be modeling the wrong function.
442 // Strict checking is important because we will be conducting
443 // very integral-type-sensitive operations on arguments and
444 // return values.
445 const FunctionSummaryTy &Spec = FSMI->second;
446 if (!Spec.matchesCall(CE))
447 return None;
448
449 return Spec;
450}
451
452void StdLibraryFunctionsChecker::initFunctionSummaries(
453 BasicValueFactory &BVF) const {
454 if (!FunctionSummaryMap.empty())
455 return;
456
457 ASTContext &ACtx = BVF.getContext();
458
459 // These types are useful for writing specifications quickly,
460 // New specifications should probably introduce more types.
461 QualType Irrelevant; // A placeholder, whenever we do not care about the type.
462 QualType IntTy = ACtx.IntTy;
463 QualType SizeTy = ACtx.getSizeType();
464 QualType SSizeTy = ACtx.getIntTypeForBitwidth(ACtx.getTypeSize(SizeTy), true);
465
466 // Don't worry about truncation here, it'd be cast back to SIZE_MAX when used.
467 LLVM_ATTRIBUTE_UNUSED int64_t SizeMax =
468 BVF.getMaxValue(SizeTy).getLimitedValue();
469 int64_t SSizeMax =
470 BVF.getMaxValue(SSizeTy).getLimitedValue();
471
472 // We are finally ready to define specifications for all supported functions.
473 //
474 // The signature needs to have the correct number of arguments.
475 // However, we insert `Irrelevant' when the type is insignificant.
476 //
477 // Argument ranges should always cover all variants. If return value
478 // is completely unknown, omit it from the respective range set.
479 //
480 // All types in the spec need to be canonical.
481 //
482 // Every item in the list of range sets represents a particular
483 // execution path the analyzer would need to explore once
484 // the call is modeled - a new program state is constructed
485 // for every range set, and each range line in the range set
486 // corresponds to a specific constraint within this state.
487 //
488 // Upon comparing to another argument, the other argument is casted
489 // to the current argument's type. This avoids proper promotion but
490 // seems useful. For example, read() receives size_t argument,
491 // and its return value, which is of type ssize_t, cannot be greater
492 // than this argument. If we made a promotion, and the size argument
493 // is equal to, say, 10, then we'd impose a range of [0, 10] on the
494 // return value, however the correct range is [-1, 10].
495 //
496 // Please update the list of functions in the header after editing!
497 //
498 // The format is as follows:
499 //
500 //{ "function name",
501 // { spec:
502 // { argument types list, ... },
503 // return type, purity, { range set list:
504 // { range list:
505 // { argument index, within or out of, {{from, to}, ...} },
506 // { argument index, compares to argument, {{how, which}} },
507 // ...
508 // }
509 // }
510 // }
511 //}
512
513#define SUMMARY(identifier, argument_types, return_type, \
514 invalidation_approach) \
515 {#identifier, {argument_types, return_type, invalidation_approach, {
516#define END_SUMMARY }}},
517#define ARGUMENT_TYPES(...) { __VA_ARGS__ }
518#define RETURN_TYPE(x) x
519#define INVALIDATION_APPROACH(x) x
520#define CASE {
521#define END_CASE },
522#define ARGUMENT_CONDITION(argument_number, condition_kind) \
523 {argument_number, condition_kind, {
524#define END_ARGUMENT_CONDITION }},
525#define RETURN_VALUE_CONDITION(condition_kind) \
526 { Ret, condition_kind, {
527#define END_RETURN_VALUE_CONDITION }},
528#define ARG_NO(x) x##U
529#define RANGE(x, y) { x, y },
530#define SINGLE_VALUE(x) RANGE(x, x)
531#define IS_LESS_THAN(arg) { BO_LE, arg }
532
533 FunctionSummaryMap = {
534 // The isascii() family of functions.
535 SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
536 INVALIDATION_APPROACH(EvalCallAsPure))
537 CASE // Boils down to isupper() or islower() or isdigit()
538 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
539 RANGE('0', '9')
540 RANGE('A', 'Z')
541 RANGE('a', 'z')
542 END_ARGUMENT_CONDITION
543 RETURN_VALUE_CONDITION(OutOfRange)
544 SINGLE_VALUE(0)
545 END_RETURN_VALUE_CONDITION
546 END_CASE
547 CASE // The locale-specific range.
548 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
549 RANGE(128, 255)
550 END_ARGUMENT_CONDITION
551 // No post-condition. We are completely unaware of
552 // locale-specific return values.
553 END_CASE
554 CASE
555 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
556 RANGE('0', '9')
557 RANGE('A', 'Z')
558 RANGE('a', 'z')
559 RANGE(128, 255)
560 END_ARGUMENT_CONDITION
561 RETURN_VALUE_CONDITION(WithinRange)
562 SINGLE_VALUE(0)
563 END_RETURN_VALUE_CONDITION
564 END_CASE
565 END_SUMMARY
566 SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
567 INVALIDATION_APPROACH(EvalCallAsPure))
568 CASE // isupper() or islower(). Note that 'Z' is less than 'a'.
569 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
570 RANGE('A', 'Z')
571 RANGE('a', 'z')
572 END_ARGUMENT_CONDITION
573 RETURN_VALUE_CONDITION(OutOfRange)
574 SINGLE_VALUE(0)
575 END_RETURN_VALUE_CONDITION
576 END_CASE
577 CASE // The locale-specific range.
578 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
579 RANGE(128, 255)
580 END_ARGUMENT_CONDITION
581 END_CASE
582 CASE // Other.
583 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
584 RANGE('A', 'Z')
585 RANGE('a', 'z')
586 RANGE(128, 255)
587 END_ARGUMENT_CONDITION
588 RETURN_VALUE_CONDITION(WithinRange)
589 SINGLE_VALUE(0)
590 END_RETURN_VALUE_CONDITION
591 END_CASE
592 END_SUMMARY
593 SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
594 INVALIDATION_APPROACH(EvalCallAsPure))
595 CASE // Is ASCII.
596 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
597 RANGE(0, 127)
598 END_ARGUMENT_CONDITION
599 RETURN_VALUE_CONDITION(OutOfRange)
600 SINGLE_VALUE(0)
601 END_RETURN_VALUE_CONDITION
602 END_CASE
603 CASE
604 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
605 RANGE(0, 127)
606 END_ARGUMENT_CONDITION
607 RETURN_VALUE_CONDITION(WithinRange)
608 SINGLE_VALUE(0)
609 END_RETURN_VALUE_CONDITION
610 END_CASE
611 END_SUMMARY
612 SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
613 INVALIDATION_APPROACH(EvalCallAsPure))
614 CASE
615 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
616 SINGLE_VALUE('\t')
617 SINGLE_VALUE(' ')
618 END_ARGUMENT_CONDITION
619 RETURN_VALUE_CONDITION(OutOfRange)
620 SINGLE_VALUE(0)
621 END_RETURN_VALUE_CONDITION
622 END_CASE
623 CASE
624 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
625 SINGLE_VALUE('\t')
626 SINGLE_VALUE(' ')
627 END_ARGUMENT_CONDITION
628 RETURN_VALUE_CONDITION(WithinRange)
629 SINGLE_VALUE(0)
630 END_RETURN_VALUE_CONDITION
631 END_CASE
632 END_SUMMARY
633 SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
634 INVALIDATION_APPROACH(EvalCallAsPure))
635 CASE // 0..31 or 127
636 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
637 RANGE(0, 32)
638 SINGLE_VALUE(127)
639 END_ARGUMENT_CONDITION
640 RETURN_VALUE_CONDITION(OutOfRange)
641 SINGLE_VALUE(0)
642 END_RETURN_VALUE_CONDITION
643 END_CASE
644 CASE
645 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
646 RANGE(0, 32)
647 SINGLE_VALUE(127)
648 END_ARGUMENT_CONDITION
649 RETURN_VALUE_CONDITION(WithinRange)
650 SINGLE_VALUE(0)
651 END_RETURN_VALUE_CONDITION
652 END_CASE
653 END_SUMMARY
654 SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
655 INVALIDATION_APPROACH(EvalCallAsPure))
656 CASE // Is a digit.
657 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
658 RANGE('0', '9')
659 END_ARGUMENT_CONDITION
660 RETURN_VALUE_CONDITION(OutOfRange)
661 SINGLE_VALUE(0)
662 END_RETURN_VALUE_CONDITION
663 END_CASE
664 CASE
665 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
666 RANGE('0', '9')
667 END_ARGUMENT_CONDITION
668 RETURN_VALUE_CONDITION(WithinRange)
669 SINGLE_VALUE(0)
670 END_RETURN_VALUE_CONDITION
671 END_CASE
672 END_SUMMARY
673 SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
674 INVALIDATION_APPROACH(EvalCallAsPure))
675 CASE
676 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
677 RANGE(33, 126)
678 END_ARGUMENT_CONDITION
679 RETURN_VALUE_CONDITION(OutOfRange)
680 SINGLE_VALUE(0)
681 END_RETURN_VALUE_CONDITION
682 END_CASE
683 CASE
684 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
685 RANGE(33, 126)
686 END_ARGUMENT_CONDITION
687 RETURN_VALUE_CONDITION(WithinRange)
688 SINGLE_VALUE(0)
689 END_RETURN_VALUE_CONDITION
690 END_CASE
691 END_SUMMARY
692 SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
693 INVALIDATION_APPROACH(EvalCallAsPure))
694 CASE // Is certainly lowercase.
695 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
696 RANGE('a', 'z')
697 END_ARGUMENT_CONDITION
698 RETURN_VALUE_CONDITION(OutOfRange)
699 SINGLE_VALUE(0)
700 END_RETURN_VALUE_CONDITION
701 END_CASE
702 CASE // Is ascii but not lowercase.
703 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
704 RANGE(0, 127)
705 END_ARGUMENT_CONDITION
706 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
707 RANGE('a', 'z')
708 END_ARGUMENT_CONDITION
709 RETURN_VALUE_CONDITION(WithinRange)
710 SINGLE_VALUE(0)
711 END_RETURN_VALUE_CONDITION
712 END_CASE
713 CASE // The locale-specific range.
714 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
715 RANGE(128, 255)
716 END_ARGUMENT_CONDITION
717 END_CASE
718 CASE // Is not an unsigned char.
719 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
720 RANGE(0, 255)
721 END_ARGUMENT_CONDITION
722 RETURN_VALUE_CONDITION(WithinRange)
723 SINGLE_VALUE(0)
724 END_RETURN_VALUE_CONDITION
725 END_CASE
726 END_SUMMARY
727 SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
728 INVALIDATION_APPROACH(EvalCallAsPure))
729 CASE
730 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
731 RANGE(32, 126)
732 END_ARGUMENT_CONDITION
733 RETURN_VALUE_CONDITION(OutOfRange)
734 SINGLE_VALUE(0)
735 END_RETURN_VALUE_CONDITION
736 END_CASE
737 CASE
738 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
739 RANGE(32, 126)
740 END_ARGUMENT_CONDITION
741 RETURN_VALUE_CONDITION(WithinRange)
742 SINGLE_VALUE(0)
743 END_RETURN_VALUE_CONDITION
744 END_CASE
745 END_SUMMARY
746 SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
747 INVALIDATION_APPROACH(EvalCallAsPure))
748 CASE
749 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
750 RANGE('!', '/')
751 RANGE(':', '@')
752 RANGE('[', '`')
753 RANGE('{', '~')
754 END_ARGUMENT_CONDITION
755 RETURN_VALUE_CONDITION(OutOfRange)
756 SINGLE_VALUE(0)
757 END_RETURN_VALUE_CONDITION
758 END_CASE
759 CASE
760 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
761 RANGE('!', '/')
762 RANGE(':', '@')
763 RANGE('[', '`')
764 RANGE('{', '~')
765 END_ARGUMENT_CONDITION
766 RETURN_VALUE_CONDITION(WithinRange)
767 SINGLE_VALUE(0)
768 END_RETURN_VALUE_CONDITION
769 END_CASE
770 END_SUMMARY
771 SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
772 INVALIDATION_APPROACH(EvalCallAsPure))
773 CASE // Space, '\f', '\n', '\r', '\t', '\v'.
774 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
775 RANGE(9, 13)
776 SINGLE_VALUE(' ')
777 END_ARGUMENT_CONDITION
778 RETURN_VALUE_CONDITION(OutOfRange)
779 SINGLE_VALUE(0)
780 END_RETURN_VALUE_CONDITION
781 END_CASE
782 CASE // The locale-specific range.
783 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
784 RANGE(128, 255)
785 END_ARGUMENT_CONDITION
786 END_CASE
787 CASE
788 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
789 RANGE(9, 13)
790 SINGLE_VALUE(' ')
791 RANGE(128, 255)
792 END_ARGUMENT_CONDITION
793 RETURN_VALUE_CONDITION(WithinRange)
794 SINGLE_VALUE(0)
795 END_RETURN_VALUE_CONDITION
796 END_CASE
797 END_SUMMARY
798 SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy),
799 INVALIDATION_APPROACH(EvalCallAsPure))
800 CASE // Is certainly uppercase.
801 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
802 RANGE('A', 'Z')
803 END_ARGUMENT_CONDITION
804 RETURN_VALUE_CONDITION(OutOfRange)
805 SINGLE_VALUE(0)
806 END_RETURN_VALUE_CONDITION
807 END_CASE
808 CASE // The locale-specific range.
809 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
810 RANGE(128, 255)
811 END_ARGUMENT_CONDITION
812 END_CASE
813 CASE // Other.
814 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
815 RANGE('A', 'Z') 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(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
823 INVALIDATION_APPROACH(EvalCallAsPure))
824 CASE
825 ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
826 RANGE('0', '9')
827 RANGE('A', 'F')
828 RANGE('a', 'f')
829 END_ARGUMENT_CONDITION
830 RETURN_VALUE_CONDITION(OutOfRange)
831 SINGLE_VALUE(0)
832 END_RETURN_VALUE_CONDITION
833 END_CASE
834 CASE
835 ARGUMENT_CONDITION(ARG_NO(0), OutOfRange)
836 RANGE('0', '9')
837 RANGE('A', 'F')
838 RANGE('a', 'f')
839 END_ARGUMENT_CONDITION
840 RETURN_VALUE_CONDITION(WithinRange)
841 SINGLE_VALUE(0)
842 END_RETURN_VALUE_CONDITION
843 END_CASE
844 END_SUMMARY
845
846 // The getc() family of functions that returns either a char or an EOF.
847 SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
848 INVALIDATION_APPROACH(NoEvalCall))
849 CASE // FIXME: EOF is assumed to be defined as -1.
850 RETURN_VALUE_CONDITION(WithinRange)
851 RANGE(-1, 255)
852 END_RETURN_VALUE_CONDITION
853 END_CASE
854 END_SUMMARY
855 SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
856 INVALIDATION_APPROACH(NoEvalCall))
857 CASE // FIXME: EOF is assumed to be defined as -1.
858 RETURN_VALUE_CONDITION(WithinRange)
859 RANGE(-1, 255)
860 END_RETURN_VALUE_CONDITION
861 END_CASE
862 END_SUMMARY
863 SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy),
864 INVALIDATION_APPROACH(NoEvalCall))
865 CASE // FIXME: EOF is assumed to be defined as -1.
866 RETURN_VALUE_CONDITION(WithinRange)
867 RANGE(-1, 255)
868 END_RETURN_VALUE_CONDITION
869 END_CASE
870 END_SUMMARY
871
872 // read()-like functions that never return more than buffer size.
873 SUMMARY(read, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
874 RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall))
875 CASE
876 RETURN_VALUE_CONDITION(ComparesToArgument)
877 IS_LESS_THAN(ARG_NO(2))
878 END_RETURN_VALUE_CONDITION
879 RETURN_VALUE_CONDITION(WithinRange)
880 RANGE(-1, SSizeMax)
881 END_RETURN_VALUE_CONDITION
882 END_CASE
883 END_SUMMARY
884 SUMMARY(write, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
885 RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall))
886 CASE
887 RETURN_VALUE_CONDITION(ComparesToArgument)
888 IS_LESS_THAN(ARG_NO(2))
889 END_RETURN_VALUE_CONDITION
890 RETURN_VALUE_CONDITION(WithinRange)
891 RANGE(-1, SSizeMax)
892 END_RETURN_VALUE_CONDITION
893 END_CASE
894 END_SUMMARY
895 SUMMARY(fread,
896 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
897 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
898 CASE
899 RETURN_VALUE_CONDITION(ComparesToArgument)
900 IS_LESS_THAN(ARG_NO(2))
901 END_RETURN_VALUE_CONDITION
902 END_CASE
903 END_SUMMARY
904 SUMMARY(fwrite,
905 ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
906 RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
907 CASE
908 RETURN_VALUE_CONDITION(ComparesToArgument)
909 IS_LESS_THAN(ARG_NO(2))
910 END_RETURN_VALUE_CONDITION
911 END_CASE
912 END_SUMMARY
913
914 // getline()-like functions either fail or read at least the delimiter.
915 SUMMARY(getline, ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
916 RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall))
917 CASE
918 RETURN_VALUE_CONDITION(WithinRange)
919 SINGLE_VALUE(-1)
920 RANGE(1, SSizeMax)
921 END_RETURN_VALUE_CONDITION
922 END_CASE
923 END_SUMMARY
924 SUMMARY(getdelim,
925 ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
926 RETURN_TYPE(SSizeTy), INVALIDATION_APPROACH(NoEvalCall))
927 CASE
928 RETURN_VALUE_CONDITION(WithinRange)
929 SINGLE_VALUE(-1)
930 RANGE(1, SSizeMax)
931 END_RETURN_VALUE_CONDITION
932 END_CASE
933 END_SUMMARY
934 };
935}
936
937void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
938 // If this checker grows large enough to support C++, Objective-C, or other
939 // standard libraries, we could use multiple register...Checker() functions,
940 // which would register various checkers with the help of the same Checker
941 // class, turning on different function summaries.
942 mgr.registerChecker<StdLibraryFunctionsChecker>();
943}