clang 19.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 effects), 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 const BugType BT_InvalidArg{this, "Function call with invalid argument"};
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 auto R = std::make_unique<PathSensitiveBugReport>(BT_InvalidArg, Msg, N);
879
880 for (ArgNo ArgN : VC->getArgsToTrack()) {
881 bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
882 R->markInteresting(Call.getArgSVal(ArgN));
883 // All tracked arguments are important, highlight them.
884 R->addRange(Call.getArgSourceRange(ArgN));
885 }
886
887 C.emitReport(std::move(R));
888 }
889
890 /// These are the errno constraints that can be passed to summary cases.
891 /// One of these should fit for a single summary case.
892 /// Usually if a failure return value exists for function, that function
893 /// needs different cases for success and failure with different errno
894 /// constraints (and different return value constraints).
895 const NoErrnoConstraint ErrnoUnchanged{};
896 const ResetErrnoConstraint ErrnoIrrelevant{};
897 const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};
898 const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
899 const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
900};
901
902int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
903
904const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
905 std::numeric_limits<ArgNo>::max();
906
907static BasicValueFactory &getBVF(ProgramStateRef State) {
908 ProgramStateManager &Mgr = State->getStateManager();
909 SValBuilder &SVB = Mgr.getSValBuilder();
910 return SVB.getBasicValueFactory();
911}
912
913} // end of anonymous namespace
914
915void StdLibraryFunctionsChecker::printArgDesc(
916 StdLibraryFunctionsChecker::ArgNo ArgN, llvm::raw_ostream &Out) {
917 Out << std::to_string(ArgN + 1);
918 Out << llvm::getOrdinalSuffix(ArgN + 1);
919 Out << " argument";
920}
921
922void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN,
923 ProgramStateRef State,
924 const CallEvent &Call,
925 llvm::raw_ostream &Out) {
926 if (const llvm::APSInt *Val =
927 State->getStateManager().getSValBuilder().getKnownValue(
928 State, getArgSVal(Call, ArgN)))
929 Out << " (which is " << *Val << ")";
930}
931
932void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
933 llvm::APSInt RMax,
934 QualType ArgT,
936 llvm::raw_ostream &Out) {
937 if (RMin.isZero() && RMax.isZero())
938 Out << "zero";
939 else if (RMin == RMax)
940 Out << RMin;
941 else if (RMin == BVF.getMinValue(ArgT)) {
942 if (RMax == -1)
943 Out << "< 0";
944 else
945 Out << "<= " << RMax;
946 } else if (RMax == BVF.getMaxValue(ArgT)) {
947 if (RMin.isOne())
948 Out << "> 0";
949 else
950 Out << ">= " << RMin;
951 } else if (RMin.isNegative() == RMax.isNegative() &&
952 RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
953 Out << RMin << " or " << RMax;
954 } else {
955 Out << "between " << RMin << " and " << RMax;
956 }
957}
958
959void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
960 llvm::APSInt RMax,
961 QualType ArgT,
963 llvm::raw_ostream &Out) {
964 if (RMin.isZero() && RMax.isZero())
965 Out << "nonzero";
966 else if (RMin == RMax) {
967 Out << "not equal to " << RMin;
968 } else if (RMin == BVF.getMinValue(ArgT)) {
969 if (RMax == -1)
970 Out << ">= 0";
971 else
972 Out << "> " << RMax;
973 } else if (RMax == BVF.getMaxValue(ArgT)) {
974 if (RMin.isOne())
975 Out << "<= 0";
976 else
977 Out << "< " << RMin;
978 } else if (RMin.isNegative() == RMax.isNegative() &&
979 RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
980 Out << "not " << RMin << " and not " << RMax;
981 } else {
982 Out << "not between " << RMin << " and " << RMax;
983 }
984}
985
986void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(
987 BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
988 if (Ranges.empty())
989 return;
990
991 for (auto [Start, End] : getRanges()) {
992 const llvm::APSInt &Min = BVF.getValue(Start, ArgT);
993 const llvm::APSInt &Max = BVF.getValue(End, ArgT);
994 assert(Min <= Max);
995 if (!F(Min, Max))
996 return;
997 }
998}
999
1000void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(
1001 BasicValueFactory &BVF, QualType ArgT, const RangeApplyFunction &F) const {
1002 if (Ranges.empty())
1003 return;
1004
1005 const IntRangeVector &R = getRanges();
1006 size_t E = R.size();
1007
1008 const llvm::APSInt &MinusInf = BVF.getMinValue(ArgT);
1009 const llvm::APSInt &PlusInf = BVF.getMaxValue(ArgT);
1010
1011 const llvm::APSInt &RangeLeft = BVF.getValue(R[0].first - 1ULL, ArgT);
1012 const llvm::APSInt &RangeRight = BVF.getValue(R[E - 1].second + 1ULL, ArgT);
1013
1014 // Iterate over the "holes" between intervals.
1015 for (size_t I = 1; I != E; ++I) {
1016 const llvm::APSInt &Min = BVF.getValue(R[I - 1].second + 1ULL, ArgT);
1017 const llvm::APSInt &Max = BVF.getValue(R[I].first - 1ULL, ArgT);
1018 if (Min <= Max) {
1019 if (!F(Min, Max))
1020 return;
1021 }
1022 }
1023 // Check the interval [T_MIN, min(R) - 1].
1024 if (RangeLeft != PlusInf) {
1025 assert(MinusInf <= RangeLeft);
1026 if (!F(MinusInf, RangeLeft))
1027 return;
1028 }
1029 // Check the interval [max(R) + 1, T_MAX],
1030 if (RangeRight != MinusInf) {
1031 assert(RangeRight <= PlusInf);
1032 if (!F(RangeRight, PlusInf))
1033 return;
1034 }
1035}
1036
1037ProgramStateRef StdLibraryFunctionsChecker::RangeConstraint::apply(
1038 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1039 CheckerContext &C) const {
1040 ConstraintManager &CM = C.getConstraintManager();
1041 SVal V = getArgSVal(Call, getArgNo());
1042 QualType T = Summary.getArgType(getArgNo());
1043
1044 if (auto N = V.getAs<NonLoc>()) {
1045 auto ExcludeRangeFromArg = [&](const llvm::APSInt &Min,
1046 const llvm::APSInt &Max) {
1047 State = CM.assumeInclusiveRange(State, *N, Min, Max, false);
1048 return static_cast<bool>(State);
1049 };
1050 // "OutOfRange R" is handled by excluding all ranges in R.
1051 // "WithinRange R" is treated as "OutOfRange [T_MIN, T_MAX] \ R".
1052 applyOnRange(negateKind(Kind), C.getSValBuilder().getBasicValueFactory(), T,
1053 ExcludeRangeFromArg);
1054 }
1055
1056 return State;
1057}
1058
1059void StdLibraryFunctionsChecker::RangeConstraint::describe(
1060 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1061 const Summary &Summary, llvm::raw_ostream &Out) const {
1062
1063 BasicValueFactory &BVF = getBVF(State);
1064 QualType T = Summary.getArgType(getArgNo());
1065
1066 Out << ((DK == Violation) ? "should be " : "is ");
1067 if (!Description.empty()) {
1068 Out << Description;
1069 } else {
1070 unsigned I = Ranges.size();
1071 if (Kind == WithinRange) {
1072 for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1073 appendInsideRangeDesc(BVF.getValue(R.first, T),
1074 BVF.getValue(R.second, T), T, BVF, Out);
1075 if (--I > 0)
1076 Out << " or ";
1077 }
1078 } else {
1079 for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
1080 appendOutOfRangeDesc(BVF.getValue(R.first, T),
1081 BVF.getValue(R.second, T), T, BVF, Out);
1082 if (--I > 0)
1083 Out << " and ";
1084 }
1085 }
1086 }
1087}
1088
1089bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(
1090 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1091 llvm::raw_ostream &Out) const {
1092 unsigned int NRanges = 0;
1093 bool HaveAllRanges = true;
1094
1095 ProgramStateManager &Mgr = State->getStateManager();
1098 SVal V = getArgSVal(Call, getArgNo());
1099
1100 if (auto N = V.getAs<NonLoc>()) {
1101 if (const llvm::APSInt *Int = N->getAsInteger()) {
1102 Out << "is ";
1103 Out << *Int;
1104 return true;
1105 }
1106 QualType T = Summary.getArgType(getArgNo());
1107 SmallString<128> MoreInfo;
1108 llvm::raw_svector_ostream MoreInfoOs(MoreInfo);
1109 auto ApplyF = [&](const llvm::APSInt &Min, const llvm::APSInt &Max) {
1110 if (CM.assumeInclusiveRange(State, *N, Min, Max, true)) {
1111 if (NRanges > 0)
1112 MoreInfoOs << " or ";
1113 appendInsideRangeDesc(Min, Max, T, BVF, MoreInfoOs);
1114 ++NRanges;
1115 } else {
1116 HaveAllRanges = false;
1117 }
1118 return true;
1119 };
1120
1121 applyOnRange(Kind, BVF, T, ApplyF);
1122 assert(NRanges > 0);
1123 if (!HaveAllRanges || NRanges == 1) {
1124 Out << "is ";
1125 Out << MoreInfo;
1126 return true;
1127 }
1128 }
1129 return false;
1130}
1131
1132ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
1133 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1134 CheckerContext &C) const {
1135
1136 ProgramStateManager &Mgr = State->getStateManager();
1137 SValBuilder &SVB = Mgr.getSValBuilder();
1138 QualType CondT = SVB.getConditionType();
1139 QualType T = Summary.getArgType(getArgNo());
1140 SVal V = getArgSVal(Call, getArgNo());
1141
1142 BinaryOperator::Opcode Op = getOpcode();
1143 ArgNo OtherArg = getOtherArgNo();
1144 SVal OtherV = getArgSVal(Call, OtherArg);
1145 QualType OtherT = Summary.getArgType(OtherArg);
1146 // Note: we avoid integral promotion for comparison.
1147 OtherV = SVB.evalCast(OtherV, T, OtherT);
1148 if (auto CompV = SVB.evalBinOp(State, Op, V, OtherV, CondT)
1150 State = State->assume(*CompV, true);
1151 return State;
1152}
1153
1154ProgramStateRef StdLibraryFunctionsChecker::NotNullConstraint::apply(
1155 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1156 CheckerContext &C) const {
1157 SVal V = getArgSVal(Call, getArgNo());
1158 if (V.isUndef())
1159 return State;
1160
1162 if (!isa<Loc>(L))
1163 return State;
1164
1165 return State->assume(L, CannotBeNull);
1166}
1167
1168void StdLibraryFunctionsChecker::NotNullConstraint::describe(
1169 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1170 const Summary &Summary, llvm::raw_ostream &Out) const {
1171 assert(CannotBeNull &&
1172 "Describe should not be used when the value must be NULL");
1173 if (DK == Violation)
1174 Out << "should not be NULL";
1175 else
1176 Out << "is not NULL";
1177}
1178
1179bool StdLibraryFunctionsChecker::NotNullConstraint::describeArgumentValue(
1180 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1181 llvm::raw_ostream &Out) const {
1182 assert(!CannotBeNull && "This function is used when the value is NULL");
1183 Out << "is NULL";
1184 return true;
1185}
1186
1187ProgramStateRef StdLibraryFunctionsChecker::NotNullBufferConstraint::apply(
1188 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1189 CheckerContext &C) const {
1190 SVal V = getArgSVal(Call, getArgNo());
1191 if (V.isUndef())
1192 return State;
1194 if (!isa<Loc>(L))
1195 return State;
1196
1197 std::optional<DefinedOrUnknownSVal> SizeArg1 =
1198 getArgSVal(Call, SizeArg1N).getAs<DefinedOrUnknownSVal>();
1199 std::optional<DefinedOrUnknownSVal> SizeArg2;
1200 if (SizeArg2N)
1201 SizeArg2 = getArgSVal(Call, *SizeArg2N).getAs<DefinedOrUnknownSVal>();
1202
1203 auto IsArgZero = [State](std::optional<DefinedOrUnknownSVal> Val) {
1204 if (!Val)
1205 return false;
1206 auto [IsNonNull, IsNull] = State->assume(*Val);
1207 return IsNull && !IsNonNull;
1208 };
1209
1210 if (IsArgZero(SizeArg1) || IsArgZero(SizeArg2))
1211 return State;
1212
1213 return State->assume(L, CannotBeNull);
1214}
1215
1216void StdLibraryFunctionsChecker::NotNullBufferConstraint::describe(
1217 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1218 const Summary &Summary, llvm::raw_ostream &Out) const {
1219 assert(CannotBeNull &&
1220 "Describe should not be used when the value must be NULL");
1221 if (DK == Violation)
1222 Out << "should not be NULL";
1223 else
1224 Out << "is not NULL";
1225}
1226
1227bool StdLibraryFunctionsChecker::NotNullBufferConstraint::describeArgumentValue(
1228 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1229 llvm::raw_ostream &Out) const {
1230 assert(!CannotBeNull && "This function is used when the value is NULL");
1231 Out << "is NULL";
1232 return true;
1233}
1234
1235ProgramStateRef StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
1236 ProgramStateRef State, const CallEvent &Call, const Summary &Summary,
1237 CheckerContext &C) const {
1238 SValBuilder &SvalBuilder = C.getSValBuilder();
1239 // The buffer argument.
1240 SVal BufV = getArgSVal(Call, getArgNo());
1241
1242 // Get the size constraint.
1243 const SVal SizeV = [this, &State, &Call, &Summary, &SvalBuilder]() {
1244 if (ConcreteSize) {
1245 return SVal(SvalBuilder.makeIntVal(*ConcreteSize));
1246 }
1247 assert(SizeArgN && "The constraint must be either a concrete value or "
1248 "encoded in an argument.");
1249 // The size argument.
1250 SVal SizeV = getArgSVal(Call, *SizeArgN);
1251 // Multiply with another argument if given.
1252 if (SizeMultiplierArgN) {
1253 SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
1254 SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
1255 Summary.getArgType(*SizeArgN));
1256 }
1257 return SizeV;
1258 }();
1259
1260 // The dynamic size of the buffer argument, got from the analyzer engine.
1261 SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1262
1263 SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
1264 SvalBuilder.getContext().BoolTy);
1265 if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
1266 return State->assume(*F, true);
1267
1268 // We can get here only if the size argument or the dynamic size is
1269 // undefined. But the dynamic size should never be undefined, only
1270 // unknown. So, here, the size of the argument is undefined, i.e. we
1271 // cannot apply the constraint. Actually, other checkers like
1272 // CallAndMessage should catch this situation earlier, because we call a
1273 // function with an uninitialized argument.
1274 llvm_unreachable("Size argument or the dynamic size is Undefined");
1275}
1276
1277void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
1278 DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
1279 const Summary &Summary, llvm::raw_ostream &Out) const {
1280 Out << ((DK == Violation) ? "should be " : "is ");
1281 Out << "a buffer with size equal to or greater than ";
1282 if (ConcreteSize) {
1283 Out << *ConcreteSize;
1284 } else if (SizeArgN) {
1285 Out << "the value of the ";
1286 printArgDesc(*SizeArgN, Out);
1287 printArgValueInfo(*SizeArgN, State, Call, Out);
1288 if (SizeMultiplierArgN) {
1289 Out << " times the ";
1290 printArgDesc(*SizeMultiplierArgN, Out);
1291 printArgValueInfo(*SizeMultiplierArgN, State, Call, Out);
1292 }
1293 }
1294}
1295
1296bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(
1297 const CallEvent &Call, ProgramStateRef State, const Summary &Summary,
1298 llvm::raw_ostream &Out) const {
1299 SVal BufV = getArgSVal(Call, getArgNo());
1300 SVal BufDynSize = getDynamicExtentWithOffset(State, BufV);
1301 if (const llvm::APSInt *Val =
1302 State->getStateManager().getSValBuilder().getKnownValue(State,
1303 BufDynSize)) {
1304 Out << "is a buffer with size " << *Val;
1305 return true;
1306 }
1307 return false;
1308}
1309
1310void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
1311 CheckerContext &C) const {
1312 std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1313 if (!FoundSummary)
1314 return;
1315
1316 const Summary &Summary = *FoundSummary;
1317 ProgramStateRef State = C.getState();
1318
1319 ProgramStateRef NewState = State;
1320 ExplodedNode *NewNode = C.getPredecessor();
1321 for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
1322 ValueConstraintPtr NegatedConstraint = Constraint->negate();
1323 ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
1324 ProgramStateRef FailureSt =
1325 NegatedConstraint->apply(NewState, Call, Summary, C);
1326 // The argument constraint is not satisfied.
1327 if (FailureSt && !SuccessSt) {
1328 if (ExplodedNode *N = C.generateErrorNode(State, NewNode))
1329 reportBug(Call, N, Constraint.get(), NegatedConstraint.get(), Summary,
1330 C);
1331 break;
1332 }
1333 // We will apply the constraint even if we cannot reason about the
1334 // argument. This means both SuccessSt and FailureSt can be true. If we
1335 // weren't applying the constraint that would mean that symbolic
1336 // execution continues on a code whose behaviour is undefined.
1337 assert(SuccessSt);
1338 NewState = SuccessSt;
1339 if (NewState != State) {
1340 SmallString<128> Msg;
1341 llvm::raw_svector_ostream Os(Msg);
1342 Os << "Assuming that the ";
1343 printArgDesc(Constraint->getArgNo(), Os);
1344 Os << " to '";
1345 Os << getFunctionName(Call);
1346 Os << "' ";
1347 Constraint->describe(ValueConstraint::Assumption, Call, NewState, Summary,
1348 Os);
1349 const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
1350 NewNode = C.addTransition(
1351 NewState, NewNode,
1352 C.getNoteTag([Msg = std::move(Msg), ArgSVal](
1353 PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
1354 if (BR.isInteresting(ArgSVal))
1355 OS << Msg;
1356 }));
1357 }
1358 }
1359}
1360
1361void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
1362 CheckerContext &C) const {
1363 std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1364 if (!FoundSummary)
1365 return;
1366
1367 // Now apply the constraints.
1368 const Summary &Summary = *FoundSummary;
1369 ProgramStateRef State = C.getState();
1370 ExplodedNode *Node = C.getPredecessor();
1371
1372 // Apply case/branch specifications.
1373 for (const SummaryCase &Case : Summary.getCases()) {
1374 ProgramStateRef NewState = State;
1375 for (const ValueConstraintPtr &Constraint : Case.getConstraints()) {
1376 NewState = Constraint->apply(NewState, Call, Summary, C);
1377 if (!NewState)
1378 break;
1379 }
1380
1381 if (NewState)
1382 NewState = Case.getErrnoConstraint().apply(NewState, Call, Summary, C);
1383
1384 if (!NewState)
1385 continue;
1386
1387 // Here it's possible that NewState == State, e.g. when other checkers
1388 // already applied the same constraints (or stricter ones).
1389 // Still add these note tags, the other checker should add only its
1390 // specialized note tags. These general note tags are handled always by
1391 // StdLibraryFunctionsChecker.
1392
1393 ExplodedNode *Pred = Node;
1394 DeclarationName FunctionName =
1395 cast<NamedDecl>(Call.getDecl())->getDeclName();
1396
1397 std::string ErrnoNote = Case.getErrnoConstraint().describe(C);
1398 std::string CaseNote;
1399 if (Case.getNote().empty()) {
1400 if (!ErrnoNote.empty())
1401 ErrnoNote =
1402 llvm::formatv("After calling '{0}' {1}", FunctionName, ErrnoNote);
1403 } else {
1404 CaseNote = llvm::formatv(Case.getNote().str().c_str(), FunctionName);
1405 }
1406 const SVal RV = Call.getReturnValue();
1407
1408 if (Summary.getInvalidationKd() == EvalCallAsPure) {
1409 // Do not expect that errno is interesting (the "pure" functions do not
1410 // affect it).
1411 if (!CaseNote.empty()) {
1412 const NoteTag *Tag = C.getNoteTag(
1413 [Node, CaseNote, RV](PathSensitiveBugReport &BR) -> std::string {
1414 // Try to omit the note if we know in advance which branch is
1415 // taken (this means, only one branch exists).
1416 // This check is performed inside the lambda, after other
1417 // (or this) checkers had a chance to add other successors.
1418 // Dereferencing the saved node object is valid because it's part
1419 // of a bug report call sequence.
1420 // FIXME: This check is not exact. We may be here after a state
1421 // split that was performed by another checker (and can not find
1422 // the successors). This is why this check is only used in the
1423 // EvalCallAsPure case.
1424 if (BR.isInteresting(RV) && Node->succ_size() > 1)
1425 return CaseNote;
1426 return "";
1427 });
1428 Pred = C.addTransition(NewState, Pred, Tag);
1429 }
1430 } else {
1431 if (!CaseNote.empty() || !ErrnoNote.empty()) {
1432 const NoteTag *Tag =
1433 C.getNoteTag([CaseNote, ErrnoNote,
1434 RV](PathSensitiveBugReport &BR) -> std::string {
1435 // If 'errno' is interesting, show the user a note about the case
1436 // (what happened at the function call) and about how 'errno'
1437 // causes the problem. ErrnoChecker sets the errno (but not RV) to
1438 // interesting.
1439 // If only the return value is interesting, show only the case
1440 // note.
1441 std::optional<Loc> ErrnoLoc =
1443 bool ErrnoImportant = !ErrnoNote.empty() && ErrnoLoc &&
1444 BR.isInteresting(ErrnoLoc->getAsRegion());
1445 if (ErrnoImportant) {
1446 BR.markNotInteresting(ErrnoLoc->getAsRegion());
1447 if (CaseNote.empty())
1448 return ErrnoNote;
1449 return llvm::formatv("{0}; {1}", CaseNote, ErrnoNote);
1450 } else {
1451 if (BR.isInteresting(RV))
1452 return CaseNote;
1453 }
1454 return "";
1455 });
1456 Pred = C.addTransition(NewState, Pred, Tag);
1457 }
1458 }
1459
1460 // Add the transition if no note tag was added.
1461 if (Pred == Node && NewState != State)
1462 C.addTransition(NewState);
1463 }
1464}
1465
1466bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
1467 CheckerContext &C) const {
1468 std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
1469 if (!FoundSummary)
1470 return false;
1471
1472 const Summary &Summary = *FoundSummary;
1473 switch (Summary.getInvalidationKd()) {
1474 case EvalCallAsPure: {
1475 ProgramStateRef State = C.getState();
1476 const LocationContext *LC = C.getLocationContext();
1477 const auto *CE = cast<CallExpr>(Call.getOriginExpr());
1478 SVal V = C.getSValBuilder().conjureSymbolVal(
1479 CE, LC, CE->getType().getCanonicalType(), C.blockCount());
1480 State = State->BindExpr(CE, LC, V);
1481
1482 C.addTransition(State);
1483
1484 return true;
1485 }
1486 case NoEvalCall:
1487 // Summary tells us to avoid performing eval::Call. The function is possibly
1488 // evaluated by another checker, or evaluated conservatively.
1489 return false;
1490 }
1491 llvm_unreachable("Unknown invalidation kind!");
1492}
1493
1494bool StdLibraryFunctionsChecker::Signature::matches(
1495 const FunctionDecl *FD) const {
1496 assert(!isInvalid());
1497 // Check the number of arguments.
1498 if (FD->param_size() != ArgTys.size())
1499 return false;
1500
1501 // The "restrict" keyword is illegal in C++, however, many libc
1502 // implementations use the "__restrict" compiler intrinsic in functions
1503 // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1504 // even in C++.
1505 // In case of any non-C99 languages, we don't want to match based on the
1506 // restrict qualifier because we cannot know if the given libc implementation
1507 // qualifies the paramter type or not.
1508 auto RemoveRestrict = [&FD](QualType T) {
1509 if (!FD->getASTContext().getLangOpts().C99)
1510 T.removeLocalRestrict();
1511 return T;
1512 };
1513
1514 // Check the return type.
1515 if (!isIrrelevant(RetTy)) {
1516 QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
1517 if (RetTy != FDRetTy)
1518 return false;
1519 }
1520
1521 // Check the argument types.
1522 for (auto [Idx, ArgTy] : llvm::enumerate(ArgTys)) {
1523 if (isIrrelevant(ArgTy))
1524 continue;
1525 QualType FDArgTy =
1526 RemoveRestrict(FD->getParamDecl(Idx)->getType().getCanonicalType());
1527 if (ArgTy != FDArgTy)
1528 return false;
1529 }
1530
1531 return true;
1532}
1533
1534std::optional<StdLibraryFunctionsChecker::Summary>
1535StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
1536 CheckerContext &C) const {
1537 if (!FD)
1538 return std::nullopt;
1539
1540 initFunctionSummaries(C);
1541
1542 auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
1543 if (FSMI == FunctionSummaryMap.end())
1544 return std::nullopt;
1545 return FSMI->second;
1546}
1547
1548std::optional<StdLibraryFunctionsChecker::Summary>
1549StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
1550 CheckerContext &C) const {
1551 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
1552 if (!FD)
1553 return std::nullopt;
1554 return findFunctionSummary(FD, C);
1555}
1556
1557void StdLibraryFunctionsChecker::initFunctionSummaries(
1558 CheckerContext &C) const {
1559 if (SummariesInitialized)
1560 return;
1561 SummariesInitialized = true;
1562
1563 SValBuilder &SVB = C.getSValBuilder();
1565 const ASTContext &ACtx = BVF.getContext();
1566 Preprocessor &PP = C.getPreprocessor();
1567
1568 // Helper class to lookup a type by its name.
1569 class LookupType {
1570 const ASTContext &ACtx;
1571
1572 public:
1573 LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
1574
1575 // Find the type. If not found then the optional is not set.
1576 std::optional<QualType> operator()(StringRef Name) {
1577 IdentifierInfo &II = ACtx.Idents.get(Name);
1578 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1579 if (LookupRes.empty())
1580 return std::nullopt;
1581
1582 // Prioritze typedef declarations.
1583 // This is needed in case of C struct typedefs. E.g.:
1584 // typedef struct FILE FILE;
1585 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1586 // and we have a TypedefDecl with the name 'FILE'.
1587 for (Decl *D : LookupRes)
1588 if (auto *TD = dyn_cast<TypedefNameDecl>(D))
1589 return ACtx.getTypeDeclType(TD).getCanonicalType();
1590
1591 // Find the first TypeDecl.
1592 // There maybe cases when a function has the same name as a struct.
1593 // E.g. in POSIX: `struct stat` and the function `stat()`:
1594 // int stat(const char *restrict path, struct stat *restrict buf);
1595 for (Decl *D : LookupRes)
1596 if (auto *TD = dyn_cast<TypeDecl>(D))
1597 return ACtx.getTypeDeclType(TD).getCanonicalType();
1598 return std::nullopt;
1599 }
1600 } lookupTy(ACtx);
1601
1602 // Below are auxiliary classes to handle optional types that we get as a
1603 // result of the lookup.
1604 class GetRestrictTy {
1605 const ASTContext &ACtx;
1606
1607 public:
1608 GetRestrictTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1609 QualType operator()(QualType Ty) {
1610 return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
1611 }
1612 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1613 if (Ty)
1614 return operator()(*Ty);
1615 return std::nullopt;
1616 }
1617 } getRestrictTy(ACtx);
1618 class GetPointerTy {
1619 const ASTContext &ACtx;
1620
1621 public:
1622 GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
1623 QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
1624 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1625 if (Ty)
1626 return operator()(*Ty);
1627 return std::nullopt;
1628 }
1629 } getPointerTy(ACtx);
1630 class {
1631 public:
1632 std::optional<QualType> operator()(std::optional<QualType> Ty) {
1633 return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
1634 }
1635 QualType operator()(QualType Ty) { return Ty.withConst(); }
1636 } getConstTy;
1637 class GetMaxValue {
1638 BasicValueFactory &BVF;
1639
1640 public:
1641 GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
1642 std::optional<RangeInt> operator()(QualType Ty) {
1643 return BVF.getMaxValue(Ty).getLimitedValue();
1644 }
1645 std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
1646 if (Ty) {
1647 return operator()(*Ty);
1648 }
1649 return std::nullopt;
1650 }
1651 } getMaxValue(BVF);
1652
1653 // These types are useful for writing specifications quickly,
1654 // New specifications should probably introduce more types.
1655 // Some types are hard to obtain from the AST, eg. "ssize_t".
1656 // In such cases it should be possible to provide multiple variants
1657 // of function summary for common cases (eg. ssize_t could be int or long
1658 // or long long, so three summary variants would be enough).
1659 // Of course, function variants are also useful for C++ overloads.
1660 const QualType VoidTy = ACtx.VoidTy;
1661 const QualType CharTy = ACtx.CharTy;
1662 const QualType WCharTy = ACtx.WCharTy;
1663 const QualType IntTy = ACtx.IntTy;
1664 const QualType UnsignedIntTy = ACtx.UnsignedIntTy;
1665 const QualType LongTy = ACtx.LongTy;
1666 const QualType SizeTy = ACtx.getSizeType();
1667
1668 const QualType VoidPtrTy = getPointerTy(VoidTy); // void *
1669 const QualType IntPtrTy = getPointerTy(IntTy); // int *
1670 const QualType UnsignedIntPtrTy =
1671 getPointerTy(UnsignedIntTy); // unsigned int *
1672 const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
1673 const QualType ConstVoidPtrTy =
1674 getPointerTy(getConstTy(VoidTy)); // const void *
1675 const QualType CharPtrTy = getPointerTy(CharTy); // char *
1676 const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
1677 const QualType ConstCharPtrTy =
1678 getPointerTy(getConstTy(CharTy)); // const char *
1679 const QualType ConstCharPtrRestrictTy = getRestrictTy(ConstCharPtrTy);
1680 const QualType Wchar_tPtrTy = getPointerTy(WCharTy); // wchar_t *
1681 const QualType ConstWchar_tPtrTy =
1682 getPointerTy(getConstTy(WCharTy)); // const wchar_t *
1683 const QualType ConstVoidPtrRestrictTy = getRestrictTy(ConstVoidPtrTy);
1684 const QualType SizePtrTy = getPointerTy(SizeTy);
1685 const QualType SizePtrRestrictTy = getRestrictTy(SizePtrTy);
1686
1687 const RangeInt IntMax = BVF.getMaxValue(IntTy).getLimitedValue();
1688 const RangeInt UnsignedIntMax =
1689 BVF.getMaxValue(UnsignedIntTy).getLimitedValue();
1690 const RangeInt LongMax = BVF.getMaxValue(LongTy).getLimitedValue();
1691 const RangeInt SizeMax = BVF.getMaxValue(SizeTy).getLimitedValue();
1692
1693 // Set UCharRangeMax to min of int or uchar maximum value.
1694 // The C standard states that the arguments of functions like isalpha must
1695 // be representable as an unsigned char. Their type is 'int', so the max
1696 // value of the argument should be min(UCharMax, IntMax). This just happen
1697 // to be true for commonly used and well tested instruction set
1698 // architectures, but not for others.
1699 const RangeInt UCharRangeMax =
1700 std::min(BVF.getMaxValue(ACtx.UnsignedCharTy).getLimitedValue(), IntMax);
1701
1702 // Get platform dependent values of some macros.
1703 // Try our best to parse this from the Preprocessor, otherwise fallback to a
1704 // default value (what is found in a library header).
1705 const auto EOFv = tryExpandAsInteger("EOF", PP).value_or(-1);
1706 const auto AT_FDCWDv = tryExpandAsInteger("AT_FDCWD", PP).value_or(-100);
1707
1708 // Auxiliary class to aid adding summaries to the summary map.
1709 struct AddToFunctionSummaryMap {
1710 const ASTContext &ACtx;
1711 FunctionSummaryMapType &Map;
1712 bool DisplayLoadedSummaries;
1713 AddToFunctionSummaryMap(const ASTContext &ACtx, FunctionSummaryMapType &FSM,
1714 bool DisplayLoadedSummaries)
1715 : ACtx(ACtx), Map(FSM), DisplayLoadedSummaries(DisplayLoadedSummaries) {
1716 }
1717
1718 // Add a summary to a FunctionDecl found by lookup. The lookup is performed
1719 // by the given Name, and in the global scope. The summary will be attached
1720 // to the found FunctionDecl only if the signatures match.
1721 //
1722 // Returns true if the summary has been added, false otherwise.
1723 bool operator()(StringRef Name, Signature Sign, Summary Sum) {
1724 if (Sign.isInvalid())
1725 return false;
1726 IdentifierInfo &II = ACtx.Idents.get(Name);
1727 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
1728 if (LookupRes.empty())
1729 return false;
1730 for (Decl *D : LookupRes) {
1731 if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1732 if (Sum.matchesAndSet(Sign, FD)) {
1733 auto Res = Map.insert({FD->getCanonicalDecl(), Sum});
1734 assert(Res.second && "Function already has a summary set!");
1735 (void)Res;
1736 if (DisplayLoadedSummaries) {
1737 llvm::errs() << "Loaded summary for: ";
1738 FD->print(llvm::errs());
1739 llvm::errs() << "\n";
1740 }
1741 return true;
1742 }
1743 }
1744 }
1745 return false;
1746 }
1747 // Add the same summary for different names with the Signature explicitly
1748 // given.
1749 void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
1750 for (StringRef Name : Names)
1751 operator()(Name, Sign, Sum);
1752 }
1753 } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
1754
1755 // Below are helpers functions to create the summaries.
1756 auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
1757 StringRef Desc = "") {
1758 return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);
1759 };
1760 auto BufferSize = [](auto... Args) {
1761 return std::make_shared<BufferSizeConstraint>(Args...);
1762 };
1763 struct {
1764 auto operator()(RangeKind Kind, IntRangeVector Ranges) {
1765 return std::make_shared<RangeConstraint>(Ret, Kind, Ranges);
1766 }
1767 auto operator()(BinaryOperator::Opcode Op, ArgNo OtherArgN) {
1768 return std::make_shared<ComparisonConstraint>(Ret, Op, OtherArgN);
1769 }
1770 } ReturnValueCondition;
1771 struct {
1772 auto operator()(RangeInt b, RangeInt e) {
1773 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
1774 }
1775 auto operator()(RangeInt b, std::optional<RangeInt> e) {
1776 if (e)
1777 return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
1778 return IntRangeVector{};
1779 }
1780 auto operator()(std::pair<RangeInt, RangeInt> i0,
1781 std::pair<RangeInt, std::optional<RangeInt>> i1) {
1782 if (i1.second)
1783 return IntRangeVector{i0, {i1.first, *(i1.second)}};
1784 return IntRangeVector{i0};
1785 }
1786 } Range;
1787 auto SingleValue = [](RangeInt v) {
1788 return IntRangeVector{std::pair<RangeInt, RangeInt>{v, v}};
1789 };
1790 auto LessThanOrEq = BO_LE;
1791 auto NotNull = [&](ArgNo ArgN) {
1792 return std::make_shared<NotNullConstraint>(ArgN);
1793 };
1794 auto IsNull = [&](ArgNo ArgN) {
1795 return std::make_shared<NotNullConstraint>(ArgN, false);
1796 };
1797 auto NotNullBuffer = [&](ArgNo ArgN, ArgNo SizeArg1N, ArgNo SizeArg2N) {
1798 return std::make_shared<NotNullBufferConstraint>(ArgN, SizeArg1N,
1799 SizeArg2N);
1800 };
1801
1802 std::optional<QualType> FileTy = lookupTy("FILE");
1803 std::optional<QualType> FilePtrTy = getPointerTy(FileTy);
1804 std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
1805
1806 std::optional<QualType> FPosTTy = lookupTy("fpos_t");
1807 std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);
1808 std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));
1809 std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);
1810
1811 constexpr llvm::StringLiteral GenericSuccessMsg(
1812 "Assuming that '{0}' is successful");
1813 constexpr llvm::StringLiteral GenericFailureMsg("Assuming that '{0}' fails");
1814
1815 // We are finally ready to define specifications for all supported functions.
1816 //
1817 // Argument ranges should always cover all variants. If return value
1818 // is completely unknown, omit it from the respective range set.
1819 //
1820 // Every item in the list of range sets represents a particular
1821 // execution path the analyzer would need to explore once
1822 // the call is modeled - a new program state is constructed
1823 // for every range set, and each range line in the range set
1824 // corresponds to a specific constraint within this state.
1825
1826 // The isascii() family of functions.
1827 // The behavior is undefined if the value of the argument is not
1828 // representable as unsigned char or is not equal to EOF. See e.g. C99
1829 // 7.4.1.2 The isalpha function (p: 181-182).
1830 addToFunctionSummaryMap(
1831 "isalnum", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1832 Summary(EvalCallAsPure)
1833 // Boils down to isupper() or islower() or isdigit().
1834 .Case({ArgumentCondition(0U, WithinRange,
1835 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1836 ReturnValueCondition(OutOfRange, SingleValue(0))},
1837 ErrnoIrrelevant, "Assuming the character is alphanumeric")
1838 // The locale-specific range.
1839 // No post-condition. We are completely unaware of
1840 // locale-specific return values.
1841 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1842 ErrnoIrrelevant)
1843 .Case(
1844 {ArgumentCondition(
1845 0U, OutOfRange,
1846 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1847 ReturnValueCondition(WithinRange, SingleValue(0))},
1848 ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
1849 .ArgConstraint(ArgumentCondition(0U, WithinRange,
1850 {{EOFv, EOFv}, {0, UCharRangeMax}},
1851 "an unsigned char value or EOF")));
1852 addToFunctionSummaryMap(
1853 "isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1854 Summary(EvalCallAsPure)
1855 .Case({ArgumentCondition(0U, WithinRange, {{'A', 'Z'}, {'a', 'z'}}),
1856 ReturnValueCondition(OutOfRange, SingleValue(0))},
1857 ErrnoIrrelevant, "Assuming the character is alphabetical")
1858 // The locale-specific range.
1859 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1860 ErrnoIrrelevant)
1861 .Case({ArgumentCondition(
1862 0U, OutOfRange,
1863 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
1864 ReturnValueCondition(WithinRange, SingleValue(0))},
1865 ErrnoIrrelevant, "Assuming the character is non-alphabetical"));
1866 addToFunctionSummaryMap(
1867 "isascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1868 Summary(EvalCallAsPure)
1869 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1870 ReturnValueCondition(OutOfRange, SingleValue(0))},
1871 ErrnoIrrelevant, "Assuming the character is an ASCII character")
1872 .Case({ArgumentCondition(0U, OutOfRange, Range(0, 127)),
1873 ReturnValueCondition(WithinRange, SingleValue(0))},
1874 ErrnoIrrelevant,
1875 "Assuming the character is not an ASCII character"));
1876 addToFunctionSummaryMap(
1877 "isblank", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1878 Summary(EvalCallAsPure)
1879 .Case({ArgumentCondition(0U, WithinRange, {{'\t', '\t'}, {' ', ' '}}),
1880 ReturnValueCondition(OutOfRange, SingleValue(0))},
1881 ErrnoIrrelevant, "Assuming the character is a blank character")
1882 .Case({ArgumentCondition(0U, OutOfRange, {{'\t', '\t'}, {' ', ' '}}),
1883 ReturnValueCondition(WithinRange, SingleValue(0))},
1884 ErrnoIrrelevant,
1885 "Assuming the character is not a blank character"));
1886 addToFunctionSummaryMap(
1887 "iscntrl", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1888 Summary(EvalCallAsPure)
1889 .Case({ArgumentCondition(0U, WithinRange, {{0, 32}, {127, 127}}),
1890 ReturnValueCondition(OutOfRange, SingleValue(0))},
1891 ErrnoIrrelevant,
1892 "Assuming the character is a control character")
1893 .Case({ArgumentCondition(0U, OutOfRange, {{0, 32}, {127, 127}}),
1894 ReturnValueCondition(WithinRange, SingleValue(0))},
1895 ErrnoIrrelevant,
1896 "Assuming the character is not a control character"));
1897 addToFunctionSummaryMap(
1898 "isdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1899 Summary(EvalCallAsPure)
1900 .Case({ArgumentCondition(0U, WithinRange, Range('0', '9')),
1901 ReturnValueCondition(OutOfRange, SingleValue(0))},
1902 ErrnoIrrelevant, "Assuming the character is a digit")
1903 .Case({ArgumentCondition(0U, OutOfRange, Range('0', '9')),
1904 ReturnValueCondition(WithinRange, SingleValue(0))},
1905 ErrnoIrrelevant, "Assuming the character is not a digit"));
1906 addToFunctionSummaryMap(
1907 "isgraph", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1908 Summary(EvalCallAsPure)
1909 .Case({ArgumentCondition(0U, WithinRange, Range(33, 126)),
1910 ReturnValueCondition(OutOfRange, SingleValue(0))},
1911 ErrnoIrrelevant,
1912 "Assuming the character has graphical representation")
1913 .Case(
1914 {ArgumentCondition(0U, OutOfRange, Range(33, 126)),
1915 ReturnValueCondition(WithinRange, SingleValue(0))},
1916 ErrnoIrrelevant,
1917 "Assuming the character does not have graphical representation"));
1918 addToFunctionSummaryMap(
1919 "islower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1920 Summary(EvalCallAsPure)
1921 // Is certainly lowercase.
1922 .Case({ArgumentCondition(0U, WithinRange, Range('a', 'z')),
1923 ReturnValueCondition(OutOfRange, SingleValue(0))},
1924 ErrnoIrrelevant, "Assuming the character is a lowercase letter")
1925 // Is ascii but not lowercase.
1926 .Case({ArgumentCondition(0U, WithinRange, Range(0, 127)),
1927 ArgumentCondition(0U, OutOfRange, Range('a', 'z')),
1928 ReturnValueCondition(WithinRange, SingleValue(0))},
1929 ErrnoIrrelevant,
1930 "Assuming the character is not a lowercase letter")
1931 // The locale-specific range.
1932 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1933 ErrnoIrrelevant)
1934 // Is not an unsigned char.
1935 .Case({ArgumentCondition(0U, OutOfRange, Range(0, UCharRangeMax)),
1936 ReturnValueCondition(WithinRange, SingleValue(0))},
1937 ErrnoIrrelevant));
1938 addToFunctionSummaryMap(
1939 "isprint", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1940 Summary(EvalCallAsPure)
1941 .Case({ArgumentCondition(0U, WithinRange, Range(32, 126)),
1942 ReturnValueCondition(OutOfRange, SingleValue(0))},
1943 ErrnoIrrelevant, "Assuming the character is printable")
1944 .Case({ArgumentCondition(0U, OutOfRange, Range(32, 126)),
1945 ReturnValueCondition(WithinRange, SingleValue(0))},
1946 ErrnoIrrelevant, "Assuming the character is non-printable"));
1947 addToFunctionSummaryMap(
1948 "ispunct", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1949 Summary(EvalCallAsPure)
1950 .Case({ArgumentCondition(
1951 0U, WithinRange,
1952 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1953 ReturnValueCondition(OutOfRange, SingleValue(0))},
1954 ErrnoIrrelevant, "Assuming the character is a punctuation mark")
1955 .Case({ArgumentCondition(
1956 0U, OutOfRange,
1957 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1958 ReturnValueCondition(WithinRange, SingleValue(0))},
1959 ErrnoIrrelevant,
1960 "Assuming the character is not a punctuation mark"));
1961 addToFunctionSummaryMap(
1962 "isspace", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1963 Summary(EvalCallAsPure)
1964 // Space, '\f', '\n', '\r', '\t', '\v'.
1965 .Case({ArgumentCondition(0U, WithinRange, {{9, 13}, {' ', ' '}}),
1966 ReturnValueCondition(OutOfRange, SingleValue(0))},
1967 ErrnoIrrelevant,
1968 "Assuming the character is a whitespace character")
1969 // The locale-specific range.
1970 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1971 ErrnoIrrelevant)
1972 .Case({ArgumentCondition(0U, OutOfRange,
1973 {{9, 13}, {' ', ' '}, {128, UCharRangeMax}}),
1974 ReturnValueCondition(WithinRange, SingleValue(0))},
1975 ErrnoIrrelevant,
1976 "Assuming the character is not a whitespace character"));
1977 addToFunctionSummaryMap(
1978 "isupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1979 Summary(EvalCallAsPure)
1980 // Is certainly uppercase.
1981 .Case({ArgumentCondition(0U, WithinRange, Range('A', 'Z')),
1982 ReturnValueCondition(OutOfRange, SingleValue(0))},
1983 ErrnoIrrelevant,
1984 "Assuming the character is an uppercase letter")
1985 // The locale-specific range.
1986 .Case({ArgumentCondition(0U, WithinRange, {{128, UCharRangeMax}})},
1987 ErrnoIrrelevant)
1988 // Other.
1989 .Case({ArgumentCondition(0U, OutOfRange,
1990 {{'A', 'Z'}, {128, UCharRangeMax}}),
1991 ReturnValueCondition(WithinRange, SingleValue(0))},
1992 ErrnoIrrelevant,
1993 "Assuming the character is not an uppercase letter"));
1994 addToFunctionSummaryMap(
1995 "isxdigit", Signature(ArgTypes{IntTy}, RetType{IntTy}),
1996 Summary(EvalCallAsPure)
1997 .Case({ArgumentCondition(0U, WithinRange,
1998 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1999 ReturnValueCondition(OutOfRange, SingleValue(0))},
2000 ErrnoIrrelevant,
2001 "Assuming the character is a hexadecimal digit")
2002 .Case({ArgumentCondition(0U, OutOfRange,
2003 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
2004 ReturnValueCondition(WithinRange, SingleValue(0))},
2005 ErrnoIrrelevant,
2006 "Assuming the character is not a hexadecimal digit"));
2007 addToFunctionSummaryMap(
2008 "toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2009 Summary(EvalCallAsPure)
2010 .ArgConstraint(ArgumentCondition(0U, WithinRange,
2011 {{EOFv, EOFv}, {0, UCharRangeMax}},
2012 "an unsigned char value or EOF")));
2013 addToFunctionSummaryMap(
2014 "tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2015 Summary(EvalCallAsPure)
2016 .ArgConstraint(ArgumentCondition(0U, WithinRange,
2017 {{EOFv, EOFv}, {0, UCharRangeMax}},
2018 "an unsigned char value or EOF")));
2019 addToFunctionSummaryMap(
2020 "toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2021 Summary(EvalCallAsPure)
2022 .ArgConstraint(ArgumentCondition(0U, WithinRange,
2023 {{EOFv, EOFv}, {0, UCharRangeMax}},
2024 "an unsigned char value or EOF")));
2025
2026 addToFunctionSummaryMap(
2027 "getchar", Signature(ArgTypes{}, RetType{IntTy}),
2028 Summary(NoEvalCall)
2029 .Case({ReturnValueCondition(WithinRange,
2030 {{EOFv, EOFv}, {0, UCharRangeMax}})},
2031 ErrnoIrrelevant));
2032
2033 // read()-like functions that never return more than buffer size.
2034 auto FreadSummary =
2035 Summary(NoEvalCall)
2036 .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2037 ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
2038 ReturnValueCondition(BO_LT, ArgNo(2)),
2039 ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2040 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2041 .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
2042 ReturnValueCondition(BO_EQ, ArgNo(2)),
2043 ReturnValueCondition(WithinRange, Range(0, SizeMax))},
2044 ErrnoMustNotBeChecked, GenericSuccessMsg)
2045 .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
2046 ReturnValueCondition(WithinRange, SingleValue(0))},
2047 ErrnoMustNotBeChecked,
2048 "Assuming that argument 'size' to '{0}' is 0")
2049 .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))
2050 .ArgConstraint(NotNull(ArgNo(3)))
2051 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2052 /*BufSizeMultiplier=*/ArgNo(2)));
2053
2054 // size_t fread(void *restrict ptr, size_t size, size_t nitems,
2055 // FILE *restrict stream);
2056 addToFunctionSummaryMap(
2057 "fread",
2058 Signature(ArgTypes{VoidPtrRestrictTy, SizeTy, SizeTy, FilePtrRestrictTy},
2059 RetType{SizeTy}),
2060 FreadSummary);
2061 // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
2062 // FILE *restrict stream);
2063 addToFunctionSummaryMap("fwrite",
2064 Signature(ArgTypes{ConstVoidPtrRestrictTy, SizeTy,
2065 SizeTy, FilePtrRestrictTy},
2066 RetType{SizeTy}),
2067 FreadSummary);
2068
2069 std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
2070 std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
2071
2072 auto ReadSummary =
2073 Summary(NoEvalCall)
2074 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
2075 ReturnValueCondition(WithinRange, Range(-1, Ssize_tMax))},
2076 ErrnoIrrelevant);
2077
2078 // FIXME these are actually defined by POSIX and not by the C standard, we
2079 // should handle them together with the rest of the POSIX functions.
2080 // ssize_t read(int fildes, void *buf, size_t nbyte);
2081 addToFunctionSummaryMap(
2082 "read", Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2083 ReadSummary);
2084 // ssize_t write(int fildes, const void *buf, size_t nbyte);
2085 addToFunctionSummaryMap(
2086 "write",
2087 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy}, RetType{Ssize_tTy}),
2088 ReadSummary);
2089
2090 auto GetLineSummary =
2091 Summary(NoEvalCall)
2092 .Case({ReturnValueCondition(WithinRange,
2093 Range({-1, -1}, {1, Ssize_tMax}))},
2094 ErrnoIrrelevant);
2095
2096 QualType CharPtrPtrRestrictTy = getRestrictTy(getPointerTy(CharPtrTy));
2097
2098 // getline()-like functions either fail or read at least the delimiter.
2099 // FIXME these are actually defined by POSIX and not by the C standard, we
2100 // should handle them together with the rest of the POSIX functions.
2101 // ssize_t getline(char **restrict lineptr, size_t *restrict n,
2102 // FILE *restrict stream);
2103 addToFunctionSummaryMap(
2104 "getline",
2105 Signature(
2106 ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, FilePtrRestrictTy},
2107 RetType{Ssize_tTy}),
2108 GetLineSummary);
2109 // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2110 // int delimiter, FILE *restrict stream);
2111 addToFunctionSummaryMap(
2112 "getdelim",
2113 Signature(ArgTypes{CharPtrPtrRestrictTy, SizePtrRestrictTy, IntTy,
2114 FilePtrRestrictTy},
2115 RetType{Ssize_tTy}),
2116 GetLineSummary);
2117
2118 {
2119 Summary GetenvSummary =
2120 Summary(NoEvalCall)
2121 .ArgConstraint(NotNull(ArgNo(0)))
2122 .Case({NotNull(Ret)}, ErrnoIrrelevant,
2123 "Assuming the environment variable exists");
2124 // In untrusted environments the envvar might not exist.
2125 if (!ShouldAssumeControlledEnvironment)
2126 GetenvSummary.Case({NotNull(Ret)->negate()}, ErrnoIrrelevant,
2127 "Assuming the environment variable does not exist");
2128
2129 // char *getenv(const char *name);
2130 addToFunctionSummaryMap(
2131 "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2132 std::move(GetenvSummary));
2133 }
2134
2135 if (!ModelPOSIX) {
2136 // Without POSIX use of 'errno' is not specified (in these cases).
2137 // Add these functions without 'errno' checks.
2138 addToFunctionSummaryMap(
2139 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2140 Summary(NoEvalCall)
2141 .Case({ReturnValueCondition(WithinRange,
2142 {{EOFv, EOFv}, {0, UCharRangeMax}})},
2143 ErrnoIrrelevant)
2144 .ArgConstraint(NotNull(ArgNo(0))));
2145 } else {
2146 const auto ReturnsZeroOrMinusOne =
2147 ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
2148 const auto ReturnsZero =
2149 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
2150 const auto ReturnsMinusOne =
2151 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
2152 const auto ReturnsEOF =
2153 ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(EOFv))};
2154 const auto ReturnsNonnegative =
2155 ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
2156 const auto ReturnsNonZero =
2157 ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
2158 const auto ReturnsFileDescriptor =
2159 ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
2160 const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
2161
2162 auto ValidFileDescriptorOrAtFdcwd = [&](ArgNo ArgN) {
2163 return std::make_shared<RangeConstraint>(
2164 ArgN, WithinRange, Range({AT_FDCWDv, AT_FDCWDv}, {0, IntMax}),
2165 "a valid file descriptor or AT_FDCWD");
2166 };
2167
2168 // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2169 addToFunctionSummaryMap(
2170 "fopen",
2171 Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
2172 RetType{FilePtrTy}),
2173 Summary(NoEvalCall)
2174 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2175 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2176 .ArgConstraint(NotNull(ArgNo(0)))
2177 .ArgConstraint(NotNull(ArgNo(1))));
2178
2179 // FILE *fdopen(int fd, const char *mode);
2180 addToFunctionSummaryMap(
2181 "fdopen",
2182 Signature(ArgTypes{IntTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2183 Summary(NoEvalCall)
2184 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2185 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2186 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2187 .ArgConstraint(NotNull(ArgNo(1))));
2188
2189 // FILE *tmpfile(void);
2190 addToFunctionSummaryMap(
2191 "tmpfile", Signature(ArgTypes{}, RetType{FilePtrTy}),
2192 Summary(NoEvalCall)
2193 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2194 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2195
2196 // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2197 // FILE *restrict stream);
2198 addToFunctionSummaryMap(
2199 "freopen",
2200 Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
2201 FilePtrRestrictTy},
2202 RetType{FilePtrTy}),
2203 Summary(NoEvalCall)
2204 .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},
2205 ErrnoMustNotBeChecked, GenericSuccessMsg)
2206 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2207 .ArgConstraint(NotNull(ArgNo(1)))
2208 .ArgConstraint(NotNull(ArgNo(2))));
2209
2210 // FILE *popen(const char *command, const char *type);
2211 addToFunctionSummaryMap(
2212 "popen",
2213 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{FilePtrTy}),
2214 Summary(NoEvalCall)
2215 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2216 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2217 .ArgConstraint(NotNull(ArgNo(0)))
2218 .ArgConstraint(NotNull(ArgNo(1))));
2219
2220 // int fclose(FILE *stream);
2221 addToFunctionSummaryMap(
2222 "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2223 Summary(NoEvalCall)
2224 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2225 .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2226 .ArgConstraint(NotNull(ArgNo(0))));
2227
2228 // int pclose(FILE *stream);
2229 addToFunctionSummaryMap(
2230 "pclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2231 Summary(NoEvalCall)
2232 .Case({ReturnValueCondition(WithinRange, {{0, IntMax}})},
2233 ErrnoMustNotBeChecked, GenericSuccessMsg)
2234 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2235 .ArgConstraint(NotNull(ArgNo(0))));
2236
2237 std::optional<QualType> Off_tTy = lookupTy("off_t");
2238 std::optional<RangeInt> Off_tMax = getMaxValue(Off_tTy);
2239
2240 // int fgetc(FILE *stream);
2241 // 'getc' is the same as 'fgetc' but may be a macro
2242 addToFunctionSummaryMap(
2243 {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2244 Summary(NoEvalCall)
2245 .Case({ReturnValueCondition(WithinRange, {{0, UCharRangeMax}})},
2246 ErrnoMustNotBeChecked, GenericSuccessMsg)
2247 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2248 ErrnoIrrelevant, GenericFailureMsg)
2249 .ArgConstraint(NotNull(ArgNo(0))));
2250
2251 // int fputc(int c, FILE *stream);
2252 // 'putc' is the same as 'fputc' but may be a macro
2253 addToFunctionSummaryMap(
2254 {"putc", "fputc"},
2255 Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2256 Summary(NoEvalCall)
2257 .Case({ArgumentCondition(0, WithinRange, Range(0, UCharRangeMax)),
2258 ReturnValueCondition(BO_EQ, ArgNo(0))},
2259 ErrnoMustNotBeChecked, GenericSuccessMsg)
2260 .Case({ArgumentCondition(0, OutOfRange, Range(0, UCharRangeMax)),
2261 ReturnValueCondition(WithinRange, Range(0, UCharRangeMax))},
2262 ErrnoMustNotBeChecked, GenericSuccessMsg)
2263 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2264 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2265 .ArgConstraint(NotNull(ArgNo(1))));
2266
2267 // char *fgets(char *restrict s, int n, FILE *restrict stream);
2268 addToFunctionSummaryMap(
2269 "fgets",
2270 Signature(ArgTypes{CharPtrRestrictTy, IntTy, FilePtrRestrictTy},
2271 RetType{CharPtrTy}),
2272 Summary(NoEvalCall)
2273 .Case({ReturnValueCondition(BO_EQ, ArgNo(0))},
2274 ErrnoMustNotBeChecked, GenericSuccessMsg)
2275 .Case({IsNull(Ret)}, ErrnoIrrelevant, GenericFailureMsg)
2276 .ArgConstraint(NotNull(ArgNo(0)))
2277 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax)))
2278 .ArgConstraint(
2279 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
2280 .ArgConstraint(NotNull(ArgNo(2))));
2281
2282 // int fputs(const char *restrict s, FILE *restrict stream);
2283 addToFunctionSummaryMap(
2284 "fputs",
2285 Signature(ArgTypes{ConstCharPtrRestrictTy, FilePtrRestrictTy},
2286 RetType{IntTy}),
2287 Summary(NoEvalCall)
2288 .Case(ReturnsNonnegative, ErrnoMustNotBeChecked, GenericSuccessMsg)
2289 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
2290 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2291 .ArgConstraint(NotNull(ArgNo(0)))
2292 .ArgConstraint(NotNull(ArgNo(1))));
2293
2294 // int ungetc(int c, FILE *stream);
2295 addToFunctionSummaryMap(
2296 "ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}),
2297 Summary(NoEvalCall)
2298 .Case({ReturnValueCondition(BO_EQ, ArgNo(0)),
2299 ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2300 ErrnoMustNotBeChecked, GenericSuccessMsg)
2301 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),
2302 ArgumentCondition(0, WithinRange, SingleValue(EOFv))},
2303 ErrnoNEZeroIrrelevant,
2304 "Assuming that 'ungetc' fails because EOF was passed as "
2305 "character")
2306 .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)),
2307 ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})},
2308 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2309 .ArgConstraint(ArgumentCondition(
2310 0, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}}))
2311 .ArgConstraint(NotNull(ArgNo(1))));
2312
2313 // int fseek(FILE *stream, long offset, int whence);
2314 // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
2315 // these for condition of arg 2.
2316 // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
2317 addToFunctionSummaryMap(
2318 "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
2319 Summary(NoEvalCall)
2320 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2321 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2322 .ArgConstraint(NotNull(ArgNo(0)))
2323 .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2324
2325 // int fseeko(FILE *stream, off_t offset, int whence);
2326 addToFunctionSummaryMap(
2327 "fseeko",
2328 Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}),
2329 Summary(NoEvalCall)
2330 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2331 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2332 .ArgConstraint(NotNull(ArgNo(0)))
2333 .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
2334
2335 // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
2336 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2337 // "The fgetpos() function shall not change the setting of errno if
2338 // successful."
2339 addToFunctionSummaryMap(
2340 "fgetpos",
2341 Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
2342 RetType{IntTy}),
2343 Summary(NoEvalCall)
2344 .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2345 .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2346 .ArgConstraint(NotNull(ArgNo(0)))
2347 .ArgConstraint(NotNull(ArgNo(1))));
2348
2349 // int fsetpos(FILE *stream, const fpos_t *pos);
2350 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2351 // "The fsetpos() function shall not change the setting of errno if
2352 // successful."
2353 addToFunctionSummaryMap(
2354 "fsetpos",
2355 Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
2356 Summary(NoEvalCall)
2357 .Case(ReturnsZero, ErrnoUnchanged, GenericSuccessMsg)
2358 .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2359 .ArgConstraint(NotNull(ArgNo(0)))
2360 .ArgConstraint(NotNull(ArgNo(1))));
2361
2362 // int fflush(FILE *stream);
2363 addToFunctionSummaryMap(
2364 "fflush", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2365 Summary(NoEvalCall)
2366 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2367 .Case(ReturnsEOF, ErrnoNEZeroIrrelevant, GenericFailureMsg));
2368
2369 // long ftell(FILE *stream);
2370 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2371 // "The ftell() function shall not change the setting of errno if
2372 // successful."
2373 addToFunctionSummaryMap(
2374 "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
2375 Summary(NoEvalCall)
2376 .Case({ReturnValueCondition(WithinRange, Range(0, LongMax))},
2377 ErrnoUnchanged, GenericSuccessMsg)
2378 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2379 .ArgConstraint(NotNull(ArgNo(0))));
2380
2381 // off_t ftello(FILE *stream);
2382 addToFunctionSummaryMap(
2383 "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}),
2384 Summary(NoEvalCall)
2385 .Case({ReturnValueCondition(WithinRange, Range(0, Off_tMax))},
2386 ErrnoMustNotBeChecked, GenericSuccessMsg)
2387 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2388 .ArgConstraint(NotNull(ArgNo(0))));
2389
2390 // int fileno(FILE *stream);
2391 // According to POSIX 'fileno' may fail and set 'errno'.
2392 // But in Linux it may fail only if the specified file pointer is invalid.
2393 // At many places 'fileno' is used without check for failure and a failure
2394 // case here would produce a large amount of likely false positive warnings.
2395 // To avoid this, we assume here that it does not fail.
2396 addToFunctionSummaryMap(
2397 "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2398 Summary(NoEvalCall)
2399 .Case(ReturnsValidFileDescriptor, ErrnoUnchanged, GenericSuccessMsg)
2400 .ArgConstraint(NotNull(ArgNo(0))));
2401
2402 // void rewind(FILE *stream);
2403 // This function indicates error only by setting of 'errno'.
2404 addToFunctionSummaryMap("rewind",
2405 Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2406 Summary(NoEvalCall)
2407 .Case({}, ErrnoMustBeChecked)
2408 .ArgConstraint(NotNull(ArgNo(0))));
2409
2410 // void clearerr(FILE *stream);
2411 addToFunctionSummaryMap(
2412 "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
2413 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2414
2415 // int feof(FILE *stream);
2416 addToFunctionSummaryMap(
2417 "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2418 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2419
2420 // int ferror(FILE *stream);
2421 addToFunctionSummaryMap(
2422 "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
2423 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2424
2425 // long a64l(const char *str64);
2426 addToFunctionSummaryMap(
2427 "a64l", Signature(ArgTypes{ConstCharPtrTy}, RetType{LongTy}),
2428 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2429
2430 // char *l64a(long value);
2431 addToFunctionSummaryMap("l64a",
2432 Signature(ArgTypes{LongTy}, RetType{CharPtrTy}),
2433 Summary(NoEvalCall)
2434 .ArgConstraint(ArgumentCondition(
2435 0, WithinRange, Range(0, LongMax))));
2436
2437 // int open(const char *path, int oflag, ...);
2438 addToFunctionSummaryMap(
2439 "open", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2440 Summary(NoEvalCall)
2441 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2442 GenericSuccessMsg)
2443 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2444 .ArgConstraint(NotNull(ArgNo(0))));
2445
2446 // int openat(int fd, const char *path, int oflag, ...);
2447 addToFunctionSummaryMap(
2448 "openat",
2449 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2450 Summary(NoEvalCall)
2451 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2452 GenericSuccessMsg)
2453 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2454 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2455 .ArgConstraint(NotNull(ArgNo(1))));
2456
2457 // int access(const char *pathname, int amode);
2458 addToFunctionSummaryMap(
2459 "access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
2460 Summary(NoEvalCall)
2461 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2462 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2463 .ArgConstraint(NotNull(ArgNo(0))));
2464
2465 // int faccessat(int dirfd, const char *pathname, int mode, int flags);
2466 addToFunctionSummaryMap(
2467 "faccessat",
2468 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, IntTy},
2469 RetType{IntTy}),
2470 Summary(NoEvalCall)
2471 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2472 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2473 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2474 .ArgConstraint(NotNull(ArgNo(1))));
2475
2476 // int dup(int fildes);
2477 addToFunctionSummaryMap(
2478 "dup", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2479 Summary(NoEvalCall)
2480 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2481 GenericSuccessMsg)
2482 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2483 .ArgConstraint(
2484 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2485
2486 // int dup2(int fildes1, int filedes2);
2487 addToFunctionSummaryMap(
2488 "dup2", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
2489 Summary(NoEvalCall)
2490 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2491 GenericSuccessMsg)
2492 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2493 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2494 .ArgConstraint(
2495 ArgumentCondition(1, WithinRange, Range(0, IntMax))));
2496
2497 // int fdatasync(int fildes);
2498 addToFunctionSummaryMap(
2499 "fdatasync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2500 Summary(NoEvalCall)
2501 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2502 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2503 .ArgConstraint(
2504 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2505
2506 // int fnmatch(const char *pattern, const char *string, int flags);
2507 addToFunctionSummaryMap(
2508 "fnmatch",
2509 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy, IntTy},
2510 RetType{IntTy}),
2511 Summary(NoEvalCall)
2512 .ArgConstraint(NotNull(ArgNo(0)))
2513 .ArgConstraint(NotNull(ArgNo(1))));
2514
2515 // int fsync(int fildes);
2516 addToFunctionSummaryMap(
2517 "fsync", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2518 Summary(NoEvalCall)
2519 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2520 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2521 .ArgConstraint(
2522 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2523
2524 // int truncate(const char *path, off_t length);
2525 addToFunctionSummaryMap(
2526 "truncate",
2527 Signature(ArgTypes{ConstCharPtrTy, Off_tTy}, RetType{IntTy}),
2528 Summary(NoEvalCall)
2529 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2530 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2531 .ArgConstraint(NotNull(ArgNo(0))));
2532
2533 // int symlink(const char *oldpath, const char *newpath);
2534 addToFunctionSummaryMap(
2535 "symlink",
2536 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2537 Summary(NoEvalCall)
2538 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2539 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2540 .ArgConstraint(NotNull(ArgNo(0)))
2541 .ArgConstraint(NotNull(ArgNo(1))));
2542
2543 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
2544 addToFunctionSummaryMap(
2545 "symlinkat",
2546 Signature(ArgTypes{ConstCharPtrTy, IntTy, ConstCharPtrTy},
2547 RetType{IntTy}),
2548 Summary(NoEvalCall)
2549 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2550 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2551 .ArgConstraint(NotNull(ArgNo(0)))
2552 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
2553 .ArgConstraint(NotNull(ArgNo(2))));
2554
2555 // int lockf(int fd, int cmd, off_t len);
2556 addToFunctionSummaryMap(
2557 "lockf", Signature(ArgTypes{IntTy, IntTy, Off_tTy}, RetType{IntTy}),
2558 Summary(NoEvalCall)
2559 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2560 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2561 .ArgConstraint(
2562 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2563
2564 std::optional<QualType> Mode_tTy = lookupTy("mode_t");
2565
2566 // int creat(const char *pathname, mode_t mode);
2567 addToFunctionSummaryMap(
2568 "creat", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2569 Summary(NoEvalCall)
2570 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2571 GenericSuccessMsg)
2572 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2573 .ArgConstraint(NotNull(ArgNo(0))));
2574
2575 // unsigned int sleep(unsigned int seconds);
2576 addToFunctionSummaryMap(
2577 "sleep", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2578 Summary(NoEvalCall)
2579 .ArgConstraint(
2580 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2581
2582 std::optional<QualType> DirTy = lookupTy("DIR");
2583 std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
2584
2585 // int dirfd(DIR *dirp);
2586 addToFunctionSummaryMap(
2587 "dirfd", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2588 Summary(NoEvalCall)
2589 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2590 GenericSuccessMsg)
2591 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2592 .ArgConstraint(NotNull(ArgNo(0))));
2593
2594 // unsigned int alarm(unsigned int seconds);
2595 addToFunctionSummaryMap(
2596 "alarm", Signature(ArgTypes{UnsignedIntTy}, RetType{UnsignedIntTy}),
2597 Summary(NoEvalCall)
2598 .ArgConstraint(
2599 ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
2600
2601 // int closedir(DIR *dir);
2602 addToFunctionSummaryMap(
2603 "closedir", Signature(ArgTypes{DirPtrTy}, RetType{IntTy}),
2604 Summary(NoEvalCall)
2605 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2606 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2607 .ArgConstraint(NotNull(ArgNo(0))));
2608
2609 // char *strdup(const char *s);
2610 addToFunctionSummaryMap(
2611 "strdup", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
2612 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2613
2614 // char *strndup(const char *s, size_t n);
2615 addToFunctionSummaryMap(
2616 "strndup",
2617 Signature(ArgTypes{ConstCharPtrTy, SizeTy}, RetType{CharPtrTy}),
2618 Summary(NoEvalCall)
2619 .ArgConstraint(NotNull(ArgNo(0)))
2620 .ArgConstraint(
2621 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2622
2623 // wchar_t *wcsdup(const wchar_t *s);
2624 addToFunctionSummaryMap(
2625 "wcsdup", Signature(ArgTypes{ConstWchar_tPtrTy}, RetType{Wchar_tPtrTy}),
2626 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2627
2628 // int mkstemp(char *template);
2629 addToFunctionSummaryMap(
2630 "mkstemp", Signature(ArgTypes{CharPtrTy}, RetType{IntTy}),
2631 Summary(NoEvalCall)
2632 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
2633 GenericSuccessMsg)
2634 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2635 .ArgConstraint(NotNull(ArgNo(0))));
2636
2637 // char *mkdtemp(char *template);
2638 addToFunctionSummaryMap(
2639 "mkdtemp", Signature(ArgTypes{CharPtrTy}, RetType{CharPtrTy}),
2640 Summary(NoEvalCall)
2641 .Case({ReturnValueCondition(BO_EQ, ArgNo(0))},
2642 ErrnoMustNotBeChecked, GenericSuccessMsg)
2643 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2644 .ArgConstraint(NotNull(ArgNo(0))));
2645
2646 // char *getcwd(char *buf, size_t size);
2647 addToFunctionSummaryMap(
2648 "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
2649 Summary(NoEvalCall)
2650 .Case({ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2651 ReturnValueCondition(BO_EQ, ArgNo(0))},
2652 ErrnoMustNotBeChecked, GenericSuccessMsg)
2653 .Case({ArgumentCondition(1, WithinRange, SingleValue(0)),
2654 IsNull(Ret)},
2655 ErrnoNEZeroIrrelevant, "Assuming that argument 'size' is 0")
2656 .Case({ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
2657 IsNull(Ret)},
2658 ErrnoNEZeroIrrelevant, GenericFailureMsg)
2659 .ArgConstraint(NotNull(ArgNo(0)))
2660 .ArgConstraint(
2661 BufferSize(/*Buffer*/ ArgNo(0), /*BufSize*/ ArgNo(1)))
2662 .ArgConstraint(
2663 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
2664
2665 // int mkdir(const char *pathname, mode_t mode);
2666 addToFunctionSummaryMap(
2667 "mkdir", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2668 Summary(NoEvalCall)
2669 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2670 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2671 .ArgConstraint(NotNull(ArgNo(0))));
2672
2673 // int mkdirat(int dirfd, const char *pathname, mode_t mode);
2674 addToFunctionSummaryMap(
2675 "mkdirat",
2676 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2677 Summary(NoEvalCall)
2678 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2679 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2680 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2681 .ArgConstraint(NotNull(ArgNo(1))));
2682
2683 std::optional<QualType> Dev_tTy = lookupTy("dev_t");
2684
2685 // int mknod(const char *pathname, mode_t mode, dev_t dev);
2686 addToFunctionSummaryMap(
2687 "mknod",
2688 Signature(ArgTypes{ConstCharPtrTy, Mode_tTy, Dev_tTy}, RetType{IntTy}),
2689 Summary(NoEvalCall)
2690 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2691 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2692 .ArgConstraint(NotNull(ArgNo(0))));
2693
2694 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2695 addToFunctionSummaryMap(
2696 "mknodat",
2697 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, Dev_tTy},
2698 RetType{IntTy}),
2699 Summary(NoEvalCall)
2700 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2701 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2702 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2703 .ArgConstraint(NotNull(ArgNo(1))));
2704
2705 // int chmod(const char *path, mode_t mode);
2706 addToFunctionSummaryMap(
2707 "chmod", Signature(ArgTypes{ConstCharPtrTy, Mode_tTy}, RetType{IntTy}),
2708 Summary(NoEvalCall)
2709 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2710 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2711 .ArgConstraint(NotNull(ArgNo(0))));
2712
2713 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
2714 addToFunctionSummaryMap(
2715 "fchmodat",
2716 Signature(ArgTypes{IntTy, ConstCharPtrTy, Mode_tTy, IntTy},
2717 RetType{IntTy}),
2718 Summary(NoEvalCall)
2719 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2720 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2721 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2722 .ArgConstraint(NotNull(ArgNo(1))));
2723
2724 // int fchmod(int fildes, mode_t mode);
2725 addToFunctionSummaryMap(
2726 "fchmod", Signature(ArgTypes{IntTy, Mode_tTy}, RetType{IntTy}),
2727 Summary(NoEvalCall)
2728 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2729 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2730 .ArgConstraint(
2731 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2732
2733 std::optional<QualType> Uid_tTy = lookupTy("uid_t");
2734 std::optional<QualType> Gid_tTy = lookupTy("gid_t");
2735
2736 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
2737 // int flags);
2738 addToFunctionSummaryMap(
2739 "fchownat",
2740 Signature(ArgTypes{IntTy, ConstCharPtrTy, Uid_tTy, Gid_tTy, IntTy},
2741 RetType{IntTy}),
2742 Summary(NoEvalCall)
2743 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2744 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2745 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2746 .ArgConstraint(NotNull(ArgNo(1))));
2747
2748 // int chown(const char *path, uid_t owner, gid_t group);
2749 addToFunctionSummaryMap(
2750 "chown",
2751 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2752 Summary(NoEvalCall)
2753 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2754 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2755 .ArgConstraint(NotNull(ArgNo(0))));
2756
2757 // int lchown(const char *path, uid_t owner, gid_t group);
2758 addToFunctionSummaryMap(
2759 "lchown",
2760 Signature(ArgTypes{ConstCharPtrTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2761 Summary(NoEvalCall)
2762 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2763 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2764 .ArgConstraint(NotNull(ArgNo(0))));
2765
2766 // int fchown(int fildes, uid_t owner, gid_t group);
2767 addToFunctionSummaryMap(
2768 "fchown", Signature(ArgTypes{IntTy, Uid_tTy, Gid_tTy}, RetType{IntTy}),
2769 Summary(NoEvalCall)
2770 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2771 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2772 .ArgConstraint(
2773 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2774
2775 // int rmdir(const char *pathname);
2776 addToFunctionSummaryMap(
2777 "rmdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2778 Summary(NoEvalCall)
2779 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2780 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2781 .ArgConstraint(NotNull(ArgNo(0))));
2782
2783 // int chdir(const char *path);
2784 addToFunctionSummaryMap(
2785 "chdir", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2786 Summary(NoEvalCall)
2787 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2788 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2789 .ArgConstraint(NotNull(ArgNo(0))));
2790
2791 // int link(const char *oldpath, const char *newpath);
2792 addToFunctionSummaryMap(
2793 "link",
2794 Signature(ArgTypes{ConstCharPtrTy, ConstCharPtrTy}, RetType{IntTy}),
2795 Summary(NoEvalCall)
2796 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2797 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2798 .ArgConstraint(NotNull(ArgNo(0)))
2799 .ArgConstraint(NotNull(ArgNo(1))));
2800
2801 // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2802 // int flag);
2803 addToFunctionSummaryMap(
2804 "linkat",
2805 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy, IntTy},
2806 RetType{IntTy}),
2807 Summary(NoEvalCall)
2808 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2809 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2810 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2811 .ArgConstraint(NotNull(ArgNo(1)))
2812 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2813 .ArgConstraint(NotNull(ArgNo(3))));
2814
2815 // int unlink(const char *pathname);
2816 addToFunctionSummaryMap(
2817 "unlink", Signature(ArgTypes{ConstCharPtrTy}, RetType{IntTy}),
2818 Summary(NoEvalCall)
2819 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2820 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2821 .ArgConstraint(NotNull(ArgNo(0))));
2822
2823 // int unlinkat(int fd, const char *path, int flag);
2824 addToFunctionSummaryMap(
2825 "unlinkat",
2826 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy}, RetType{IntTy}),
2827 Summary(NoEvalCall)
2828 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2829 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2830 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2831 .ArgConstraint(NotNull(ArgNo(1))));
2832
2833 std::optional<QualType> StructStatTy = lookupTy("stat");
2834 std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
2835 std::optional<QualType> StructStatPtrRestrictTy =
2836 getRestrictTy(StructStatPtrTy);
2837
2838 // int fstat(int fd, struct stat *statbuf);
2839 addToFunctionSummaryMap(
2840 "fstat", Signature(ArgTypes{IntTy, StructStatPtrTy}, RetType{IntTy}),
2841 Summary(NoEvalCall)
2842 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2843 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2844 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
2845 .ArgConstraint(NotNull(ArgNo(1))));
2846
2847 // int stat(const char *restrict path, struct stat *restrict buf);
2848 addToFunctionSummaryMap(
2849 "stat",
2850 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2851 RetType{IntTy}),
2852 Summary(NoEvalCall)
2853 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2854 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2855 .ArgConstraint(NotNull(ArgNo(0)))
2856 .ArgConstraint(NotNull(ArgNo(1))));
2857
2858 // int lstat(const char *restrict path, struct stat *restrict buf);
2859 addToFunctionSummaryMap(
2860 "lstat",
2861 Signature(ArgTypes{ConstCharPtrRestrictTy, StructStatPtrRestrictTy},
2862 RetType{IntTy}),
2863 Summary(NoEvalCall)
2864 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2865 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2866 .ArgConstraint(NotNull(ArgNo(0)))
2867 .ArgConstraint(NotNull(ArgNo(1))));
2868
2869 // int fstatat(int fd, const char *restrict path,
2870 // struct stat *restrict buf, int flag);
2871 addToFunctionSummaryMap(
2872 "fstatat",
2873 Signature(ArgTypes{IntTy, ConstCharPtrRestrictTy,
2874 StructStatPtrRestrictTy, IntTy},
2875 RetType{IntTy}),
2876 Summary(NoEvalCall)
2877 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2878 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2879 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2880 .ArgConstraint(NotNull(ArgNo(1)))
2881 .ArgConstraint(NotNull(ArgNo(2))));
2882
2883 // DIR *opendir(const char *name);
2884 addToFunctionSummaryMap(
2885 "opendir", Signature(ArgTypes{ConstCharPtrTy}, RetType{DirPtrTy}),
2886 Summary(NoEvalCall)
2887 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2888 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2889 .ArgConstraint(NotNull(ArgNo(0))));
2890
2891 // DIR *fdopendir(int fd);
2892 addToFunctionSummaryMap(
2893 "fdopendir", Signature(ArgTypes{IntTy}, RetType{DirPtrTy}),
2894 Summary(NoEvalCall)
2895 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
2896 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2897 .ArgConstraint(
2898 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2899
2900 // int isatty(int fildes);
2901 addToFunctionSummaryMap(
2902 "isatty", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2903 Summary(NoEvalCall)
2904 .Case({ReturnValueCondition(WithinRange, Range(0, 1))},
2905 ErrnoIrrelevant)
2906 .ArgConstraint(
2907 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2908
2909 // int close(int fildes);
2910 addToFunctionSummaryMap(
2911 "close", Signature(ArgTypes{IntTy}, RetType{IntTy}),
2912 Summary(NoEvalCall)
2913 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2914 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2915 .ArgConstraint(
2916 ArgumentCondition(0, WithinRange, Range(-1, IntMax))));
2917
2918 // long fpathconf(int fildes, int name);
2919 addToFunctionSummaryMap("fpathconf",
2920 Signature(ArgTypes{IntTy, IntTy}, RetType{LongTy}),
2921 Summary(NoEvalCall)
2922 .ArgConstraint(ArgumentCondition(
2923 0, WithinRange, Range(0, IntMax))));
2924
2925 // long pathconf(const char *path, int name);
2926 addToFunctionSummaryMap(
2927 "pathconf", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{LongTy}),
2928 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2929
2930 // void rewinddir(DIR *dir);
2931 addToFunctionSummaryMap(
2932 "rewinddir", Signature(ArgTypes{DirPtrTy}, RetType{VoidTy}),
2933 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2934
2935 // void seekdir(DIR *dirp, long loc);
2936 addToFunctionSummaryMap(
2937 "seekdir", Signature(ArgTypes{DirPtrTy, LongTy}, RetType{VoidTy}),
2938 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2939
2940 // int rand_r(unsigned int *seedp);
2941 addToFunctionSummaryMap(
2942 "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
2943 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
2944
2945 // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2946 // off_t offset);
2947 // FIXME: Improve for errno modeling.
2948 addToFunctionSummaryMap(
2949 "mmap",
2950 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off_tTy},
2951 RetType{VoidPtrTy}),
2952 Summary(NoEvalCall)
2953 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2954 .ArgConstraint(
2955 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2956
2957 std::optional<QualType> Off64_tTy = lookupTy("off64_t");
2958 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2959 // off64_t offset);
2960 // FIXME: Improve for errno modeling.
2961 addToFunctionSummaryMap(
2962 "mmap64",
2963 Signature(ArgTypes{VoidPtrTy, SizeTy, IntTy, IntTy, IntTy, Off64_tTy},
2964 RetType{VoidPtrTy}),
2965 Summary(NoEvalCall)
2966 .ArgConstraint(ArgumentCondition(1, WithinRange, Range(1, SizeMax)))
2967 .ArgConstraint(
2968 ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
2969
2970 // int pipe(int fildes[2]);
2971 addToFunctionSummaryMap(
2972 "pipe", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
2973 Summary(NoEvalCall)
2974 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
2975 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2976 .ArgConstraint(NotNull(ArgNo(0))));
2977
2978 // off_t lseek(int fildes, off_t offset, int whence);
2979 // In the first case we can not tell for sure if it failed or not.
2980 // A return value different from of the expected offset (that is unknown
2981 // here) may indicate failure. For this reason we do not enforce the errno
2982 // check (can cause false positive).
2983 addToFunctionSummaryMap(
2984 "lseek", Signature(ArgTypes{IntTy, Off_tTy, IntTy}, RetType{Off_tTy}),
2985 Summary(NoEvalCall)
2986 .Case(ReturnsNonnegative, ErrnoIrrelevant)
2987 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
2988 .ArgConstraint(
2989 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
2990
2991 // ssize_t readlink(const char *restrict path, char *restrict buf,
2992 // size_t bufsize);
2993 addToFunctionSummaryMap(
2994 "readlink",
2995 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
2996 RetType{Ssize_tTy}),
2997 Summary(NoEvalCall)
2998 .Case({ArgumentCondition(2, WithinRange, Range(1, IntMax)),
2999 ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3000 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3001 ErrnoMustNotBeChecked, GenericSuccessMsg)
3002 .Case({ArgumentCondition(2, WithinRange, SingleValue(0)),
3003 ReturnValueCondition(WithinRange, SingleValue(0))},
3004 ErrnoMustNotBeChecked,
3005 "Assuming that argument 'bufsize' is 0")
3006 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3007 .ArgConstraint(NotNull(ArgNo(0)))
3008 .ArgConstraint(NotNull(ArgNo(1)))
3009 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3010 /*BufSize=*/ArgNo(2)))
3011 .ArgConstraint(
3012 ArgumentCondition(2, WithinRange, Range(0, SizeMax))));
3013
3014 // ssize_t readlinkat(int fd, const char *restrict path,
3015 // char *restrict buf, size_t bufsize);
3016 addToFunctionSummaryMap(
3017 "readlinkat",
3018 Signature(
3019 ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
3020 RetType{Ssize_tTy}),
3021 Summary(NoEvalCall)
3022 .Case({ArgumentCondition(3, WithinRange, Range(1, IntMax)),
3023 ReturnValueCondition(LessThanOrEq, ArgNo(3)),
3024 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3025 ErrnoMustNotBeChecked, GenericSuccessMsg)
3026 .Case({ArgumentCondition(3, WithinRange, SingleValue(0)),
3027 ReturnValueCondition(WithinRange, SingleValue(0))},
3028 ErrnoMustNotBeChecked,
3029 "Assuming that argument 'bufsize' is 0")
3030 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3031 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
3032 .ArgConstraint(NotNull(ArgNo(1)))
3033 .ArgConstraint(NotNull(ArgNo(2)))
3034 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
3035 /*BufSize=*/ArgNo(3)))
3036 .ArgConstraint(
3037 ArgumentCondition(3, WithinRange, Range(0, SizeMax))));
3038
3039 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
3040 // *newpath);
3041 addToFunctionSummaryMap(
3042 "renameat",
3043 Signature(ArgTypes{IntTy, ConstCharPtrTy, IntTy, ConstCharPtrTy},
3044 RetType{IntTy}),
3045 Summary(NoEvalCall)
3046 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3047 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3048 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
3049 .ArgConstraint(NotNull(ArgNo(1)))
3050 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
3051 .ArgConstraint(NotNull(ArgNo(3))));
3052
3053 // char *realpath(const char *restrict file_name,
3054 // char *restrict resolved_name);
3055 // FIXME: If the argument 'resolved_name' is not NULL, macro 'PATH_MAX'
3056 // should be defined in "limits.h" to guarrantee a success.
3057 addToFunctionSummaryMap(
3058 "realpath",
3059 Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy},
3060 RetType{CharPtrTy}),
3061 Summary(NoEvalCall)
3062 .Case({NotNull(Ret)}, ErrnoMustNotBeChecked, GenericSuccessMsg)
3063 .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3064 .ArgConstraint(NotNull(ArgNo(0))));
3065
3066 QualType CharPtrConstPtr = getPointerTy(getConstTy(CharPtrTy));
3067
3068 // int execv(const char *path, char *const argv[]);
3069 addToFunctionSummaryMap(
3070 "execv",
3071 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3072 Summary(NoEvalCall)
3073 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3074 .ArgConstraint(NotNull(ArgNo(0))));
3075
3076 // int execvp(const char *file, char *const argv[]);
3077 addToFunctionSummaryMap(
3078 "execvp",
3079 Signature(ArgTypes{ConstCharPtrTy, CharPtrConstPtr}, RetType{IntTy}),
3080 Summary(NoEvalCall)
3081 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
3082 .ArgConstraint(NotNull(ArgNo(0))));
3083
3084 // int getopt(int argc, char * const argv[], const char *optstring);
3085 addToFunctionSummaryMap(
3086 "getopt",
3087 Signature(ArgTypes{IntTy, CharPtrConstPtr, ConstCharPtrTy},
3088 RetType{IntTy}),
3089 Summary(NoEvalCall)
3090 .Case({ReturnValueCondition(WithinRange, Range(-1, UCharRangeMax))},
3091 ErrnoIrrelevant)
3092 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3093 .ArgConstraint(NotNull(ArgNo(1)))
3094 .ArgConstraint(NotNull(ArgNo(2))));
3095
3096 std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
3097 std::optional<QualType> StructSockaddrPtrTy =
3098 getPointerTy(StructSockaddrTy);
3099 std::optional<QualType> ConstStructSockaddrPtrTy =
3100 getPointerTy(getConstTy(StructSockaddrTy));
3101 std::optional<QualType> StructSockaddrPtrRestrictTy =
3102 getRestrictTy(StructSockaddrPtrTy);
3103 std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
3104 getRestrictTy(ConstStructSockaddrPtrTy);
3105 std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
3106 std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
3107 std::optional<QualType> Socklen_tPtrRestrictTy =
3108 getRestrictTy(Socklen_tPtrTy);
3109 std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
3110
3111 // In 'socket.h' of some libc implementations with C99, sockaddr parameter
3112 // is a transparent union of the underlying sockaddr_ family of pointers
3113 // instead of being a pointer to struct sockaddr. In these cases, the
3114 // standardized signature will not match, thus we try to match with another
3115 // signature that has the joker Irrelevant type. We also remove those
3116 // constraints which require pointer types for the sockaddr param.
3117
3118 // int socket(int domain, int type, int protocol);
3119 addToFunctionSummaryMap(
3120 "socket", Signature(ArgTypes{IntTy, IntTy, IntTy}, RetType{IntTy}),
3121 Summary(NoEvalCall)
3122 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
3123 GenericSuccessMsg)
3124 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg));
3125
3126 auto Accept =
3127 Summary(NoEvalCall)
3128 .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked,
3129 GenericSuccessMsg)
3130 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3131 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)));
3132 if (!addToFunctionSummaryMap(
3133 "accept",
3134 // int accept(int socket, struct sockaddr *restrict address,
3135 // socklen_t *restrict address_len);
3136 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3137 Socklen_tPtrRestrictTy},
3138 RetType{IntTy}),
3139 Accept))
3140 addToFunctionSummaryMap(
3141 "accept",
3142 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3143 RetType{IntTy}),
3144 Accept);
3145
3146 // int bind(int socket, const struct sockaddr *address, socklen_t
3147 // address_len);
3148 if (!addToFunctionSummaryMap(
3149 "bind",
3150 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3151 RetType{IntTy}),
3152 Summary(NoEvalCall)
3153 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3154 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3155 .ArgConstraint(
3156 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3157 .ArgConstraint(NotNull(ArgNo(1)))
3158 .ArgConstraint(
3159 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
3160 .ArgConstraint(
3161 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax)))))
3162 // Do not add constraints on sockaddr.
3163 addToFunctionSummaryMap(
3164 "bind",
3165 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3166 Summary(NoEvalCall)
3167 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3168 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3169 .ArgConstraint(
3170 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3171 .ArgConstraint(
3172 ArgumentCondition(2, WithinRange, Range(0, Socklen_tMax))));
3173
3174 // int getpeername(int socket, struct sockaddr *restrict address,
3175 // socklen_t *restrict address_len);
3176 if (!addToFunctionSummaryMap(
3177 "getpeername",
3178 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3179 Socklen_tPtrRestrictTy},
3180 RetType{IntTy}),
3181 Summary(NoEvalCall)
3182 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3183 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3184 .ArgConstraint(
3185 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3186 .ArgConstraint(NotNull(ArgNo(1)))
3187 .ArgConstraint(NotNull(ArgNo(2)))))
3188 addToFunctionSummaryMap(
3189 "getpeername",
3190 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3191 RetType{IntTy}),
3192 Summary(NoEvalCall)
3193 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3194 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3195 .ArgConstraint(
3196 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3197
3198 // int getsockname(int socket, struct sockaddr *restrict address,
3199 // socklen_t *restrict address_len);
3200 if (!addToFunctionSummaryMap(
3201 "getsockname",
3202 Signature(ArgTypes{IntTy, StructSockaddrPtrRestrictTy,
3203 Socklen_tPtrRestrictTy},
3204 RetType{IntTy}),
3205 Summary(NoEvalCall)
3206 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3207 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3208 .ArgConstraint(
3209 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3210 .ArgConstraint(NotNull(ArgNo(1)))
3211 .ArgConstraint(NotNull(ArgNo(2)))))
3212 addToFunctionSummaryMap(
3213 "getsockname",
3214 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tPtrRestrictTy},
3215 RetType{IntTy}),
3216 Summary(NoEvalCall)
3217 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3218 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3219 .ArgConstraint(
3220 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3221
3222 // int connect(int socket, const struct sockaddr *address, socklen_t
3223 // address_len);
3224 if (!addToFunctionSummaryMap(
3225 "connect",
3226 Signature(ArgTypes{IntTy, ConstStructSockaddrPtrTy, Socklen_tTy},
3227 RetType{IntTy}),
3228 Summary(NoEvalCall)
3229 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3230 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3231 .ArgConstraint(
3232 ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3233 .ArgConstraint(NotNull(ArgNo(1)))))
3234 addToFunctionSummaryMap(
3235 "connect",
3236 Signature(ArgTypes{IntTy, Irrelevant, Socklen_tTy}, RetType{IntTy}),
3237 Summary(NoEvalCall)
3238 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3239 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3240 .ArgConstraint(
3241 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3242
3243 auto Recvfrom =
3244 Summary(NoEvalCall)
3245 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3246 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3247 ErrnoMustNotBeChecked, GenericSuccessMsg)
3248 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3249 ArgumentCondition(2, WithinRange, SingleValue(0))},
3250 ErrnoMustNotBeChecked, GenericSuccessMsg)
3251 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3252 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3253 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3254 /*BufSize=*/ArgNo(2)));
3255 if (!addToFunctionSummaryMap(
3256 "recvfrom",
3257 // ssize_t recvfrom(int socket, void *restrict buffer,
3258 // size_t length,
3259 // int flags, struct sockaddr *restrict address,
3260 // socklen_t *restrict address_len);
3261 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3262 StructSockaddrPtrRestrictTy,
3263 Socklen_tPtrRestrictTy},
3264 RetType{Ssize_tTy}),
3265 Recvfrom))
3266 addToFunctionSummaryMap(
3267 "recvfrom",
3268 Signature(ArgTypes{IntTy, VoidPtrRestrictTy, SizeTy, IntTy,
3269 Irrelevant, Socklen_tPtrRestrictTy},
3270 RetType{Ssize_tTy}),
3271 Recvfrom);
3272
3273 auto Sendto =
3274 Summary(NoEvalCall)
3275 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3276 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3277 ErrnoMustNotBeChecked, GenericSuccessMsg)
3278 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3279 ArgumentCondition(2, WithinRange, SingleValue(0))},
3280 ErrnoMustNotBeChecked, GenericSuccessMsg)
3281 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3282 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3283 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3284 /*BufSize=*/ArgNo(2)));
3285 if (!addToFunctionSummaryMap(
3286 "sendto",
3287 // ssize_t sendto(int socket, const void *message, size_t length,
3288 // int flags, const struct sockaddr *dest_addr,
3289 // socklen_t dest_len);
3290 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy,
3291 ConstStructSockaddrPtrTy, Socklen_tTy},
3292 RetType{Ssize_tTy}),
3293 Sendto))
3294 addToFunctionSummaryMap(
3295 "sendto",
3296 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy, Irrelevant,
3297 Socklen_tTy},
3298 RetType{Ssize_tTy}),
3299 Sendto);
3300
3301 // int listen(int sockfd, int backlog);
3302 addToFunctionSummaryMap(
3303 "listen", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3304 Summary(NoEvalCall)
3305 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3306 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3307 .ArgConstraint(
3308 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3309
3310 // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3311 addToFunctionSummaryMap(
3312 "recv",
3313 Signature(ArgTypes{IntTy, VoidPtrTy, SizeTy, IntTy},
3314 RetType{Ssize_tTy}),
3315 Summary(NoEvalCall)
3316 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3317 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3318 ErrnoMustNotBeChecked, GenericSuccessMsg)
3319 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3320 ArgumentCondition(2, WithinRange, SingleValue(0))},
3321 ErrnoMustNotBeChecked, GenericSuccessMsg)
3322 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3323 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3324 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3325 /*BufSize=*/ArgNo(2))));
3326
3327 std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
3328 std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
3329 std::optional<QualType> ConstStructMsghdrPtrTy =
3330 getPointerTy(getConstTy(StructMsghdrTy));
3331
3332 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3333 addToFunctionSummaryMap(
3334 "recvmsg",
3335 Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
3336 RetType{Ssize_tTy}),
3337 Summary(NoEvalCall)
3338 .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3339 ErrnoMustNotBeChecked, GenericSuccessMsg)
3340 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3341 .ArgConstraint(
3342 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3343
3344 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3345 addToFunctionSummaryMap(
3346 "sendmsg",
3347 Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
3348 RetType{Ssize_tTy}),
3349 Summary(NoEvalCall)
3350 .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3351 ErrnoMustNotBeChecked, GenericSuccessMsg)
3352 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3353 .ArgConstraint(
3354 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3355
3356 // int setsockopt(int socket, int level, int option_name,
3357 // const void *option_value, socklen_t option_len);
3358 addToFunctionSummaryMap(
3359 "setsockopt",
3360 Signature(ArgTypes{IntTy, IntTy, IntTy, ConstVoidPtrTy, Socklen_tTy},
3361 RetType{IntTy}),
3362 Summary(NoEvalCall)
3363 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3364 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3365 .ArgConstraint(NotNull(ArgNo(3)))
3366 .ArgConstraint(
3367 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3368 .ArgConstraint(
3369 ArgumentCondition(4, WithinRange, Range(0, Socklen_tMax))));
3370
3371 // int getsockopt(int socket, int level, int option_name,
3372 // void *restrict option_value,
3373 // socklen_t *restrict option_len);
3374 addToFunctionSummaryMap(
3375 "getsockopt",
3376 Signature(ArgTypes{IntTy, IntTy, IntTy, VoidPtrRestrictTy,
3377 Socklen_tPtrRestrictTy},
3378 RetType{IntTy}),
3379 Summary(NoEvalCall)
3380 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3381 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3382 .ArgConstraint(NotNull(ArgNo(3)))
3383 .ArgConstraint(NotNull(ArgNo(4))));
3384
3385 // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3386 addToFunctionSummaryMap(
3387 "send",
3388 Signature(ArgTypes{IntTy, ConstVoidPtrTy, SizeTy, IntTy},
3389 RetType{Ssize_tTy}),
3390 Summary(NoEvalCall)
3391 .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
3392 ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
3393 ErrnoMustNotBeChecked, GenericSuccessMsg)
3394 .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
3395 ArgumentCondition(2, WithinRange, SingleValue(0))},
3396 ErrnoMustNotBeChecked, GenericSuccessMsg)
3397 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3398 .ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
3399 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3400 /*BufSize=*/ArgNo(2))));
3401
3402 // int socketpair(int domain, int type, int protocol, int sv[2]);
3403 addToFunctionSummaryMap(
3404 "socketpair",
3405 Signature(ArgTypes{IntTy, IntTy, IntTy, IntPtrTy}, RetType{IntTy}),
3406 Summary(NoEvalCall)
3407 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3408 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3409 .ArgConstraint(NotNull(ArgNo(3))));
3410
3411 // int shutdown(int socket, int how);
3412 addToFunctionSummaryMap(
3413 "shutdown", Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3414 Summary(NoEvalCall)
3415 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3416 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3417 .ArgConstraint(
3418 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3419
3420 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
3421 // char *restrict node, socklen_t nodelen,
3422 // char *restrict service,
3423 // socklen_t servicelen, int flags);
3424 //
3425 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
3426 // parameter is never handled as a transparent union in netdb.h
3427 addToFunctionSummaryMap(
3428 "getnameinfo",
3429 Signature(ArgTypes{ConstStructSockaddrPtrRestrictTy, Socklen_tTy,
3430 CharPtrRestrictTy, Socklen_tTy, CharPtrRestrictTy,
3431 Socklen_tTy, IntTy},
3432 RetType{IntTy}),
3433 Summary(NoEvalCall)
3434 .ArgConstraint(
3435 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3436 .ArgConstraint(
3437 ArgumentCondition(1, WithinRange, Range(0, Socklen_tMax)))
3438 .ArgConstraint(
3439 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3440 .ArgConstraint(
3441 ArgumentCondition(3, WithinRange, Range(0, Socklen_tMax)))
3442 .ArgConstraint(
3443 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3444 .ArgConstraint(
3445 ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
3446
3447 std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
3448 std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
3449
3450 // int utime(const char *filename, struct utimbuf *buf);
3451 addToFunctionSummaryMap(
3452 "utime",
3453 Signature(ArgTypes{ConstCharPtrTy, StructUtimbufPtrTy}, RetType{IntTy}),
3454 Summary(NoEvalCall)
3455 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3456 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3457 .ArgConstraint(NotNull(ArgNo(0))));
3458
3459 std::optional<QualType> StructTimespecTy = lookupTy("timespec");
3460 std::optional<QualType> StructTimespecPtrTy =
3461 getPointerTy(StructTimespecTy);
3462 std::optional<QualType> ConstStructTimespecPtrTy =
3463 getPointerTy(getConstTy(StructTimespecTy));
3464
3465 // int futimens(int fd, const struct timespec times[2]);
3466 addToFunctionSummaryMap(
3467 "futimens",
3468 Signature(ArgTypes{IntTy, ConstStructTimespecPtrTy}, RetType{IntTy}),
3469 Summary(NoEvalCall)
3470 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3471 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3472 .ArgConstraint(
3473 ArgumentCondition(0, WithinRange, Range(0, IntMax))));
3474
3475 // int utimensat(int dirfd, const char *pathname,
3476 // const struct timespec times[2], int flags);
3477 addToFunctionSummaryMap(
3478 "utimensat",
3479 Signature(
3480 ArgTypes{IntTy, ConstCharPtrTy, ConstStructTimespecPtrTy, IntTy},
3481 RetType{IntTy}),
3482 Summary(NoEvalCall)
3483 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3484 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3485 .ArgConstraint(NotNull(ArgNo(1))));
3486
3487 std::optional<QualType> StructTimevalTy = lookupTy("timeval");
3488 std::optional<QualType> ConstStructTimevalPtrTy =
3489 getPointerTy(getConstTy(StructTimevalTy));
3490
3491 // int utimes(const char *filename, const struct timeval times[2]);
3492 addToFunctionSummaryMap(
3493 "utimes",
3494 Signature(ArgTypes{ConstCharPtrTy, ConstStructTimevalPtrTy},
3495 RetType{IntTy}),
3496 Summary(NoEvalCall)
3497 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3498 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3499 .ArgConstraint(NotNull(ArgNo(0))));
3500
3501 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3502 addToFunctionSummaryMap(
3503 "nanosleep",
3504 Signature(ArgTypes{ConstStructTimespecPtrTy, StructTimespecPtrTy},
3505 RetType{IntTy}),
3506 Summary(NoEvalCall)
3507 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3508 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3509 .ArgConstraint(NotNull(ArgNo(0))));
3510
3511 std::optional<QualType> Time_tTy = lookupTy("time_t");
3512 std::optional<QualType> ConstTime_tPtrTy =
3513 getPointerTy(getConstTy(Time_tTy));
3514 std::optional<QualType> ConstTime_tPtrRestrictTy =
3515 getRestrictTy(ConstTime_tPtrTy);
3516
3517 std::optional<QualType> StructTmTy = lookupTy("tm");
3518 std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
3519 std::optional<QualType> StructTmPtrRestrictTy =
3520 getRestrictTy(StructTmPtrTy);
3521 std::optional<QualType> ConstStructTmPtrTy =
3522 getPointerTy(getConstTy(StructTmTy));
3523 std::optional<QualType> ConstStructTmPtrRestrictTy =
3524 getRestrictTy(ConstStructTmPtrTy);
3525
3526 // struct tm * localtime(const time_t *tp);
3527 addToFunctionSummaryMap(
3528 "localtime",
3529 Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3530 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3531
3532 // struct tm *localtime_r(const time_t *restrict timer,
3533 // struct tm *restrict result);
3534 addToFunctionSummaryMap(
3535 "localtime_r",
3536 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3537 RetType{StructTmPtrTy}),
3538 Summary(NoEvalCall)
3539 .ArgConstraint(NotNull(ArgNo(0)))
3540 .ArgConstraint(NotNull(ArgNo(1))));
3541
3542 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3543 addToFunctionSummaryMap(
3544 "asctime_r",
3545 Signature(ArgTypes{ConstStructTmPtrRestrictTy, CharPtrRestrictTy},
3546 RetType{CharPtrTy}),
3547 Summary(NoEvalCall)
3548 .ArgConstraint(NotNull(ArgNo(0)))
3549 .ArgConstraint(NotNull(ArgNo(1)))
3550 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3551 /*MinBufSize=*/BVF.getValue(26, IntTy))));
3552
3553 // char *ctime_r(const time_t *timep, char *buf);
3554 addToFunctionSummaryMap(
3555 "ctime_r",
3556 Signature(ArgTypes{ConstTime_tPtrTy, CharPtrTy}, RetType{CharPtrTy}),
3557 Summary(NoEvalCall)
3558 .ArgConstraint(NotNull(ArgNo(0)))
3559 .ArgConstraint(NotNull(ArgNo(1)))
3560 .ArgConstraint(BufferSize(
3561 /*Buffer=*/ArgNo(1),
3562 /*MinBufSize=*/BVF.getValue(26, IntTy))));
3563
3564 // struct tm *gmtime_r(const time_t *restrict timer,
3565 // struct tm *restrict result);
3566 addToFunctionSummaryMap(
3567 "gmtime_r",
3568 Signature(ArgTypes{ConstTime_tPtrRestrictTy, StructTmPtrRestrictTy},
3569 RetType{StructTmPtrTy}),
3570 Summary(NoEvalCall)
3571 .ArgConstraint(NotNull(ArgNo(0)))
3572 .ArgConstraint(NotNull(ArgNo(1))));
3573
3574 // struct tm * gmtime(const time_t *tp);
3575 addToFunctionSummaryMap(
3576 "gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
3577 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3578
3579 std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
3580
3581 // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3582 addToFunctionSummaryMap(
3583 "clock_gettime",
3584 Signature(ArgTypes{Clockid_tTy, StructTimespecPtrTy}, RetType{IntTy}),
3585 Summary(NoEvalCall)
3586 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3587 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3588 .ArgConstraint(NotNull(ArgNo(1))));
3589
3590 std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
3591 std::optional<QualType> StructItimervalPtrTy =
3592 getPointerTy(StructItimervalTy);
3593
3594 // int getitimer(int which, struct itimerval *curr_value);
3595 addToFunctionSummaryMap(
3596 "getitimer",
3597 Signature(ArgTypes{IntTy, StructItimervalPtrTy}, RetType{IntTy}),
3598 Summary(NoEvalCall)
3599 .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
3600 .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
3601 .ArgConstraint(NotNull(ArgNo(1))));
3602
3603 std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
3604 std::optional<QualType> Pthread_cond_tPtrTy =
3605 getPointerTy(Pthread_cond_tTy);
3606 std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
3607 std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
3608 std::optional<QualType> Pthread_tPtrRestrictTy =
3609 getRestrictTy(Pthread_tPtrTy);
3610 std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
3611 std::optional<QualType> Pthread_mutex_tPtrTy =
3612 getPointerTy(Pthread_mutex_tTy);
3613 std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
3614 getRestrictTy(Pthread_mutex_tPtrTy);
3615 std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
3616 std::optional<QualType> Pthread_attr_tPtrTy =
3617 getPointerTy(Pthread_attr_tTy);
3618 std::optional<QualType> ConstPthread_attr_tPtrTy =
3619 getPointerTy(getConstTy(Pthread_attr_tTy));
3620 std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
3621 getRestrictTy(ConstPthread_attr_tPtrTy);
3622 std::optional<QualType> Pthread_mutexattr_tTy =
3623 lookupTy("pthread_mutexattr_t");
3624 std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
3625 getPointerTy(getConstTy(Pthread_mutexattr_tTy));
3626 std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
3627 getRestrictTy(ConstPthread_mutexattr_tPtrTy);
3628
3629 QualType PthreadStartRoutineTy = getPointerTy(
3630 ACtx.getFunctionType(/*ResultTy=*/VoidPtrTy, /*Args=*/VoidPtrTy,
3632
3633 // int pthread_cond_signal(pthread_cond_t *cond);
3634 // int pthread_cond_broadcast(pthread_cond_t *cond);
3635 addToFunctionSummaryMap(
3636 {"pthread_cond_signal", "pthread_cond_broadcast"},
3637 Signature(ArgTypes{Pthread_cond_tPtrTy}, RetType{IntTy}),
3638 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3639
3640 // int pthread_create(pthread_t *restrict thread,
3641 // const pthread_attr_t *restrict attr,
3642 // void *(*start_routine)(void*), void *restrict arg);
3643 addToFunctionSummaryMap(
3644 "pthread_create",
3645 Signature(ArgTypes{Pthread_tPtrRestrictTy,
3646 ConstPthread_attr_tPtrRestrictTy,
3647 PthreadStartRoutineTy, VoidPtrRestrictTy},
3648 RetType{IntTy}),
3649 Summary(NoEvalCall)
3650 .ArgConstraint(NotNull(ArgNo(0)))
3651 .ArgConstraint(NotNull(ArgNo(2))));
3652
3653 // int pthread_attr_destroy(pthread_attr_t *attr);
3654 // int pthread_attr_init(pthread_attr_t *attr);
3655 addToFunctionSummaryMap(
3656 {"pthread_attr_destroy", "pthread_attr_init"},
3657 Signature(ArgTypes{Pthread_attr_tPtrTy}, RetType{IntTy}),
3658 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3659
3660 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
3661 // size_t *restrict stacksize);
3662 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
3663 // size_t *restrict guardsize);
3664 addToFunctionSummaryMap(
3665 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
3666 Signature(ArgTypes{ConstPthread_attr_tPtrRestrictTy, SizePtrRestrictTy},
3667 RetType{IntTy}),
3668 Summary(NoEvalCall)
3669 .ArgConstraint(NotNull(ArgNo(0)))
3670 .ArgConstraint(NotNull(ArgNo(1))));
3671
3672 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3673 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
3674 addToFunctionSummaryMap(
3675 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
3676 Signature(ArgTypes{Pthread_attr_tPtrTy, SizeTy}, RetType{IntTy}),
3677 Summary(NoEvalCall)
3678 .ArgConstraint(NotNull(ArgNo(0)))
3679 .ArgConstraint(
3680 ArgumentCondition(1, WithinRange, Range(0, SizeMax))));
3681
3682 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
3683 // pthread_mutexattr_t *restrict attr);
3684 addToFunctionSummaryMap(
3685 "pthread_mutex_init",
3686 Signature(ArgTypes{Pthread_mutex_tPtrRestrictTy,
3687 ConstPthread_mutexattr_tPtrRestrictTy},
3688 RetType{IntTy}),
3689 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3690
3691 // int pthread_mutex_destroy(pthread_mutex_t *mutex);
3692 // int pthread_mutex_lock(pthread_mutex_t *mutex);
3693 // int pthread_mutex_trylock(pthread_mutex_t *mutex);
3694 // int pthread_mutex_unlock(pthread_mutex_t *mutex);
3695 addToFunctionSummaryMap(
3696 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
3697 "pthread_mutex_unlock"},
3698 Signature(ArgTypes{Pthread_mutex_tPtrTy}, RetType{IntTy}),
3699 Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
3700 }
3701
3702 // Functions for testing.
3703 if (AddTestFunctions) {
3704 const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue();
3705
3706 addToFunctionSummaryMap(
3707 "__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
3708 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3709
3710 addToFunctionSummaryMap(
3711 "__not_null_buffer",
3712 Signature(ArgTypes{VoidPtrTy, IntTy, IntTy}, RetType{IntTy}),
3713 Summary(EvalCallAsPure)
3714 .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2))));
3715
3716 // Test inside range constraints.
3717 addToFunctionSummaryMap(
3718 "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3719 Summary(EvalCallAsPure)
3720 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
3721 addToFunctionSummaryMap(
3722 "__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3723 Summary(EvalCallAsPure)
3724 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3725 addToFunctionSummaryMap(
3726 "__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3727 Summary(EvalCallAsPure)
3728 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
3729 addToFunctionSummaryMap(
3730 "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3731 Summary(EvalCallAsPure)
3732 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));
3733 addToFunctionSummaryMap(
3734 "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3735 Summary(EvalCallAsPure)
3736 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));
3737 addToFunctionSummaryMap(
3738 "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3739 Summary(EvalCallAsPure)
3740 .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));
3741 addToFunctionSummaryMap("__range_m1_inf",
3742 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3743 Summary(EvalCallAsPure)
3744 .ArgConstraint(ArgumentCondition(
3745 0U, WithinRange, Range(-1, IntMax))));
3746 addToFunctionSummaryMap("__range_0_inf",
3747 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3748 Summary(EvalCallAsPure)
3749 .ArgConstraint(ArgumentCondition(
3750 0U, WithinRange, Range(0, IntMax))));
3751 addToFunctionSummaryMap("__range_1_inf",
3752 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3753 Summary(EvalCallAsPure)
3754 .ArgConstraint(ArgumentCondition(
3755 0U, WithinRange, Range(1, IntMax))));
3756 addToFunctionSummaryMap("__range_minf_m1",
3757 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3758 Summary(EvalCallAsPure)
3759 .ArgConstraint(ArgumentCondition(
3760 0U, WithinRange, Range(IntMin, -1))));
3761 addToFunctionSummaryMap("__range_minf_0",
3762 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3763 Summary(EvalCallAsPure)
3764 .ArgConstraint(ArgumentCondition(
3765 0U, WithinRange, Range(IntMin, 0))));
3766 addToFunctionSummaryMap("__range_minf_1",
3767 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3768 Summary(EvalCallAsPure)
3769 .ArgConstraint(ArgumentCondition(
3770 0U, WithinRange, Range(IntMin, 1))));
3771 addToFunctionSummaryMap("__range_1_2__4_6",
3772 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3773 Summary(EvalCallAsPure)
3774 .ArgConstraint(ArgumentCondition(
3775 0U, WithinRange, Range({1, 2}, {4, 6}))));
3776 addToFunctionSummaryMap(
3777 "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3778 Summary(EvalCallAsPure)
3779 .ArgConstraint(ArgumentCondition(0U, WithinRange,
3780 Range({1, 2}, {4, IntMax}))));
3781
3782 // Test out of range constraints.
3783 addToFunctionSummaryMap(
3784 "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3785 Summary(EvalCallAsPure)
3786 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));
3787 addToFunctionSummaryMap(
3788 "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3789 Summary(EvalCallAsPure)
3790 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3791 addToFunctionSummaryMap(
3792 "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3793 Summary(EvalCallAsPure)
3794 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));
3795 addToFunctionSummaryMap(
3796 "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3797 Summary(EvalCallAsPure)
3798 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
3799 addToFunctionSummaryMap(
3800 "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3801 Summary(EvalCallAsPure)
3802 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
3803 addToFunctionSummaryMap(
3804 "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3805 Summary(EvalCallAsPure)
3806 .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
3807 addToFunctionSummaryMap("__range_out_m1_inf",
3808 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3809 Summary(EvalCallAsPure)
3810 .ArgConstraint(ArgumentCondition(
3811 0U, OutOfRange, Range(-1, IntMax))));
3812 addToFunctionSummaryMap("__range_out_0_inf",
3813 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3814 Summary(EvalCallAsPure)
3815 .ArgConstraint(ArgumentCondition(
3816 0U, OutOfRange, Range(0, IntMax))));
3817 addToFunctionSummaryMap("__range_out_1_inf",
3818 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3819 Summary(EvalCallAsPure)
3820 .ArgConstraint(ArgumentCondition(
3821 0U, OutOfRange, Range(1, IntMax))));
3822 addToFunctionSummaryMap("__range_out_minf_m1",
3823 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3824 Summary(EvalCallAsPure)
3825 .ArgConstraint(ArgumentCondition(
3826 0U, OutOfRange, Range(IntMin, -1))));
3827 addToFunctionSummaryMap("__range_out_minf_0",
3828 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3829 Summary(EvalCallAsPure)
3830 .ArgConstraint(ArgumentCondition(
3831 0U, OutOfRange, Range(IntMin, 0))));
3832 addToFunctionSummaryMap("__range_out_minf_1",
3833 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3834 Summary(EvalCallAsPure)
3835 .ArgConstraint(ArgumentCondition(
3836 0U, OutOfRange, Range(IntMin, 1))));
3837 addToFunctionSummaryMap("__range_out_1_2__4_6",
3838 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3839 Summary(EvalCallAsPure)
3840 .ArgConstraint(ArgumentCondition(
3841 0U, OutOfRange, Range({1, 2}, {4, 6}))));
3842 addToFunctionSummaryMap(
3843 "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3844 Summary(EvalCallAsPure)
3845 .ArgConstraint(
3846 ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
3847
3848 // Test range kind.
3849 addToFunctionSummaryMap(
3850 "__within", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3851 Summary(EvalCallAsPure)
3852 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
3853 addToFunctionSummaryMap(
3854 "__out_of", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3855 Summary(EvalCallAsPure)
3856 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
3857
3858 addToFunctionSummaryMap(
3859 "__two_constrained_args",
3860 Signature(ArgTypes{IntTy, IntTy}, RetType{IntTy}),
3861 Summary(EvalCallAsPure)
3862 .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1)))
3863 .ArgConstraint(ArgumentCondition(1U, WithinRange, SingleValue(1))));
3864 addToFunctionSummaryMap(
3865 "__arg_constrained_twice", Signature(ArgTypes{IntTy}, RetType{IntTy}),
3866 Summary(EvalCallAsPure)
3867 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1)))
3868 .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(2))));
3869 addToFunctionSummaryMap(
3870 "__defaultparam",
3871 Signature(ArgTypes{Irrelevant, IntTy}, RetType{IntTy}),
3872 Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
3873 addToFunctionSummaryMap(
3874 "__variadic",
3875 Signature(ArgTypes{VoidPtrTy, ConstCharPtrTy}, RetType{IntTy}),
3876 Summary(EvalCallAsPure)
3877 .ArgConstraint(NotNull(ArgNo(0)))
3878 .ArgConstraint(NotNull(ArgNo(1))));
3879 addToFunctionSummaryMap(
3880 "__buf_size_arg_constraint",
3881 Signature(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy}),
3882 Summary(EvalCallAsPure)
3883 .ArgConstraint(
3884 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
3885 addToFunctionSummaryMap(
3886 "__buf_size_arg_constraint_mul",
3887 Signature(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy}),
3888 Summary(EvalCallAsPure)
3889 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
3890 /*BufSizeMultiplier=*/ArgNo(2))));
3891 addToFunctionSummaryMap(
3892 "__buf_size_arg_constraint_concrete",
3893 Signature(ArgTypes{ConstVoidPtrTy}, RetType{IntTy}),
3894 Summary(EvalCallAsPure)
3895 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
3896 /*BufSize=*/BVF.getValue(10, IntTy))));
3897 addToFunctionSummaryMap(
3898 {"__test_restrict_param_0", "__test_restrict_param_1",
3899 "__test_restrict_param_2"},
3900 Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
3901 Summary(EvalCallAsPure));
3902
3903 // Test the application of cases.
3904 addToFunctionSummaryMap(
3905 "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
3906 Summary(EvalCallAsPure)
3907 .Case({ReturnValueCondition(WithinRange, SingleValue(0))},
3908 ErrnoIrrelevant, "Function returns 0")
3909 .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
3910 ErrnoIrrelevant, "Function returns 1"));
3911 addToFunctionSummaryMap(
3912 "__test_case_range_1_2__4_6",
3913 Signature(ArgTypes{IntTy}, RetType{IntTy}),
3914 Summary(EvalCallAsPure)
3915 .Case({ArgumentCondition(0U, WithinRange,
3916 IntRangeVector{{IntMin, 0}, {3, 3}}),
3917 ReturnValueCondition(WithinRange, SingleValue(1))},
3918 ErrnoIrrelevant)
3919 .Case({ArgumentCondition(0U, WithinRange,
3920 IntRangeVector{{3, 3}, {7, IntMax}}),
3921 ReturnValueCondition(WithinRange, SingleValue(2))},
3922 ErrnoIrrelevant)
3923 .Case({ArgumentCondition(0U, WithinRange,
3924 IntRangeVector{{IntMin, 0}, {7, IntMax}}),
3925 ReturnValueCondition(WithinRange, SingleValue(3))},
3926 ErrnoIrrelevant)
3927 .Case({ArgumentCondition(
3928 0U, WithinRange,
3929 IntRangeVector{{IntMin, 0}, {3, 3}, {7, IntMax}}),
3930 ReturnValueCondition(WithinRange, SingleValue(4))},
3931 ErrnoIrrelevant));
3932 }
3933}
3934
3935void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
3936 auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
3937 Checker->CheckName = mgr.getCurrentCheckerName();
3938 const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
3939 Checker->DisplayLoadedSummaries =
3940 Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
3941 Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
3942 Checker->ShouldAssumeControlledEnvironment =
3943 Opts.ShouldAssumeControlledEnvironment;
3944}
3945
3946bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3947 const CheckerManager &mgr) {
3948 return true;
3949}
3950
3951void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager &mgr) {
3952 auto *Checker = mgr.getChecker<StdLibraryFunctionsChecker>();
3953 Checker->AddTestFunctions = true;
3954}
3955
3956bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
3957 const CheckerManager &mgr) {
3958 return true;
3959}
#define V(N, I)
Definition: ASTContext.h:3301
DynTypedNode Node
static bool isInvalid(LocType Loc, bool *Invalid)
__device__ __2f16 b
do v
Definition: arm_acle.h:83
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1076
CanQualType LongTy
Definition: ASTContext.h:1103
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:1600
IdentifierTable & Idents
Definition: ASTContext.h:647
const LangOptions & getLangOpts() const
Definition: ASTContext.h:778
CanQualType BoolTy
Definition: ASTContext.h:1095
QualType getRestrictType(QualType T) const
Return the uniqued reference to the type for a restrict qualified type.
Definition: ASTContext.h:1288
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
CanQualType CharTy
Definition: ASTContext.h:1096
CanQualType IntTy
Definition: ASTContext.h:1103
CanQualType VoidTy
Definition: ASTContext.h:1094
CanQualType UnsignedCharTy
Definition: ASTContext.h:1104
CanQualType UnsignedIntTy
Definition: ASTContext.h:1104
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:1578
CanQualType WCharTy
Definition: ASTContext.h:1097
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:3945
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Definition: DeclBase.cpp:1824
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:523
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:1971
const ParmVarDecl * getParamDecl(unsigned i) const
Definition: Decl.h:2708
QualType getReturnType() const
Definition: Decl.h:2756
FunctionDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition: Decl.cpp:3613
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition: Decl.cpp:3688
size_t param_size() const
Definition: Decl.h:2701
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:940
QualType withConst() const
Definition: Type.h:1168
QualType getCanonicalType() const
Definition: Type.h:7424
bool isVoidType() const
Definition: Type.h:7922
QualType getType() const
Definition: Decl.h:717
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:153
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:779
const ExplodedNode * getErrorNode() const
Definition: BugReporter.h:402
void markNotInteresting(SymbolRef sym)
bool isInteresting(SymbolRef sym) const
ConstraintManager & getConstraintManager()
Definition: ProgramState.h:582
A Range represents the closed range [from, to].
BasicValueFactory & getBasicValueFactory()
Definition: SValBuilder.h:161
ASTContext & getContext()
Definition: SValBuilder.h:148
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
Definition: SValBuilder.h:290
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:153
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:224
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.
The JSON file list parser is used to communicate input to InstallAPI.
BinaryOperatorKind
const FunctionProtoType * T
unsigned long uint64_t
#define bool
Definition: stdbool.h:24
Extra information about a function prototype.
Definition: Type.h:4751