clang 18.0.0git
StdLibraryFunctionsChecker.cpp
Go to the documentation of this file.
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//
11// This checker provides a specification format - `Summary' - and
12// contains descriptions of some library functions in this format. Each
13// specification contains a list of branches for splitting the program state
14// upon call, and range constraints on argument and return-value symbols that
15// are satisfied on each branch. This spec can be expanded to include more
16// items, like external effects of the function.
17//
18// The main difference between this approach and the body farms technique is
19// in more explicit control over how many branches are produced. For example,
20// consider standard C function `ispunct(int x)', which returns a non-zero value
21// iff `x' is a punctuation character, that is, when `x' is in range
22// ['!', '/'] [':', '@'] U ['[', '\`'] U ['{', '~'].
23// `Summary' provides only two branches for this function. However,
24// any attempt to describe this range with if-statements in the body farm
25// would result in many more branches. Because each branch needs to be analyzed
26// independently, this significantly reduces performance. Additionally,
27// once we consider a branch on which `x' is in range, say, ['!', '/'],
28// we assume that such branch is an important separate path through the program,
29// which may lead to false positives because considering this particular path
30// was not consciously intended, and therefore it might have been unreachable.
31//
32// This checker uses eval::Call for modeling pure functions (functions without
33// side effets), for which their `Summary' is a precise model. This avoids
34// unnecessary invalidation passes. Conflicts with other checkers are unlikely
35// because if the function has no other effects, other checkers would probably
36// never want to improve upon the modeling done by this checker.
37//
38// Non-pure functions, for which only partial improvement over the default
39// behavior is expected, are modeled via check::PostCall, non-intrusively.
40//
41//===----------------------------------------------------------------------===//
42
43#include "ErrnoModeling.h"
52#include "llvm/ADT/STLExtras.h"
53#include "llvm/ADT/SmallString.h"
54#include "llvm/ADT/StringExtras.h"
55#include "llvm/Support/FormatVariadic.h"
56
57#include <optional>
58#include <string>
59
60using namespace clang;
61using namespace clang::ento;
62
63namespace {
64class StdLibraryFunctionsChecker
65 : public Checker<check::PreCall, check::PostCall, eval::Call> {
66
67 class Summary;
68
69 /// Specify how much the analyzer engine should entrust modeling this function
70 /// to us.
71 enum InvalidationKind {
72 /// No \c eval::Call for the function, it can be modeled elsewhere.
73 /// This checker checks only pre and post conditions.
74 NoEvalCall,
75 /// The function is modeled completely in this checker.
76 EvalCallAsPure
77 };
78
79 /// Given a range, should the argument stay inside or outside this range?
80 enum RangeKind { OutOfRange, WithinRange };
81
82 static RangeKind negateKind(RangeKind K) {
83 switch (K) {
84 case OutOfRange:
85 return WithinRange;
86 case WithinRange:
87 return OutOfRange;
88 }
89 llvm_unreachable("Unknown range kind");
90 }
91
92 /// The universal integral type to use in value range descriptions.
93 /// Unsigned to make sure overflows are well-defined.
94 typedef uint64_t RangeInt;
95
96 /// Describes a single range constraint. Eg. {{0, 1}, {3, 4}} is
97 /// a non-negative integer, which less than 5 and not equal to 2.
98 typedef std::vector<std::pair<RangeInt, RangeInt>> IntRangeVector;
99
100 /// A reference to an argument or return value by its number.
101 /// ArgNo in CallExpr and CallEvent is defined as Unsigned, but
102 /// obviously uint32_t should be enough for all practical purposes.
103 typedef uint32_t ArgNo;
104 /// Special argument number for specifying the return value.
105 static const ArgNo Ret;
106
107 /// Get a string representation of an argument index.
108 /// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
109 static void printArgDesc(ArgNo, llvm::raw_ostream &Out);
110 /// Print value X of the argument in form " (which is X)",
111 /// if the value is a fixed known value, otherwise print nothing.
112 /// This is used as simple explanation of values if possible.
113 static void printArgValueInfo(ArgNo ArgN, ProgramStateRef State,
114 const CallEvent &Call, llvm::raw_ostream &Out);
115 /// Append textual description of a numeric range [RMin,RMax] to
116 /// \p Out.
117 static void appendInsideRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
118 QualType ArgT, BasicValueFactory &BVF,
119 llvm::raw_ostream &Out);
120 /// Append textual description of a numeric range out of [RMin,RMax] to
121 /// \p Out.
122 static void appendOutOfRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
123 QualType ArgT, BasicValueFactory &BVF,
124 llvm::raw_ostream &Out);
125
126 class ValueConstraint;
127
128 /// Pointer to the ValueConstraint. We need a copyable, polymorphic and
129 /// default initializable type (vector needs that). A raw pointer was good,
130 /// however, we cannot default initialize that. unique_ptr makes the Summary
131 /// class non-copyable, therefore not an option. Releasing the copyability
132 /// requirement would render the initialization of the Summary map infeasible.
133 /// Mind that a pointer to a new value constraint is created when the negate
134 /// function is used.
135 using ValueConstraintPtr = std::shared_ptr<ValueConstraint>;
136
137 /// Polymorphic base class that represents a constraint on a given argument
138 /// (or return value) of a function. Derived classes implement different kind
139 /// of constraints, e.g range constraints or correlation between two
140 /// arguments.
141 /// These are used as argument constraints (preconditions) of functions, in
142 /// which case a bug report may be emitted if the constraint is not satisfied.
143 /// Another use is as conditions for summary cases, to create different
144 /// classes of behavior for a function. In this case no description of the
145 /// constraint is needed because the summary cases have an own (not generated)
146 /// description string.
147 class ValueConstraint {
148 public:
149 ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
150 virtual ~ValueConstraint() {}
151
152 /// Apply the effects of the constraint on the given program state. If null
153 /// is returned then the constraint is not feasible.
154 virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
155 const Summary &Summary,
156 CheckerContext &C) const = 0;
157
158 /// Represents that in which context do we require a description of the
159 /// constraint.
160 enum DescriptionKind {
161 /// Describe a constraint that was violated.
162 /// Description should start with something like "should be".
163 Violation,
164 /// Describe a constraint that was assumed to be true.
165 /// This can be used when a precondition is satisfied, or when a summary
166 /// case is applied.
167 /// Description should start with something like "is".
168 Assumption
169 };
170
171 /// Give a description that explains the constraint to the user. Used when
172 /// a bug is reported or when the constraint is applied and displayed as a
173 /// note. The description should not mention the argument (getArgNo).
174 /// See StdLibraryFunctionsChecker::reportBug about how this function is
175 /// used (this function is used not only there).
176 virtual void describe(DescriptionKind DK, const CallEvent &Call,
177 ProgramStateRef State, const Summary &Summary,
178 llvm::raw_ostream &Out) const {
179 // There are some descendant classes that are not used as argument
180 // constraints, e.g. ComparisonConstraint. In that case we can safely
181 // ignore the implementation of this function.
182 llvm_unreachable(
183 "Description not implemented for summary case constraints");
184 }
185
186 /// Give a description that explains the actual argument value (where the
187 /// current ValueConstraint applies to) to the user. This function should be
188 /// called only when the current constraint is satisfied by the argument.
189 /// It should produce a more precise description than the constraint itself.
190 /// The actual value of the argument and the program state can be used to
191 /// make the description more precise. In the most simple case, if the
192 /// argument has a fixed known value this value can be printed into \p Out,
193 /// this is done by default.
194 /// The function should return true if a description was printed to \p Out,
195 /// otherwise false.
196 /// See StdLibraryFunctionsChecker::reportBug about how this function is
197 /// used.
198 virtual bool describeArgumentValue(const CallEvent &Call,
199 ProgramStateRef State,
200 const Summary &Summary,
201 llvm::raw_ostream &Out) const {
202 if (auto N = getArgSVal(Call, getArgNo()).getAs<NonLoc>()) {
203 if (const llvm::APSInt *Int = N->getAsInteger()) {
204 Out << *Int;
205 return true;
206 }
207 }
208 return false;
209 }
210
211 /// Return those arguments that should be tracked when we report a bug about
212 /// argument constraint violation. By default it is the argument that is
213 /// constrained, however, in some special cases we need to track other
214 /// arguments as well. E.g. a buffer size might be encoded in another
215 /// argument.
216 /// The "return value" argument number can not occur as returned value.
217 virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }
218
219 /// Get a constraint that represents exactly the opposite of the current.
220 virtual ValueConstraintPtr negate() const {
221 llvm_unreachable("Not implemented");
222 };
223
224 /// Check whether the constraint is malformed or not. It is malformed if the
225 /// specified argument has a mismatch with the given FunctionDecl (e.g. the
226 /// arg number is out-of-range of the function's argument list).
227 /// This condition can indicate if a probably wrong or unexpected function
228 /// was found where the constraint is to be applied.
229 bool checkValidity(const FunctionDecl *FD) const {
230 const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
231 assert(ValidArg && "Arg out of range!");
232 if (!ValidArg)
233 return false;
234 // Subclasses may further refine the validation.
235 return checkSpecificValidity(FD);
236 }
237
238 /// Return the argument number (may be placeholder for "return value").
239 ArgNo getArgNo() const { return ArgN; }
240
241 protected:
242 /// Argument to which to apply the constraint. It can be a real argument of
243 /// the function to check, or a special value to indicate the return value
244 /// of the function.
245 /// Every constraint is assigned to one main argument, even if other
246 /// arguments are involved.
247 ArgNo ArgN;
248
249 /// Do constraint-specific validation check.
250 virtual bool checkSpecificValidity(const FunctionDecl *FD) const {
251 return true;
252 }
253 };
254
255 /// Check if a single argument falls into a specific "range".
256 /// A range is formed as a set of intervals.
257 /// E.g. \code {['A', 'Z'], ['a', 'z'], ['_', '_']} \endcode
258 /// The intervals are closed intervals that contain one or more values.
259 ///
260 /// The default constructed RangeConstraint has an empty range, applying
261 /// such constraint does not involve any assumptions, thus the State remains
262 /// unchanged. This is meaningful, if the range is dependent on a looked up
263 /// type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
264 /// is default initialized to be empty.
265 class RangeConstraint : public ValueConstraint {
266 /// The constraint can be specified by allowing or disallowing the range.
267 /// WithinRange indicates allowing the range, OutOfRange indicates
268 /// disallowing it (allowing the complementary range).
269 RangeKind Kind;
270
271 /// A set of intervals.
272 IntRangeVector Ranges;
273
274 /// A textual description of this constraint for the specific case where the
275 /// constraint is used. If empty a generated description will be used that
276 /// is built from the range of the constraint.
277 StringRef Description;
278
279 public:
280 RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges,
281 StringRef Desc = "")
282 : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges), Description(Desc) {
283 }
284
285 const IntRangeVector &getRanges() const { return Ranges; }
286
287 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
288 const Summary &Summary,
289 CheckerContext &C) const override;
290
291 void describe(DescriptionKind DK, const CallEvent &Call,
292 ProgramStateRef State, const Summary &Summary,
293 llvm::raw_ostream &Out) const override;
294
295 bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
296 const Summary &Summary,
297 llvm::raw_ostream &Out) const override;
298
299 ValueConstraintPtr negate() const override {
300 RangeConstraint Tmp(*this);
301 Tmp.Kind = negateKind(Kind);
302 return std::make_shared<RangeConstraint>(Tmp);
303 }
304
305 protected:
306 bool checkSpecificValidity(const FunctionDecl *FD) const override {
307 const bool ValidArg =
308 getArgType(FD, ArgN)->isIntegralType(FD->getASTContext());
309 assert(ValidArg &&
310 "This constraint should be applied on an integral type");
311 return ValidArg;
312 }
313
314 private:
315 /// A callback function that is used when iterating over the range
316 /// intervals. It gets the begin and end (inclusive) of one interval.
317 /// This is used to make any kind of task possible that needs an iteration
318 /// over the intervals.
319 using RangeApplyFunction =
320 std::function<bool(const llvm::APSInt &Min, const llvm::APSInt &Max)>;
321
322 /// Call a function on the intervals of the range.
323 /// The function is called with all intervals in the range.
324 void applyOnWithinRange(BasicValueFactory &BVF, QualType ArgT,
325 const RangeApplyFunction &F) const;
326 /// Call a function on all intervals in the complementary range.
327 /// The function is called with all intervals that fall out of the range.
328 /// E.g. consider an interval list [A, B] and [C, D]
329 /// \code
330 /// -------+--------+------------------+------------+----------->
331 /// A B C D
332 /// \endcode
333 /// We get the ranges [-inf, A - 1], [D + 1, +inf], [B + 1, C - 1].
334 /// The \p ArgT is used to determine the min and max of the type that is
335 /// used as "-inf" and "+inf".
336 void applyOnOutOfRange(BasicValueFactory &BVF, QualType ArgT,
337 const RangeApplyFunction &F) const;
338 /// Call a function on the intervals of the range or the complementary
339 /// range.
340 void applyOnRange(RangeKind Kind, BasicValueFactory &BVF, QualType ArgT,
341 const RangeApplyFunction &F) const {
342 switch (Kind) {
343 case OutOfRange:
344 applyOnOutOfRange(BVF, ArgT, F);
345 break;
346 case WithinRange:
347 applyOnWithinRange(BVF, ArgT, F);
348 break;
349 };
350 }
351 };
352
353 /// Check relation of an argument to another.
354 class ComparisonConstraint : public ValueConstraint {
356 ArgNo OtherArgN;
357
358 public:
359 ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
360 ArgNo OtherArgN)
361 : ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}
362 ArgNo getOtherArgNo() const { return OtherArgN; }
363 BinaryOperator::Opcode getOpcode() const { return Opcode; }
364 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
365 const Summary &Summary,
366 CheckerContext &C) const override;
367 };
368
369 /// Check null or non-null-ness of an argument that is of pointer type.
370 class NotNullConstraint : public ValueConstraint {
371 using ValueConstraint::ValueConstraint;
372 // This variable has a role when we negate the constraint.
373 bool CannotBeNull = true;
374
375 public:
376 NotNullConstraint(ArgNo ArgN, bool CannotBeNull = true)
377 : ValueConstraint(ArgN), CannotBeNull(CannotBeNull) {}
378
379 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
380 const Summary &Summary,
381 CheckerContext &C) const override;
382
383 void describe(DescriptionKind DK, const CallEvent &Call,
384 ProgramStateRef State, const Summary &Summary,
385 llvm::raw_ostream &Out) const override;
386
387 bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
388 const Summary &Summary,
389 llvm::raw_ostream &Out) const override;
390
391 ValueConstraintPtr negate() const override {
392 NotNullConstraint Tmp(*this);
393 Tmp.CannotBeNull = !this->CannotBeNull;
394 return std::make_shared<NotNullConstraint>(Tmp);
395 }
396
397 protected:
398 bool checkSpecificValidity(const FunctionDecl *FD) const override {
399 const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
400 assert(ValidArg &&
401 "This constraint should be applied only on a pointer type");
402 return ValidArg;
403 }
404 };
405
406 /// Check null or non-null-ness of an argument that is of pointer type.
407 /// The argument is meant to be a buffer that has a size constraint, and it
408 /// is allowed to have a NULL value if the size is 0. The size can depend on
409 /// 1 or 2 additional arguments, if one of these is 0 the buffer is allowed to
410 /// be NULL. This is useful for functions like `fread` which have this special
411 /// property.
412 class NotNullBufferConstraint : public ValueConstraint {
413 using ValueConstraint::ValueConstraint;
414 ArgNo SizeArg1N;
415 std::optional<ArgNo> SizeArg2N;
416 // This variable has a role when we negate the constraint.
417 bool CannotBeNull = true;
418
419 public:
420 NotNullBufferConstraint(ArgNo ArgN, ArgNo SizeArg1N,
421 std::optional<ArgNo> SizeArg2N,
422 bool CannotBeNull = true)
423 : ValueConstraint(ArgN), SizeArg1N(SizeArg1N), SizeArg2N(SizeArg2N),
424 CannotBeNull(CannotBeNull) {}
425
426 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
427 const Summary &Summary,
428 CheckerContext &C) const override;
429
430 void describe(DescriptionKind DK, const CallEvent &Call,
431 ProgramStateRef State, const Summary &Summary,
432 llvm::raw_ostream &Out) const override;
433
434 bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
435 const Summary &Summary,
436 llvm::raw_ostream &Out) const override;
437
438 ValueConstraintPtr negate() const override {
439 NotNullBufferConstraint Tmp(*this);
440 Tmp.CannotBeNull = !this->CannotBeNull;
441 return std::make_shared<NotNullBufferConstraint>(Tmp);
442 }
443
444 protected:
445 bool checkSpecificValidity(const FunctionDecl *FD) const override {
446 const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
447 assert(ValidArg &&
448 "This constraint should be applied only on a pointer type");
449 return ValidArg;
450 }
451 };
452
453 // Represents a buffer argument with an additional size constraint. The
454 // constraint may be a concrete value, or a symbolic value in an argument.
455 // Example 1. Concrete value as the minimum buffer size.
456 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
457 // // `buf` size must be at least 26 bytes according the POSIX standard.
458 // Example 2. Argument as a buffer size.
459 // ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
460 // Example 3. The size is computed as a multiplication of other args.
461 // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
462 // // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
463 class BufferSizeConstraint : public ValueConstraint {
464 // The concrete value which is the minimum size for the buffer.
465 std::optional<llvm::APSInt> ConcreteSize;
466 // The argument which holds the size of the buffer.
467 std::optional<ArgNo> SizeArgN;
468 // The argument which is a multiplier to size. This is set in case of
469 // `fread` like functions where the size is computed as a multiplication of
470 // two arguments.
471 std::optional<ArgNo> SizeMultiplierArgN;
472 // The operator we use in apply. This is negated in negate().
473 BinaryOperator::Opcode Op = BO_LE;
474
475 public:
476 BufferSizeConstraint(ArgNo Buffer, llvm::APSInt BufMinSize)
477 : ValueConstraint(Buffer), ConcreteSize(BufMinSize) {}
478 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
479 : ValueConstraint(Buffer), SizeArgN(BufSize) {}
480 BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
481 : ValueConstraint(Buffer), SizeArgN(BufSize),
482 SizeMultiplierArgN(BufSizeMultiplier) {}
483
484 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
485 const Summary &Summary,
486 CheckerContext &C) const override;
487
488 void describe(DescriptionKind DK, const CallEvent &Call,
489 ProgramStateRef State, const Summary &Summary,
490 llvm::raw_ostream &Out) const override;
491
492 bool describeArgumentValue(const CallEvent &Call, ProgramStateRef State,
493 const Summary &Summary,
494 llvm::raw_ostream &Out) const override;
495
496 std::vector<ArgNo> getArgsToTrack() const override {
497 std::vector<ArgNo> Result{ArgN};
498 if (SizeArgN)
499 Result.push_back(*SizeArgN);
500 if (SizeMultiplierArgN)
501 Result.push_back(*SizeMultiplierArgN);
502 return Result;
503 }
504
505 ValueConstraintPtr negate() const override {
506 BufferSizeConstraint Tmp(*this);
508 return std::make_shared<BufferSizeConstraint>(Tmp);
509 }
510
511 protected:
512 bool checkSpecificValidity(const FunctionDecl *FD) const override {
513 const bool ValidArg = getArgType(FD, ArgN)->isPointerType();
514 assert(ValidArg &&
515 "This constraint should be applied only on a pointer type");
516 return ValidArg;
517 }
518 };
519
520 /// The complete list of constraints that defines a single branch.
521 using ConstraintSet = std::vector<ValueConstraintPtr>;
522
523 /// Define how a function affects the system variable 'errno'.
524 /// This works together with the \c ErrnoModeling and \c ErrnoChecker classes.
525 /// Currently 3 use cases exist: success, failure, irrelevant.
526 /// In the future the failure case can be customized to set \c errno to a
527 /// more specific constraint (for example > 0), or new case can be added
528 /// for functions which require check of \c errno in both success and failure
529 /// case.
530 class ErrnoConstraintBase {
531 public:
532 /// Apply specific state changes related to the errno variable.
533 virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
534 const Summary &Summary,
535 CheckerContext &C) const = 0;
536 /// Get a description about what happens with 'errno' here and how it causes
537 /// a later bug report created by ErrnoChecker.
538 /// Empty return value means that 'errno' related bug may not happen from
539 /// the current analyzed function.
540 virtual const std::string describe(CheckerContext &C) const { return ""; }
541
542 virtual ~ErrnoConstraintBase() {}
543
544 protected:
545 ErrnoConstraintBase() = default;
546
547 /// This is used for conjure symbol for errno to differentiate from the
548 /// original call expression (same expression is used for the errno symbol).
549 static int Tag;
550 };
551
552 /// Reset errno constraints to irrelevant.
553 /// This is applicable to functions that may change 'errno' and are not
554 /// modeled elsewhere.
555 class ResetErrnoConstraint : public ErrnoConstraintBase {
556 public:
557 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
558 const Summary &Summary,
559 CheckerContext &C) const override {
561 }
562 };
563
564 /// Do not change errno constraints.
565 /// This is applicable to functions that are modeled in another checker
566 /// and the already set errno constraints should not be changed in the
567 /// post-call event.
568 class NoErrnoConstraint : public ErrnoConstraintBase {
569 public:
570 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
571 const Summary &Summary,
572 CheckerContext &C) const override {
573 return State;
574 }
575 };
576
577 /// Set errno constraint at failure cases of standard functions.
578 /// Failure case: 'errno' becomes not equal to 0 and may or may not be checked
579 /// by the program. \c ErrnoChecker does not emit a bug report after such a
580 /// function call.
581 class FailureErrnoConstraint : public ErrnoConstraintBase {
582 public:
583 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
584 const Summary &Summary,
585 CheckerContext &C) const override {
586 SValBuilder &SVB = C.getSValBuilder();
587 NonLoc ErrnoSVal =
588 SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(),
589 C.getLocationContext(), C.getASTContext().IntTy,
590 C.blockCount())
591 .castAs<NonLoc>();
592 return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);
593 }
594 };
595
596 /// Set errno constraint at success cases of standard functions.
597 /// Success case: 'errno' is not allowed to be used because the value is
598 /// undefined after successful call.
599 /// \c ErrnoChecker can emit bug report after such a function call if errno
600 /// is used.
601 class SuccessErrnoConstraint : public ErrnoConstraintBase {
602 public:
603 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
604 const Summary &Summary,
605 CheckerContext &C) const override {
607 }
608
609 const std::string describe(CheckerContext &C) const override {
610 return "'errno' becomes undefined after the call";
611 }
612 };
613
614 /// Set errno constraint at functions that indicate failure only with 'errno'.
615 /// In this case 'errno' is required to be observed.
616 /// \c ErrnoChecker can emit bug report after such a function call if errno
617 /// is overwritten without a read before.
618 class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {
619 public:
620 ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
621 const Summary &Summary,
622 CheckerContext &C) const override {
624 Call.getOriginExpr());
625 }
626
627 const std::string describe(CheckerContext &C) const override {
628 return "reading 'errno' is required to find out if the call has failed";
629 }
630 };
631
632 /// A single branch of a function summary.
633 ///
634 /// A branch is defined by a series of constraints - "assumptions" -
635 /// that together form a single possible outcome of invoking the function.
636 /// When static analyzer considers a branch, it tries to introduce
637 /// a child node in the Exploded Graph. The child node has to include
638 /// constraints that define the branch. If the constraints contradict
639 /// existing constraints in the state, the node is not created and the branch
640 /// is dropped; otherwise it's queued for future exploration.
641 /// The branch is accompanied by a note text that may be displayed
642 /// to the user when a bug is found on a path that takes this branch.
643 ///
644 /// For example, consider the branches in `isalpha(x)`:
645 /// Branch 1)
646 /// x is in range ['A', 'Z'] or in ['a', 'z']
647 /// then the return value is not 0. (I.e. out-of-range [0, 0])
648 /// and the note may say "Assuming the character is alphabetical"
649 /// Branch 2)
650 /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
651 /// then the return value is 0
652 /// and the note may say "Assuming the character is non-alphabetical".
653 class SummaryCase {
654 ConstraintSet Constraints;
655 const ErrnoConstraintBase &ErrnoConstraint;
656 StringRef Note;
657
658 public:
659 SummaryCase(ConstraintSet &&Constraints, const ErrnoConstraintBase &ErrnoC,
660 StringRef Note)
661 : Constraints(std::move(Constraints)), ErrnoConstraint(ErrnoC),
662 Note(Note) {}
663
664 SummaryCase(const ConstraintSet &Constraints,
665 const ErrnoConstraintBase &ErrnoC, StringRef Note)
666 : Constraints(Constraints), ErrnoConstraint(ErrnoC), Note(Note) {}
667
668 const ConstraintSet &getConstraints() const { return Constraints; }
669 const ErrnoConstraintBase &getErrnoConstraint() const {
670 return ErrnoConstraint;
671 }
672 StringRef getNote() const { return Note; }
673 };
674
675 using ArgTypes = std::vector<std::optional<QualType>>;
676 using RetType = std::optional<QualType>;
677
678 // A placeholder type, we use it whenever we do not care about the concrete
679 // type in a Signature.
680 const QualType Irrelevant{};
681 bool static isIrrelevant(QualType T) { return T.isNull(); }
682
683 // The signature of a function we want to describe with a summary. This is a
684 // concessive signature, meaning there may be irrelevant types in the
685 // signature which we do not check against a function with concrete types.
686 // All types in the spec need to be canonical.
687 class Signature {
688 using ArgQualTypes = std::vector<QualType>;
689 ArgQualTypes ArgTys;
690 QualType RetTy;
691 // True if any component type is not found by lookup.
692 bool Invalid = false;
693
694 public:
695 // Construct a signature from optional types. If any of the optional types
696 // are not set then the signature will be invalid.
697 Signature(ArgTypes ArgTys, RetType RetTy) {
698 for (std::optional<QualType> Arg : ArgTys) {
699 if (!Arg) {
700 Invalid = true;
701 return;
702 } else {
703 assertArgTypeSuitableForSignature(*Arg);
704 this->ArgTys.push_back(*Arg);
705 }
706 }
707 if (!RetTy) {
708 Invalid = true;
709 return;
710 } else {
711 assertRetTypeSuitableForSignature(*RetTy);
712 this->RetTy = *RetTy;
713 }
714 }
715
716 bool isInvalid() const { return Invalid; }
717 bool matches(const FunctionDecl *FD) const;
718
719 private:
720 static void assertArgTypeSuitableForSignature(QualType T) {
721 assert((T.isNull() || !T->isVoidType()) &&
722 "We should have no void types in the spec");
723 assert((T.isNull() || T.isCanonical()) &&
724 "We should only have canonical types in the spec");
725 }
726 static void assertRetTypeSuitableForSignature(QualType T) {
727 assert((T.isNull() || T.isCanonical()) &&
728 "We should only have canonical types in the spec");
729 }
730 };
731
732 static QualType getArgType(const FunctionDecl *FD, ArgNo ArgN) {
733 assert(FD && "Function must be set");
734 QualType T = (ArgN == Ret)
736 : FD->getParamDecl(ArgN)->getType().getCanonicalType();
737 return T;
738 }
739
740 using SummaryCases = std::vector<SummaryCase>;
741
742 /// A summary includes information about
743 /// * function prototype (signature)
744 /// * approach to invalidation,
745 /// * a list of branches - so, a list of list of ranges,
746 /// * a list of argument constraints, that must be true on every branch.
747 /// If these constraints are not satisfied that means a fatal error
748 /// usually resulting in undefined behaviour.
749 ///
750 /// Application of a summary:
751 /// The signature and argument constraints together contain information
752 /// about which functions are handled by the summary. The signature can use
753 /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
754 /// a signature means that type is not compared to the type of the parameter
755 /// in the found FunctionDecl. Argument constraints may specify additional
756 /// rules for the given parameter's type, those rules are checked once the
757 /// signature is matched.
758 class Summary {
759 const InvalidationKind InvalidationKd;
760 SummaryCases Cases;
761 ConstraintSet ArgConstraints;
762
763 // The function to which the summary applies. This is set after lookup and
764 // match to the signature.
765 const FunctionDecl *FD = nullptr;
766
767 public:
768 Summary(InvalidationKind InvalidationKd) : InvalidationKd(InvalidationKd) {}
769
770 Summary &Case(ConstraintSet &&CS, const ErrnoConstraintBase &ErrnoC,
771 StringRef Note = "") {
772 Cases.push_back(SummaryCase(std::move(CS), ErrnoC, Note));
773 return *this;
774 }
775 Summary &Case(const ConstraintSet &CS, const ErrnoConstraintBase &ErrnoC,
776 StringRef Note = "") {
777 Cases.push_back(SummaryCase(CS, ErrnoC, Note));
778 return *this;
779 }
780 Summary &ArgConstraint(ValueConstraintPtr VC) {
781 assert(VC->getArgNo() != Ret &&
782 "Arg constraint should not refer to the return value");
783 ArgConstraints.push_back(VC);
784 return *this;
785 }
786
787 InvalidationKind getInvalidationKd() const { return InvalidationKd; }
788 const SummaryCases &getCases() const { return Cases; }
789 const ConstraintSet &getArgConstraints() const { return ArgConstraints; }
790
791 QualType getArgType(ArgNo ArgN) const {
792 return StdLibraryFunctionsChecker::getArgType(FD, ArgN);
793 }
794
795 // Returns true if the summary should be applied to the given function.
796 // And if yes then store the function declaration.
797 bool matchesAndSet(const Signature &Sign, const FunctionDecl *FD) {
798 bool Result = Sign.matches(FD) && validateByConstraints(FD);
799 if (Result) {
800 assert(!this->FD && "FD must not be set more than once");
801 this->FD = FD;
802 }
803 return Result;
804 }
805
806 private:
807 // Once we know the exact type of the function then do validation check on
808 // all the given constraints.
809 bool validateByConstraints(const FunctionDecl *FD) const {
810 for (const SummaryCase &Case : Cases)
811 for (const ValueConstraintPtr &Constraint : Case.getConstraints())
812 if (!Constraint->checkValidity(FD))
813 return false;
814 for (const ValueConstraintPtr &Constraint : ArgConstraints)
815 if (!Constraint->checkValidity(FD))
816 return false;
817 return true;
818 }
819 };
820
821 // The map of all functions supported by the checker. It is initialized
822 // lazily, and it doesn't change after initialization.
823 using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
824 mutable FunctionSummaryMapType FunctionSummaryMap;
825
826 mutable std::unique_ptr<BugType> BT_InvalidArg;
827 mutable bool SummariesInitialized = false;
828
829 static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
830 return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
831 }
832 static std::string getFunctionName(const CallEvent &Call) {
833 assert(Call.getDecl() &&
834 "Call was found by a summary, should have declaration");
835 return cast<NamedDecl>(Call.getDecl())->getNameAsString();
836 }
837
838public:
839 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
840 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
841 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
842
843 CheckerNameRef CheckName;
844 bool AddTestFunctions = false;
845
846 bool DisplayLoadedSummaries = false;
847 bool ModelPOSIX = false;
848 bool ShouldAssumeControlledEnvironment = false;
849
850private:
851 std::optional<Summary> findFunctionSummary(const FunctionDecl *FD,
852 CheckerContext &C) const;
853 std::optional<Summary> findFunctionSummary(const CallEvent &Call,
854 CheckerContext &C) const;
855
856 void initFunctionSummaries(CheckerContext &C) const;
857
858 void reportBug(const CallEvent &Call, ExplodedNode *N,
859 const ValueConstraint *VC, const ValueConstraint *NegatedVC,
860 const Summary &Summary, CheckerContext &C) const {
861 assert(Call.getDecl() &&
862 "Function found in summary must have a declaration available");
864 llvm::raw_svector_ostream MsgOs(Msg);
865
866 MsgOs << "The ";
867 printArgDesc(VC->getArgNo(), MsgOs);
868 MsgOs << " to '" << getFunctionName(Call) << "' ";
869 bool ValuesPrinted =
870 NegatedVC->describeArgumentValue(Call, N->getState(), Summary, MsgOs);
871 if (ValuesPrinted)
872 MsgOs << " but ";
873 else
874 MsgOs << "is out of the accepted range; It ";
875 VC->describe(ValueConstraint::Violation, Call, C.getState(), Summary,
876 MsgOs);
877 Msg[0] = toupper(Msg[0]);
878 if (!BT_InvalidArg)
879 BT_InvalidArg = std::make_unique<BugType>(
880 CheckName, "Function call with invalid argument",
882 auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
883
884 for (ArgNo ArgN : VC->getArgsToTrack()) {
885 bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
886 R->markInteresting(Call.getArgSVal(ArgN));
887 // All tracked arguments are important, highlight them.
888 R->addRange(Call.getArgSourceRange(ArgN));
889 }
890
891 C.emitReport(std::move(R));
892 }
893
894 /// These are the errno constraints that can be passed to summary cases.
895 /// One of these should fit for a single summary case.
896 /// Usually if a failure return value exists for function, that function
897 /// needs different cases for success and failure with different errno
898 /// constraints (and different return value constraints).
899 const NoErrnoConstraint ErrnoUnchanged{};
900 const ResetErrnoConstraint ErrnoIrrelevant{};
901 const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};
902 const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
903 const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
904};
905
906int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
907
908const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
909 std::numeric_limits<ArgNo>::max();
910
911static BasicValueFactory &getBVF(ProgramStateRef State) {
912 ProgramStateManager &Mgr = State->getStateManager();
913 SValBuilder &SVB = Mgr.getSValBuilder();
914 return SVB.getBasicValueFactory();
915}
916
917} // end of anonymous namespace
918
919void StdLibraryFunctionsChecker::printArgDesc(
920 StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {
921 Out << std::to_string(ArgN + 1);
922 Out << llvm::getOrdinalSuffix(ArgN + 1);
923 Out << " argument";
924}
925
926void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN,
927 ProgramStateRef State,
928 const CallEvent &Call,
929 llvm::raw_ostream &Out) {
930 if (const llvm::APSInt *Val =
931 State->getStateManager().getSValBuilder().getKnownValue(
932 State, getArgSVal(Call, ArgN)))
933 Out << " (which is " << *Val << ")";
934}
935
936void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
937 llvm::APSInt RMax,
938 QualType ArgT,
940 llvm::raw_ostream &Out) {
941 if (RMin.isZero() && RMax.isZero())
942 Out << "zero";
943 else if (RMin == RMax)
944 Out << RMin;
945 else if (RMin == BVF.getMinValue(ArgT)) {
946 if (RMax == -1)
947 Out << "< 0";
948 else
949 Out << "<= " << RMax;
950 } else if (RMax == BVF.getMaxValue(ArgT)) {
951 if (RMin.isOne())
952 Out << "> 0";
953 else
954 Out << ">= " << RMin;
955 } else if (RMin.isNegative() == RMax.isNegative() &&
956 RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
957 Out << RMin << " or " << RMax;
958 } else {
959 Out << "between " << RMin << " and " << RMax;
960 }
961}
962
963void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
964 llvm::APSInt RMax,
965 QualType ArgT,
967 llvm::raw_ostream &Out) {
968 if (RMin.isZero() && RMax.isZero())
969 Out << "nonzero";
970 else if (RMin == RMax) {
971 Out << "not equal to " << RMin;
972 } else if (RMin == BVF.getMinValue(ArgT)) {
973 if (RMax == -1)
974 Out << ">= 0";
975 else
976 Out << "> " << RMax;
977 } else if (RMax == BVF.getMaxValue(ArgT)) {
978 if (RMin.isOne())
979 Out << "<= 0";
980 else
981 Out << "< " << RMin;
982 } else if (RMin.isNegative() == RMax.isNegative() &&
983 RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
984 Out << "not " << RMin << " and not " << RMax;
985 } else {
986 Out << "not between " << RMin << " and " << RMax;
987 }
988}
989
990void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(
991 BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
992 if (Ranges.empty())
993 return;
994
995 for (auto [Start, End] : getRanges()) {
996 const llvm::APSInt &Min = BVF.getValue(Start, ArgT);
997 const llvm::APSInt &Max = BVF.getValue(End, ArgT);
998 assert(Min <= Max);
999 if (!F(Min, Max))
1000 return;
1001 }
1002}
1003
1004void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(
1005 BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
1006 if (Ranges.empty())
1007 return;
1008
1009 const IntRangeVector &R = getRanges();
1010 size_t E = R.size();
1011
1012 const llvm::APSInt &MinusInf = BVF.getMinValue(ArgT);
1013 const llvm::APSInt &PlusInf = BVF.getMaxValue(ArgT);
1014
1015 const llvm::APSInt &RangeLeft = BVF.getValue(R[0].first - 1ULL, ArgT);
1016 const llvm::APSInt &RangeRight = BVF.getValue(R[E - 1].second + 1ULL, ArgT);
1017
1018 // Iterate over the "holes" between intervals.
1019 for (size_t I = 1; I != E; ++I) {
1020 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, ArgT);
1021 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, ArgT);
1022 if (Min <= Max) {
1023 if (!F(Min, Max))
1024 return;
1025 }
1026 }
1027 // Check the interval [T_MIN, min(R) - 1].
1028 if (RangeLeft != PlusInf) {
1029 assert(MinusInf <= RangeLeft);
1030 if (!F(MinusInf, RangeLeft))
1031 return;
1032 }
1033 // Check the interval [max(R) + 1, T_MAX],
1034 if (RangeRight != MinusInf) {
1035 assert(RangeRight <= PlusInf);
1036 if (!F(RangeRight, PlusInf))
1037 return;
1038 }
1039}
1040
1041ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::apply(
1042 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1043 CheckerContext &C) const {
1044 ConstraintManager &CM = C.getConstraintManager();
1045 SVal V = getArgSVal(Call, getArgNo());
1046 QualType T = Summary.getArgType(getArgNo());
1047
1048 if (auto N = V.getAs<NonLoc>()) {
1049 auto ExcludeRangeFromArg = [&](const llvm::APSInt &Min,
1050 const llvm::APSInt &Max) {
1051 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
1052 return static_cast<bool>(State);
1053 };
1054 // "OutOfRange R" is handled by excluding all ranges in R.
1055 // "WithinRange R" is treated as "OutOfRange [T_MIN, T_MAX] \ R".
1056 applyOnRange(negateKind(Kind), C.getSValBuilder().getBasicValueFactory(), T,
1057 ExcludeRangeFromArg);
1058 }
1059
1060 return State;
1061}
1062
1063void StdLibraryFunctionsChecker::RangeConstraint::describe(
1064 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1065 const Summary &Summary, llvm::raw_ostream &Out) const {
1066
1067 BasicValueFactory &BVF = getBVF(State);
1068 QualType T = Summary.getArgType(getArgNo());
1069
1070 Out << ((DK == Violation) ? "should be " : "is ");
1071 if (!Description.empty()) {
1072 Out << Description;
1073 } else {
1074 unsigned I = Ranges.size();
1075 if (Kind == WithinRange) {
1076 for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1077 appendInsideRangeDesc(BVF.getValue(R.first, T),
1078 BVF.getValue(R.second, T), T, BVF, Out);
1079 if (--I > 0)
1080 Out << " or ";
1081 }
1082 } else {
1083 for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1084 appendOutOfRangeDesc(BVF.getValue(R.first, T),
1085 BVF.getValue(R.second, T), T, BVF, Out);
1086 if (--I > 0)
1087 Out << " and ";
1088 }
1089 }
1090 }
1091}
1092
1093bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(
1094 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1095 llvm::raw_ostream &Out) const {
1096 unsigned int NRanges = 0;
1097 bool HaveAllRanges = true;
1098
1099 ProgramStateManager &Mgr = State->getStateManager();
1102 SVal V = getArgSVal(Call, getArgNo());
1103
1104 if (auto N = V.getAs<NonLoc>()) {
1105 if (const llvm::APSInt *Int = N->getAsInteger()) {
1106 Out << "is ";
1107 Out << *Int;
1108 return true;
1109 }
1110 QualType T = Summary.getArgType(getArgNo());
1111 SmallString<128> MoreInfo;
1112 llvm::raw_svector_ostream MoreInfoOs(MoreInfo);
1113 auto ApplyF = [&](const llvm::APSInt &Min, const llvm::APSInt &Max) {
1114 if (CM.assumeInclusiveRange(State, *N, Min, Max, true)) {
1115 if (NRanges > 0)
1116 MoreInfoOs << " or ";
1117 appendInsideRangeDesc(Min, Max, T, BVF, MoreInfoOs);
1118 ++NRanges;
1119 } else {
1120 HaveAllRanges = false;
1121 }
1122 return true;
1123 };
1124
1125 applyOnRange(Kind, BVF, T, ApplyF);
1126 assert(NRanges > 0);
1127 if (!HaveAllRanges || NRanges == 1) {
1128 Out << "is ";
1129 Out << MoreInfo;
1130 return true;
1131 }
1132 }
1133 return false;
1134}
1135
1136ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
1137 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1138 CheckerContext &C) const {
1139
1140 ProgramStateManager &Mgr = State->getStateManager();
1141 SValBuilder &SVB = Mgr.getSValBuilder();
1142 QualType CondT = SVB.getConditionType();
1143 QualType T = Summary.getArgType(getArgNo());
1144 SVal V = getArgSVal(Call, getArgNo());
1145
1146 BinaryOperator::Opcode Op = getOpcode();
1147 ArgNo OtherArg = getOtherArgNo();
1148 SVal OtherV = getArgSVal(Call, OtherArg);
1149 QualType OtherT = Summary.getArgType(OtherArg);
1150 // Note: we avoid integral promotion for comparison.
1151 OtherV = SVB.evalCast(OtherV, T, OtherT);
1152 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
1154 State = State->assume(*CompV, true);
1155 return State;
1156}
1157
1158ProgramStateRef StdLibraryFunctionsChecker::NotNullConstraint::apply(
1159 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1160 CheckerContext &C) const {
1161 SVal V = getArgSVal(Call, getArgNo());
1162 if (V.isUndef())
1163 return State;
1164
1166 if (!isa<Loc>(L))
1167 return State;
1168
1169 return State->assume(L, CannotBeNull);
1170}
1171
1172void StdLibraryFunctionsChecker::NotNullConstraint::describe(
1173 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1174 const Summary &Summary, llvm::raw_ostream &Out) const {
1175 assert(CannotBeNull &&
1176 "Describe should not be used when the value must be NULL");
1177 if (DK == Violation)
1178 Out << "should not be NULL";
1179 else
1180 Out << "is not NULL";
1181}
1182
1183bool StdLibraryFunctionsChecker::NotNullConstraint::describeArgumentValue(
1184 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1185 llvm::raw_ostream &Out) const {
1186 assert(!CannotBeNull && "This function is used when the value is NULL");
1187 Out << "is NULL";
1188 return true;
1189}
1190
1191ProgramStateRef StdLibraryFunctionsChecker::NotNullBufferConstraint::apply(
1192 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1193 CheckerContext &C) const {
1194 SVal V = getArgSVal(Call, getArgNo());
1195 if (V.isUndef())
1196 return State;
1198 if (!isa<Loc>(L))
1199 return State;
1200
1201 std::optional<DefinedOrUnknownSVal> SizeArg1 =
1202 getArgSVal(Call, SizeArg1N).getAs<DefinedOrUnknownSVal>();
1203 std::optional<DefinedOrUnknownSVal> SizeArg2;
1204 if (SizeArg2N)
1205 SizeArg2 = getArgSVal(Call, *SizeArg2N).getAs<DefinedOrUnknownSVal>();
1206
1207 auto IsArgZero = [State](std::optional<DefinedOrUnknownSVal> Val) {
1208 if (!Val)
1209 return false;
1210 auto [IsNonNull, IsNull] = State->assume(*Val);
1211 return IsNull && !IsNonNull;
1212 };
1213
1214 if (IsArgZero(SizeArg1) || IsArgZero(SizeArg2))
1215 return State;
1216
1217 return State->assume(L, CannotBeNull);
1218}
1219
1220void StdLibraryFunctionsChecker::NotNullBufferConstraint::describe(
1221 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1222 const Summary &Summary, llvm::raw_ostream &Out) const {
1223 assert(CannotBeNull &&
1224 "Describe should not be used when the value must be NULL");
1225 if (DK == Violation)
1226 Out << "should not be NULL";
1227 else
1228 Out << "is not NULL";
1229}
1230
1231bool StdLibraryFunctionsChecker::NotNullBufferConstraint::describeArgumentValue(
1232 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1233 llvm::raw_ostream &Out) const {
1234 assert(!CannotBeNull && "This function is used when the value is NULL");
1235 Out << "is NULL";
1236 return true;
1237}
1238
1239ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
1240 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1241 CheckerContext &C) const {
1242 SValBuilder &SvalBuilder = C.getSValBuilder();
1243 // The buffer argument.
1244 SVal BufV = getArgSVal(Call, getArgNo());
1245
1246 // Get the size constraint.
1247 const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
1248 if (ConcreteSize) {
1249 return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
1250 }
1251 assert(SizeArgN && "The constraint must be either a concrete value or "
1252 "encoded in an argument.");
1253 // The size argument.
1254 SVal SizeV = getArgSVal(Call, *SizeArgN);
1255 // Multiply with another argument if given.
1256 if (SizeMultiplierArgN) {
1257 SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
1258 SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
1259 Summary.getArgType(*SizeArgN));
1260 }
1261 return SizeV;
1262 }();
1263
1264 // The dynamic size of the buffer argument, got from the analyzer engine.
1265 SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1266
1267 SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
1268 SvalBuilder.getContext().BoolTy);
1269 if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
1270 return State->assume(*F, true);
1271
1272 // We can get here only if the size argument or the dynamic size is
1273 // undefined. But the dynamic size should never be undefined, only
1274 // unknown. So, here, the size of the argument is undefined, i.e. we
1275 // cannot apply the constraint. Actually, other checkers like
1276 // CallAndMessage should catch this situation earlier, because we call a
1277 // function with an uninitialized argument.
1278 llvm_unreachable("Size argument or the dynamic size is Undefined");
1279}
1280
1281void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
1282 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1283 const Summary &Summary, llvm::raw_ostream &Out) const {
1284 Out << ((DK == Violation) ? "should be " : "is ");
1285 Out << "a buffer with size equal to or greater than ";
1286 if (ConcreteSize) {
1287 Out << *ConcreteSize;
1288 } else if (SizeArgN) {
1289 Out << "the value of the ";
1290 printArgDesc(*SizeArgN, Out);
1291 printArgValueInfo(*SizeArgN, State, Call, Out);
1292 if (SizeMultiplierArgN) {
1293 Out << " times the ";
1294 printArgDesc(*SizeMultiplierArgN, Out);
1295 printArgValueInfo(*SizeMultiplierArgN, State, Call, Out);
1296 }
1297 }
1298}
1299
1300bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(
1301 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1302 llvm::raw_ostream &Out) const {
1303 SVal BufV = getArgSVal(Call, getArgNo());
1304 SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1305 if (const llvm::APSInt *Val =
1306 State->getStateManager().getSValBuilder().getKnownValue(State,
1307 BufDynSize)) {
1308 Out << "is a buffer with size " << *Val;
1309 return true;
1310 }
1311 return false;
1312}
1313
1314void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
1315 CheckerContext &C) const {
1316 std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1317 if (!FoundSummary)
1318 return;
1319
1320 const Summary &Summary = *FoundSummary;
1321 ProgramStateRef State = C.getState();
1322
1323 ProgramStateRef NewState = State;
1324 ExplodedNode *NewNode = C.getPredecessor();
1325 for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
1326 ValueConstraintPtr NegatedConstraint = Constraint->negate();
1327 ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
1328 ProgramStateRef FailureSt =
1329 NegatedConstraint->apply(NewState, Call, Summary, C);
1330 // The argument constraint is not satisfied.
1331 if (FailureSt && !SuccessSt) {
1332 if (ExplodedNode *N = C.generateErrorNode(State, NewNode))
1333 reportBug(Call, N, Constraint.get(), NegatedConstraint.get(), Summary,
1334 C);
1335 break;
1336 }
1337 // We will apply the constraint even if we cannot reason about the
1338 // argument. This means both SuccessSt and FailureSt can be true. If we
1339 // weren't applying the constraint that would mean that symbolic
1340 // execution continues on a code whose behaviour is undefined.
1341 assert(SuccessSt);
1342 NewState = SuccessSt;
1343 if (NewState != State) {
1344 SmallString<128> Msg;
1345 llvm::raw_svector_ostream Os(Msg);
1346 Os << "Assuming that the ";
1347 printArgDesc(Constraint->getArgNo(), Os);
1348 Os << " to '";
1349 Os << getFunctionName(Call);
1350 Os << "' ";
1351 Constraint->describe(ValueConstraint::Assumption, Call, NewState, Summary,
1352 Os);
1353 const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
1354 NewNode = C.addTransition(
1355 NewState, NewNode,
1356 C.getNoteTag([Msg = std::move(Msg), ArgSVal](
1357 PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
1358 if (BR.isInteresting(ArgSVal))
1359 OS << Msg;
1360 }));
1361 }
1362 }
1363}
1364
1365void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
1366 CheckerContext &C) const {
1367 std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1368 if (!FoundSummary)
1369 return;
1370
1371 // Now apply the constraints.
1372 const Summary &Summary = *FoundSummary;
1373 ProgramStateRef State = C.getState();
1374 ExplodedNode *Node = C.getPredecessor();
1375
1376 // Apply case/branch specifications.
1377 for (const SummaryCase &Case : Summary.getCases()) {
1378 ProgramStateRef NewState = State;
1379 for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {
1380 NewState = Constraint->apply(NewState, Call, Summary, C);
1381 if (!NewState)
1382 break;
1383 }
1384
1385 if (NewState)
1386 NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);
1387
1388 if (!NewState)
1389 continue;
1390
1391 // Here it's possible that NewState == State, e.g. when other checkers
1392 // already applied the same constraints (or stricter ones).
1393 // Still add these note tags, the other checker should add only its
1394 // specialized note tags. These general note tags are handled always by
1395 // StdLibraryFunctionsChecker.
1396
1397 ExplodedNode *Pred = Node;
1398 DeclarationName FunctionName =
1399 cast<NamedDecl>(Call.getDecl())->getDeclName();
1400
1401 std::string ErrnoNote = Case.getErrnoConstraint().describe(C);
1402 std::string CaseNote;
1403 if (Case.getNote().empty()) {
1404 if (!ErrnoNote.empty())
1405 ErrnoNote =
1406 llvm::formatv("After calling '{0}' {1}", FunctionName, ErrnoNote);
1407 } else {
1408 CaseNote = llvm::formatv(Case.getNote().str().c_str(), FunctionName);
1409 }
1410 const SVal RV = Call.getReturnValue();
1411
1412 if (Summary.getInvalidationKd() == EvalCallAsPure) {
1413 // Do not expect that errno is interesting (the "pure" functions do not
1414 // affect it).
1415 if (!CaseNote.empty()) {
1416 const NoteTag *Tag = C.getNoteTag(
1417 [Node, CaseNote, RV](PathSensitiveBugReport &BR) -> std::string {
1418 // Try to omit the note if we know in advance which branch is
1419 // taken (this means, only one branch exists).
1420 // This check is performed inside the lambda, after other
1421 // (or this) checkers had a chance to add other successors.
1422 // Dereferencing the saved node object is valid because it's part
1423 // of a bug report call sequence.
1424 // FIXME: This check is not exact. We may be here after a state
1425 // split that was performed by another checker (and can not find
1426 // the successors). This is why this check is only used in the
1427 // EvalCallAsPure case.
1428 if (BR.isInteresting(RV) && Node->succ_size() > 1)
1429 return CaseNote;
1430 return "";
1431 });
1432 Pred = C.addTransition(NewState, Pred, Tag);
1433 }
1434 } else {
1435 if (!CaseNote.empty() || !ErrnoNote.empty()) {
1436 const NoteTag *Tag =
1437 C.getNoteTag([CaseNote, ErrnoNote,
1438 RV](PathSensitiveBugReport &BR) -> std::string {
1439 // If 'errno' is interesting, show the user a note about the case
1440 // (what happened at the function call) and about how 'errno'
1441 // causes the problem. ErrnoChecker sets the errno (but not RV) to
1442 // interesting.
1443 // If only the return value is interesting, show only the case
1444 // note.
1445 std::optional<Loc> ErrnoLoc =
1447 bool ErrnoImportant = !ErrnoNote.empty() && ErrnoLoc &&
1448 BR.isInteresting(ErrnoLoc->getAsRegion());
1449 if (ErrnoImportant) {
1450 BR.markNotInteresting(ErrnoLoc->getAsRegion());
1451 if (CaseNote.empty())
1452 return ErrnoNote;
1453 return llvm::formatv("{0}; {1}", CaseNote, ErrnoNote);
1454 } else {
1455 if (BR.isInteresting(RV))
1456 return CaseNote;
1457 }
1458 return "";
1459 });
1460 Pred = C.addTransition(NewState, Pred, Tag);
1461 }
1462 }
1463
1464 // Add the transition if no note tag was added.
1465 if (Pred == Node && NewState != State)
1466 C.addTransition(NewState);
1467 }
1468}
1469
1470bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
1471 CheckerContext &C) const {
1472 std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1473 if (!FoundSummary)
1474 return false;
1475
1476 const Summary &Summary = *FoundSummary;
1477 switch (Summary.getInvalidationKd()) {
1478 case EvalCallAsPure: {
1479 ProgramStateRef State = C.getState();
1480 const LocationContext *LC = C.getLocationContext();
1481 const auto *CE = cast<CallExpr>(Call.getOriginExpr());
1482 SVal V = C.getSValBuilder().conjureSymbolVal(
1483 CE, LC, CE->getType().getCanonicalType(), C.blockCount());
1484 State = State->BindExpr(CE, LC, V);
1485
1486 C.addTransition(State);
1487
1488 return true;
1489 }
1490 case NoEvalCall:
1491 // Summary tells us to avoid performing eval::Call. The function is possibly
1492 // evaluated by another checker, or evaluated conservatively.
1493 return false;
1494 }
1495 llvm_unreachable("Unknown invalidation kind!");
1496}
1497
1498bool StdLibraryFunctionsChecker::Signature::matches(
1499 const FunctionDecl *FD) const {
1500 assert(!isInvalid());
1501 // Check the number of arguments.
1502 if (FD->param_size() != ArgTys.size())
1503 return false;
1504
1505 // The "restrict" keyword is illegal in C++, however, many libc
1506 // implementations use the "__restrict" compiler intrinsic in functions
1507 // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1508 // even in C++.
1509 // In case of any non-C99 languages, we don't want to match based on the
1510 // restrict qualifier because we cannot know if the given libc implementation
1511 // qualifies the paramter type or not.
1512 auto RemoveRestrict = [&FD](QualType T) {
1513 if (!FD->getASTContext().getLangOpts().C99)
1515 return T;
1516 };
1517
1518 // Check the return type.
1519 if (!isIrrelevant(RetTy)) {
1520 QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1521 if (RetTy != FDRetTy)
1522 return false;
1523 }
1524
1525 // Check the argument types.
1526 for (auto [Idx, ArgTy] : llvm::enumerate(ArgTys)) {
1527 if (isIrrelevant(ArgTy))
1528 continue;
1529 QualType FDArgTy =
1530 RemoveRestrict(FD->getParamDecl(Idx)->getType().getCanonicalType());
1531 if (ArgTy != FDArgTy)
1532 return false;
1533 }
1534
1535 return true;
1536}
1537
1538std::optional<StdLibraryFunctionsChecker::Summary>
1539StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
1540 CheckerContext &C) const {
1541 if (!FD)
1542 return std::nullopt;
1543
1544 initFunctionSummaries(C);
1545
1546 auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
1547 if (FSMI == FunctionSummaryMap.end())
1548 return std::nullopt;
1549 return FSMI->second;
1550}
1551
1552std::optional<StdLibraryFunctionsChecker::Summary>
1553StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
1554 CheckerContext &C) const {
1555 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
1556 if (!FD)
1557 return std::nullopt;
1558 return findFunctionSummary(FD, C);
1559}
1560
1561void StdLibraryFunctionsChecker::initFunctionSummaries(
1562 CheckerContext &C) const {
1563 if (SummariesInitialized)
1564 return;
1565 SummariesInitialized = true;
1566
1567 SValBuilder &SVB = C.getSValBuilder();
1569 const ASTContext &ACtx = BVF.getContext();
1570 Preprocessor &PP = C.getPreprocessor();
1571
1572 // Helper class to lookup a type by its name.
1573 class LookupType {
1574 const ASTContext &ACtx;
1575
1576 public:
1577 LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1578
1579 // Find the type. If not found then the optional is not set.
1580 std::optional<QualType> operator()(StringRef Name) {
1581 IdentifierInfo &II = ACtx.Idents.get(Name);
1582 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1583 if (LookupRes.empty())
1584 return std::nullopt;
1585
1586 // Prioritze typedef declarations.
1587 // This is needed in case of C struct typedefs. E.g.:
1588 // typedef struct FILE FILE;
1589 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1590 // and we have a TypedefDecl with the name 'FILE'.
1591 for (Decl *D : LookupRes)
1592 if (auto *TD = dyn_cast<TypedefNameDecl>(D))
1593 return ACtx.getTypeDeclType(TD).getCanonicalType();
1594
1595 // Find the first TypeDecl.
1596 // There maybe cases when a function has the same name as a struct.
1597 // E.g. in POSIX: `struct stat` and the function `stat()`:
1598 // int stat(const char *restrict path, struct stat *restrict buf);
1599 for (Decl *D : LookupRes)
1600 if (auto *TD = dyn_cast<TypeDecl>(D))
1601 return ACtx.getTypeDeclType(TD).getCanonicalType();
1602 return std::nullopt;
1603 }
1604 } lookupTy(ACtx);
1605
1606 // Below are auxiliary classes to handle optional types that we get as a
1607 // result of the lookup.
1608 class GetRestrictTy {
1609 const ASTContext &ACtx;
1610
1611 public:
1612 GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1613 QualType operator()(QualType Ty) {
1614 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
1615 }
1616 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1617 if (Ty)
1618 return operator()(*Ty);
1619 return std::nullopt;
1620 }
1621 } getRestrictTy(ACtx);
1622 class GetPointerTy {
1623 const ASTContext &ACtx;
1624
1625 public:
1626 GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1627 QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
1628 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1629 if (Ty)
1630 return operator()(*Ty);
1631 return std::nullopt;
1632 }
1633 } getPointerTy(ACtx);
1634 class {
1635 public:
1636 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1637 return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
1638 }
1639 QualType operator()(QualType Ty) { return Ty.withConst(); }
1640 } getConstTy;
1641 class GetMaxValue {
1642 BasicValueFactory &BVF;
1643
1644 public:
1645 GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1646 std::optional<RangeInt> operator()(QualType Ty) {
1647 return BVF.getMaxValue(Ty).getLimitedValue();
1648 }
1649 std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
1650 if (Ty) {
1651 return operator()(*Ty);
1652 }
1653 return std::nullopt;
1654 }
1655 } getMaxValue(BVF);
1656
1657 // These types are useful for writing specifications quickly,
1658 // New specifications should probably introduce more types.
1659 // Some types are hard to obtain from the AST, eg. "ssize_t".
1660 // In such cases it should be possible to provide multiple variants
1661 // of function summary for common cases (eg. ssize_t could be int or long
1662 // or long long, so three summary variants would be enough).
1663 // Of course, function variants are also useful for C++ overloads.
1664 const QualType VoidTy = ACtx.VoidTy;
1665 const QualType CharTy = ACtx.CharTy;
1666 const QualType WCharTy = ACtx.WCharTy;
1667 const QualType IntTy = ACtx.IntTy;
1668 const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
1669 const QualType LongTy = ACtx.LongTy;
1670 const QualType SizeTy = ACtx.getSizeType();
1671
1672 const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1673 const QualType IntPtrTy = getPointerTy(IntTy); // int *
1674 const QualType UnsignedIntPtrTy =
1675 getPointerTy(UnsignedIntTy); // unsigned int *
1676 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
1677 const QualType ConstVoidPtrTy =
1678 getPointerTy(getConstTy(VoidTy)); // const void *
1679 const QualType CharPtrTy = getPointerTy(CharTy); // char *
1680 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
1681 const QualType ConstCharPtrTy =
1682 getPointerTy(getConstTy(CharTy)); // const char *
1683 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1684 const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
1685 const QualType ConstWchar_tPtrTy =
1686 getPointerTy(getConstTy(WCharTy)); // const wchar_t *
1687 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1688 const QualType SizePtrTy = getPointerTy(SizeTy);
1689 const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
1690
1691 const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
1692 const RangeInt UnsignedIntMax =
1693 BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
1694 const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
1695 const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
1696
1697 // Set UCharRangeMax to min of int or uchar maximum value.
1698 // The C standard states that the arguments of functions like isalpha must
1699 // be representable as an unsigned char. Their type is 'int', so the max
1700 // value of the argument should be min(UCharMax, IntMax). This just happen
1701 // to be true for commonly used and well tested instruction set
1702 // architectures, but not for others.
1703 const RangeInt UCharRangeMax =
1704 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
1705
1706 // Get platform dependent values of some macros.
1707 // Try our best to parse this from the Preprocessor, otherwise fallback to a
1708 // default value (what is found in a library header).
1709 const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1);
1710 const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100);
1711
1712 // Auxiliary class to aid adding summaries to the summary map.
1713 struct AddToFunctionSummaryMap {
1714 const ASTContext &ACtx;
1715 FunctionSummaryMapType &Map;
1716 bool DisplayLoadedSummaries;
1717 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
1718 bool DisplayLoadedSummaries)
1719 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
1720 }
1721
1722 // Add a summary to a FunctionDecl found by lookup. The lookup is performed
1723 // by the given Name, and in the global scope. The summary will be attached
1724 // to the found FunctionDecl only if the signatures match.
1725 //
1726 // Returns true if the summary has been added, false otherwise.
1727 bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1728 if (Sign.isInvalid())
1729 return false;
1730 IdentifierInfo &II = ACtx.Idents.get(Name);
1731 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1732 if (LookupRes.empty())
1733 return false;
1734 for (Decl *D : LookupRes) {
1735 if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1736 if (Sum.matchesAndSet(Sign, FD)) {
1737 auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
1738 assert(Res.second && "Function already has a summary set!");
1739 (void)Res;
1740 if (DisplayLoadedSummaries) {
1741 llvm::errs() << "Loaded summary for: ";
1742 FD->print(llvm::errs());
1743 llvm::errs() << "\n";
1744 }
1745 return true;
1746 }
1747 }
1748 }
1749 return false;
1750 }
1751 // Add the same summary for different names with the Signature explicitly
1752 // given.
1753 void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
1754 for (StringRef Name : Names)
1755 operator()(Name, Sign, Sum);
1756 }
1757 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1758
1759 // Below are helpers functions to create the summaries.
1760 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
1761 StringRef Desc = "") {
1762 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);
1763 };
1764 auto BufferSize = [](auto... Args) {
1765 return std::make_shared<BufferSizeConstraint>(Args...);
1766 };
1767 struct {
1768 auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1769 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1770 }
1771 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1772 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1773 }
1774 } ReturnValueCondition;
1775 struct {
1776 auto operator()(RangeInt b, RangeInt e) {
1777 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1778 }
1779 auto operator()(RangeInt b, std::optional<RangeInt> e) {
1780 if (e)
1781 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1782 return IntRangeVector{};
1783 }
1784 auto operator()(std::pair<RangeInt, RangeInt> i0,
1785 std::pair<RangeInt, std::optional<RangeInt>> i1) {
1786 if (i1.second)
1787 return IntRangeVector{i0, {i1.first, *(i1.second)}};
1788 return IntRangeVector{i0};
1789 }
1790 } Range;
1791 auto SingleValue = [](RangeInt v) {
1792 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1793 };
1794 auto LessThanOrEq = BO_LE;
1795 auto NotNull = [&](ArgNo ArgN) {
1796 return std::make_shared<NotNullConstraint>(ArgN);
1797 };
1798 auto IsNull = [&](ArgNo ArgN) {
1799 return std::make_shared<NotNullConstraint>(ArgN, false);
1800 };
1801 auto NotNullBuffer = [&](ArgNo ArgN, ArgNo SizeArg1N, ArgNo SizeArg2N) {
1802 return std::make_shared<NotNullBufferConstraint>(ArgN, SizeArg1N,
1803 SizeArg2N);
1804 };
1805
1806 std::optional<QualType> FileTy = lookupTy("FILE");
1807 std::optional<QualType> FilePtrTy = getPointerTy(FileTy);
1808 std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1809
1810 std::optional<QualType> FPosTTy = lookupTy("fpos_t");
1811 std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);
1812 std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));
1813 std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);
1814
1815 constexpr llvm::StringLiteral GenericSuccessMsg(
1816 "Assuming that '{0}' is successful");
1817 constexpr llvm::StringLiteral GenericFailureMsg("Assuming that '{0}' fails");
1818
1819 // We are finally ready to define specifications for all supported functions.
1820 //
1821 // Argument ranges should always cover all variants. If return value
1822 // is completely unknown, omit it from the respective range set.
1823 //
1824 // Every item in the list of range sets represents a particular
1825 // execution path the analyzer would need to explore once
1826 // the call is modeled - a new program state is constructed
1827 // for every range set, and each range line in the range set
1828 // corresponds to a specific constraint within this state.
1829
1830 // The isascii() family of functions.
1831 // The behavior is undefined if the value of the argument is not
1832 // representable as unsigned char or is not equal to EOF. See e.g. C99
1833 // 7.4.1.2 The isalpha function (p: 181-182).
1834 addToFunctionSummaryMap(
1835 "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1836 Summary(EvalCallAsPure)
1837 // Boils down to isupper() or islower() or isdigit().
1838 .Case({ArgumentCondition(0U, WithinRange,
1839 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1840 ReturnValueCondition(OutOfRange, SingleValue(0))},
1841 ErrnoIrrelevant, "Assuming the character is alphanumeric")
1842 // The locale-specific range.
1843 // No post-condition. We are completely unaware of
1844 // locale-specific return values.
1845 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1846 ErrnoIrrelevant)
1847 .Case(
1848 {ArgumentCondition(
1849 0U, OutOfRange,
1850 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1851 ReturnValueCondition(WithinRange, SingleValue(0))},
1852 ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
1853 .ArgConstraint(ArgumentCondition(0U, WithinRange,
1854 {{EOFv, EOFv}, {0, UCharRangeMax}},
1855 "an unsigned char value or EOF")));
1856 addToFunctionSummaryMap(
1857 "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1858 Summary(EvalCallAsPure)
1859 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1860 ReturnValueCondition(OutOfRange, SingleValue(0))},
1861 ErrnoIrrelevant, "Assuming the character is alphabetical")
1862 // The locale-specific range.
1863 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1864 ErrnoIrrelevant)
1865 .Case({ArgumentCondition(
1866 0U, OutOfRange,
1867 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1868 ReturnValueCondition(WithinRange, SingleValue(0))},
1869 ErrnoIrrelevant, "Assuming the character is non-alphabetical"));
1870 addToFunctionSummaryMap(
1871 "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1872 Summary(EvalCallAsPure)
1873 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1874 ReturnValueCondition(OutOfRange, SingleValue(0))},
1875 ErrnoIrrelevant, "Assuming the character is an ASCII character")
1876 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1877 ReturnValueCondition(WithinRange, SingleValue(0))},
1878 ErrnoIrrelevant,
1879 "Assuming the character is not an ASCII character"));
1880 addToFunctionSummaryMap(
1881 "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1882 Summary(EvalCallAsPure)
1883 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1884 ReturnValueCondition(OutOfRange, SingleValue(0))},
1885 ErrnoIrrelevant, "Assuming the character is a blank character")
1886 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1887 ReturnValueCondition(WithinRange, SingleValue(0))},
1888 ErrnoIrrelevant,
1889 "Assuming the character is not a blank character"));
1890 addToFunctionSummaryMap(
1891 "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1892 Summary(EvalCallAsPure)
1893 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1894 ReturnValueCondition(OutOfRange, SingleValue(0))},
1895 ErrnoIrrelevant,
1896 "Assuming the character is a control character")
1897 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1898 ReturnValueCondition(WithinRange, SingleValue(0))},
1899 ErrnoIrrelevant,
1900 "Assuming the character is not a control character"));
1901 addToFunctionSummaryMap(
1902 "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1903 Summary(EvalCallAsPure)
1904 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1905 ReturnValueCondition(OutOfRange, SingleValue(0))},
1906 ErrnoIrrelevant, "Assuming the character is a digit")
1907 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1908 ReturnValueCondition(WithinRange, SingleValue(0))},
1909 ErrnoIrrelevant, "Assuming the character is not a digit"));
1910 addToFunctionSummaryMap(
1911 "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1912 Summary(EvalCallAsPure)
1913 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1914 ReturnValueCondition(OutOfRange, SingleValue(0))},
1915 ErrnoIrrelevant,
1916 "Assuming the character has graphical representation")
1917 .Case(
1918 {ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1919 ReturnValueCondition(WithinRange, SingleValue(0))},
1920 ErrnoIrrelevant,
1921 "Assuming the character does not have graphical representation"));
1922 addToFunctionSummaryMap(
1923 "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1924 Summary(EvalCallAsPure)
1925 // Is certainly lowercase.
1926 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1927 ReturnValueCondition(OutOfRange, SingleValue(0))},
1928 ErrnoIrrelevant, "Assuming the character is a lowercase letter")
1929 // Is ascii but not lowercase.
1930 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1931 ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1932 ReturnValueCondition(WithinRange, SingleValue(0))},
1933 ErrnoIrrelevant,
1934 "Assuming the character is not a lowercase letter")
1935 // The locale-specific range.
1936 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1937 ErrnoIrrelevant)
1938 // Is not an unsigned char.
1939 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1940 ReturnValueCondition(WithinRange, SingleValue(0))},
1941 ErrnoIrrelevant));
1942 addToFunctionSummaryMap(
1943 "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1944 Summary(EvalCallAsPure)
1945 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1946 ReturnValueCondition(OutOfRange, SingleValue(0))},
1947 ErrnoIrrelevant, "Assuming the character is printable")
1948 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1949 ReturnValueCondition(WithinRange, SingleValue(0))},
1950 ErrnoIrrelevant, "Assuming the character is non-printable"));
1951 addToFunctionSummaryMap(
1952 "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1953 Summary(EvalCallAsPure)
1954 .Case({ArgumentCondition(
1955 0U, WithinRange,
1956 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1957 ReturnValueCondition(OutOfRange, SingleValue(0))},
1958 ErrnoIrrelevant, "Assuming the character is a punctuation mark")
1959 .Case({ArgumentCondition(
1960 0U, OutOfRange,
1961 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1962 ReturnValueCondition(WithinRange, SingleValue(0))},
1963 ErrnoIrrelevant,
1964 "Assuming the character is not a punctuation mark"));
1965 addToFunctionSummaryMap(
1966 "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1967 Summary(EvalCallAsPure)
1968 // Space, '\f', '\n', '\r', '\t', '\v'.
1969 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1970 ReturnValueCondition(OutOfRange, SingleValue(0))},
1971 ErrnoIrrelevant,
1972 "Assuming the character is a whitespace character")
1973 // The locale-specific range.
1974 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1975 ErrnoIrrelevant)
1976 .Case({ArgumentCondition(0U, OutOfRange,
1977 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1978 ReturnValueCondition(WithinRange, SingleValue(0))},
1979 ErrnoIrrelevant,
1980 "Assuming the character is not a whitespace character"));
1981 addToFunctionSummaryMap(
1982 "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1983 Summary(EvalCallAsPure)
1984 // Is certainly uppercase.
1985 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1986 ReturnValueCondition(OutOfRange, SingleValue(0))},
1987 ErrnoIrrelevant,
1988 "Assuming the character is an uppercase letter")
1989 // The locale-specific range.
1990 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1991 ErrnoIrrelevant)
1992 // Other.
1993 .Case({ArgumentCondition(0U, OutOfRange,
1994 {{'A', 'Z'}, {128, UCharRangeMax}}),
1995 ReturnValueCondition(WithinRange, SingleValue(0))},
1996 ErrnoIrrelevant,
1997 "Assuming the character is not an uppercase letter"));
1998 addToFunctionSummaryMap(
1999 "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2000 Summary(EvalCallAsPure)
2001 .Case({ArgumentCondition(0U, WithinRange,
2002 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
2003 ReturnValueCondition(OutOfRange, SingleValue(0))},
2004 ErrnoIrrelevant,
2005 "Assuming the character is a hexadecimal digit")
2006 .Case({ArgumentCondition(0U, OutOfRange,
2007 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
2008 ReturnValueCondition(WithinRange, SingleValue(0))},
2009 ErrnoIrrelevant,
2010 "Assuming the character is not a hexadecimal digit"));
2011 addToFunctionSummaryMap(
2012 "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2013 Summary(EvalCallAsPure)
2014 .ArgConstraint(ArgumentCondition(0U, WithinRange,
2015 {{EOFv, EOFv}, {0, UCharRangeMax}},
2016 "an unsigned char value or EOF")));
2017 addToFunctionSummaryMap(
2018 "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2019 Summary(EvalCallAsPure)
2020 .ArgConstraint(ArgumentCondition(0U, WithinRange,
2021 {{EOFv, EOFv}, {0, UCharRangeMax}},
2022 "an unsigned char value or EOF")));
2023 addToFunctionSummaryMap(
2024 "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2025 Summary(EvalCallAsPure)
2026 .ArgConstraint(ArgumentCondition(0U, WithinRange,
2027 {{EOFv, EOFv}, {0, UCharRangeMax}},
2028 "an unsigned char value or EOF")));
2029
2030 // The getc() family of functions that returns either a char or an EOF.
2031 addToFunctionSummaryMap(
2032 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2033 Summary(NoEvalCall)
2034 .Case({ReturnValueCondition(WithinRange,
2035 {{EOFv, EOFv}, {0, UCharRangeMax}})},
2036 ErrnoIrrelevant));
2037 addToFunctionSummaryMap(
2038 "getchar", Signature(ArgTypes{}, RetType{IntTy}),
2039 Summary(NoEvalCall)
2040 .Case({ReturnValueCondition(WithinRange,
2041 {{EOFv, EOFv}, {0, UCharRangeMax}})},
2042 ErrnoIrrelevant));
2043
2044 // read()-like functions that never return more than buffer size.
2045 auto FreadSummary =
2046 Summary(NoEvalCall)
2047 .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2048 ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
2049 ReturnValueCondition(BO_LT, ArgNo(2)),
2050 ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2051 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2052 .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2053 ReturnValueCondition(BO_EQ, ArgNo(2)),
2054 ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2055 ErrnoMustNotBeChecked, GenericSuccessMsg)
2056 .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
2057 ReturnValueCondition(WithinRange, SingleValue(0))},
2058 ErrnoMustNotBeChecked,
2059 "Assuming that argument 'size' to '{0}' is 0")
2060 .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))
2061 .ArgConstraint(NotNull(ArgNo(3)))
2062 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2063 /*BufSizeMultiplier=*/ArgNo(2)));
2064
2065 // size_t fread(void *restrict ptr, size_t size, size_t nitems,
2066 // FILE *restrict stream);
2067 addToFunctionSummaryMap(
2068 "fread",
2069 Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
2070 RetType{SizeTy}),
2071 FreadSummary);
2072 // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
2073 // FILE *restrict stream);
2074 addToFunctionSummaryMap("fwrite",
2075 Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
2076 SizeTy, FilePtrRestrictTy},
2077 RetType{SizeTy}),
2078 FreadSummary);
2079
2080 std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
2081 std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
2082
2083 auto ReadSummary =
2084 Summary(NoEvalCall)
2085 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2086 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
2087 ErrnoIrrelevant);
2088
2089 // FIXME these are actually defined by POSIX and not by the C standard, we
2090 // should handle them together with the rest of the POSIX functions.
2091 // ssize_t read(int fildes, void *buf, size_t nbyte);
2092 addToFunctionSummaryMap(
2093 "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2094 ReadSummary);
2095 // ssize_t write(int fildes, const void *buf, size_t nbyte);
2096 addToFunctionSummaryMap(
2097 "write",
2098 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2099 ReadSummary);
2100
2101 auto GetLineSummary =
2102 Summary(NoEvalCall)
2103 .Case({ReturnValueCondition(WithinRange,
2104 Range({-1, -1}, {1, Ssize_tMax}))},
2105 ErrnoIrrelevant);
2106
2107 QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
2108
2109 // getline()-like functions either fail or read at least the delimiter.
2110 // FIXME these are actually defined by POSIX and not by the C standard, we
2111 // should handle them together with the rest of the POSIX functions.
2112 // ssize_t getline(char **restrict lineptr, size_t *restrict n,
2113 // FILE *restrict stream);
2114 addToFunctionSummaryMap(
2115 "getline",
2116 Signature(
2117 ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
2118 RetType{Ssize_tTy}),
2119 GetLineSummary);
2120 // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2121 // int delimiter, FILE *restrict stream);
2122 addToFunctionSummaryMap(
2123 "getdelim",
2124 Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
2125 FilePtrRestrictTy},
2126 RetType{Ssize_tTy}),
2127 GetLineSummary);
2128
2129 {
2130 Summary GetenvSummary =
2131 Summary(NoEvalCall)
2132 .ArgConstraint(NotNull(ArgNo(0)))
2133 .Case({NotNull(Ret)}, ErrnoIrrelevant,
2134 "Assuming the environment variable exists");
2135 // In untrusted environments the envvar might not exist.
2136 if (!ShouldAssumeControlledEnvironment)
2137 GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,
2138 "Assuming the environment variable does not exist");
2139
2140 // char *getenv(const char *name);
2141 addToFunctionSummaryMap(
2142 "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2143 std::move(GetenvSummary));
2144 }
2145
2146 if (ModelPOSIX) {
2147 const auto ReturnsZeroOrMinusOne =
2148 ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
2149 const auto ReturnsZero =
2150 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
2151 const auto ReturnsMinusOne =
2152 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
2153 const auto ReturnsNonnegative =
2154 ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
2155 const auto ReturnsNonZero =
2156 ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
2157 const auto ReturnsFileDescriptor =
2158 ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
2159 const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
2160
2161 auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {
2162 return std::make_shared<RangeConstraint>(
2163 ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),
2164 "a valid file descriptor or AT_FDCWD");
2165 };
2166
2167 // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2168 addToFunctionSummaryMap(
2169 "fopen",
2170 Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
2171 RetType{FilePtrTy}),
2172 Summary(NoEvalCall)
2173 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2174 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2175 .ArgConstraint(NotNull(ArgNo(0)))
2176 .ArgConstraint(NotNull(ArgNo(1))));
2177
2178 // FILE *tmpfile(void);
2179 addToFunctionSummaryMap(
2180 "tmpfile", Signature(ArgTypes{}, RetType{FilePtrTy}),
2181 Summary(NoEvalCall)
2182 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2183 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2184
2185 // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2186 // FILE *restrict stream);
2187 addToFunctionSummaryMap(
2188 "freopen",
2189 Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
2190 FilePtrRestrictTy},
2191 RetType{FilePtrTy}),
2192 Summary(NoEvalCall)
2193 .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},
2194 ErrnoMustNotBeChecked, GenericSuccessMsg)
2195 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2196 .ArgConstraint(NotNull(ArgNo(1)))
2197 .ArgConstraint(NotNull(ArgNo(2))));
2198
2199 // int fclose(FILE *stream);
2200 addToFunctionSummaryMap(
2201 "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2202 Summary(NoEvalCall)
2203 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2204 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2205 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2206 .ArgConstraint(NotNull(ArgNo(0))));
2207
2208 // int fseek(FILE *stream, long offset, int whence);
2209 // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
2210 // these for condition of arg 2.
2211 // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
2212 addToFunctionSummaryMap(
2213 "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
2214 Summary(NoEvalCall)
2215 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2216 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2217 .ArgConstraint(NotNull(ArgNo(0)))
2218 .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2219
2220 // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
2221 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2222 // "The fgetpos() function shall not change the setting of errno if
2223 // successful."
2224 addToFunctionSummaryMap(
2225 "fgetpos",
2226 Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
2227 RetType{IntTy}),
2228 Summary(NoEvalCall)
2229 .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2230 .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2231 .ArgConstraint(NotNull(ArgNo(0)))
2232 .ArgConstraint(NotNull(ArgNo(1))));
2233
2234 // int fsetpos(FILE *stream, const fpos_t *pos);
2235 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2236 // "The fsetpos() function shall not change the setting of errno if
2237 // successful."
2238 addToFunctionSummaryMap(
2239 "fsetpos",
2240 Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
2241 Summary(NoEvalCall)
2242 .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2243 .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2244 .ArgConstraint(NotNull(ArgNo(0)))
2245 .ArgConstraint(NotNull(ArgNo(1))));
2246
2247 // long ftell(FILE *stream);
2248 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2249 // "The ftell() function shall not change the setting of errno if
2250 // successful."
2251 addToFunctionSummaryMap(
2252 "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
2253 Summary(NoEvalCall)
2254 .Case({ReturnValueCondition(WithinRange, Range(1, LongMax))},
2255 ErrnoUnchanged, GenericSuccessMsg)
2256 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2257 .ArgConstraint(NotNull(ArgNo(0))));
2258
2259 // int fileno(FILE *stream);
2260 addToFunctionSummaryMap(
2261 "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2262 Summary(NoEvalCall)
2263 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2264 GenericSuccessMsg)
2265 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2266 .ArgConstraint(NotNull(ArgNo(0))));
2267
2268 // void rewind(FILE *stream);
2269 // This function indicates error only by setting of 'errno'.
2270 addToFunctionSummaryMap("rewind",
2271 Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2272 Summary(NoEvalCall)
2273 .Case({}, ErrnoMustBeChecked)
2274 .ArgConstraint(NotNull(ArgNo(0))));
2275
2276 // void clearerr(FILE *stream);
2277 addToFunctionSummaryMap(
2278 "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2279 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2280
2281 // int feof(FILE *stream);
2282 addToFunctionSummaryMap(
2283 "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2284 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2285
2286 // int ferror(FILE *stream);
2287 addToFunctionSummaryMap(
2288 "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2289 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2290
2291 // long a64l(const char *str64);
2292 addToFunctionSummaryMap(
2293 "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
2294 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2295
2296 // char *l64a(long value);
2297 addToFunctionSummaryMap("l64a",
2298 Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
2299 Summary(NoEvalCall)
2300 .ArgConstraint(ArgumentCondition(
2301 0, WithinRange, Range(0, LongMax))));
2302
2303 // int open(const char *path, int oflag, ...);
2304 addToFunctionSummaryMap(
2305 "open", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2306 Summary(NoEvalCall)
2307 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2308 GenericSuccessMsg)
2309 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2310 .ArgConstraint(NotNull(ArgNo(0))));
2311
2312 // int openat(int fd, const char *path, int oflag, ...);
2313 addToFunctionSummaryMap(
2314 "openat",
2315 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2316 Summary(NoEvalCall)
2317 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2318 GenericSuccessMsg)
2319 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2320 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2321 .ArgConstraint(NotNull(ArgNo(1))));
2322
2323 // int access(const char *pathname, int amode);
2324 addToFunctionSummaryMap(
2325 "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2326 Summary(NoEvalCall)
2327 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2328 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2329 .ArgConstraint(NotNull(ArgNo(0))));
2330
2331 // int faccessat(int dirfd, const char *pathname, int mode, int flags);
2332 addToFunctionSummaryMap(
2333 "faccessat",
2334 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
2335 RetType{IntTy}),
2336 Summary(NoEvalCall)
2337 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2338 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2339 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2340 .ArgConstraint(NotNull(ArgNo(1))));
2341
2342 // int dup(int fildes);
2343 addToFunctionSummaryMap(
2344 "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2345 Summary(NoEvalCall)
2346 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2347 GenericSuccessMsg)
2348 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2349 .ArgConstraint(
2350 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2351
2352 // int dup2(int fildes1, int filedes2);
2353 addToFunctionSummaryMap(
2354 "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2355 Summary(NoEvalCall)
2356 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2357 GenericSuccessMsg)
2358 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2359 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2360 .ArgConstraint(
2361 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
2362
2363 // int fdatasync(int fildes);
2364 addToFunctionSummaryMap(
2365 "fdatasync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2366 Summary(NoEvalCall)
2367 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2368 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2369 .ArgConstraint(
2370 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2371
2372 // int fnmatch(const char *pattern, const char *string, int flags);
2373 addToFunctionSummaryMap(
2374 "fnmatch",
2375 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
2376 RetType{IntTy}),
2377 Summary(NoEvalCall)
2378 .ArgConstraint(NotNull(ArgNo(0)))
2379 .ArgConstraint(NotNull(ArgNo(1))));
2380
2381 // int fsync(int fildes);
2382 addToFunctionSummaryMap(
2383 "fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2384 Summary(NoEvalCall)
2385 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2386 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2387 .ArgConstraint(
2388 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2389
2390 std::optional<QualType> Off_tTy = lookupTy("off_t");
2391
2392 // int truncate(const char *path, off_t length);
2393 addToFunctionSummaryMap(
2394 "truncate",
2395 Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
2396 Summary(NoEvalCall)
2397 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2398 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2399 .ArgConstraint(NotNull(ArgNo(0))));
2400
2401 // int symlink(const char *oldpath, const char *newpath);
2402 addToFunctionSummaryMap(
2403 "symlink",
2404 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2405 Summary(NoEvalCall)
2406 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2407 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2408 .ArgConstraint(NotNull(ArgNo(0)))
2409 .ArgConstraint(NotNull(ArgNo(1))));
2410
2411 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
2412 addToFunctionSummaryMap(
2413 "symlinkat",
2414 Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
2415 RetType{IntTy}),
2416 Summary(NoEvalCall)
2417 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2418 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2419 .ArgConstraint(NotNull(ArgNo(0)))
2420 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
2421 .ArgConstraint(NotNull(ArgNo(2))));
2422
2423 // int lockf(int fd, int cmd, off_t len);
2424 addToFunctionSummaryMap(
2425 "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
2426 Summary(NoEvalCall)
2427 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2428 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2429 .ArgConstraint(
2430 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2431
2432 std::optional<QualType> Mode_tTy = lookupTy("mode_t");
2433
2434 // int creat(const char *pathname, mode_t mode);
2435 addToFunctionSummaryMap(
2436 "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2437 Summary(NoEvalCall)
2438 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2439 GenericSuccessMsg)
2440 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2441 .ArgConstraint(NotNull(ArgNo(0))));
2442
2443 // unsigned int sleep(unsigned int seconds);
2444 addToFunctionSummaryMap(
2445 "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2446 Summary(NoEvalCall)
2447 .ArgConstraint(
2448 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2449
2450 std::optional<QualType> DirTy = lookupTy("DIR");
2451 std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
2452
2453 // int dirfd(DIR *dirp);
2454 addToFunctionSummaryMap(
2455 "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2456 Summary(NoEvalCall)
2457 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2458 GenericSuccessMsg)
2459 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2460 .ArgConstraint(NotNull(ArgNo(0))));
2461
2462 // unsigned int alarm(unsigned int seconds);
2463 addToFunctionSummaryMap(
2464 "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2465 Summary(NoEvalCall)
2466 .ArgConstraint(
2467 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2468
2469 // int closedir(DIR *dir);
2470 addToFunctionSummaryMap(
2471 "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2472 Summary(NoEvalCall)
2473 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2474 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2475 .ArgConstraint(NotNull(ArgNo(0))));
2476
2477 // char *strdup(const char *s);
2478 addToFunctionSummaryMap(
2479 "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2480 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2481
2482 // char *strndup(const char *s, size_t n);
2483 addToFunctionSummaryMap(
2484 "strndup",
2485 Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
2486 Summary(NoEvalCall)
2487 .ArgConstraint(NotNull(ArgNo(0)))
2488 .ArgConstraint(
2489 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2490
2491 // wchar_t *wcsdup(const wchar_t *s);
2492 addToFunctionSummaryMap(
2493 "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
2494 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2495
2496 // int mkstemp(char *template);
2497 addToFunctionSummaryMap(
2498 "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
2499 Summary(NoEvalCall)
2500 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2501 GenericSuccessMsg)
2502 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2503 .ArgConstraint(NotNull(ArgNo(0))));
2504
2505 // char *mkdtemp(char *template);
2506 // FIXME: Improve for errno modeling.
2507 addToFunctionSummaryMap(
2508 "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
2509 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2510
2511 // char *getcwd(char *buf, size_t size);
2512 // FIXME: Improve for errno modeling.
2513 addToFunctionSummaryMap(
2514 "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
2515 Summary(NoEvalCall)
2516 .ArgConstraint(
2517 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2518
2519 // int mkdir(const char *pathname, mode_t mode);
2520 addToFunctionSummaryMap(
2521 "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2522 Summary(NoEvalCall)
2523 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2524 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2525 .ArgConstraint(NotNull(ArgNo(0))));
2526
2527 // int mkdirat(int dirfd, const char *pathname, mode_t mode);
2528 addToFunctionSummaryMap(
2529 "mkdirat",
2530 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2531 Summary(NoEvalCall)
2532 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2533 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2534 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2535 .ArgConstraint(NotNull(ArgNo(1))));
2536
2537 std::optional<QualType> Dev_tTy = lookupTy("dev_t");
2538
2539 // int mknod(const char *pathname, mode_t mode, dev_t dev);
2540 addToFunctionSummaryMap(
2541 "mknod",
2542 Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
2543 Summary(NoEvalCall)
2544 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2545 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2546 .ArgConstraint(NotNull(ArgNo(0))));
2547
2548 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2549 addToFunctionSummaryMap(
2550 "mknodat",
2551 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
2552 RetType{IntTy}),
2553 Summary(NoEvalCall)
2554 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2555 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2556 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2557 .ArgConstraint(NotNull(ArgNo(1))));
2558
2559 // int chmod(const char *path, mode_t mode);
2560 addToFunctionSummaryMap(
2561 "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2562 Summary(NoEvalCall)
2563 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2564 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2565 .ArgConstraint(NotNull(ArgNo(0))));
2566
2567 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
2568 addToFunctionSummaryMap(
2569 "fchmodat",
2570 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
2571 RetType{IntTy}),
2572 Summary(NoEvalCall)
2573 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2574 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2575 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2576 .ArgConstraint(NotNull(ArgNo(1))));
2577
2578 // int fchmod(int fildes, mode_t mode);
2579 addToFunctionSummaryMap(
2580 "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
2581 Summary(NoEvalCall)
2582 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2583 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2584 .ArgConstraint(
2585 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2586
2587 std::optional<QualType> Uid_tTy = lookupTy("uid_t");
2588 std::optional<QualType> Gid_tTy = lookupTy("gid_t");
2589
2590 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
2591 // int flags);
2592 addToFunctionSummaryMap(
2593 "fchownat",
2594 Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
2595 RetType{IntTy}),
2596 Summary(NoEvalCall)
2597 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2598 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2599 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2600 .ArgConstraint(NotNull(ArgNo(1))));
2601
2602 // int chown(const char *path, uid_t owner, gid_t group);
2603 addToFunctionSummaryMap(
2604 "chown",
2605 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2606 Summary(NoEvalCall)
2607 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2608 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2609 .ArgConstraint(NotNull(ArgNo(0))));
2610
2611 // int lchown(const char *path, uid_t owner, gid_t group);
2612 addToFunctionSummaryMap(
2613 "lchown",
2614 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2615 Summary(NoEvalCall)
2616 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2617 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2618 .ArgConstraint(NotNull(ArgNo(0))));
2619
2620 // int fchown(int fildes, uid_t owner, gid_t group);
2621 addToFunctionSummaryMap(
2622 "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2623 Summary(NoEvalCall)
2624 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2625 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2626 .ArgConstraint(
2627 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2628
2629 // int rmdir(const char *pathname);
2630 addToFunctionSummaryMap(
2631 "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2632 Summary(NoEvalCall)
2633 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2634 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2635 .ArgConstraint(NotNull(ArgNo(0))));
2636
2637 // int chdir(const char *path);
2638 addToFunctionSummaryMap(
2639 "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2640 Summary(NoEvalCall)
2641 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2642 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2643 .ArgConstraint(NotNull(ArgNo(0))));
2644
2645 // int link(const char *oldpath, const char *newpath);
2646 addToFunctionSummaryMap(
2647 "link",
2648 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2649 Summary(NoEvalCall)
2650 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2651 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2652 .ArgConstraint(NotNull(ArgNo(0)))
2653 .ArgConstraint(NotNull(ArgNo(1))));
2654
2655 // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2656 // int flag);
2657 addToFunctionSummaryMap(
2658 "linkat",
2659 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
2660 RetType{IntTy}),
2661 Summary(NoEvalCall)
2662 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2663 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2664 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2665 .ArgConstraint(NotNull(ArgNo(1)))
2666 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2667 .ArgConstraint(NotNull(ArgNo(3))));
2668
2669 // int unlink(const char *pathname);
2670 addToFunctionSummaryMap(
2671 "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2672 Summary(NoEvalCall)
2673 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2674 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2675 .ArgConstraint(NotNull(ArgNo(0))));
2676
2677 // int unlinkat(int fd, const char *path, int flag);
2678 addToFunctionSummaryMap(
2679 "unlinkat",
2680 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2681 Summary(NoEvalCall)
2682 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2683 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2684 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2685 .ArgConstraint(NotNull(ArgNo(1))));
2686
2687 std::optional<QualType> StructStatTy = lookupTy("stat");
2688 std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2689 std::optional<QualType> StructStatPtrRestrictTy =
2690 getRestrictTy(StructStatPtrTy);
2691
2692 // int fstat(int fd, struct stat *statbuf);
2693 addToFunctionSummaryMap(
2694 "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
2695 Summary(NoEvalCall)
2696 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2697 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2698 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2699 .ArgConstraint(NotNull(ArgNo(1))));
2700
2701 // int stat(const char *restrict path, struct stat *restrict buf);
2702 addToFunctionSummaryMap(
2703 "stat",
2704 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2705 RetType{IntTy}),
2706 Summary(NoEvalCall)
2707 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2708 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2709 .ArgConstraint(NotNull(ArgNo(0)))
2710 .ArgConstraint(NotNull(ArgNo(1))));
2711
2712 // int lstat(const char *restrict path, struct stat *restrict buf);
2713 addToFunctionSummaryMap(
2714 "lstat",
2715 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2716 RetType{IntTy}),
2717 Summary(NoEvalCall)
2718 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2719 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2720 .ArgConstraint(NotNull(ArgNo(0)))
2721 .ArgConstraint(NotNull(ArgNo(1))));
2722
2723 // int fstatat(int fd, const char *restrict path,
2724 // struct stat *restrict buf, int flag);
2725 addToFunctionSummaryMap(
2726 "fstatat",
2727 Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
2728 StructStatPtrRestrictTy, IntTy},
2729 RetType{IntTy}),
2730 Summary(NoEvalCall)
2731 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2732 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2733 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2734 .ArgConstraint(NotNull(ArgNo(1)))
2735 .ArgConstraint(NotNull(ArgNo(2))));
2736
2737 // DIR *opendir(const char *name);
2738 // FIXME: Improve for errno modeling.
2739 addToFunctionSummaryMap(
2740 "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
2741 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2742
2743 // DIR *fdopendir(int fd);
2744 // FIXME: Improve for errno modeling.
2745 addToFunctionSummaryMap("fdopendir",
2746 Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
2747 Summary(NoEvalCall)
2748 .ArgConstraint(ArgumentCondition(
2749 0, WithinRange, Range(0, IntMax))));
2750
2751 // int isatty(int fildes);
2752 addToFunctionSummaryMap(
2753 "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2754 Summary(NoEvalCall)
2755 .Case({ReturnValueCondition(WithinRange, Range(0, 1))},
2756 ErrnoIrrelevant)
2757 .ArgConstraint(
2758 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2759
2760 // FILE *popen(const char *command, const char *type);
2761 // FIXME: Improve for errno modeling.
2762 addToFunctionSummaryMap(
2763 "popen",
2764 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2765 Summary(NoEvalCall)
2766 .ArgConstraint(NotNull(ArgNo(0)))
2767 .ArgConstraint(NotNull(ArgNo(1))));
2768
2769 // int pclose(FILE *stream);
2770 // FIXME: Improve for errno modeling.
2771 addToFunctionSummaryMap(
2772 "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2773 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2774
2775 // int close(int fildes);
2776 addToFunctionSummaryMap(
2777 "close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2778 Summary(NoEvalCall)
2779 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2780 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2781 .ArgConstraint(
2782 ArgumentCondition(0, WithinRange, Range(-1, IntMax))));
2783
2784 // long fpathconf(int fildes, int name);
2785 addToFunctionSummaryMap("fpathconf",
2786 Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
2787 Summary(NoEvalCall)
2788 .ArgConstraint(ArgumentCondition(
2789 0, WithinRange, Range(0, IntMax))));
2790
2791 // long pathconf(const char *path, int name);
2792 addToFunctionSummaryMap(
2793 "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
2794 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2795
2796 // FILE *fdopen(int fd, const char *mode);
2797 // FIXME: Improve for errno modeling.
2798 addToFunctionSummaryMap(
2799 "fdopen",
2800 Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2801 Summary(NoEvalCall)
2802 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2803 .ArgConstraint(NotNull(ArgNo(1))));
2804
2805 // void rewinddir(DIR *dir);
2806 addToFunctionSummaryMap(
2807 "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
2808 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2809
2810 // void seekdir(DIR *dirp, long loc);
2811 addToFunctionSummaryMap(
2812 "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
2813 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2814
2815 // int rand_r(unsigned int *seedp);
2816 addToFunctionSummaryMap(
2817 "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
2818 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2819
2820 // int fseeko(FILE *stream, off_t offset, int whence);
2821 addToFunctionSummaryMap(
2822 "fseeko",
2823 Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2824 Summary(NoEvalCall)
2825 .Case(ReturnsZeroOrMinusOne, ErrnoIrrelevant)
2826 .ArgConstraint(NotNull(ArgNo(0))));
2827
2828 // off_t ftello(FILE *stream);
2829 addToFunctionSummaryMap(
2830 "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
2831 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2832
2833 // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2834 // off_t offset);
2835 // FIXME: Improve for errno modeling.
2836 addToFunctionSummaryMap(
2837 "mmap",
2838 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
2839 RetType{VoidPtrTy}),
2840 Summary(NoEvalCall)
2841 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2842 .ArgConstraint(
2843 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2844
2845 std::optional<QualType> Off64_tTy = lookupTy("off64_t");
2846 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2847 // off64_t offset);
2848 // FIXME: Improve for errno modeling.
2849 addToFunctionSummaryMap(
2850 "mmap64",
2851 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
2852 RetType{VoidPtrTy}),
2853 Summary(NoEvalCall)
2854 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2855 .ArgConstraint(
2856 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2857
2858 // int pipe(int fildes[2]);
2859 addToFunctionSummaryMap(
2860 "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2861 Summary(NoEvalCall)
2862 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2863 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2864 .ArgConstraint(NotNull(ArgNo(0))));
2865
2866 // off_t lseek(int fildes, off_t offset, int whence);
2867 // In the first case we can not tell for sure if it failed or not.
2868 // A return value different from of the expected offset (that is unknown
2869 // here) may indicate failure. For this reason we do not enforce the errno
2870 // check (can cause false positive).
2871 addToFunctionSummaryMap(
2872 "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
2873 Summary(NoEvalCall)
2874 .Case(ReturnsNonnegative, ErrnoIrrelevant)
2875 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2876 .ArgConstraint(
2877 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2878
2879 // ssize_t readlink(const char *restrict path, char *restrict buf,
2880 // size_t bufsize);
2881 addToFunctionSummaryMap(
2882 "readlink",
2883 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2884 RetType{Ssize_tTy}),
2885 Summary(NoEvalCall)
2886 .Case({ArgumentCondition(2, WithinRange, Range(1, IntMax)),
2887 ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2888 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
2889 ErrnoMustNotBeChecked, GenericSuccessMsg)
2890 .Case({ArgumentCondition(2, WithinRange, SingleValue(0)),
2891 ReturnValueCondition(WithinRange, SingleValue(0))},
2892 ErrnoMustNotBeChecked,
2893 "Assuming that argument 'bufsize' is 0")
2894 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2895 .ArgConstraint(NotNull(ArgNo(0)))
2896 .ArgConstraint(NotNull(ArgNo(1)))
2897 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2898 /*BufSize=*/ArgNo(2)))
2899 .ArgConstraint(
2900 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
2901
2902 // ssize_t readlinkat(int fd, const char *restrict path,
2903 // char *restrict buf, size_t bufsize);
2904 addToFunctionSummaryMap(
2905 "readlinkat",
2906 Signature(
2907 ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2908 RetType{Ssize_tTy}),
2909 Summary(NoEvalCall)
2910 .Case({ArgumentCondition(3, WithinRange, Range(1, IntMax)),
2911 ReturnValueCondition(LessThanOrEq, ArgNo(3)),
2912 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
2913 ErrnoMustNotBeChecked, GenericSuccessMsg)
2914 .Case({ArgumentCondition(3, WithinRange, SingleValue(0)),
2915 ReturnValueCondition(WithinRange, SingleValue(0))},
2916 ErrnoMustNotBeChecked,
2917 "Assuming that argument 'bufsize' is 0")
2918 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2919 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2920 .ArgConstraint(NotNull(ArgNo(1)))
2921 .ArgConstraint(NotNull(ArgNo(2)))
2922 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
2923 /*BufSize=*/ArgNo(3)))
2924 .ArgConstraint(
2925 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
2926
2927 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
2928 // *newpath);
2929 addToFunctionSummaryMap(
2930 "renameat",
2931 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
2932 RetType{IntTy}),
2933 Summary(NoEvalCall)
2934 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2935 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2936 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2937 .ArgConstraint(NotNull(ArgNo(1)))
2938 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2939 .ArgConstraint(NotNull(ArgNo(3))));
2940
2941 // char *realpath(const char *restrict file_name,
2942 // char *restrict resolved_name);
2943 // FIXME: Improve for errno modeling.
2944 addToFunctionSummaryMap(
2945 "realpath",
2946 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
2947 RetType{CharPtrTy}),
2948 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2949
2950 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
2951
2952 // int execv(const char *path, char *const argv[]);
2953 addToFunctionSummaryMap(
2954 "execv",
2955 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
2956 Summary(NoEvalCall)
2957 .Case({ReturnValueCondition(WithinRange, SingleValue(-1))},
2958 ErrnoIrrelevant)
2959 .ArgConstraint(NotNull(ArgNo(0))));
2960
2961 // int execvp(const char *file, char *const argv[]);
2962 addToFunctionSummaryMap(
2963 "execvp",
2964 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
2965 Summary(NoEvalCall)
2966 .Case({ReturnValueCondition(WithinRange, SingleValue(-1))},
2967 ErrnoIrrelevant)
2968 .ArgConstraint(NotNull(ArgNo(0))));
2969
2970 // int getopt(int argc, char * const argv[], const char *optstring);
2971 addToFunctionSummaryMap(
2972 "getopt",
2973 Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
2974 RetType{IntTy}),
2975 Summary(NoEvalCall)
2976 .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
2977 ErrnoIrrelevant)
2978 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2979 .ArgConstraint(NotNull(ArgNo(1)))
2980 .ArgConstraint(NotNull(ArgNo(2))));
2981
2982 std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
2983 std::optional<QualType> StructSockaddrPtrTy =
2984 getPointerTy(StructSockaddrTy);
2985 std::optional<QualType> ConstStructSockaddrPtrTy =
2986 getPointerTy(getConstTy(StructSockaddrTy));
2987 std::optional<QualType> StructSockaddrPtrRestrictTy =
2988 getRestrictTy(StructSockaddrPtrTy);
2989 std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
2990 getRestrictTy(ConstStructSockaddrPtrTy);
2991 std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
2992 std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
2993 std::optional<QualType> Socklen_tPtrRestrictTy =
2994 getRestrictTy(Socklen_tPtrTy);
2995 std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
2996
2997 // In 'socket.h' of some libc implementations with C99, sockaddr parameter
2998 // is a transparent union of the underlying sockaddr_ family of pointers
2999 // instead of being a pointer to struct sockaddr. In these cases, the
3000 // standardized signature will not match, thus we try to match with another
3001 // signature that has the joker Irrelevant type. We also remove those
3002 // constraints which require pointer types for the sockaddr param.
3003
3004 // int socket(int domain, int type, int protocol);
3005 addToFunctionSummaryMap(
3006 "socket", Signature(ArgTypes{IntTy, IntTy, IntTy}, RetType{IntTy}),
3007 Summary(NoEvalCall)
3008 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
3009 GenericSuccessMsg)
3010 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg));
3011
3012 auto Accept =
3013 Summary(NoEvalCall)
3014 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
3015 GenericSuccessMsg)
3016 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3017 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
3018 if (!addToFunctionSummaryMap(
3019 "accept",
3020 // int accept(int socket, struct sockaddr *restrict address,
3021 // socklen_t *restrict address_len);
3022 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3023 Socklen_tPtrRestrictTy},
3024 RetType{IntTy}),
3025 Accept))
3026 addToFunctionSummaryMap(
3027 "accept",
3028 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3029 RetType{IntTy}),
3030 Accept);
3031
3032 // int bind(int socket, const struct sockaddr *address, socklen_t
3033 // address_len);
3034 if (!addToFunctionSummaryMap(
3035 "bind",
3036 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3037 RetType{IntTy}),
3038 Summary(NoEvalCall)
3039 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3040 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3041 .ArgConstraint(
3042 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3043 .ArgConstraint(NotNull(ArgNo(1)))
3044 .ArgConstraint(
3045 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
3046 .ArgConstraint(
3047 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
3048 // Do not add constraints on sockaddr.
3049 addToFunctionSummaryMap(
3050 "bind",
3051 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3052 Summary(NoEvalCall)
3053 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3054 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3055 .ArgConstraint(
3056 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3057 .ArgConstraint(
3058 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
3059
3060 // int getpeername(int socket, struct sockaddr *restrict address,
3061 // socklen_t *restrict address_len);
3062 if (!addToFunctionSummaryMap(
3063 "getpeername",
3064 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3065 Socklen_tPtrRestrictTy},
3066 RetType{IntTy}),
3067 Summary(NoEvalCall)
3068 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3069 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3070 .ArgConstraint(
3071 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3072 .ArgConstraint(NotNull(ArgNo(1)))
3073 .ArgConstraint(NotNull(ArgNo(2)))))
3074 addToFunctionSummaryMap(
3075 "getpeername",
3076 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3077 RetType{IntTy}),
3078 Summary(NoEvalCall)
3079 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3080 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3081 .ArgConstraint(
3082 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3083
3084 // int getsockname(int socket, struct sockaddr *restrict address,
3085 // socklen_t *restrict address_len);
3086 if (!addToFunctionSummaryMap(
3087 "getsockname",
3088 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3089 Socklen_tPtrRestrictTy},
3090 RetType{IntTy}),
3091 Summary(NoEvalCall)
3092 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3093 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3094 .ArgConstraint(
3095 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3096 .ArgConstraint(NotNull(ArgNo(1)))
3097 .ArgConstraint(NotNull(ArgNo(2)))))
3098 addToFunctionSummaryMap(
3099 "getsockname",
3100 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3101 RetType{IntTy}),
3102 Summary(NoEvalCall)
3103 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3104 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3105 .ArgConstraint(
3106 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3107
3108 // int connect(int socket, const struct sockaddr *address, socklen_t
3109 // address_len);
3110 if (!addToFunctionSummaryMap(
3111 "connect",
3112 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3113 RetType{IntTy}),
3114 Summary(NoEvalCall)
3115 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3116 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3117 .ArgConstraint(
3118 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3119 .ArgConstraint(NotNull(ArgNo(1)))))
3120 addToFunctionSummaryMap(
3121 "connect",
3122 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3123 Summary(NoEvalCall)
3124 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3125 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3126 .ArgConstraint(
3127 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3128
3129 auto Recvfrom =
3130 Summary(NoEvalCall)
3131 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3132 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3133 ErrnoMustNotBeChecked, GenericSuccessMsg)
3134 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3135 ArgumentCondition(2, WithinRange, SingleValue(0))},
3136 ErrnoMustNotBeChecked, GenericSuccessMsg)
3137 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3138 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3139 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3140 /*BufSize=*/ArgNo(2)));
3141 if (!addToFunctionSummaryMap(
3142 "recvfrom",
3143 // ssize_t recvfrom(int socket, void *restrict buffer,
3144 // size_t length,
3145 // int flags, struct sockaddr *restrict address,
3146 // socklen_t *restrict address_len);
3147 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3148 StructSockaddrPtrRestrictTy,
3149 Socklen_tPtrRestrictTy},
3150 RetType{Ssize_tTy}),
3151 Recvfrom))
3152 addToFunctionSummaryMap(
3153 "recvfrom",
3154 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3155 Irrelevant, Socklen_tPtrRestrictTy},
3156 RetType{Ssize_tTy}),
3157 Recvfrom);
3158
3159 auto Sendto =
3160 Summary(NoEvalCall)
3161 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3162 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3163 ErrnoMustNotBeChecked, GenericSuccessMsg)
3164 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3165 ArgumentCondition(2, WithinRange, SingleValue(0))},
3166 ErrnoMustNotBeChecked, GenericSuccessMsg)
3167 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3168 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3169 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3170 /*BufSize=*/ArgNo(2)));
3171 if (!addToFunctionSummaryMap(
3172 "sendto",
3173 // ssize_t sendto(int socket, const void *message, size_t length,
3174 // int flags, const struct sockaddr *dest_addr,
3175 // socklen_t dest_len);
3176 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
3177 ConstStructSockaddrPtrTy, Socklen_tTy},
3178 RetType{Ssize_tTy}),
3179 Sendto))
3180 addToFunctionSummaryMap(
3181 "sendto",
3182 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
3183 Socklen_tTy},
3184 RetType{Ssize_tTy}),
3185 Sendto);
3186
3187 // int listen(int sockfd, int backlog);
3188 addToFunctionSummaryMap(
3189 "listen", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3190 Summary(NoEvalCall)
3191 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3192 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3193 .ArgConstraint(
3194 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3195
3196 // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3197 addToFunctionSummaryMap(
3198 "recv",
3199 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
3200 RetType{Ssize_tTy}),
3201 Summary(NoEvalCall)
3202 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3203 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3204 ErrnoMustNotBeChecked, GenericSuccessMsg)
3205 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3206 ArgumentCondition(2, WithinRange, SingleValue(0))},
3207 ErrnoMustNotBeChecked, GenericSuccessMsg)
3208 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3209 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3210 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3211 /*BufSize=*/ArgNo(2))));
3212
3213 std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
3214 std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
3215 std::optional<QualType> ConstStructMsghdrPtrTy =
3216 getPointerTy(getConstTy(StructMsghdrTy));
3217
3218 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3219 addToFunctionSummaryMap(
3220 "recvmsg",
3221 Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
3222 RetType{Ssize_tTy}),
3223 Summary(NoEvalCall)
3224 .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3225 ErrnoMustNotBeChecked, GenericSuccessMsg)
3226 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3227 .ArgConstraint(
3228 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3229
3230 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3231 addToFunctionSummaryMap(
3232 "sendmsg",
3233 Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
3234 RetType{Ssize_tTy}),
3235 Summary(NoEvalCall)
3236 .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3237 ErrnoMustNotBeChecked, GenericSuccessMsg)
3238 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3239 .ArgConstraint(
3240 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3241
3242 // int setsockopt(int socket, int level, int option_name,
3243 // const void *option_value, socklen_t option_len);
3244 addToFunctionSummaryMap(
3245 "setsockopt",
3246 Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
3247 RetType{IntTy}),
3248 Summary(NoEvalCall)
3249 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3250 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3251 .ArgConstraint(NotNull(ArgNo(3)))
3252 .ArgConstraint(
3253 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3254 .ArgConstraint(
3255 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
3256
3257 // int getsockopt(int socket, int level, int option_name,
3258 // void *restrict option_value,
3259 // socklen_t *restrict option_len);
3260 addToFunctionSummaryMap(
3261 "getsockopt",
3262 Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
3263 Socklen_tPtrRestrictTy},
3264 RetType{IntTy}),
3265 Summary(NoEvalCall)
3266 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3267 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3268 .ArgConstraint(NotNull(ArgNo(3)))
3269 .ArgConstraint(NotNull(ArgNo(4))));
3270
3271 // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3272 addToFunctionSummaryMap(
3273 "send",
3274 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
3275 RetType{Ssize_tTy}),
3276 Summary(NoEvalCall)
3277 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3278 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3279 ErrnoMustNotBeChecked, GenericSuccessMsg)
3280 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3281 ArgumentCondition(2, WithinRange, SingleValue(0))},
3282 ErrnoMustNotBeChecked, GenericSuccessMsg)
3283 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3284 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3285 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3286 /*BufSize=*/ArgNo(2))));
3287
3288 // int socketpair(int domain, int type, int protocol, int sv[2]);
3289 addToFunctionSummaryMap(
3290 "socketpair",
3291 Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
3292 Summary(NoEvalCall)
3293 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3294 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3295 .ArgConstraint(NotNull(ArgNo(3))));
3296
3297 // int shutdown(int socket, int how);
3298 addToFunctionSummaryMap(
3299 "shutdown", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3300 Summary(NoEvalCall)
3301 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3302 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3303 .ArgConstraint(
3304 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3305
3306 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
3307 // char *restrict node, socklen_t nodelen,
3308 // char *restrict service,
3309 // socklen_t servicelen, int flags);
3310 //
3311 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
3312 // parameter is never handled as a transparent union in netdb.h
3313 addToFunctionSummaryMap(
3314 "getnameinfo",
3315 Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
3316 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
3317 Socklen_tTy, IntTy},
3318 RetType{IntTy}),
3319 Summary(NoEvalCall)
3320 .ArgConstraint(
3321 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3322 .ArgConstraint(
3323 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
3324 .ArgConstraint(
3325 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3326 .ArgConstraint(
3327 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
3328 .ArgConstraint(
3329 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3330 .ArgConstraint(
3331 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
3332
3333 std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
3334 std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
3335
3336 // int utime(const char *filename, struct utimbuf *buf);
3337 addToFunctionSummaryMap(
3338 "utime",
3339 Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
3340 Summary(NoEvalCall)
3341 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3342 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3343 .ArgConstraint(NotNull(ArgNo(0))));
3344
3345 std::optional<QualType> StructTimespecTy = lookupTy("timespec");
3346 std::optional<QualType> StructTimespecPtrTy =
3347 getPointerTy(StructTimespecTy);
3348 std::optional<QualType> ConstStructTimespecPtrTy =
3349 getPointerTy(getConstTy(StructTimespecTy));
3350
3351 // int futimens(int fd, const struct timespec times[2]);
3352 addToFunctionSummaryMap(
3353 "futimens",
3354 Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
3355 Summary(NoEvalCall)
3356 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3357 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3358 .ArgConstraint(
3359 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3360
3361 // int utimensat(int dirfd, const char *pathname,
3362 // const struct timespec times[2], int flags);
3363 addToFunctionSummaryMap(
3364 "utimensat",
3365 Signature(
3366 ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy},
3367 RetType{IntTy}),
3368 Summary(NoEvalCall)
3369 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3370 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3371 .ArgConstraint(NotNull(ArgNo(1))));
3372
3373 std::optional<QualType> StructTimevalTy = lookupTy("timeval");
3374 std::optional<QualType> ConstStructTimevalPtrTy =
3375 getPointerTy(getConstTy(StructTimevalTy));
3376
3377 // int utimes(const char *filename, const struct timeval times[2]);
3378 addToFunctionSummaryMap(
3379 "utimes",
3380 Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
3381 RetType{IntTy}),
3382 Summary(NoEvalCall)
3383 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3384 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3385 .ArgConstraint(NotNull(ArgNo(0))));
3386
3387 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3388 addToFunctionSummaryMap(
3389 "nanosleep",
3390 Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
3391 RetType{IntTy}),
3392 Summary(NoEvalCall)
3393 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3394 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3395 .ArgConstraint(NotNull(ArgNo(0))));
3396
3397 std::optional<QualType> Time_tTy = lookupTy("time_t");
3398 std::optional<QualType> ConstTime_tPtrTy =
3399 getPointerTy(getConstTy(Time_tTy));
3400 std::optional<QualType> ConstTime_tPtrRestrictTy =
3401 getRestrictTy(ConstTime_tPtrTy);
3402
3403 std::optional<QualType> StructTmTy = lookupTy("tm");
3404 std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
3405 std::optional<QualType> StructTmPtrRestrictTy =
3406 getRestrictTy(StructTmPtrTy);
3407 std::optional<QualType> ConstStructTmPtrTy =
3408 getPointerTy(getConstTy(StructTmTy));
3409 std::optional<QualType> ConstStructTmPtrRestrictTy =
3410 getRestrictTy(ConstStructTmPtrTy);
3411
3412 // struct tm * localtime(const time_t *tp);
3413 addToFunctionSummaryMap(
3414 "localtime",
3415 Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3416 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3417
3418 // struct tm *localtime_r(const time_t *restrict timer,
3419 // struct tm *restrict result);
3420 addToFunctionSummaryMap(
3421 "localtime_r",
3422 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3423 RetType{StructTmPtrTy}),
3424 Summary(NoEvalCall)
3425 .ArgConstraint(NotNull(ArgNo(0)))
3426 .ArgConstraint(NotNull(ArgNo(1))));
3427
3428 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3429 addToFunctionSummaryMap(
3430 "asctime_r",
3431 Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
3432 RetType{CharPtrTy}),
3433 Summary(NoEvalCall)
3434 .ArgConstraint(NotNull(ArgNo(0)))
3435 .ArgConstraint(NotNull(ArgNo(1)))
3436 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3437 /*MinBufSize=*/BVF.getValue(26, IntTy))));
3438
3439 // char *ctime_r(const time_t *timep, char *buf);
3440 addToFunctionSummaryMap(
3441 "ctime_r",
3442 Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
3443 Summary(NoEvalCall)
3444 .ArgConstraint(NotNull(ArgNo(0)))
3445 .ArgConstraint(NotNull(ArgNo(1)))
3446 .ArgConstraint(BufferSize(
3447 /*Buffer=*/ArgNo(1),
3448 /*MinBufSize=*/BVF.getValue(26, IntTy))));
3449
3450 // struct tm *gmtime_r(const time_t *restrict timer,
3451 // struct tm *restrict result);
3452 addToFunctionSummaryMap(
3453 "gmtime_r",
3454 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3455 RetType{StructTmPtrTy}),
3456 Summary(NoEvalCall)
3457 .ArgConstraint(NotNull(ArgNo(0)))
3458 .ArgConstraint(NotNull(ArgNo(1))));
3459
3460 // struct tm * gmtime(const time_t *tp);
3461 addToFunctionSummaryMap(
3462 "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3463 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3464
3465 std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
3466
3467 // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3468 addToFunctionSummaryMap(
3469 "clock_gettime",
3470 Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
3471 Summary(NoEvalCall)
3472 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3473 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3474 .ArgConstraint(NotNull(ArgNo(1))));
3475
3476 std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
3477 std::optional<QualType> StructItimervalPtrTy =
3478 getPointerTy(StructItimervalTy);
3479
3480 // int getitimer(int which, struct itimerval *curr_value);
3481 addToFunctionSummaryMap(
3482 "getitimer",
3483 Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
3484 Summary(NoEvalCall)
3485 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3486 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3487 .ArgConstraint(NotNull(ArgNo(1))));
3488
3489 std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
3490 std::optional<QualType> Pthread_cond_tPtrTy =
3491 getPointerTy(Pthread_cond_tTy);
3492 std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
3493 std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
3494 std::optional<QualType> Pthread_tPtrRestrictTy =
3495 getRestrictTy(Pthread_tPtrTy);
3496 std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
3497 std::optional<QualType> Pthread_mutex_tPtrTy =
3498 getPointerTy(Pthread_mutex_tTy);
3499 std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
3500 getRestrictTy(Pthread_mutex_tPtrTy);
3501 std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
3502 std::optional<QualType> Pthread_attr_tPtrTy =
3503 getPointerTy(Pthread_attr_tTy);
3504 std::optional<QualType> ConstPthread_attr_tPtrTy =
3505 getPointerTy(getConstTy(Pthread_attr_tTy));
3506 std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
3507 getRestrictTy(ConstPthread_attr_tPtrTy);
3508 std::optional<QualType> Pthread_mutexattr_tTy =
3509 lookupTy("pthread_mutexattr_t");
3510 std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
3511 getPointerTy(getConstTy(Pthread_mutexattr_tTy));
3512 std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
3513 getRestrictTy(ConstPthread_mutexattr_tPtrTy);
3514
3515 QualType PthreadStartRoutineTy = getPointerTy(
3516 ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
3518
3519 // int pthread_cond_signal(pthread_cond_t *cond);
3520 // int pthread_cond_broadcast(pthread_cond_t *cond);
3521 addToFunctionSummaryMap(
3522 {"pthread_cond_signal", "pthread_cond_broadcast"},
3523 Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
3524 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3525
3526 // int pthread_create(pthread_t *restrict thread,
3527 // const pthread_attr_t *restrict attr,
3528 // void *(*start_routine)(void*), void *restrict arg);
3529 addToFunctionSummaryMap(
3530 "pthread_create",
3531 Signature(ArgTypes{Pthread_tPtrRestrictTy,
3532 ConstPthread_attr_tPtrRestrictTy,
3533 PthreadStartRoutineTy, VoidPtrRestrictTy},
3534 RetType{IntTy}),
3535 Summary(NoEvalCall)
3536 .ArgConstraint(NotNull(ArgNo(0)))
3537 .ArgConstraint(NotNull(ArgNo(2))));
3538
3539 // int pthread_attr_destroy(pthread_attr_t *attr);
3540 // int pthread_attr_init(pthread_attr_t *attr);
3541 addToFunctionSummaryMap(
3542 {"pthread_attr_destroy", "pthread_attr_init"},
3543 Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
3544 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3545
3546 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
3547 // size_t *restrict stacksize);
3548 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
3549 // size_t *restrict guardsize);
3550 addToFunctionSummaryMap(
3551 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
3552 Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
3553 RetType{IntTy}),
3554 Summary(NoEvalCall)
3555 .ArgConstraint(NotNull(ArgNo(0)))
3556 .ArgConstraint(NotNull(ArgNo(1))));
3557
3558 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3559 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
3560 addToFunctionSummaryMap(
3561 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
3562 Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
3563 Summary(NoEvalCall)
3564 .ArgConstraint(NotNull(ArgNo(0)))
3565 .ArgConstraint(
3566 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
3567
3568 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
3569 // pthread_mutexattr_t *restrict attr);
3570 addToFunctionSummaryMap(
3571 "pthread_mutex_init",
3572 Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
3573 ConstPthread_mutexattr_tPtrRestrictTy},
3574 RetType{IntTy}),
3575 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3576
3577 // int pthread_mutex_destroy(pthread_mutex_t *mutex);
3578 // int pthread_mutex_lock(pthread_mutex_t *mutex);
3579 // int pthread_mutex_trylock(pthread_mutex_t *mutex);
3580 // int pthread_mutex_unlock(pthread_mutex_t *mutex);
3581 addToFunctionSummaryMap(
3582 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
3583 "pthread_mutex_unlock"},
3584 Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
3585 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3586 }
3587
3588 // Functions for testing.
3589 if (AddTestFunctions) {
3590 const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue();
3591
3592 addToFunctionSummaryMap(
3593 "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
3594 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3595
3596 addToFunctionSummaryMap(
3597 "__not_null_buffer",
3598 Signature(ArgTypes{VoidPtrTy, IntTy, IntTy}, RetType{IntTy}),
3599 Summary(EvalCallAsPure)
3600 .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2))));
3601
3602 // Test inside range constraints.
3603 addToFunctionSummaryMap(
3604 "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3605 Summary(EvalCallAsPure)
3606 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
3607 addToFunctionSummaryMap(
3608 "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3609 Summary(EvalCallAsPure)
3610 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3611 addToFunctionSummaryMap(
3612 "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3613 Summary(EvalCallAsPure)
3614 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
3615 addToFunctionSummaryMap(
3616 "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3617 Summary(EvalCallAsPure)
3618 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));
3619 addToFunctionSummaryMap(
3620 "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3621 Summary(EvalCallAsPure)
3622 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));
3623 addToFunctionSummaryMap(
3624 "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3625 Summary(EvalCallAsPure)
3626 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));
3627 addToFunctionSummaryMap("__range_m1_inf",
3628 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3629 Summary(EvalCallAsPure)
3630 .ArgConstraint(ArgumentCondition(
3631 0U, WithinRange, Range(-1, IntMax))));
3632 addToFunctionSummaryMap("__range_0_inf",
3633 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3634 Summary(EvalCallAsPure)
3635 .ArgConstraint(ArgumentCondition(
3636 0U, WithinRange, Range(0, IntMax))));
3637 addToFunctionSummaryMap("__range_1_inf",
3638 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3639 Summary(EvalCallAsPure)
3640 .ArgConstraint(ArgumentCondition(
3641 0U, WithinRange, Range(1, IntMax))));
3642 addToFunctionSummaryMap("__range_minf_m1",
3643 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3644 Summary(EvalCallAsPure)
3645 .ArgConstraint(ArgumentCondition(
3646 0U, WithinRange, Range(IntMin, -1))));
3647 addToFunctionSummaryMap("__range_minf_0",
3648 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3649 Summary(EvalCallAsPure)
3650 .ArgConstraint(ArgumentCondition(
3651 0U, WithinRange, Range(IntMin, 0))));
3652 addToFunctionSummaryMap("__range_minf_1",
3653 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3654 Summary(EvalCallAsPure)
3655 .ArgConstraint(ArgumentCondition(
3656 0U, WithinRange, Range(IntMin, 1))));
3657 addToFunctionSummaryMap("__range_1_2__4_6",
3658 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3659 Summary(EvalCallAsPure)
3660 .ArgConstraint(ArgumentCondition(
3661 0U, WithinRange, Range({1, 2}, {4, 6}))));
3662 addToFunctionSummaryMap(
3663 "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3664 Summary(EvalCallAsPure)
3665 .ArgConstraint(ArgumentCondition(0U, WithinRange,
3666 Range({1, 2}, {4, IntMax}))));
3667
3668 // Test out of range constraints.
3669 addToFunctionSummaryMap(
3670 "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3671 Summary(EvalCallAsPure)
3672 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));
3673 addToFunctionSummaryMap(
3674 "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3675 Summary(EvalCallAsPure)
3676 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3677 addToFunctionSummaryMap(
3678 "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3679 Summary(EvalCallAsPure)
3680 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));
3681 addToFunctionSummaryMap(
3682 "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3683 Summary(EvalCallAsPure)
3684 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
3685 addToFunctionSummaryMap(
3686 "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3687 Summary(EvalCallAsPure)
3688 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
3689 addToFunctionSummaryMap(
3690 "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3691 Summary(EvalCallAsPure)
3692 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
3693 addToFunctionSummaryMap("__range_out_m1_inf",
3694 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3695 Summary(EvalCallAsPure)
3696 .ArgConstraint(ArgumentCondition(
3697 0U, OutOfRange, Range(-1, IntMax))));
3698 addToFunctionSummaryMap("__range_out_0_inf",
3699 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3700 Summary(EvalCallAsPure)
3701 .ArgConstraint(ArgumentCondition(
3702 0U, OutOfRange, Range(0, IntMax))));
3703 addToFunctionSummaryMap("__range_out_1_inf",
3704 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3705 Summary(EvalCallAsPure)
3706 .ArgConstraint(ArgumentCondition(
3707 0U, OutOfRange, Range(1, IntMax))));
3708 addToFunctionSummaryMap("__range_out_minf_m1",
3709 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3710 Summary(EvalCallAsPure)
3711 .ArgConstraint(ArgumentCondition(
3712 0U, OutOfRange, Range(IntMin, -1))));
3713 addToFunctionSummaryMap("__range_out_minf_0",
3714 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3715 Summary(EvalCallAsPure)
3716 .ArgConstraint(ArgumentCondition(
3717 0U, OutOfRange, Range(IntMin, 0))));
3718 addToFunctionSummaryMap("__range_out_minf_1",
3719 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3720 Summary(EvalCallAsPure)
3721 .ArgConstraint(ArgumentCondition(
3722 0U, OutOfRange, Range(IntMin, 1))));
3723 addToFunctionSummaryMap("__range_out_1_2__4_6",
3724 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3725 Summary(EvalCallAsPure)
3726 .ArgConstraint(ArgumentCondition(
3727 0U, OutOfRange, Range({1, 2}, {4, 6}))));
3728 addToFunctionSummaryMap(
3729 "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3730 Summary(EvalCallAsPure)
3731 .ArgConstraint(
3732 ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
3733
3734 // Test range kind.
3735 addToFunctionSummaryMap(
3736 "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3737 Summary(EvalCallAsPure)
3738 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3739 addToFunctionSummaryMap(
3740 "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3741 Summary(EvalCallAsPure)
3742 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3743
3744 addToFunctionSummaryMap(
3745 "__two_constrained_args",
3746 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3747 Summary(EvalCallAsPure)
3748 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
3749 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
3750 addToFunctionSummaryMap(
3751 "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3752 Summary(EvalCallAsPure)
3753 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
3754 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
3755 addToFunctionSummaryMap(
3756 "__defaultparam",
3757 Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
3758 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3759 addToFunctionSummaryMap(
3760 "__variadic",
3761 Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
3762 Summary(EvalCallAsPure)
3763 .ArgConstraint(NotNull(ArgNo(0)))
3764 .ArgConstraint(NotNull(ArgNo(1))));
3765 addToFunctionSummaryMap(
3766 "__buf_size_arg_constraint",
3767 Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
3768 Summary(EvalCallAsPure)
3769 .ArgConstraint(
3770 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
3771 addToFunctionSummaryMap(
3772 "__buf_size_arg_constraint_mul",
3773 Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
3774 Summary(EvalCallAsPure)
3775 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
3776 /*BufSizeMultiplier=*/ArgNo(2))));
3777 addToFunctionSummaryMap(
3778 "__buf_size_arg_constraint_concrete",
3779 Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
3780 Summary(EvalCallAsPure)
3781 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
3782 /*BufSize=*/BVF.getValue(10, IntTy))));
3783 addToFunctionSummaryMap(
3784 {"__test_restrict_param_0", "__test_restrict_param_1",
3785 "__test_restrict_param_2"},
3786 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
3787 Summary(EvalCallAsPure));
3788
3789 // Test the application of cases.
3790 addToFunctionSummaryMap(
3791 "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
3792 Summary(EvalCallAsPure)
3793 .Case({ReturnValueCondition(WithinRange, SingleValue(0))},
3794 ErrnoIrrelevant, "Function returns 0")
3795 .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
3796 ErrnoIrrelevant, "Function returns 1"));
3797 addToFunctionSummaryMap(
3798 "__test_case_range_1_2__4_6",
3799 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3800 Summary(EvalCallAsPure)
3801 .Case({ArgumentCondition(0U, WithinRange,
3802 IntRangeVector{{IntMin, 0}, {3, 3}}),
3803 ReturnValueCondition(WithinRange, SingleValue(1))},
3804 ErrnoIrrelevant)
3805 .Case({ArgumentCondition(0U, WithinRange,
3806 IntRangeVector{{3, 3}, {7, IntMax}}),
3807 ReturnValueCondition(WithinRange, SingleValue(2))},
3808 ErrnoIrrelevant)
3809 .Case({ArgumentCondition(0U, WithinRange,
3810 IntRangeVector{{IntMin, 0}, {7, IntMax}}),
3811 ReturnValueCondition(WithinRange, SingleValue(3))},
3812 ErrnoIrrelevant)
3813 .Case({ArgumentCondition(
3814 0U, WithinRange,
3815 IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),
3816 ReturnValueCondition(WithinRange, SingleValue(4))},
3817 ErrnoIrrelevant));
3818 }
3819}
3820
3821void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
3822 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
3823 Checker->CheckName = mgr.getCurrentCheckerName();
3824 const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
3825 Checker->DisplayLoadedSummaries =
3826 Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
3827 Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
3828 Checker->ShouldAssumeControlledEnvironment =
3829 Opts.ShouldAssumeControlledEnvironment;
3830}
3831
3832bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3833 const CheckerManager &mgr) {
3834 return true;
3835}
3836
3837void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) {
3838 auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>();
3839 Checker->AddTestFunctions = true;
3840}
3841
3842bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
3843 const CheckerManager &mgr) {
3844 return true;
3845}
#define V(N, I)
Definition: ASTContext.h:3241
DynTypedNode Node
static bool isInvalid(LocType Loc, bool *Invalid)
__device__ __2f16 b
do v
Definition: arm_acle.h:76
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1065
CanQualType LongTy
Definition: ASTContext.h:1092
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getTypeDeclType(const TypeDecl *Decl, const TypeDecl *PrevDecl=nullptr) const
Return the unique reference to the type for the specified type declaration.
Definition: ASTContext.h:1572
IdentifierTable & Idents
Definition: ASTContext.h:636
const LangOptions & getLangOpts() const
Definition: ASTContext.h:767
CanQualType BoolTy
Definition: ASTContext.h:1084
QualType getRestrictType(QualType T) const
Return the uniqued reference to the type for a restrict qualified type.
Definition: ASTContext.h:1269
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
CanQualType CharTy
Definition: ASTContext.h:1085
CanQualType IntTy
Definition: ASTContext.h:1092
CanQualType VoidTy
Definition: ASTContext.h:1083
CanQualType UnsignedCharTy
Definition: ASTContext.h:1093
CanQualType UnsignedIntTy
Definition: ASTContext.h:1093
QualType getFunctionType(QualType ResultTy, ArrayRef< QualType > Args, const FunctionProtoType::ExtProtoInfo &EPI) const
Return a normal function type with a typed argument list.
Definition: ASTContext.h:1550
CanQualType WCharTy
Definition: ASTContext.h:1086
Stores options for the analyzer from the command line.
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
static Opcode negateComparisonOp(Opcode Opc)
Definition: Expr.h:3967
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Definition: DeclBase.cpp:1797
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:85
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:501
void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const
The name of a declaration.
Represents a function declaration or definition.
Definition: Decl.h:1957
const ParmVarDecl * getParamDecl(unsigned i) const
Definition: Decl.h:2664
QualType getReturnType() const
Definition: Decl.h:2712
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition: Decl.cpp:3554
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition: Decl.cpp:3629
size_t param_size() const
Definition: Decl.h:2657
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
A (possibly-)qualified type.
Definition: Type.h:737
QualType withConst() const
Definition: Type.h:948
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:804
QualType getCanonicalType() const
Definition: Type.h:6832
void removeLocalRestrict()
Definition: Type.h:6891
bool isCanonical() const
Definition: Type.h:6837
bool isVoidType() const
Definition: Type.h:7343
QualType getType() const
Definition: Decl.h:715
const llvm::APSInt & getMaxValue(const llvm::APSInt &v)
const llvm::APSInt & getMinValue(const llvm::APSInt &v)
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:152
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
CheckerNameRef getCurrentCheckerName() const
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
ProgramStateRef assumeInclusiveRange(ProgramStateRef State, NonLoc Value, const llvm::APSInt &From, const llvm::APSInt &To, bool InBound)
const ProgramStateRef & getState() const
The tag upon which the TagVisitor reacts.
Definition: BugReporter.h:763
const ExplodedNode * getErrorNode() const
Definition: BugReporter.h:401
void markNotInteresting(SymbolRef sym)
bool isInteresting(SymbolRef sym) const
ConstraintManager & getConstraintManager()
Definition: ProgramState.h:580
A Range represents the closed range [from, to].
BasicValueFactory & getBasicValueFactory()
Definition: SValBuilder.h:157
ASTContext & getContext()
Definition: SValBuilder.h:144
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
Definition: SValBuilder.h:286
SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy)
Cast a given SVal to another SVal using given QualType's.
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Expr *expr, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
QualType getConditionType() const
Definition: SValBuilder.h:149
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition: SVals.h:55
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition: SVals.h:86
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition: SVals.h:82
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
std::optional< Loc > getErrnoLoc(ProgramStateRef State)
Returns the location that points to the MemoryRegion where the 'errno' value is stored.
ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State, CheckerContext &C)
Set errno state for the common case when a standard function is successful.
ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState)
Set the errno check state, do not modify the errno value.
ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, CheckerContext &C, const Expr *InvalE)
Set errno state for the common case when a standard function indicates failure only by errno.
ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C, NonLoc ErrnoSym)
Set errno state for the common case when a standard function fails.
@ Irrelevant
We do not know anything about 'errno'.
Definition: ErrnoModeling.h:29
SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV)
Get the dynamic extent for a symbolic value that represents a buffer.
std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)
Try to parse the value of a defined preprocessor macro.
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:210
bool matches(const til::SExpr *E1, const til::SExpr *E2)
Stencil describe(llvm::StringRef Id)
Produces a human-readable rendering of the node bound to Id, suitable for diagnostics and debugging.
BinaryOperatorKind
unsigned long uint64_t
Definition: Format.h:5226
#define bool
Definition: stdbool.h:20
Extra information about a function prototype.
Definition: Type.h:4236