1 //=== StdLibraryFunctionsChecker.cpp - Model standard functions -*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This checker improves modeling of a few simple library functions.
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.
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.
32 // This checker uses eval::Call for modeling pure functions (functions without
33 // side effets), for which their `Summary' is a precise model. This avoids
34 // unnecessary invalidation passes. Conflicts with other checkers are unlikely
35 // because if the function has no other effects, other checkers would probably
36 // never want to improve upon the modeling done by this checker.
38 // Non-pure functions, for which only partial improvement over the default
39 // behavior is expected, are modeled via check::PostCall, non-intrusively.
41 //===----------------------------------------------------------------------===//
43 #include "ErrnoModeling.h"
44 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
45 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
46 #include "clang/StaticAnalyzer/Core/Checker.h"
47 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
48 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
49 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
50 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
51 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.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"
60 using namespace clang
;
61 using namespace clang::ento
;
64 class StdLibraryFunctionsChecker
65 : public Checker
<check::PreCall
, check::PostCall
, eval::Call
> {
69 /// Specify how much the analyzer engine should entrust modeling this function
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.
75 /// The function is modeled completely in this checker.
79 /// Given a range, should the argument stay inside or outside this range?
80 enum RangeKind
{ OutOfRange
, WithinRange
};
82 static RangeKind
negateKind(RangeKind K
) {
89 llvm_unreachable("Unknown range kind");
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
;
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
;
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
;
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
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
122 static void appendOutOfRangeDesc(llvm::APSInt RMin
, llvm::APSInt RMax
,
123 QualType ArgT
, BasicValueFactory
&BVF
,
124 llvm::raw_ostream
&Out
);
126 class ValueConstraint
;
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
>;
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
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
{
149 ValueConstraint(ArgNo ArgN
) : ArgN(ArgN
) {}
150 virtual ~ValueConstraint() {}
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;
158 /// Represents that in which context do we require a description of the
160 enum DescriptionKind
{
161 /// Describe a constraint that was violated.
162 /// Description should start with something like "should be".
164 /// Describe a constraint that was assumed to be true.
165 /// This can be used when a precondition is satisfied, or when a summary
167 /// Description should start with something like "is".
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.
183 "Description not implemented for summary case constraints");
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,
196 /// See StdLibraryFunctionsChecker::reportBug about how this function is
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()) {
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
216 /// The "return value" argument number can not occur as returned value.
217 virtual std::vector
<ArgNo
> getArgsToTrack() const { return {ArgN
}; }
219 /// Get a constraint that represents exactly the opposite of the current.
220 virtual ValueConstraintPtr
negate() const {
221 llvm_unreachable("Not implemented");
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!");
234 // Subclasses may further refine the validation.
235 return checkSpecificValidity(FD
);
238 /// Return the argument number (may be placeholder for "return value").
239 ArgNo
getArgNo() const { return ArgN
; }
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
245 /// Every constraint is assigned to one main argument, even if other
246 /// arguments are involved.
249 /// Do constraint-specific validation check.
250 virtual bool checkSpecificValidity(const FunctionDecl
*FD
) const {
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.
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).
271 /// A set of intervals.
272 IntRangeVector Ranges
;
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
;
280 RangeConstraint(ArgNo ArgN
, RangeKind Kind
, const IntRangeVector
&Ranges
,
282 : ValueConstraint(ArgN
), Kind(Kind
), Ranges(Ranges
), Description(Desc
) {
285 const IntRangeVector
&getRanges() const { return Ranges
; }
287 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
288 const Summary
&Summary
,
289 CheckerContext
&C
) const override
;
291 void describe(DescriptionKind DK
, const CallEvent
&Call
,
292 ProgramStateRef State
, const Summary
&Summary
,
293 llvm::raw_ostream
&Out
) const override
;
295 bool describeArgumentValue(const CallEvent
&Call
, ProgramStateRef State
,
296 const Summary
&Summary
,
297 llvm::raw_ostream
&Out
) const override
;
299 ValueConstraintPtr
negate() const override
{
300 RangeConstraint
Tmp(*this);
301 Tmp
.Kind
= negateKind(Kind
);
302 return std::make_shared
<RangeConstraint
>(Tmp
);
306 bool checkSpecificValidity(const FunctionDecl
*FD
) const override
{
307 const bool ValidArg
=
308 getArgType(FD
, ArgN
)->isIntegralType(FD
->getASTContext());
310 "This constraint should be applied on an integral type");
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
)>;
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]
330 /// -------+--------+------------------+------------+----------->
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
340 void applyOnRange(RangeKind Kind
, BasicValueFactory
&BVF
, QualType ArgT
,
341 const RangeApplyFunction
&F
) const {
344 applyOnOutOfRange(BVF
, ArgT
, F
);
347 applyOnWithinRange(BVF
, ArgT
, F
);
353 /// Check relation of an argument to another.
354 class ComparisonConstraint
: public ValueConstraint
{
355 BinaryOperator::Opcode Opcode
;
359 ComparisonConstraint(ArgNo ArgN
, BinaryOperator::Opcode Opcode
,
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
;
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;
376 NotNullConstraint(ArgNo ArgN
, bool CannotBeNull
= true)
377 : ValueConstraint(ArgN
), CannotBeNull(CannotBeNull
) {}
379 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
380 const Summary
&Summary
,
381 CheckerContext
&C
) const override
;
383 void describe(DescriptionKind DK
, const CallEvent
&Call
,
384 ProgramStateRef State
, const Summary
&Summary
,
385 llvm::raw_ostream
&Out
) const override
;
387 bool describeArgumentValue(const CallEvent
&Call
, ProgramStateRef State
,
388 const Summary
&Summary
,
389 llvm::raw_ostream
&Out
) const override
;
391 ValueConstraintPtr
negate() const override
{
392 NotNullConstraint
Tmp(*this);
393 Tmp
.CannotBeNull
= !this->CannotBeNull
;
394 return std::make_shared
<NotNullConstraint
>(Tmp
);
398 bool checkSpecificValidity(const FunctionDecl
*FD
) const override
{
399 const bool ValidArg
= getArgType(FD
, ArgN
)->isPointerType();
401 "This constraint should be applied only on a pointer type");
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
412 class NotNullBufferConstraint
: public ValueConstraint
{
413 using ValueConstraint::ValueConstraint
;
415 std::optional
<ArgNo
> SizeArg2N
;
416 // This variable has a role when we negate the constraint.
417 bool CannotBeNull
= true;
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
) {}
426 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
427 const Summary
&Summary
,
428 CheckerContext
&C
) const override
;
430 void describe(DescriptionKind DK
, const CallEvent
&Call
,
431 ProgramStateRef State
, const Summary
&Summary
,
432 llvm::raw_ostream
&Out
) const override
;
434 bool describeArgumentValue(const CallEvent
&Call
, ProgramStateRef State
,
435 const Summary
&Summary
,
436 llvm::raw_ostream
&Out
) const override
;
438 ValueConstraintPtr
negate() const override
{
439 NotNullBufferConstraint
Tmp(*this);
440 Tmp
.CannotBeNull
= !this->CannotBeNull
;
441 return std::make_shared
<NotNullBufferConstraint
>(Tmp
);
445 bool checkSpecificValidity(const FunctionDecl
*FD
) const override
{
446 const bool ValidArg
= getArgType(FD
, ArgN
)->isPointerType();
448 "This constraint should be applied only on a pointer type");
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
471 std::optional
<ArgNo
> SizeMultiplierArgN
;
472 // The operator we use in apply. This is negated in negate().
473 BinaryOperator::Opcode Op
= BO_LE
;
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
) {}
484 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
485 const Summary
&Summary
,
486 CheckerContext
&C
) const override
;
488 void describe(DescriptionKind DK
, const CallEvent
&Call
,
489 ProgramStateRef State
, const Summary
&Summary
,
490 llvm::raw_ostream
&Out
) const override
;
492 bool describeArgumentValue(const CallEvent
&Call
, ProgramStateRef State
,
493 const Summary
&Summary
,
494 llvm::raw_ostream
&Out
) const override
;
496 std::vector
<ArgNo
> getArgsToTrack() const override
{
497 std::vector
<ArgNo
> Result
{ArgN
};
499 Result
.push_back(*SizeArgN
);
500 if (SizeMultiplierArgN
)
501 Result
.push_back(*SizeMultiplierArgN
);
505 ValueConstraintPtr
negate() const override
{
506 BufferSizeConstraint
Tmp(*this);
507 Tmp
.Op
= BinaryOperator::negateComparisonOp(Op
);
508 return std::make_shared
<BufferSizeConstraint
>(Tmp
);
512 bool checkSpecificValidity(const FunctionDecl
*FD
) const override
{
513 const bool ValidArg
= getArgType(FD
, ArgN
)->isPointerType();
515 "This constraint should be applied only on a pointer type");
520 /// The complete list of constraints that defines a single branch.
521 using ConstraintSet
= std::vector
<ValueConstraintPtr
>;
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
530 class ErrnoConstraintBase
{
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 NoteTag about the changes made to 'errno' and the possible bug.
537 /// It may return \c nullptr (if no bug report from \c ErrnoChecker is
539 virtual const NoteTag
*describe(CheckerContext
&C
,
540 StringRef FunctionName
) const {
544 virtual ~ErrnoConstraintBase() {}
547 ErrnoConstraintBase() = default;
549 /// This is used for conjure symbol for errno to differentiate from the
550 /// original call expression (same expression is used for the errno symbol).
554 /// Reset errno constraints to irrelevant.
555 /// This is applicable to functions that may change 'errno' and are not
556 /// modeled elsewhere.
557 class ResetErrnoConstraint
: public ErrnoConstraintBase
{
559 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
560 const Summary
&Summary
,
561 CheckerContext
&C
) const override
{
562 return errno_modeling::setErrnoState(State
, errno_modeling::Irrelevant
);
566 /// Do not change errno constraints.
567 /// This is applicable to functions that are modeled in another checker
568 /// and the already set errno constraints should not be changed in the
570 class NoErrnoConstraint
: public ErrnoConstraintBase
{
572 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
573 const Summary
&Summary
,
574 CheckerContext
&C
) const override
{
579 /// Set errno constraint at failure cases of standard functions.
580 /// Failure case: 'errno' becomes not equal to 0 and may or may not be checked
581 /// by the program. \c ErrnoChecker does not emit a bug report after such a
583 class FailureErrnoConstraint
: public ErrnoConstraintBase
{
585 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
586 const Summary
&Summary
,
587 CheckerContext
&C
) const override
{
588 SValBuilder
&SVB
= C
.getSValBuilder();
590 SVB
.conjureSymbolVal(&Tag
, Call
.getOriginExpr(),
591 C
.getLocationContext(), C
.getASTContext().IntTy
,
594 return errno_modeling::setErrnoForStdFailure(State
, C
, ErrnoSVal
);
598 /// Set errno constraint at success cases of standard functions.
599 /// Success case: 'errno' is not allowed to be used.
600 /// \c ErrnoChecker can emit bug report after such a function call if errno
602 class SuccessErrnoConstraint
: public ErrnoConstraintBase
{
604 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
605 const Summary
&Summary
,
606 CheckerContext
&C
) const override
{
607 return errno_modeling::setErrnoForStdSuccess(State
, C
);
610 const NoteTag
*describe(CheckerContext
&C
,
611 StringRef FunctionName
) const override
{
612 return errno_modeling::getNoteTagForStdSuccess(C
, FunctionName
);
616 class ErrnoMustBeCheckedConstraint
: public ErrnoConstraintBase
{
618 ProgramStateRef
apply(ProgramStateRef State
, const CallEvent
&Call
,
619 const Summary
&Summary
,
620 CheckerContext
&C
) const override
{
621 return errno_modeling::setErrnoStdMustBeChecked(State
, C
,
622 Call
.getOriginExpr());
625 const NoteTag
*describe(CheckerContext
&C
,
626 StringRef FunctionName
) const override
{
627 return errno_modeling::getNoteTagForStdMustBeChecked(C
, FunctionName
);
631 /// A single branch of a function summary.
633 /// A branch is defined by a series of constraints - "assumptions" -
634 /// that together form a single possible outcome of invoking the function.
635 /// When static analyzer considers a branch, it tries to introduce
636 /// a child node in the Exploded Graph. The child node has to include
637 /// constraints that define the branch. If the constraints contradict
638 /// existing constraints in the state, the node is not created and the branch
639 /// is dropped; otherwise it's queued for future exploration.
640 /// The branch is accompanied by a note text that may be displayed
641 /// to the user when a bug is found on a path that takes this branch.
643 /// For example, consider the branches in `isalpha(x)`:
645 /// x is in range ['A', 'Z'] or in ['a', 'z']
646 /// then the return value is not 0. (I.e. out-of-range [0, 0])
647 /// and the note may say "Assuming the character is alphabetical"
649 /// x is out-of-range ['A', 'Z'] and out-of-range ['a', 'z']
650 /// then the return value is 0
651 /// and the note may say "Assuming the character is non-alphabetical".
653 ConstraintSet Constraints
;
654 const ErrnoConstraintBase
&ErrnoConstraint
;
658 SummaryCase(ConstraintSet
&&Constraints
, const ErrnoConstraintBase
&ErrnoC
,
660 : Constraints(std::move(Constraints
)), ErrnoConstraint(ErrnoC
),
663 SummaryCase(const ConstraintSet
&Constraints
,
664 const ErrnoConstraintBase
&ErrnoC
, StringRef Note
)
665 : Constraints(Constraints
), ErrnoConstraint(ErrnoC
), Note(Note
) {}
667 const ConstraintSet
&getConstraints() const { return Constraints
; }
668 const ErrnoConstraintBase
&getErrnoConstraint() const {
669 return ErrnoConstraint
;
671 StringRef
getNote() const { return Note
; }
674 using ArgTypes
= std::vector
<std::optional
<QualType
>>;
675 using RetType
= std::optional
<QualType
>;
677 // A placeholder type, we use it whenever we do not care about the concrete
678 // type in a Signature.
679 const QualType Irrelevant
{};
680 bool static isIrrelevant(QualType T
) { return T
.isNull(); }
682 // The signature of a function we want to describe with a summary. This is a
683 // concessive signature, meaning there may be irrelevant types in the
684 // signature which we do not check against a function with concrete types.
685 // All types in the spec need to be canonical.
687 using ArgQualTypes
= std::vector
<QualType
>;
690 // True if any component type is not found by lookup.
691 bool Invalid
= false;
694 // Construct a signature from optional types. If any of the optional types
695 // are not set then the signature will be invalid.
696 Signature(ArgTypes ArgTys
, RetType RetTy
) {
697 for (std::optional
<QualType
> Arg
: ArgTys
) {
702 assertArgTypeSuitableForSignature(*Arg
);
703 this->ArgTys
.push_back(*Arg
);
710 assertRetTypeSuitableForSignature(*RetTy
);
711 this->RetTy
= *RetTy
;
715 bool isInvalid() const { return Invalid
; }
716 bool matches(const FunctionDecl
*FD
) const;
719 static void assertArgTypeSuitableForSignature(QualType T
) {
720 assert((T
.isNull() || !T
->isVoidType()) &&
721 "We should have no void types in the spec");
722 assert((T
.isNull() || T
.isCanonical()) &&
723 "We should only have canonical types in the spec");
725 static void assertRetTypeSuitableForSignature(QualType T
) {
726 assert((T
.isNull() || T
.isCanonical()) &&
727 "We should only have canonical types in the spec");
731 static QualType
getArgType(const FunctionDecl
*FD
, ArgNo ArgN
) {
732 assert(FD
&& "Function must be set");
733 QualType T
= (ArgN
== Ret
)
734 ? FD
->getReturnType().getCanonicalType()
735 : FD
->getParamDecl(ArgN
)->getType().getCanonicalType();
739 using SummaryCases
= std::vector
<SummaryCase
>;
741 /// A summary includes information about
742 /// * function prototype (signature)
743 /// * approach to invalidation,
744 /// * a list of branches - so, a list of list of ranges,
745 /// * a list of argument constraints, that must be true on every branch.
746 /// If these constraints are not satisfied that means a fatal error
747 /// usually resulting in undefined behaviour.
749 /// Application of a summary:
750 /// The signature and argument constraints together contain information
751 /// about which functions are handled by the summary. The signature can use
752 /// "wildcards", i.e. Irrelevant types. Irrelevant type of a parameter in
753 /// a signature means that type is not compared to the type of the parameter
754 /// in the found FunctionDecl. Argument constraints may specify additional
755 /// rules for the given parameter's type, those rules are checked once the
756 /// signature is matched.
758 const InvalidationKind InvalidationKd
;
760 ConstraintSet ArgConstraints
;
762 // The function to which the summary applies. This is set after lookup and
763 // match to the signature.
764 const FunctionDecl
*FD
= nullptr;
767 Summary(InvalidationKind InvalidationKd
) : InvalidationKd(InvalidationKd
) {}
769 Summary
&Case(ConstraintSet
&&CS
, const ErrnoConstraintBase
&ErrnoC
,
770 StringRef Note
= "") {
771 Cases
.push_back(SummaryCase(std::move(CS
), ErrnoC
, Note
));
774 Summary
&Case(const ConstraintSet
&CS
, const ErrnoConstraintBase
&ErrnoC
,
775 StringRef Note
= "") {
776 Cases
.push_back(SummaryCase(CS
, ErrnoC
, Note
));
779 Summary
&ArgConstraint(ValueConstraintPtr VC
) {
780 assert(VC
->getArgNo() != Ret
&&
781 "Arg constraint should not refer to the return value");
782 ArgConstraints
.push_back(VC
);
786 InvalidationKind
getInvalidationKd() const { return InvalidationKd
; }
787 const SummaryCases
&getCases() const { return Cases
; }
788 const ConstraintSet
&getArgConstraints() const { return ArgConstraints
; }
790 QualType
getArgType(ArgNo ArgN
) const {
791 return StdLibraryFunctionsChecker::getArgType(FD
, ArgN
);
794 // Returns true if the summary should be applied to the given function.
795 // And if yes then store the function declaration.
796 bool matchesAndSet(const Signature
&Sign
, const FunctionDecl
*FD
) {
797 bool Result
= Sign
.matches(FD
) && validateByConstraints(FD
);
799 assert(!this->FD
&& "FD must not be set more than once");
806 // Once we know the exact type of the function then do validation check on
807 // all the given constraints.
808 bool validateByConstraints(const FunctionDecl
*FD
) const {
809 for (const SummaryCase
&Case
: Cases
)
810 for (const ValueConstraintPtr
&Constraint
: Case
.getConstraints())
811 if (!Constraint
->checkValidity(FD
))
813 for (const ValueConstraintPtr
&Constraint
: ArgConstraints
)
814 if (!Constraint
->checkValidity(FD
))
820 // The map of all functions supported by the checker. It is initialized
821 // lazily, and it doesn't change after initialization.
822 using FunctionSummaryMapType
= llvm::DenseMap
<const FunctionDecl
*, Summary
>;
823 mutable FunctionSummaryMapType FunctionSummaryMap
;
825 mutable std::unique_ptr
<BugType
> BT_InvalidArg
;
826 mutable bool SummariesInitialized
= false;
828 static SVal
getArgSVal(const CallEvent
&Call
, ArgNo ArgN
) {
829 return ArgN
== Ret
? Call
.getReturnValue() : Call
.getArgSVal(ArgN
);
831 static std::string
getFunctionName(const CallEvent
&Call
) {
832 assert(Call
.getDecl() &&
833 "Call was found by a summary, should have declaration");
834 return cast
<NamedDecl
>(Call
.getDecl())->getNameAsString();
838 void checkPreCall(const CallEvent
&Call
, CheckerContext
&C
) const;
839 void checkPostCall(const CallEvent
&Call
, CheckerContext
&C
) const;
840 bool evalCall(const CallEvent
&Call
, CheckerContext
&C
) const;
842 CheckerNameRef CheckName
;
843 bool AddTestFunctions
= false;
845 bool DisplayLoadedSummaries
= false;
846 bool ModelPOSIX
= false;
847 bool ShouldAssumeControlledEnvironment
= false;
850 std::optional
<Summary
> findFunctionSummary(const FunctionDecl
*FD
,
851 CheckerContext
&C
) const;
852 std::optional
<Summary
> findFunctionSummary(const CallEvent
&Call
,
853 CheckerContext
&C
) const;
855 void initFunctionSummaries(CheckerContext
&C
) const;
857 void reportBug(const CallEvent
&Call
, ExplodedNode
*N
,
858 const ValueConstraint
*VC
, const ValueConstraint
*NegatedVC
,
859 const Summary
&Summary
, CheckerContext
&C
) const {
860 assert(Call
.getDecl() &&
861 "Function found in summary must have a declaration available");
862 SmallString
<256> Msg
;
863 llvm::raw_svector_ostream
MsgOs(Msg
);
866 printArgDesc(VC
->getArgNo(), MsgOs
);
867 MsgOs
<< " to '" << getFunctionName(Call
) << "' ";
869 NegatedVC
->describeArgumentValue(Call
, N
->getState(), Summary
, MsgOs
);
873 MsgOs
<< "is out of the accepted range; It ";
874 VC
->describe(ValueConstraint::Violation
, Call
, C
.getState(), Summary
,
876 Msg
[0] = toupper(Msg
[0]);
878 BT_InvalidArg
= std::make_unique
<BugType
>(
879 CheckName
, "Function call with invalid argument",
880 categories::LogicError
);
881 auto R
= std::make_unique
<PathSensitiveBugReport
>(*BT_InvalidArg
, Msg
, N
);
883 for (ArgNo ArgN
: VC
->getArgsToTrack()) {
884 bugreporter::trackExpressionValue(N
, Call
.getArgExpr(ArgN
), *R
);
885 R
->markInteresting(Call
.getArgSVal(ArgN
));
886 // All tracked arguments are important, highlight them.
887 R
->addRange(Call
.getArgSourceRange(ArgN
));
890 C
.emitReport(std::move(R
));
893 /// These are the errno constraints that can be passed to summary cases.
894 /// One of these should fit for a single summary case.
895 /// Usually if a failure return value exists for function, that function
896 /// needs different cases for success and failure with different errno
897 /// constraints (and different return value constraints).
898 const NoErrnoConstraint ErrnoUnchanged
{};
899 const ResetErrnoConstraint ErrnoIrrelevant
{};
900 const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked
{};
901 const SuccessErrnoConstraint ErrnoMustNotBeChecked
{};
902 const FailureErrnoConstraint ErrnoNEZeroIrrelevant
{};
905 int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag
= 0;
907 const StdLibraryFunctionsChecker::ArgNo
StdLibraryFunctionsChecker::Ret
=
908 std::numeric_limits
<ArgNo
>::max();
910 static BasicValueFactory
&getBVF(ProgramStateRef State
) {
911 ProgramStateManager
&Mgr
= State
->getStateManager();
912 SValBuilder
&SVB
= Mgr
.getSValBuilder();
913 return SVB
.getBasicValueFactory();
916 } // end of anonymous namespace
918 void StdLibraryFunctionsChecker::printArgDesc(
919 StdLibraryFunctionsChecker::ArgNo ArgN
, llvm::raw_ostream
&Out
) {
920 Out
<< std::to_string(ArgN
+ 1);
921 Out
<< llvm::getOrdinalSuffix(ArgN
+ 1);
925 void StdLibraryFunctionsChecker::printArgValueInfo(ArgNo ArgN
,
926 ProgramStateRef State
,
927 const CallEvent
&Call
,
928 llvm::raw_ostream
&Out
) {
929 if (const llvm::APSInt
*Val
=
930 State
->getStateManager().getSValBuilder().getKnownValue(
931 State
, getArgSVal(Call
, ArgN
)))
932 Out
<< " (which is " << *Val
<< ")";
935 void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin
,
938 BasicValueFactory
&BVF
,
939 llvm::raw_ostream
&Out
) {
940 if (RMin
.isZero() && RMax
.isZero())
942 else if (RMin
== RMax
)
944 else if (RMin
== BVF
.getMinValue(ArgT
)) {
948 Out
<< "<= " << RMax
;
949 } else if (RMax
== BVF
.getMaxValue(ArgT
)) {
953 Out
<< ">= " << RMin
;
954 } else if (RMin
.isNegative() == RMax
.isNegative() &&
955 RMin
.getLimitedValue() == RMax
.getLimitedValue() - 1) {
956 Out
<< RMin
<< " or " << RMax
;
958 Out
<< "between " << RMin
<< " and " << RMax
;
962 void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin
,
965 BasicValueFactory
&BVF
,
966 llvm::raw_ostream
&Out
) {
967 if (RMin
.isZero() && RMax
.isZero())
969 else if (RMin
== RMax
) {
970 Out
<< "not equal to " << RMin
;
971 } else if (RMin
== BVF
.getMinValue(ArgT
)) {
976 } else if (RMax
== BVF
.getMaxValue(ArgT
)) {
981 } else if (RMin
.isNegative() == RMax
.isNegative() &&
982 RMin
.getLimitedValue() == RMax
.getLimitedValue() - 1) {
983 Out
<< "not " << RMin
<< " and not " << RMax
;
985 Out
<< "not between " << RMin
<< " and " << RMax
;
989 void StdLibraryFunctionsChecker::RangeConstraint::applyOnWithinRange(
990 BasicValueFactory
&BVF
, QualType ArgT
, const RangeApplyFunction
&F
) const {
994 for (auto [Start
, End
] : getRanges()) {
995 const llvm::APSInt
&Min
= BVF
.getValue(Start
, ArgT
);
996 const llvm::APSInt
&Max
= BVF
.getValue(End
, ArgT
);
1003 void StdLibraryFunctionsChecker::RangeConstraint::applyOnOutOfRange(
1004 BasicValueFactory
&BVF
, QualType ArgT
, const RangeApplyFunction
&F
) const {
1008 const IntRangeVector
&R
= getRanges();
1009 size_t E
= R
.size();
1011 const llvm::APSInt
&MinusInf
= BVF
.getMinValue(ArgT
);
1012 const llvm::APSInt
&PlusInf
= BVF
.getMaxValue(ArgT
);
1014 const llvm::APSInt
&RangeLeft
= BVF
.getValue(R
[0].first
- 1ULL, ArgT
);
1015 const llvm::APSInt
&RangeRight
= BVF
.getValue(R
[E
- 1].second
+ 1ULL, ArgT
);
1017 // Iterate over the "holes" between intervals.
1018 for (size_t I
= 1; I
!= E
; ++I
) {
1019 const llvm::APSInt
&Min
= BVF
.getValue(R
[I
- 1].second
+ 1ULL, ArgT
);
1020 const llvm::APSInt
&Max
= BVF
.getValue(R
[I
].first
- 1ULL, ArgT
);
1026 // Check the interval [T_MIN, min(R) - 1].
1027 if (RangeLeft
!= PlusInf
) {
1028 assert(MinusInf
<= RangeLeft
);
1029 if (!F(MinusInf
, RangeLeft
))
1032 // Check the interval [max(R) + 1, T_MAX],
1033 if (RangeRight
!= MinusInf
) {
1034 assert(RangeRight
<= PlusInf
);
1035 if (!F(RangeRight
, PlusInf
))
1040 ProgramStateRef
StdLibraryFunctionsChecker::RangeConstraint::apply(
1041 ProgramStateRef State
, const CallEvent
&Call
, const Summary
&Summary
,
1042 CheckerContext
&C
) const {
1043 ConstraintManager
&CM
= C
.getConstraintManager();
1044 SVal V
= getArgSVal(Call
, getArgNo());
1045 QualType T
= Summary
.getArgType(getArgNo());
1047 if (auto N
= V
.getAs
<NonLoc
>()) {
1048 auto ExcludeRangeFromArg
= [&](const llvm::APSInt
&Min
,
1049 const llvm::APSInt
&Max
) {
1050 State
= CM
.assumeInclusiveRange(State
, *N
, Min
, Max
, false);
1051 return static_cast<bool>(State
);
1053 // "OutOfRange R" is handled by excluding all ranges in R.
1054 // "WithinRange R" is treated as "OutOfRange [T_MIN, T_MAX] \ R".
1055 applyOnRange(negateKind(Kind
), C
.getSValBuilder().getBasicValueFactory(), T
,
1056 ExcludeRangeFromArg
);
1062 void StdLibraryFunctionsChecker::RangeConstraint::describe(
1063 DescriptionKind DK
, const CallEvent
&Call
, ProgramStateRef State
,
1064 const Summary
&Summary
, llvm::raw_ostream
&Out
) const {
1066 BasicValueFactory
&BVF
= getBVF(State
);
1067 QualType T
= Summary
.getArgType(getArgNo());
1069 Out
<< ((DK
== Violation
) ? "should be " : "is ");
1070 if (!Description
.empty()) {
1073 unsigned I
= Ranges
.size();
1074 if (Kind
== WithinRange
) {
1075 for (const std::pair
<RangeInt
, RangeInt
> &R
: Ranges
) {
1076 appendInsideRangeDesc(BVF
.getValue(R
.first
, T
),
1077 BVF
.getValue(R
.second
, T
), T
, BVF
, Out
);
1082 for (const std::pair
<RangeInt
, RangeInt
> &R
: Ranges
) {
1083 appendOutOfRangeDesc(BVF
.getValue(R
.first
, T
),
1084 BVF
.getValue(R
.second
, T
), T
, BVF
, Out
);
1092 bool StdLibraryFunctionsChecker::RangeConstraint::describeArgumentValue(
1093 const CallEvent
&Call
, ProgramStateRef State
, const Summary
&Summary
,
1094 llvm::raw_ostream
&Out
) const {
1095 unsigned int NRanges
= 0;
1096 bool HaveAllRanges
= true;
1098 ProgramStateManager
&Mgr
= State
->getStateManager();
1099 BasicValueFactory
&BVF
= Mgr
.getSValBuilder().getBasicValueFactory();
1100 ConstraintManager
&CM
= Mgr
.getConstraintManager();
1101 SVal V
= getArgSVal(Call
, getArgNo());
1103 if (auto N
= V
.getAs
<NonLoc
>()) {
1104 if (const llvm::APSInt
*Int
= N
->getAsInteger()) {
1109 QualType T
= Summary
.getArgType(getArgNo());
1110 SmallString
<128> MoreInfo
;
1111 llvm::raw_svector_ostream
MoreInfoOs(MoreInfo
);
1112 auto ApplyF
= [&](const llvm::APSInt
&Min
, const llvm::APSInt
&Max
) {
1113 if (CM
.assumeInclusiveRange(State
, *N
, Min
, Max
, true)) {
1115 MoreInfoOs
<< " or ";
1116 appendInsideRangeDesc(Min
, Max
, T
, BVF
, MoreInfoOs
);
1119 HaveAllRanges
= false;
1124 applyOnRange(Kind
, BVF
, T
, ApplyF
);
1125 assert(NRanges
> 0);
1126 if (!HaveAllRanges
|| NRanges
== 1) {
1135 ProgramStateRef
StdLibraryFunctionsChecker::ComparisonConstraint::apply(
1136 ProgramStateRef State
, const CallEvent
&Call
, const Summary
&Summary
,
1137 CheckerContext
&C
) const {
1139 ProgramStateManager
&Mgr
= State
->getStateManager();
1140 SValBuilder
&SVB
= Mgr
.getSValBuilder();
1141 QualType CondT
= SVB
.getConditionType();
1142 QualType T
= Summary
.getArgType(getArgNo());
1143 SVal V
= getArgSVal(Call
, getArgNo());
1145 BinaryOperator::Opcode Op
= getOpcode();
1146 ArgNo OtherArg
= getOtherArgNo();
1147 SVal OtherV
= getArgSVal(Call
, OtherArg
);
1148 QualType OtherT
= Summary
.getArgType(OtherArg
);
1149 // Note: we avoid integral promotion for comparison.
1150 OtherV
= SVB
.evalCast(OtherV
, T
, OtherT
);
1151 if (auto CompV
= SVB
.evalBinOp(State
, Op
, V
, OtherV
, CondT
)
1152 .getAs
<DefinedOrUnknownSVal
>())
1153 State
= State
->assume(*CompV
, true);
1157 ProgramStateRef
StdLibraryFunctionsChecker::NotNullConstraint::apply(
1158 ProgramStateRef State
, const CallEvent
&Call
, const Summary
&Summary
,
1159 CheckerContext
&C
) const {
1160 SVal V
= getArgSVal(Call
, getArgNo());
1164 DefinedOrUnknownSVal L
= V
.castAs
<DefinedOrUnknownSVal
>();
1168 return State
->assume(L
, CannotBeNull
);
1171 void StdLibraryFunctionsChecker::NotNullConstraint::describe(
1172 DescriptionKind DK
, const CallEvent
&Call
, ProgramStateRef State
,
1173 const Summary
&Summary
, llvm::raw_ostream
&Out
) const {
1174 assert(CannotBeNull
&&
1175 "Describe should not be used when the value must be NULL");
1176 if (DK
== Violation
)
1177 Out
<< "should not be NULL";
1179 Out
<< "is not NULL";
1182 bool StdLibraryFunctionsChecker::NotNullConstraint::describeArgumentValue(
1183 const CallEvent
&Call
, ProgramStateRef State
, const Summary
&Summary
,
1184 llvm::raw_ostream
&Out
) const {
1185 assert(!CannotBeNull
&& "This function is used when the value is NULL");
1190 ProgramStateRef
StdLibraryFunctionsChecker::NotNullBufferConstraint::apply(
1191 ProgramStateRef State
, const CallEvent
&Call
, const Summary
&Summary
,
1192 CheckerContext
&C
) const {
1193 SVal V
= getArgSVal(Call
, getArgNo());
1196 DefinedOrUnknownSVal L
= V
.castAs
<DefinedOrUnknownSVal
>();
1200 std::optional
<DefinedOrUnknownSVal
> SizeArg1
=
1201 getArgSVal(Call
, SizeArg1N
).getAs
<DefinedOrUnknownSVal
>();
1202 std::optional
<DefinedOrUnknownSVal
> SizeArg2
;
1204 SizeArg2
= getArgSVal(Call
, *SizeArg2N
).getAs
<DefinedOrUnknownSVal
>();
1206 auto IsArgZero
= [State
](std::optional
<DefinedOrUnknownSVal
> Val
) {
1209 auto [IsNonNull
, IsNull
] = State
->assume(*Val
);
1210 return IsNull
&& !IsNonNull
;
1213 if (IsArgZero(SizeArg1
) || IsArgZero(SizeArg2
))
1216 return State
->assume(L
, CannotBeNull
);
1219 void StdLibraryFunctionsChecker::NotNullBufferConstraint::describe(
1220 DescriptionKind DK
, const CallEvent
&Call
, ProgramStateRef State
,
1221 const Summary
&Summary
, llvm::raw_ostream
&Out
) const {
1222 assert(CannotBeNull
&&
1223 "Describe should not be used when the value must be NULL");
1224 if (DK
== Violation
)
1225 Out
<< "should not be NULL";
1227 Out
<< "is not NULL";
1230 bool StdLibraryFunctionsChecker::NotNullBufferConstraint::describeArgumentValue(
1231 const CallEvent
&Call
, ProgramStateRef State
, const Summary
&Summary
,
1232 llvm::raw_ostream
&Out
) const {
1233 assert(!CannotBeNull
&& "This function is used when the value is NULL");
1238 ProgramStateRef
StdLibraryFunctionsChecker::BufferSizeConstraint::apply(
1239 ProgramStateRef State
, const CallEvent
&Call
, const Summary
&Summary
,
1240 CheckerContext
&C
) const {
1241 SValBuilder
&SvalBuilder
= C
.getSValBuilder();
1242 // The buffer argument.
1243 SVal BufV
= getArgSVal(Call
, getArgNo());
1245 // Get the size constraint.
1246 const SVal SizeV
= [this, &State
, &Call
, &Summary
, &SvalBuilder
]() {
1248 return SVal(SvalBuilder
.makeIntVal(*ConcreteSize
));
1250 assert(SizeArgN
&& "The constraint must be either a concrete value or "
1251 "encoded in an argument.");
1252 // The size argument.
1253 SVal SizeV
= getArgSVal(Call
, *SizeArgN
);
1254 // Multiply with another argument if given.
1255 if (SizeMultiplierArgN
) {
1256 SVal SizeMulV
= getArgSVal(Call
, *SizeMultiplierArgN
);
1257 SizeV
= SvalBuilder
.evalBinOp(State
, BO_Mul
, SizeV
, SizeMulV
,
1258 Summary
.getArgType(*SizeArgN
));
1263 // The dynamic size of the buffer argument, got from the analyzer engine.
1264 SVal BufDynSize
= getDynamicExtentWithOffset(State
, BufV
);
1266 SVal Feasible
= SvalBuilder
.evalBinOp(State
, Op
, SizeV
, BufDynSize
,
1267 SvalBuilder
.getContext().BoolTy
);
1268 if (auto F
= Feasible
.getAs
<DefinedOrUnknownSVal
>())
1269 return State
->assume(*F
, true);
1271 // We can get here only if the size argument or the dynamic size is
1272 // undefined. But the dynamic size should never be undefined, only
1273 // unknown. So, here, the size of the argument is undefined, i.e. we
1274 // cannot apply the constraint. Actually, other checkers like
1275 // CallAndMessage should catch this situation earlier, because we call a
1276 // function with an uninitialized argument.
1277 llvm_unreachable("Size argument or the dynamic size is Undefined");
1280 void StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
1281 DescriptionKind DK
, const CallEvent
&Call
, ProgramStateRef State
,
1282 const Summary
&Summary
, llvm::raw_ostream
&Out
) const {
1283 Out
<< ((DK
== Violation
) ? "should be " : "is ");
1284 Out
<< "a buffer with size equal to or greater than ";
1286 Out
<< *ConcreteSize
;
1287 } else if (SizeArgN
) {
1288 Out
<< "the value of the ";
1289 printArgDesc(*SizeArgN
, Out
);
1290 printArgValueInfo(*SizeArgN
, State
, Call
, Out
);
1291 if (SizeMultiplierArgN
) {
1292 Out
<< " times the ";
1293 printArgDesc(*SizeMultiplierArgN
, Out
);
1294 printArgValueInfo(*SizeMultiplierArgN
, State
, Call
, Out
);
1299 bool StdLibraryFunctionsChecker::BufferSizeConstraint::describeArgumentValue(
1300 const CallEvent
&Call
, ProgramStateRef State
, const Summary
&Summary
,
1301 llvm::raw_ostream
&Out
) const {
1302 SVal BufV
= getArgSVal(Call
, getArgNo());
1303 SVal BufDynSize
= getDynamicExtentWithOffset(State
, BufV
);
1304 if (const llvm::APSInt
*Val
=
1305 State
->getStateManager().getSValBuilder().getKnownValue(State
,
1307 Out
<< "is a buffer with size " << *Val
;
1313 void StdLibraryFunctionsChecker::checkPreCall(const CallEvent
&Call
,
1314 CheckerContext
&C
) const {
1315 std::optional
<Summary
> FoundSummary
= findFunctionSummary(Call
, C
);
1319 const Summary
&Summary
= *FoundSummary
;
1320 ProgramStateRef State
= C
.getState();
1322 ProgramStateRef NewState
= State
;
1323 ExplodedNode
*NewNode
= C
.getPredecessor();
1324 for (const ValueConstraintPtr
&Constraint
: Summary
.getArgConstraints()) {
1325 ValueConstraintPtr NegatedConstraint
= Constraint
->negate();
1326 ProgramStateRef SuccessSt
= Constraint
->apply(NewState
, Call
, Summary
, C
);
1327 ProgramStateRef FailureSt
=
1328 NegatedConstraint
->apply(NewState
, Call
, Summary
, C
);
1329 // The argument constraint is not satisfied.
1330 if (FailureSt
&& !SuccessSt
) {
1331 if (ExplodedNode
*N
= C
.generateErrorNode(State
, NewNode
))
1332 reportBug(Call
, N
, Constraint
.get(), NegatedConstraint
.get(), Summary
,
1336 // We will apply the constraint even if we cannot reason about the
1337 // argument. This means both SuccessSt and FailureSt can be true. If we
1338 // weren't applying the constraint that would mean that symbolic
1339 // execution continues on a code whose behaviour is undefined.
1341 NewState
= SuccessSt
;
1342 if (NewState
!= State
) {
1343 SmallString
<128> Msg
;
1344 llvm::raw_svector_ostream
Os(Msg
);
1345 Os
<< "Assuming that the ";
1346 printArgDesc(Constraint
->getArgNo(), Os
);
1348 Os
<< getFunctionName(Call
);
1350 Constraint
->describe(ValueConstraint::Assumption
, Call
, NewState
, Summary
,
1352 const auto ArgSVal
= Call
.getArgSVal(Constraint
->getArgNo());
1353 NewNode
= C
.addTransition(
1355 C
.getNoteTag([Msg
= std::move(Msg
), ArgSVal
](
1356 PathSensitiveBugReport
&BR
, llvm::raw_ostream
&OS
) {
1357 if (BR
.isInteresting(ArgSVal
))
1364 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent
&Call
,
1365 CheckerContext
&C
) const {
1366 std::optional
<Summary
> FoundSummary
= findFunctionSummary(Call
, C
);
1370 // Now apply the constraints.
1371 const Summary
&Summary
= *FoundSummary
;
1372 ProgramStateRef State
= C
.getState();
1373 ExplodedNode
*Node
= C
.getPredecessor();
1375 // Apply case/branch specifications.
1376 for (const SummaryCase
&Case
: Summary
.getCases()) {
1377 ProgramStateRef NewState
= State
;
1378 for (const ValueConstraintPtr
&Constraint
: Case
.getConstraints()) {
1379 NewState
= Constraint
->apply(NewState
, Call
, Summary
, C
);
1385 NewState
= Case
.getErrnoConstraint().apply(NewState
, Call
, Summary
, C
);
1390 // Here it's possible that NewState == State, e.g. when other checkers
1391 // already applied the same constraints (or stricter ones).
1392 // Still add these note tags, the other checker should add only its
1393 // specialized note tags. These general note tags are handled always by
1394 // StdLibraryFunctionsChecker.
1395 ExplodedNode
*Pred
= Node
;
1396 if (!Case
.getNote().empty()) {
1397 const SVal RV
= Call
.getReturnValue();
1398 // If there is a description for this execution branch (summary case),
1399 // use it as a note tag.
1401 llvm::formatv(Case
.getNote().str().c_str(),
1402 cast
<NamedDecl
>(Call
.getDecl())->getDeclName());
1403 if (Summary
.getInvalidationKd() == EvalCallAsPure
) {
1404 const NoteTag
*Tag
= C
.getNoteTag(
1405 [Node
, Note
, RV
](PathSensitiveBugReport
&BR
) -> std::string
{
1406 // Try to omit the note if we know in advance which branch is
1407 // taken (this means, only one branch exists).
1408 // This check is performed inside the lambda, after other
1409 // (or this) checkers had a chance to add other successors.
1410 // Dereferencing the saved node object is valid because it's part
1411 // of a bug report call sequence.
1412 // FIXME: This check is not exact. We may be here after a state
1413 // split that was performed by another checker (and can not find
1414 // the successors). This is why this check is only used in the
1415 // EvalCallAsPure case.
1416 if (BR
.isInteresting(RV
) && Node
->succ_size() > 1)
1420 Pred
= C
.addTransition(NewState
, Pred
, Tag
);
1422 const NoteTag
*Tag
=
1423 C
.getNoteTag([Note
, RV
](PathSensitiveBugReport
&BR
) -> std::string
{
1424 if (BR
.isInteresting(RV
))
1428 Pred
= C
.addTransition(NewState
, Pred
, Tag
);
1432 // - a nullpointer, if we reach an already existing node (theoretically);
1433 // - a sink, when NewState is posteriorly overconstrained.
1434 // In these situations we cannot add the errno note tag.
1435 if (!Pred
|| Pred
->isSink())
1439 // If we can get a note tag for the errno change, add this additionally to
1440 // the previous. This note is only about value of 'errno' and is displayed
1441 // if 'errno' is interesting.
1442 if (const auto *D
= dyn_cast
<FunctionDecl
>(Call
.getDecl()))
1443 if (const NoteTag
*NT
=
1444 Case
.getErrnoConstraint().describe(C
, D
->getNameAsString()))
1445 Pred
= C
.addTransition(NewState
, Pred
, NT
);
1447 // Add the transition if no note tag could be added.
1448 if (Pred
== Node
&& NewState
!= State
)
1449 C
.addTransition(NewState
);
1453 bool StdLibraryFunctionsChecker::evalCall(const CallEvent
&Call
,
1454 CheckerContext
&C
) const {
1455 std::optional
<Summary
> FoundSummary
= findFunctionSummary(Call
, C
);
1459 const Summary
&Summary
= *FoundSummary
;
1460 switch (Summary
.getInvalidationKd()) {
1461 case EvalCallAsPure
: {
1462 ProgramStateRef State
= C
.getState();
1463 const LocationContext
*LC
= C
.getLocationContext();
1464 const auto *CE
= cast
<CallExpr
>(Call
.getOriginExpr());
1465 SVal V
= C
.getSValBuilder().conjureSymbolVal(
1466 CE
, LC
, CE
->getType().getCanonicalType(), C
.blockCount());
1467 State
= State
->BindExpr(CE
, LC
, V
);
1469 C
.addTransition(State
);
1474 // Summary tells us to avoid performing eval::Call. The function is possibly
1475 // evaluated by another checker, or evaluated conservatively.
1478 llvm_unreachable("Unknown invalidation kind!");
1481 bool StdLibraryFunctionsChecker::Signature::matches(
1482 const FunctionDecl
*FD
) const {
1483 assert(!isInvalid());
1484 // Check the number of arguments.
1485 if (FD
->param_size() != ArgTys
.size())
1488 // The "restrict" keyword is illegal in C++, however, many libc
1489 // implementations use the "__restrict" compiler intrinsic in functions
1490 // prototypes. The "__restrict" keyword qualifies a type as a restricted type
1492 // In case of any non-C99 languages, we don't want to match based on the
1493 // restrict qualifier because we cannot know if the given libc implementation
1494 // qualifies the paramter type or not.
1495 auto RemoveRestrict
= [&FD
](QualType T
) {
1496 if (!FD
->getASTContext().getLangOpts().C99
)
1497 T
.removeLocalRestrict();
1501 // Check the return type.
1502 if (!isIrrelevant(RetTy
)) {
1503 QualType FDRetTy
= RemoveRestrict(FD
->getReturnType().getCanonicalType());
1504 if (RetTy
!= FDRetTy
)
1508 // Check the argument types.
1509 for (auto [Idx
, ArgTy
] : llvm::enumerate(ArgTys
)) {
1510 if (isIrrelevant(ArgTy
))
1513 RemoveRestrict(FD
->getParamDecl(Idx
)->getType().getCanonicalType());
1514 if (ArgTy
!= FDArgTy
)
1521 std::optional
<StdLibraryFunctionsChecker::Summary
>
1522 StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl
*FD
,
1523 CheckerContext
&C
) const {
1525 return std::nullopt
;
1527 initFunctionSummaries(C
);
1529 auto FSMI
= FunctionSummaryMap
.find(FD
->getCanonicalDecl());
1530 if (FSMI
== FunctionSummaryMap
.end())
1531 return std::nullopt
;
1532 return FSMI
->second
;
1535 std::optional
<StdLibraryFunctionsChecker::Summary
>
1536 StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent
&Call
,
1537 CheckerContext
&C
) const {
1538 const FunctionDecl
*FD
= dyn_cast_or_null
<FunctionDecl
>(Call
.getDecl());
1540 return std::nullopt
;
1541 return findFunctionSummary(FD
, C
);
1544 void StdLibraryFunctionsChecker::initFunctionSummaries(
1545 CheckerContext
&C
) const {
1546 if (SummariesInitialized
)
1548 SummariesInitialized
= true;
1550 SValBuilder
&SVB
= C
.getSValBuilder();
1551 BasicValueFactory
&BVF
= SVB
.getBasicValueFactory();
1552 const ASTContext
&ACtx
= BVF
.getContext();
1553 Preprocessor
&PP
= C
.getPreprocessor();
1555 // Helper class to lookup a type by its name.
1557 const ASTContext
&ACtx
;
1560 LookupType(const ASTContext
&ACtx
) : ACtx(ACtx
) {}
1562 // Find the type. If not found then the optional is not set.
1563 std::optional
<QualType
> operator()(StringRef Name
) {
1564 IdentifierInfo
&II
= ACtx
.Idents
.get(Name
);
1565 auto LookupRes
= ACtx
.getTranslationUnitDecl()->lookup(&II
);
1566 if (LookupRes
.empty())
1567 return std::nullopt
;
1569 // Prioritze typedef declarations.
1570 // This is needed in case of C struct typedefs. E.g.:
1571 // typedef struct FILE FILE;
1572 // In this case, we have a RecordDecl 'struct FILE' with the name 'FILE'
1573 // and we have a TypedefDecl with the name 'FILE'.
1574 for (Decl
*D
: LookupRes
)
1575 if (auto *TD
= dyn_cast
<TypedefNameDecl
>(D
))
1576 return ACtx
.getTypeDeclType(TD
).getCanonicalType();
1578 // Find the first TypeDecl.
1579 // There maybe cases when a function has the same name as a struct.
1580 // E.g. in POSIX: `struct stat` and the function `stat()`:
1581 // int stat(const char *restrict path, struct stat *restrict buf);
1582 for (Decl
*D
: LookupRes
)
1583 if (auto *TD
= dyn_cast
<TypeDecl
>(D
))
1584 return ACtx
.getTypeDeclType(TD
).getCanonicalType();
1585 return std::nullopt
;
1589 // Below are auxiliary classes to handle optional types that we get as a
1590 // result of the lookup.
1591 class GetRestrictTy
{
1592 const ASTContext
&ACtx
;
1595 GetRestrictTy(const ASTContext
&ACtx
) : ACtx(ACtx
) {}
1596 QualType
operator()(QualType Ty
) {
1597 return ACtx
.getLangOpts().C99
? ACtx
.getRestrictType(Ty
) : Ty
;
1599 std::optional
<QualType
> operator()(std::optional
<QualType
> Ty
) {
1601 return operator()(*Ty
);
1602 return std::nullopt
;
1604 } getRestrictTy(ACtx
);
1605 class GetPointerTy
{
1606 const ASTContext
&ACtx
;
1609 GetPointerTy(const ASTContext
&ACtx
) : ACtx(ACtx
) {}
1610 QualType
operator()(QualType Ty
) { return ACtx
.getPointerType(Ty
); }
1611 std::optional
<QualType
> operator()(std::optional
<QualType
> Ty
) {
1613 return operator()(*Ty
);
1614 return std::nullopt
;
1616 } getPointerTy(ACtx
);
1619 std::optional
<QualType
> operator()(std::optional
<QualType
> Ty
) {
1620 return Ty
? std::optional
<QualType
>(Ty
->withConst()) : std::nullopt
;
1622 QualType
operator()(QualType Ty
) { return Ty
.withConst(); }
1625 BasicValueFactory
&BVF
;
1628 GetMaxValue(BasicValueFactory
&BVF
) : BVF(BVF
) {}
1629 std::optional
<RangeInt
> operator()(QualType Ty
) {
1630 return BVF
.getMaxValue(Ty
).getLimitedValue();
1632 std::optional
<RangeInt
> operator()(std::optional
<QualType
> Ty
) {
1634 return operator()(*Ty
);
1636 return std::nullopt
;
1640 // These types are useful for writing specifications quickly,
1641 // New specifications should probably introduce more types.
1642 // Some types are hard to obtain from the AST, eg. "ssize_t".
1643 // In such cases it should be possible to provide multiple variants
1644 // of function summary for common cases (eg. ssize_t could be int or long
1645 // or long long, so three summary variants would be enough).
1646 // Of course, function variants are also useful for C++ overloads.
1647 const QualType VoidTy
= ACtx
.VoidTy
;
1648 const QualType CharTy
= ACtx
.CharTy
;
1649 const QualType WCharTy
= ACtx
.WCharTy
;
1650 const QualType IntTy
= ACtx
.IntTy
;
1651 const QualType UnsignedIntTy
= ACtx
.UnsignedIntTy
;
1652 const QualType LongTy
= ACtx
.LongTy
;
1653 const QualType SizeTy
= ACtx
.getSizeType();
1655 const QualType VoidPtrTy
= getPointerTy(VoidTy
); // void *
1656 const QualType IntPtrTy
= getPointerTy(IntTy
); // int *
1657 const QualType UnsignedIntPtrTy
=
1658 getPointerTy(UnsignedIntTy
); // unsigned int *
1659 const QualType VoidPtrRestrictTy
= getRestrictTy(VoidPtrTy
);
1660 const QualType ConstVoidPtrTy
=
1661 getPointerTy(getConstTy(VoidTy
)); // const void *
1662 const QualType CharPtrTy
= getPointerTy(CharTy
); // char *
1663 const QualType CharPtrRestrictTy
= getRestrictTy(CharPtrTy
);
1664 const QualType ConstCharPtrTy
=
1665 getPointerTy(getConstTy(CharTy
)); // const char *
1666 const QualType ConstCharPtrRestrictTy
= getRestrictTy(ConstCharPtrTy
);
1667 const QualType Wchar_tPtrTy
= getPointerTy(WCharTy
); // wchar_t *
1668 const QualType ConstWchar_tPtrTy
=
1669 getPointerTy(getConstTy(WCharTy
)); // const wchar_t *
1670 const QualType ConstVoidPtrRestrictTy
= getRestrictTy(ConstVoidPtrTy
);
1671 const QualType SizePtrTy
= getPointerTy(SizeTy
);
1672 const QualType SizePtrRestrictTy
= getRestrictTy(SizePtrTy
);
1674 const RangeInt IntMax
= BVF
.getMaxValue(IntTy
).getLimitedValue();
1675 const RangeInt UnsignedIntMax
=
1676 BVF
.getMaxValue(UnsignedIntTy
).getLimitedValue();
1677 const RangeInt LongMax
= BVF
.getMaxValue(LongTy
).getLimitedValue();
1678 const RangeInt SizeMax
= BVF
.getMaxValue(SizeTy
).getLimitedValue();
1680 // Set UCharRangeMax to min of int or uchar maximum value.
1681 // The C standard states that the arguments of functions like isalpha must
1682 // be representable as an unsigned char. Their type is 'int', so the max
1683 // value of the argument should be min(UCharMax, IntMax). This just happen
1684 // to be true for commonly used and well tested instruction set
1685 // architectures, but not for others.
1686 const RangeInt UCharRangeMax
=
1687 std::min(BVF
.getMaxValue(ACtx
.UnsignedCharTy
).getLimitedValue(), IntMax
);
1689 // Get platform dependent values of some macros.
1690 // Try our best to parse this from the Preprocessor, otherwise fallback to a
1691 // default value (what is found in a library header).
1692 const auto EOFv
= tryExpandAsInteger("EOF", PP
).value_or(-1);
1693 const auto AT_FDCWDv
= tryExpandAsInteger("AT_FDCWD", PP
).value_or(-100);
1695 // Auxiliary class to aid adding summaries to the summary map.
1696 struct AddToFunctionSummaryMap
{
1697 const ASTContext
&ACtx
;
1698 FunctionSummaryMapType
&Map
;
1699 bool DisplayLoadedSummaries
;
1700 AddToFunctionSummaryMap(const ASTContext
&ACtx
, FunctionSummaryMapType
&FSM
,
1701 bool DisplayLoadedSummaries
)
1702 : ACtx(ACtx
), Map(FSM
), DisplayLoadedSummaries(DisplayLoadedSummaries
) {
1705 // Add a summary to a FunctionDecl found by lookup. The lookup is performed
1706 // by the given Name, and in the global scope. The summary will be attached
1707 // to the found FunctionDecl only if the signatures match.
1709 // Returns true if the summary has been added, false otherwise.
1710 bool operator()(StringRef Name
, Signature Sign
, Summary Sum
) {
1711 if (Sign
.isInvalid())
1713 IdentifierInfo
&II
= ACtx
.Idents
.get(Name
);
1714 auto LookupRes
= ACtx
.getTranslationUnitDecl()->lookup(&II
);
1715 if (LookupRes
.empty())
1717 for (Decl
*D
: LookupRes
) {
1718 if (auto *FD
= dyn_cast
<FunctionDecl
>(D
)) {
1719 if (Sum
.matchesAndSet(Sign
, FD
)) {
1720 auto Res
= Map
.insert({FD
->getCanonicalDecl(), Sum
});
1721 assert(Res
.second
&& "Function already has a summary set!");
1723 if (DisplayLoadedSummaries
) {
1724 llvm::errs() << "Loaded summary for: ";
1725 FD
->print(llvm::errs());
1726 llvm::errs() << "\n";
1734 // Add the same summary for different names with the Signature explicitly
1736 void operator()(std::vector
<StringRef
> Names
, Signature Sign
, Summary Sum
) {
1737 for (StringRef Name
: Names
)
1738 operator()(Name
, Sign
, Sum
);
1740 } addToFunctionSummaryMap(ACtx
, FunctionSummaryMap
, DisplayLoadedSummaries
);
1742 // Below are helpers functions to create the summaries.
1743 auto ArgumentCondition
= [](ArgNo ArgN
, RangeKind Kind
, IntRangeVector Ranges
,
1744 StringRef Desc
= "") {
1745 return std::make_shared
<RangeConstraint
>(ArgN
, Kind
, Ranges
, Desc
);
1747 auto BufferSize
= [](auto... Args
) {
1748 return std::make_shared
<BufferSizeConstraint
>(Args
...);
1751 auto operator()(RangeKind Kind
, IntRangeVector Ranges
) {
1752 return std::make_shared
<RangeConstraint
>(Ret
, Kind
, Ranges
);
1754 auto operator()(BinaryOperator::Opcode Op
, ArgNo OtherArgN
) {
1755 return std::make_shared
<ComparisonConstraint
>(Ret
, Op
, OtherArgN
);
1757 } ReturnValueCondition
;
1759 auto operator()(RangeInt b
, RangeInt e
) {
1760 return IntRangeVector
{std::pair
<RangeInt
, RangeInt
>{b
, e
}};
1762 auto operator()(RangeInt b
, std::optional
<RangeInt
> e
) {
1764 return IntRangeVector
{std::pair
<RangeInt
, RangeInt
>{b
, *e
}};
1765 return IntRangeVector
{};
1767 auto operator()(std::pair
<RangeInt
, RangeInt
> i0
,
1768 std::pair
<RangeInt
, std::optional
<RangeInt
>> i1
) {
1770 return IntRangeVector
{i0
, {i1
.first
, *(i1
.second
)}};
1771 return IntRangeVector
{i0
};
1774 auto SingleValue
= [](RangeInt v
) {
1775 return IntRangeVector
{std::pair
<RangeInt
, RangeInt
>{v
, v
}};
1777 auto LessThanOrEq
= BO_LE
;
1778 auto NotNull
= [&](ArgNo ArgN
) {
1779 return std::make_shared
<NotNullConstraint
>(ArgN
);
1781 auto IsNull
= [&](ArgNo ArgN
) {
1782 return std::make_shared
<NotNullConstraint
>(ArgN
, false);
1784 auto NotNullBuffer
= [&](ArgNo ArgN
, ArgNo SizeArg1N
, ArgNo SizeArg2N
) {
1785 return std::make_shared
<NotNullBufferConstraint
>(ArgN
, SizeArg1N
,
1789 std::optional
<QualType
> FileTy
= lookupTy("FILE");
1790 std::optional
<QualType
> FilePtrTy
= getPointerTy(FileTy
);
1791 std::optional
<QualType
> FilePtrRestrictTy
= getRestrictTy(FilePtrTy
);
1793 std::optional
<QualType
> FPosTTy
= lookupTy("fpos_t");
1794 std::optional
<QualType
> FPosTPtrTy
= getPointerTy(FPosTTy
);
1795 std::optional
<QualType
> ConstFPosTPtrTy
= getPointerTy(getConstTy(FPosTTy
));
1796 std::optional
<QualType
> FPosTPtrRestrictTy
= getRestrictTy(FPosTPtrTy
);
1798 constexpr llvm::StringLiteral
GenericSuccessMsg(
1799 "Assuming that '{0}' is successful");
1800 constexpr llvm::StringLiteral
GenericFailureMsg("Assuming that '{0}' fails");
1802 // We are finally ready to define specifications for all supported functions.
1804 // Argument ranges should always cover all variants. If return value
1805 // is completely unknown, omit it from the respective range set.
1807 // Every item in the list of range sets represents a particular
1808 // execution path the analyzer would need to explore once
1809 // the call is modeled - a new program state is constructed
1810 // for every range set, and each range line in the range set
1811 // corresponds to a specific constraint within this state.
1813 // The isascii() family of functions.
1814 // The behavior is undefined if the value of the argument is not
1815 // representable as unsigned char or is not equal to EOF. See e.g. C99
1816 // 7.4.1.2 The isalpha function (p: 181-182).
1817 addToFunctionSummaryMap(
1818 "isalnum", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1819 Summary(EvalCallAsPure
)
1820 // Boils down to isupper() or islower() or isdigit().
1821 .Case({ArgumentCondition(0U, WithinRange
,
1822 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}),
1823 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1824 ErrnoIrrelevant
, "Assuming the character is alphanumeric")
1825 // The locale-specific range.
1826 // No post-condition. We are completely unaware of
1827 // locale-specific return values.
1828 .Case({ArgumentCondition(0U, WithinRange
, {{128, UCharRangeMax
}})},
1833 {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax
}}),
1834 ReturnValueCondition(WithinRange
, SingleValue(0))},
1835 ErrnoIrrelevant
, "Assuming the character is non-alphanumeric")
1836 .ArgConstraint(ArgumentCondition(0U, WithinRange
,
1837 {{EOFv
, EOFv
}, {0, UCharRangeMax
}},
1838 "an unsigned char value or EOF")));
1839 addToFunctionSummaryMap(
1840 "isalpha", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1841 Summary(EvalCallAsPure
)
1842 .Case({ArgumentCondition(0U, WithinRange
, {{'A', 'Z'}, {'a', 'z'}}),
1843 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1844 ErrnoIrrelevant
, "Assuming the character is alphabetical")
1845 // The locale-specific range.
1846 .Case({ArgumentCondition(0U, WithinRange
, {{128, UCharRangeMax
}})},
1848 .Case({ArgumentCondition(
1850 {{'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax
}}),
1851 ReturnValueCondition(WithinRange
, SingleValue(0))},
1852 ErrnoIrrelevant
, "Assuming the character is non-alphabetical"));
1853 addToFunctionSummaryMap(
1854 "isascii", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1855 Summary(EvalCallAsPure
)
1856 .Case({ArgumentCondition(0U, WithinRange
, Range(0, 127)),
1857 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1858 ErrnoIrrelevant
, "Assuming the character is an ASCII character")
1859 .Case({ArgumentCondition(0U, OutOfRange
, Range(0, 127)),
1860 ReturnValueCondition(WithinRange
, SingleValue(0))},
1862 "Assuming the character is not an ASCII character"));
1863 addToFunctionSummaryMap(
1864 "isblank", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1865 Summary(EvalCallAsPure
)
1866 .Case({ArgumentCondition(0U, WithinRange
, {{'\t', '\t'}, {' ', ' '}}),
1867 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1868 ErrnoIrrelevant
, "Assuming the character is a blank character")
1869 .Case({ArgumentCondition(0U, OutOfRange
, {{'\t', '\t'}, {' ', ' '}}),
1870 ReturnValueCondition(WithinRange
, SingleValue(0))},
1872 "Assuming the character is not a blank character"));
1873 addToFunctionSummaryMap(
1874 "iscntrl", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1875 Summary(EvalCallAsPure
)
1876 .Case({ArgumentCondition(0U, WithinRange
, {{0, 32}, {127, 127}}),
1877 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1879 "Assuming the character is a control character")
1880 .Case({ArgumentCondition(0U, OutOfRange
, {{0, 32}, {127, 127}}),
1881 ReturnValueCondition(WithinRange
, SingleValue(0))},
1883 "Assuming the character is not a control character"));
1884 addToFunctionSummaryMap(
1885 "isdigit", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1886 Summary(EvalCallAsPure
)
1887 .Case({ArgumentCondition(0U, WithinRange
, Range('0', '9')),
1888 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1889 ErrnoIrrelevant
, "Assuming the character is a digit")
1890 .Case({ArgumentCondition(0U, OutOfRange
, Range('0', '9')),
1891 ReturnValueCondition(WithinRange
, SingleValue(0))},
1892 ErrnoIrrelevant
, "Assuming the character is not a digit"));
1893 addToFunctionSummaryMap(
1894 "isgraph", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1895 Summary(EvalCallAsPure
)
1896 .Case({ArgumentCondition(0U, WithinRange
, Range(33, 126)),
1897 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1899 "Assuming the character has graphical representation")
1901 {ArgumentCondition(0U, OutOfRange
, Range(33, 126)),
1902 ReturnValueCondition(WithinRange
, SingleValue(0))},
1904 "Assuming the character does not have graphical representation"));
1905 addToFunctionSummaryMap(
1906 "islower", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1907 Summary(EvalCallAsPure
)
1908 // Is certainly lowercase.
1909 .Case({ArgumentCondition(0U, WithinRange
, Range('a', 'z')),
1910 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1911 ErrnoIrrelevant
, "Assuming the character is a lowercase letter")
1912 // Is ascii but not lowercase.
1913 .Case({ArgumentCondition(0U, WithinRange
, Range(0, 127)),
1914 ArgumentCondition(0U, OutOfRange
, Range('a', 'z')),
1915 ReturnValueCondition(WithinRange
, SingleValue(0))},
1917 "Assuming the character is not a lowercase letter")
1918 // The locale-specific range.
1919 .Case({ArgumentCondition(0U, WithinRange
, {{128, UCharRangeMax
}})},
1921 // Is not an unsigned char.
1922 .Case({ArgumentCondition(0U, OutOfRange
, Range(0, UCharRangeMax
)),
1923 ReturnValueCondition(WithinRange
, SingleValue(0))},
1925 addToFunctionSummaryMap(
1926 "isprint", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1927 Summary(EvalCallAsPure
)
1928 .Case({ArgumentCondition(0U, WithinRange
, Range(32, 126)),
1929 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1930 ErrnoIrrelevant
, "Assuming the character is printable")
1931 .Case({ArgumentCondition(0U, OutOfRange
, Range(32, 126)),
1932 ReturnValueCondition(WithinRange
, SingleValue(0))},
1933 ErrnoIrrelevant
, "Assuming the character is non-printable"));
1934 addToFunctionSummaryMap(
1935 "ispunct", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1936 Summary(EvalCallAsPure
)
1937 .Case({ArgumentCondition(
1939 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1940 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1941 ErrnoIrrelevant
, "Assuming the character is a punctuation mark")
1942 .Case({ArgumentCondition(
1944 {{'!', '/'}, {':', '@'}, {'[', '`'}, {'{', '~'}}),
1945 ReturnValueCondition(WithinRange
, SingleValue(0))},
1947 "Assuming the character is not a punctuation mark"));
1948 addToFunctionSummaryMap(
1949 "isspace", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1950 Summary(EvalCallAsPure
)
1951 // Space, '\f', '\n', '\r', '\t', '\v'.
1952 .Case({ArgumentCondition(0U, WithinRange
, {{9, 13}, {' ', ' '}}),
1953 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1955 "Assuming the character is a whitespace character")
1956 // The locale-specific range.
1957 .Case({ArgumentCondition(0U, WithinRange
, {{128, UCharRangeMax
}})},
1959 .Case({ArgumentCondition(0U, OutOfRange
,
1960 {{9, 13}, {' ', ' '}, {128, UCharRangeMax
}}),
1961 ReturnValueCondition(WithinRange
, SingleValue(0))},
1963 "Assuming the character is not a whitespace character"));
1964 addToFunctionSummaryMap(
1965 "isupper", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1966 Summary(EvalCallAsPure
)
1967 // Is certainly uppercase.
1968 .Case({ArgumentCondition(0U, WithinRange
, Range('A', 'Z')),
1969 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1971 "Assuming the character is an uppercase letter")
1972 // The locale-specific range.
1973 .Case({ArgumentCondition(0U, WithinRange
, {{128, UCharRangeMax
}})},
1976 .Case({ArgumentCondition(0U, OutOfRange
,
1977 {{'A', 'Z'}, {128, UCharRangeMax
}}),
1978 ReturnValueCondition(WithinRange
, SingleValue(0))},
1980 "Assuming the character is not an uppercase letter"));
1981 addToFunctionSummaryMap(
1982 "isxdigit", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1983 Summary(EvalCallAsPure
)
1984 .Case({ArgumentCondition(0U, WithinRange
,
1985 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1986 ReturnValueCondition(OutOfRange
, SingleValue(0))},
1988 "Assuming the character is a hexadecimal digit")
1989 .Case({ArgumentCondition(0U, OutOfRange
,
1990 {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
1991 ReturnValueCondition(WithinRange
, SingleValue(0))},
1993 "Assuming the character is not a hexadecimal digit"));
1994 addToFunctionSummaryMap(
1995 "toupper", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
1996 Summary(EvalCallAsPure
)
1997 .ArgConstraint(ArgumentCondition(0U, WithinRange
,
1998 {{EOFv
, EOFv
}, {0, UCharRangeMax
}},
1999 "an unsigned char value or EOF")));
2000 addToFunctionSummaryMap(
2001 "tolower", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2002 Summary(EvalCallAsPure
)
2003 .ArgConstraint(ArgumentCondition(0U, WithinRange
,
2004 {{EOFv
, EOFv
}, {0, UCharRangeMax
}},
2005 "an unsigned char value or EOF")));
2006 addToFunctionSummaryMap(
2007 "toascii", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2008 Summary(EvalCallAsPure
)
2009 .ArgConstraint(ArgumentCondition(0U, WithinRange
,
2010 {{EOFv
, EOFv
}, {0, UCharRangeMax
}},
2011 "an unsigned char value or EOF")));
2013 // The getc() family of functions that returns either a char or an EOF.
2014 addToFunctionSummaryMap(
2015 {"getc", "fgetc"}, Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2017 .Case({ReturnValueCondition(WithinRange
,
2018 {{EOFv
, EOFv
}, {0, UCharRangeMax
}})},
2020 addToFunctionSummaryMap(
2021 "getchar", Signature(ArgTypes
{}, RetType
{IntTy
}),
2023 .Case({ReturnValueCondition(WithinRange
,
2024 {{EOFv
, EOFv
}, {0, UCharRangeMax
}})},
2027 // read()-like functions that never return more than buffer size.
2030 .Case({ArgumentCondition(1U, WithinRange
, Range(1, SizeMax
)),
2031 ArgumentCondition(2U, WithinRange
, Range(1, SizeMax
)),
2032 ReturnValueCondition(BO_LT
, ArgNo(2)),
2033 ReturnValueCondition(WithinRange
, Range(0, SizeMax
))},
2034 ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2035 .Case({ArgumentCondition(1U, WithinRange
, Range(1, SizeMax
)),
2036 ReturnValueCondition(BO_EQ
, ArgNo(2)),
2037 ReturnValueCondition(WithinRange
, Range(0, SizeMax
))},
2038 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2039 .Case({ArgumentCondition(1U, WithinRange
, SingleValue(0)),
2040 ReturnValueCondition(WithinRange
, SingleValue(0))},
2041 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2042 .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))
2043 .ArgConstraint(NotNull(ArgNo(3)))
2044 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
2045 /*BufSizeMultiplier=*/ArgNo(2)));
2047 // size_t fread(void *restrict ptr, size_t size, size_t nitems,
2048 // FILE *restrict stream);
2049 addToFunctionSummaryMap(
2051 Signature(ArgTypes
{VoidPtrRestrictTy
, SizeTy
, SizeTy
, FilePtrRestrictTy
},
2054 // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems,
2055 // FILE *restrict stream);
2056 addToFunctionSummaryMap("fwrite",
2057 Signature(ArgTypes
{ConstVoidPtrRestrictTy
, SizeTy
,
2058 SizeTy
, FilePtrRestrictTy
},
2062 std::optional
<QualType
> Ssize_tTy
= lookupTy("ssize_t");
2063 std::optional
<RangeInt
> Ssize_tMax
= getMaxValue(Ssize_tTy
);
2067 .Case({ReturnValueCondition(LessThanOrEq
, ArgNo(2)),
2068 ReturnValueCondition(WithinRange
, Range(-1, Ssize_tMax
))},
2071 // FIXME these are actually defined by POSIX and not by the C standard, we
2072 // should handle them together with the rest of the POSIX functions.
2073 // ssize_t read(int fildes, void *buf, size_t nbyte);
2074 addToFunctionSummaryMap(
2075 "read", Signature(ArgTypes
{IntTy
, VoidPtrTy
, SizeTy
}, RetType
{Ssize_tTy
}),
2077 // ssize_t write(int fildes, const void *buf, size_t nbyte);
2078 addToFunctionSummaryMap(
2080 Signature(ArgTypes
{IntTy
, ConstVoidPtrTy
, SizeTy
}, RetType
{Ssize_tTy
}),
2083 auto GetLineSummary
=
2085 .Case({ReturnValueCondition(WithinRange
,
2086 Range({-1, -1}, {1, Ssize_tMax
}))},
2089 QualType CharPtrPtrRestrictTy
= getRestrictTy(getPointerTy(CharPtrTy
));
2091 // getline()-like functions either fail or read at least the delimiter.
2092 // FIXME these are actually defined by POSIX and not by the C standard, we
2093 // should handle them together with the rest of the POSIX functions.
2094 // ssize_t getline(char **restrict lineptr, size_t *restrict n,
2095 // FILE *restrict stream);
2096 addToFunctionSummaryMap(
2099 ArgTypes
{CharPtrPtrRestrictTy
, SizePtrRestrictTy
, FilePtrRestrictTy
},
2100 RetType
{Ssize_tTy
}),
2102 // ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
2103 // int delimiter, FILE *restrict stream);
2104 addToFunctionSummaryMap(
2106 Signature(ArgTypes
{CharPtrPtrRestrictTy
, SizePtrRestrictTy
, IntTy
,
2108 RetType
{Ssize_tTy
}),
2112 Summary GetenvSummary
=
2114 .ArgConstraint(NotNull(ArgNo(0)))
2115 .Case({NotNull(Ret
)}, ErrnoIrrelevant
,
2116 "Assuming the environment variable exists");
2117 // In untrusted environments the envvar might not exist.
2118 if (!ShouldAssumeControlledEnvironment
)
2119 GetenvSummary
.Case({NotNull(Ret
)->negate()}, ErrnoIrrelevant
,
2120 "Assuming the environment variable does not exist");
2122 // char *getenv(const char *name);
2123 addToFunctionSummaryMap(
2124 "getenv", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{CharPtrTy
}),
2125 std::move(GetenvSummary
));
2129 const auto ReturnsZeroOrMinusOne
=
2130 ConstraintSet
{ReturnValueCondition(WithinRange
, Range(-1, 0))};
2131 const auto ReturnsZero
=
2132 ConstraintSet
{ReturnValueCondition(WithinRange
, SingleValue(0))};
2133 const auto ReturnsMinusOne
=
2134 ConstraintSet
{ReturnValueCondition(WithinRange
, SingleValue(-1))};
2135 const auto ReturnsNonnegative
=
2136 ConstraintSet
{ReturnValueCondition(WithinRange
, Range(0, IntMax
))};
2137 const auto ReturnsNonZero
=
2138 ConstraintSet
{ReturnValueCondition(OutOfRange
, SingleValue(0))};
2139 const auto ReturnsFileDescriptor
=
2140 ConstraintSet
{ReturnValueCondition(WithinRange
, Range(-1, IntMax
))};
2141 const auto &ReturnsValidFileDescriptor
= ReturnsNonnegative
;
2143 auto ValidFileDescriptorOrAtFdcwd
= [&](ArgNo ArgN
) {
2144 return std::make_shared
<RangeConstraint
>(
2145 ArgN
, WithinRange
, Range({AT_FDCWDv
, AT_FDCWDv
}, {0, IntMax
}),
2146 "a valid file descriptor or AT_FDCWD");
2149 // FILE *fopen(const char *restrict pathname, const char *restrict mode);
2150 addToFunctionSummaryMap(
2152 Signature(ArgTypes
{ConstCharPtrRestrictTy
, ConstCharPtrRestrictTy
},
2153 RetType
{FilePtrTy
}),
2155 .Case({NotNull(Ret
)}, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2156 .Case({IsNull(Ret
)}, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2157 .ArgConstraint(NotNull(ArgNo(0)))
2158 .ArgConstraint(NotNull(ArgNo(1))));
2160 // FILE *tmpfile(void);
2161 addToFunctionSummaryMap(
2162 "tmpfile", Signature(ArgTypes
{}, RetType
{FilePtrTy
}),
2164 .Case({NotNull(Ret
)}, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2165 .Case({IsNull(Ret
)}, ErrnoNEZeroIrrelevant
, GenericFailureMsg
));
2167 // FILE *freopen(const char *restrict pathname, const char *restrict mode,
2168 // FILE *restrict stream);
2169 addToFunctionSummaryMap(
2171 Signature(ArgTypes
{ConstCharPtrRestrictTy
, ConstCharPtrRestrictTy
,
2173 RetType
{FilePtrTy
}),
2175 .Case({ReturnValueCondition(BO_EQ
, ArgNo(2))},
2176 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2177 .Case({IsNull(Ret
)}, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2178 .ArgConstraint(NotNull(ArgNo(1)))
2179 .ArgConstraint(NotNull(ArgNo(2))));
2181 // int fclose(FILE *stream);
2182 addToFunctionSummaryMap(
2183 "fclose", Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2185 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2186 .Case({ReturnValueCondition(WithinRange
, SingleValue(EOFv
))},
2187 ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2188 .ArgConstraint(NotNull(ArgNo(0))));
2190 // int fseek(FILE *stream, long offset, int whence);
2191 // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
2192 // these for condition of arg 2.
2193 // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
2194 addToFunctionSummaryMap(
2195 "fseek", Signature(ArgTypes
{FilePtrTy
, LongTy
, IntTy
}, RetType
{IntTy
}),
2197 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2198 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2199 .ArgConstraint(NotNull(ArgNo(0)))
2200 .ArgConstraint(ArgumentCondition(2, WithinRange
, {{0, 2}})));
2202 // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
2203 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2204 // "The fgetpos() function shall not change the setting of errno if
2206 addToFunctionSummaryMap(
2208 Signature(ArgTypes
{FilePtrRestrictTy
, FPosTPtrRestrictTy
},
2211 .Case(ReturnsZero
, ErrnoUnchanged
, GenericSuccessMsg
)
2212 .Case(ReturnsNonZero
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2213 .ArgConstraint(NotNull(ArgNo(0)))
2214 .ArgConstraint(NotNull(ArgNo(1))));
2216 // int fsetpos(FILE *stream, const fpos_t *pos);
2217 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2218 // "The fsetpos() function shall not change the setting of errno if
2220 addToFunctionSummaryMap(
2222 Signature(ArgTypes
{FilePtrTy
, ConstFPosTPtrTy
}, RetType
{IntTy
}),
2224 .Case(ReturnsZero
, ErrnoUnchanged
, GenericSuccessMsg
)
2225 .Case(ReturnsNonZero
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2226 .ArgConstraint(NotNull(ArgNo(0)))
2227 .ArgConstraint(NotNull(ArgNo(1))));
2229 // long ftell(FILE *stream);
2230 // From 'The Open Group Base Specifications Issue 7, 2018 edition':
2231 // "The ftell() function shall not change the setting of errno if
2233 addToFunctionSummaryMap(
2234 "ftell", Signature(ArgTypes
{FilePtrTy
}, RetType
{LongTy
}),
2236 .Case({ReturnValueCondition(WithinRange
, Range(1, LongMax
))},
2237 ErrnoUnchanged
, GenericSuccessMsg
)
2238 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2239 .ArgConstraint(NotNull(ArgNo(0))));
2241 // int fileno(FILE *stream);
2242 addToFunctionSummaryMap(
2243 "fileno", Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2245 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2247 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2248 .ArgConstraint(NotNull(ArgNo(0))));
2250 // void rewind(FILE *stream);
2251 // This function indicates error only by setting of 'errno'.
2252 addToFunctionSummaryMap("rewind",
2253 Signature(ArgTypes
{FilePtrTy
}, RetType
{VoidTy
}),
2255 .Case({}, ErrnoMustBeChecked
)
2256 .ArgConstraint(NotNull(ArgNo(0))));
2258 // void clearerr(FILE *stream);
2259 addToFunctionSummaryMap(
2260 "clearerr", Signature(ArgTypes
{FilePtrTy
}, RetType
{VoidTy
}),
2261 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2263 // int feof(FILE *stream);
2264 addToFunctionSummaryMap(
2265 "feof", Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2266 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2268 // int ferror(FILE *stream);
2269 addToFunctionSummaryMap(
2270 "ferror", Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2271 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2273 // long a64l(const char *str64);
2274 addToFunctionSummaryMap(
2275 "a64l", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{LongTy
}),
2276 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2278 // char *l64a(long value);
2279 addToFunctionSummaryMap("l64a",
2280 Signature(ArgTypes
{LongTy
}, RetType
{CharPtrTy
}),
2282 .ArgConstraint(ArgumentCondition(
2283 0, WithinRange
, Range(0, LongMax
))));
2285 // int open(const char *path, int oflag, ...);
2286 addToFunctionSummaryMap(
2287 "open", Signature(ArgTypes
{ConstCharPtrTy
, IntTy
}, RetType
{IntTy
}),
2289 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2291 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2292 .ArgConstraint(NotNull(ArgNo(0))));
2294 // int openat(int fd, const char *path, int oflag, ...);
2295 addToFunctionSummaryMap(
2297 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, IntTy
}, RetType
{IntTy
}),
2299 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2301 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2302 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2303 .ArgConstraint(NotNull(ArgNo(1))));
2305 // int access(const char *pathname, int amode);
2306 addToFunctionSummaryMap(
2307 "access", Signature(ArgTypes
{ConstCharPtrTy
, IntTy
}, RetType
{IntTy
}),
2309 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2310 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2311 .ArgConstraint(NotNull(ArgNo(0))));
2313 // int faccessat(int dirfd, const char *pathname, int mode, int flags);
2314 addToFunctionSummaryMap(
2316 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, IntTy
, IntTy
},
2319 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2320 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2321 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2322 .ArgConstraint(NotNull(ArgNo(1))));
2324 // int dup(int fildes);
2325 addToFunctionSummaryMap(
2326 "dup", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2328 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2330 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2332 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2334 // int dup2(int fildes1, int filedes2);
2335 addToFunctionSummaryMap(
2336 "dup2", Signature(ArgTypes
{IntTy
, IntTy
}, RetType
{IntTy
}),
2338 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2340 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2341 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
2343 ArgumentCondition(1, WithinRange
, Range(0, IntMax
))));
2345 // int fdatasync(int fildes);
2346 addToFunctionSummaryMap(
2347 "fdatasync", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2349 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2350 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2352 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2354 // int fnmatch(const char *pattern, const char *string, int flags);
2355 addToFunctionSummaryMap(
2357 Signature(ArgTypes
{ConstCharPtrTy
, ConstCharPtrTy
, IntTy
},
2360 .ArgConstraint(NotNull(ArgNo(0)))
2361 .ArgConstraint(NotNull(ArgNo(1))));
2363 // int fsync(int fildes);
2364 addToFunctionSummaryMap(
2365 "fsync", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2367 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2368 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2370 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2372 std::optional
<QualType
> Off_tTy
= lookupTy("off_t");
2374 // int truncate(const char *path, off_t length);
2375 addToFunctionSummaryMap(
2377 Signature(ArgTypes
{ConstCharPtrTy
, Off_tTy
}, RetType
{IntTy
}),
2379 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2380 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2381 .ArgConstraint(NotNull(ArgNo(0))));
2383 // int symlink(const char *oldpath, const char *newpath);
2384 addToFunctionSummaryMap(
2386 Signature(ArgTypes
{ConstCharPtrTy
, ConstCharPtrTy
}, RetType
{IntTy
}),
2388 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2389 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2390 .ArgConstraint(NotNull(ArgNo(0)))
2391 .ArgConstraint(NotNull(ArgNo(1))));
2393 // int symlinkat(const char *oldpath, int newdirfd, const char *newpath);
2394 addToFunctionSummaryMap(
2396 Signature(ArgTypes
{ConstCharPtrTy
, IntTy
, ConstCharPtrTy
},
2399 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2400 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2401 .ArgConstraint(NotNull(ArgNo(0)))
2402 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(1)))
2403 .ArgConstraint(NotNull(ArgNo(2))));
2405 // int lockf(int fd, int cmd, off_t len);
2406 addToFunctionSummaryMap(
2407 "lockf", Signature(ArgTypes
{IntTy
, IntTy
, Off_tTy
}, RetType
{IntTy
}),
2409 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2410 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2412 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2414 std::optional
<QualType
> Mode_tTy
= lookupTy("mode_t");
2416 // int creat(const char *pathname, mode_t mode);
2417 addToFunctionSummaryMap(
2418 "creat", Signature(ArgTypes
{ConstCharPtrTy
, Mode_tTy
}, RetType
{IntTy
}),
2420 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2422 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2423 .ArgConstraint(NotNull(ArgNo(0))));
2425 // unsigned int sleep(unsigned int seconds);
2426 addToFunctionSummaryMap(
2427 "sleep", Signature(ArgTypes
{UnsignedIntTy
}, RetType
{UnsignedIntTy
}),
2430 ArgumentCondition(0, WithinRange
, Range(0, UnsignedIntMax
))));
2432 std::optional
<QualType
> DirTy
= lookupTy("DIR");
2433 std::optional
<QualType
> DirPtrTy
= getPointerTy(DirTy
);
2435 // int dirfd(DIR *dirp);
2436 addToFunctionSummaryMap(
2437 "dirfd", Signature(ArgTypes
{DirPtrTy
}, RetType
{IntTy
}),
2439 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2441 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2442 .ArgConstraint(NotNull(ArgNo(0))));
2444 // unsigned int alarm(unsigned int seconds);
2445 addToFunctionSummaryMap(
2446 "alarm", Signature(ArgTypes
{UnsignedIntTy
}, RetType
{UnsignedIntTy
}),
2449 ArgumentCondition(0, WithinRange
, Range(0, UnsignedIntMax
))));
2451 // int closedir(DIR *dir);
2452 addToFunctionSummaryMap(
2453 "closedir", Signature(ArgTypes
{DirPtrTy
}, RetType
{IntTy
}),
2455 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2456 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2457 .ArgConstraint(NotNull(ArgNo(0))));
2459 // char *strdup(const char *s);
2460 addToFunctionSummaryMap(
2461 "strdup", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{CharPtrTy
}),
2462 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2464 // char *strndup(const char *s, size_t n);
2465 addToFunctionSummaryMap(
2467 Signature(ArgTypes
{ConstCharPtrTy
, SizeTy
}, RetType
{CharPtrTy
}),
2469 .ArgConstraint(NotNull(ArgNo(0)))
2471 ArgumentCondition(1, WithinRange
, Range(0, SizeMax
))));
2473 // wchar_t *wcsdup(const wchar_t *s);
2474 addToFunctionSummaryMap(
2475 "wcsdup", Signature(ArgTypes
{ConstWchar_tPtrTy
}, RetType
{Wchar_tPtrTy
}),
2476 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2478 // int mkstemp(char *template);
2479 addToFunctionSummaryMap(
2480 "mkstemp", Signature(ArgTypes
{CharPtrTy
}, RetType
{IntTy
}),
2482 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2484 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2485 .ArgConstraint(NotNull(ArgNo(0))));
2487 // char *mkdtemp(char *template);
2488 // FIXME: Improve for errno modeling.
2489 addToFunctionSummaryMap(
2490 "mkdtemp", Signature(ArgTypes
{CharPtrTy
}, RetType
{CharPtrTy
}),
2491 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2493 // char *getcwd(char *buf, size_t size);
2494 // FIXME: Improve for errno modeling.
2495 addToFunctionSummaryMap(
2496 "getcwd", Signature(ArgTypes
{CharPtrTy
, SizeTy
}, RetType
{CharPtrTy
}),
2499 ArgumentCondition(1, WithinRange
, Range(0, SizeMax
))));
2501 // int mkdir(const char *pathname, mode_t mode);
2502 addToFunctionSummaryMap(
2503 "mkdir", Signature(ArgTypes
{ConstCharPtrTy
, Mode_tTy
}, RetType
{IntTy
}),
2505 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2506 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2507 .ArgConstraint(NotNull(ArgNo(0))));
2509 // int mkdirat(int dirfd, const char *pathname, mode_t mode);
2510 addToFunctionSummaryMap(
2512 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, Mode_tTy
}, RetType
{IntTy
}),
2514 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2515 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2516 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2517 .ArgConstraint(NotNull(ArgNo(1))));
2519 std::optional
<QualType
> Dev_tTy
= lookupTy("dev_t");
2521 // int mknod(const char *pathname, mode_t mode, dev_t dev);
2522 addToFunctionSummaryMap(
2524 Signature(ArgTypes
{ConstCharPtrTy
, Mode_tTy
, Dev_tTy
}, RetType
{IntTy
}),
2526 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2527 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2528 .ArgConstraint(NotNull(ArgNo(0))));
2530 // int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
2531 addToFunctionSummaryMap(
2533 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, Mode_tTy
, Dev_tTy
},
2536 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2537 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2538 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2539 .ArgConstraint(NotNull(ArgNo(1))));
2541 // int chmod(const char *path, mode_t mode);
2542 addToFunctionSummaryMap(
2543 "chmod", Signature(ArgTypes
{ConstCharPtrTy
, Mode_tTy
}, RetType
{IntTy
}),
2545 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2546 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2547 .ArgConstraint(NotNull(ArgNo(0))));
2549 // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags);
2550 addToFunctionSummaryMap(
2552 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, Mode_tTy
, IntTy
},
2555 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2556 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2557 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2558 .ArgConstraint(NotNull(ArgNo(1))));
2560 // int fchmod(int fildes, mode_t mode);
2561 addToFunctionSummaryMap(
2562 "fchmod", Signature(ArgTypes
{IntTy
, Mode_tTy
}, RetType
{IntTy
}),
2564 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2565 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2567 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2569 std::optional
<QualType
> Uid_tTy
= lookupTy("uid_t");
2570 std::optional
<QualType
> Gid_tTy
= lookupTy("gid_t");
2572 // int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
2574 addToFunctionSummaryMap(
2576 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, Uid_tTy
, Gid_tTy
, IntTy
},
2579 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2580 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2581 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2582 .ArgConstraint(NotNull(ArgNo(1))));
2584 // int chown(const char *path, uid_t owner, gid_t group);
2585 addToFunctionSummaryMap(
2587 Signature(ArgTypes
{ConstCharPtrTy
, Uid_tTy
, Gid_tTy
}, RetType
{IntTy
}),
2589 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2590 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2591 .ArgConstraint(NotNull(ArgNo(0))));
2593 // int lchown(const char *path, uid_t owner, gid_t group);
2594 addToFunctionSummaryMap(
2596 Signature(ArgTypes
{ConstCharPtrTy
, Uid_tTy
, Gid_tTy
}, RetType
{IntTy
}),
2598 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2599 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2600 .ArgConstraint(NotNull(ArgNo(0))));
2602 // int fchown(int fildes, uid_t owner, gid_t group);
2603 addToFunctionSummaryMap(
2604 "fchown", Signature(ArgTypes
{IntTy
, Uid_tTy
, Gid_tTy
}, RetType
{IntTy
}),
2606 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2607 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2609 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2611 // int rmdir(const char *pathname);
2612 addToFunctionSummaryMap(
2613 "rmdir", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{IntTy
}),
2615 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2616 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2617 .ArgConstraint(NotNull(ArgNo(0))));
2619 // int chdir(const char *path);
2620 addToFunctionSummaryMap(
2621 "chdir", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{IntTy
}),
2623 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2624 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2625 .ArgConstraint(NotNull(ArgNo(0))));
2627 // int link(const char *oldpath, const char *newpath);
2628 addToFunctionSummaryMap(
2630 Signature(ArgTypes
{ConstCharPtrTy
, ConstCharPtrTy
}, RetType
{IntTy
}),
2632 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2633 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2634 .ArgConstraint(NotNull(ArgNo(0)))
2635 .ArgConstraint(NotNull(ArgNo(1))));
2637 // int linkat(int fd1, const char *path1, int fd2, const char *path2,
2639 addToFunctionSummaryMap(
2641 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, IntTy
, ConstCharPtrTy
, IntTy
},
2644 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2645 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2646 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2647 .ArgConstraint(NotNull(ArgNo(1)))
2648 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2649 .ArgConstraint(NotNull(ArgNo(3))));
2651 // int unlink(const char *pathname);
2652 addToFunctionSummaryMap(
2653 "unlink", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{IntTy
}),
2655 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2656 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2657 .ArgConstraint(NotNull(ArgNo(0))));
2659 // int unlinkat(int fd, const char *path, int flag);
2660 addToFunctionSummaryMap(
2662 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, IntTy
}, RetType
{IntTy
}),
2664 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2665 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2666 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2667 .ArgConstraint(NotNull(ArgNo(1))));
2669 std::optional
<QualType
> StructStatTy
= lookupTy("stat");
2670 std::optional
<QualType
> StructStatPtrTy
= getPointerTy(StructStatTy
);
2671 std::optional
<QualType
> StructStatPtrRestrictTy
=
2672 getRestrictTy(StructStatPtrTy
);
2674 // int fstat(int fd, struct stat *statbuf);
2675 addToFunctionSummaryMap(
2676 "fstat", Signature(ArgTypes
{IntTy
, StructStatPtrTy
}, RetType
{IntTy
}),
2678 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2679 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2680 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
2681 .ArgConstraint(NotNull(ArgNo(1))));
2683 // int stat(const char *restrict path, struct stat *restrict buf);
2684 addToFunctionSummaryMap(
2686 Signature(ArgTypes
{ConstCharPtrRestrictTy
, StructStatPtrRestrictTy
},
2689 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2690 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2691 .ArgConstraint(NotNull(ArgNo(0)))
2692 .ArgConstraint(NotNull(ArgNo(1))));
2694 // int lstat(const char *restrict path, struct stat *restrict buf);
2695 addToFunctionSummaryMap(
2697 Signature(ArgTypes
{ConstCharPtrRestrictTy
, StructStatPtrRestrictTy
},
2700 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2701 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2702 .ArgConstraint(NotNull(ArgNo(0)))
2703 .ArgConstraint(NotNull(ArgNo(1))));
2705 // int fstatat(int fd, const char *restrict path,
2706 // struct stat *restrict buf, int flag);
2707 addToFunctionSummaryMap(
2709 Signature(ArgTypes
{IntTy
, ConstCharPtrRestrictTy
,
2710 StructStatPtrRestrictTy
, IntTy
},
2713 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2714 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2715 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2716 .ArgConstraint(NotNull(ArgNo(1)))
2717 .ArgConstraint(NotNull(ArgNo(2))));
2719 // DIR *opendir(const char *name);
2720 // FIXME: Improve for errno modeling.
2721 addToFunctionSummaryMap(
2722 "opendir", Signature(ArgTypes
{ConstCharPtrTy
}, RetType
{DirPtrTy
}),
2723 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2725 // DIR *fdopendir(int fd);
2726 // FIXME: Improve for errno modeling.
2727 addToFunctionSummaryMap("fdopendir",
2728 Signature(ArgTypes
{IntTy
}, RetType
{DirPtrTy
}),
2730 .ArgConstraint(ArgumentCondition(
2731 0, WithinRange
, Range(0, IntMax
))));
2733 // int isatty(int fildes);
2734 addToFunctionSummaryMap(
2735 "isatty", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2737 .Case({ReturnValueCondition(WithinRange
, Range(0, 1))},
2740 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2742 // FILE *popen(const char *command, const char *type);
2743 // FIXME: Improve for errno modeling.
2744 addToFunctionSummaryMap(
2746 Signature(ArgTypes
{ConstCharPtrTy
, ConstCharPtrTy
}, RetType
{FilePtrTy
}),
2748 .ArgConstraint(NotNull(ArgNo(0)))
2749 .ArgConstraint(NotNull(ArgNo(1))));
2751 // int pclose(FILE *stream);
2752 // FIXME: Improve for errno modeling.
2753 addToFunctionSummaryMap(
2754 "pclose", Signature(ArgTypes
{FilePtrTy
}, RetType
{IntTy
}),
2755 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2757 // int close(int fildes);
2758 addToFunctionSummaryMap(
2759 "close", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
2761 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2762 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2764 ArgumentCondition(0, WithinRange
, Range(-1, IntMax
))));
2766 // long fpathconf(int fildes, int name);
2767 addToFunctionSummaryMap("fpathconf",
2768 Signature(ArgTypes
{IntTy
, IntTy
}, RetType
{LongTy
}),
2770 .ArgConstraint(ArgumentCondition(
2771 0, WithinRange
, Range(0, IntMax
))));
2773 // long pathconf(const char *path, int name);
2774 addToFunctionSummaryMap(
2775 "pathconf", Signature(ArgTypes
{ConstCharPtrTy
, IntTy
}, RetType
{LongTy
}),
2776 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2778 // FILE *fdopen(int fd, const char *mode);
2779 // FIXME: Improve for errno modeling.
2780 addToFunctionSummaryMap(
2782 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
}, RetType
{FilePtrTy
}),
2784 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
2785 .ArgConstraint(NotNull(ArgNo(1))));
2787 // void rewinddir(DIR *dir);
2788 addToFunctionSummaryMap(
2789 "rewinddir", Signature(ArgTypes
{DirPtrTy
}, RetType
{VoidTy
}),
2790 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2792 // void seekdir(DIR *dirp, long loc);
2793 addToFunctionSummaryMap(
2794 "seekdir", Signature(ArgTypes
{DirPtrTy
, LongTy
}, RetType
{VoidTy
}),
2795 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2797 // int rand_r(unsigned int *seedp);
2798 addToFunctionSummaryMap(
2799 "rand_r", Signature(ArgTypes
{UnsignedIntPtrTy
}, RetType
{IntTy
}),
2800 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2802 // int fseeko(FILE *stream, off_t offset, int whence);
2803 addToFunctionSummaryMap(
2805 Signature(ArgTypes
{FilePtrTy
, Off_tTy
, IntTy
}, RetType
{IntTy
}),
2807 .Case(ReturnsZeroOrMinusOne
, ErrnoIrrelevant
)
2808 .ArgConstraint(NotNull(ArgNo(0))));
2810 // off_t ftello(FILE *stream);
2811 addToFunctionSummaryMap(
2812 "ftello", Signature(ArgTypes
{FilePtrTy
}, RetType
{Off_tTy
}),
2813 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2815 // void *mmap(void *addr, size_t length, int prot, int flags, int fd,
2817 // FIXME: Improve for errno modeling.
2818 addToFunctionSummaryMap(
2820 Signature(ArgTypes
{VoidPtrTy
, SizeTy
, IntTy
, IntTy
, IntTy
, Off_tTy
},
2821 RetType
{VoidPtrTy
}),
2823 .ArgConstraint(ArgumentCondition(1, WithinRange
, Range(1, SizeMax
)))
2825 ArgumentCondition(4, WithinRange
, Range(-1, IntMax
))));
2827 std::optional
<QualType
> Off64_tTy
= lookupTy("off64_t");
2828 // void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
2830 // FIXME: Improve for errno modeling.
2831 addToFunctionSummaryMap(
2833 Signature(ArgTypes
{VoidPtrTy
, SizeTy
, IntTy
, IntTy
, IntTy
, Off64_tTy
},
2834 RetType
{VoidPtrTy
}),
2836 .ArgConstraint(ArgumentCondition(1, WithinRange
, Range(1, SizeMax
)))
2838 ArgumentCondition(4, WithinRange
, Range(-1, IntMax
))));
2840 // int pipe(int fildes[2]);
2841 addToFunctionSummaryMap(
2842 "pipe", Signature(ArgTypes
{IntPtrTy
}, RetType
{IntTy
}),
2844 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2845 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2846 .ArgConstraint(NotNull(ArgNo(0))));
2848 // off_t lseek(int fildes, off_t offset, int whence);
2849 // In the first case we can not tell for sure if it failed or not.
2850 // A return value different from of the expected offset (that is unknown
2851 // here) may indicate failure. For this reason we do not enforce the errno
2852 // check (can cause false positive).
2853 addToFunctionSummaryMap(
2854 "lseek", Signature(ArgTypes
{IntTy
, Off_tTy
, IntTy
}, RetType
{Off_tTy
}),
2856 .Case(ReturnsNonnegative
, ErrnoIrrelevant
)
2857 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2859 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
2861 // ssize_t readlink(const char *restrict path, char *restrict buf,
2863 addToFunctionSummaryMap(
2865 Signature(ArgTypes
{ConstCharPtrRestrictTy
, CharPtrRestrictTy
, SizeTy
},
2866 RetType
{Ssize_tTy
}),
2868 .Case({ReturnValueCondition(LessThanOrEq
, ArgNo(2)),
2869 ReturnValueCondition(WithinRange
, Range(0, Ssize_tMax
))},
2870 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2871 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2872 .ArgConstraint(NotNull(ArgNo(0)))
2873 .ArgConstraint(NotNull(ArgNo(1)))
2874 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
2875 /*BufSize=*/ArgNo(2)))
2877 ArgumentCondition(2, WithinRange
, Range(0, SizeMax
))));
2879 // ssize_t readlinkat(int fd, const char *restrict path,
2880 // char *restrict buf, size_t bufsize);
2881 addToFunctionSummaryMap(
2884 ArgTypes
{IntTy
, ConstCharPtrRestrictTy
, CharPtrRestrictTy
, SizeTy
},
2885 RetType
{Ssize_tTy
}),
2887 .Case({ReturnValueCondition(LessThanOrEq
, ArgNo(3)),
2888 ReturnValueCondition(WithinRange
, Range(0, Ssize_tMax
))},
2889 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2890 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2891 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2892 .ArgConstraint(NotNull(ArgNo(1)))
2893 .ArgConstraint(NotNull(ArgNo(2)))
2894 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(2),
2895 /*BufSize=*/ArgNo(3)))
2897 ArgumentCondition(3, WithinRange
, Range(0, SizeMax
))));
2899 // int renameat(int olddirfd, const char *oldpath, int newdirfd, const char
2901 addToFunctionSummaryMap(
2903 Signature(ArgTypes
{IntTy
, ConstCharPtrTy
, IntTy
, ConstCharPtrTy
},
2906 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
2907 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2908 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
2909 .ArgConstraint(NotNull(ArgNo(1)))
2910 .ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(2)))
2911 .ArgConstraint(NotNull(ArgNo(3))));
2913 // char *realpath(const char *restrict file_name,
2914 // char *restrict resolved_name);
2915 // FIXME: Improve for errno modeling.
2916 addToFunctionSummaryMap(
2918 Signature(ArgTypes
{ConstCharPtrRestrictTy
, CharPtrRestrictTy
},
2919 RetType
{CharPtrTy
}),
2920 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
2922 QualType CharPtrConstPtr
= getPointerTy(getConstTy(CharPtrTy
));
2924 // int execv(const char *path, char *const argv[]);
2925 addToFunctionSummaryMap(
2927 Signature(ArgTypes
{ConstCharPtrTy
, CharPtrConstPtr
}, RetType
{IntTy
}),
2929 .Case({ReturnValueCondition(WithinRange
, SingleValue(-1))},
2931 .ArgConstraint(NotNull(ArgNo(0))));
2933 // int execvp(const char *file, char *const argv[]);
2934 addToFunctionSummaryMap(
2936 Signature(ArgTypes
{ConstCharPtrTy
, CharPtrConstPtr
}, RetType
{IntTy
}),
2938 .Case({ReturnValueCondition(WithinRange
, SingleValue(-1))},
2940 .ArgConstraint(NotNull(ArgNo(0))));
2942 // int getopt(int argc, char * const argv[], const char *optstring);
2943 addToFunctionSummaryMap(
2945 Signature(ArgTypes
{IntTy
, CharPtrConstPtr
, ConstCharPtrTy
},
2948 .Case({ReturnValueCondition(WithinRange
, Range(-1, UCharRangeMax
))},
2950 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
2951 .ArgConstraint(NotNull(ArgNo(1)))
2952 .ArgConstraint(NotNull(ArgNo(2))));
2954 std::optional
<QualType
> StructSockaddrTy
= lookupTy("sockaddr");
2955 std::optional
<QualType
> StructSockaddrPtrTy
=
2956 getPointerTy(StructSockaddrTy
);
2957 std::optional
<QualType
> ConstStructSockaddrPtrTy
=
2958 getPointerTy(getConstTy(StructSockaddrTy
));
2959 std::optional
<QualType
> StructSockaddrPtrRestrictTy
=
2960 getRestrictTy(StructSockaddrPtrTy
);
2961 std::optional
<QualType
> ConstStructSockaddrPtrRestrictTy
=
2962 getRestrictTy(ConstStructSockaddrPtrTy
);
2963 std::optional
<QualType
> Socklen_tTy
= lookupTy("socklen_t");
2964 std::optional
<QualType
> Socklen_tPtrTy
= getPointerTy(Socklen_tTy
);
2965 std::optional
<QualType
> Socklen_tPtrRestrictTy
=
2966 getRestrictTy(Socklen_tPtrTy
);
2967 std::optional
<RangeInt
> Socklen_tMax
= getMaxValue(Socklen_tTy
);
2969 // In 'socket.h' of some libc implementations with C99, sockaddr parameter
2970 // is a transparent union of the underlying sockaddr_ family of pointers
2971 // instead of being a pointer to struct sockaddr. In these cases, the
2972 // standardized signature will not match, thus we try to match with another
2973 // signature that has the joker Irrelevant type. We also remove those
2974 // constraints which require pointer types for the sockaddr param.
2976 // int socket(int domain, int type, int protocol);
2977 addToFunctionSummaryMap(
2978 "socket", Signature(ArgTypes
{IntTy
, IntTy
, IntTy
}, RetType
{IntTy
}),
2980 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2982 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
));
2986 .Case(ReturnsValidFileDescriptor
, ErrnoMustNotBeChecked
,
2988 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
2989 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)));
2990 if (!addToFunctionSummaryMap(
2992 // int accept(int socket, struct sockaddr *restrict address,
2993 // socklen_t *restrict address_len);
2994 Signature(ArgTypes
{IntTy
, StructSockaddrPtrRestrictTy
,
2995 Socklen_tPtrRestrictTy
},
2998 addToFunctionSummaryMap(
3000 Signature(ArgTypes
{IntTy
, Irrelevant
, Socklen_tPtrRestrictTy
},
3004 // int bind(int socket, const struct sockaddr *address, socklen_t
3006 if (!addToFunctionSummaryMap(
3008 Signature(ArgTypes
{IntTy
, ConstStructSockaddrPtrTy
, Socklen_tTy
},
3011 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3012 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3014 ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3015 .ArgConstraint(NotNull(ArgNo(1)))
3017 BufferSize(/*Buffer=*/ArgNo(1), /*BufSize=*/ArgNo(2)))
3019 ArgumentCondition(2, WithinRange
, Range(0, Socklen_tMax
)))))
3020 // Do not add constraints on sockaddr.
3021 addToFunctionSummaryMap(
3023 Signature(ArgTypes
{IntTy
, Irrelevant
, Socklen_tTy
}, RetType
{IntTy
}),
3025 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3026 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3028 ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3030 ArgumentCondition(2, WithinRange
, Range(0, Socklen_tMax
))));
3032 // int getpeername(int socket, struct sockaddr *restrict address,
3033 // socklen_t *restrict address_len);
3034 if (!addToFunctionSummaryMap(
3036 Signature(ArgTypes
{IntTy
, StructSockaddrPtrRestrictTy
,
3037 Socklen_tPtrRestrictTy
},
3040 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3041 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3043 ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3044 .ArgConstraint(NotNull(ArgNo(1)))
3045 .ArgConstraint(NotNull(ArgNo(2)))))
3046 addToFunctionSummaryMap(
3048 Signature(ArgTypes
{IntTy
, Irrelevant
, Socklen_tPtrRestrictTy
},
3051 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3052 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3054 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3056 // int getsockname(int socket, struct sockaddr *restrict address,
3057 // socklen_t *restrict address_len);
3058 if (!addToFunctionSummaryMap(
3060 Signature(ArgTypes
{IntTy
, StructSockaddrPtrRestrictTy
,
3061 Socklen_tPtrRestrictTy
},
3064 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3065 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3067 ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3068 .ArgConstraint(NotNull(ArgNo(1)))
3069 .ArgConstraint(NotNull(ArgNo(2)))))
3070 addToFunctionSummaryMap(
3072 Signature(ArgTypes
{IntTy
, Irrelevant
, Socklen_tPtrRestrictTy
},
3075 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3076 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3078 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3080 // int connect(int socket, const struct sockaddr *address, socklen_t
3082 if (!addToFunctionSummaryMap(
3084 Signature(ArgTypes
{IntTy
, ConstStructSockaddrPtrTy
, Socklen_tTy
},
3087 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3088 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3090 ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3091 .ArgConstraint(NotNull(ArgNo(1)))))
3092 addToFunctionSummaryMap(
3094 Signature(ArgTypes
{IntTy
, Irrelevant
, Socklen_tTy
}, RetType
{IntTy
}),
3096 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3097 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3099 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3103 .Case({ReturnValueCondition(LessThanOrEq
, ArgNo(2)),
3104 ReturnValueCondition(WithinRange
, Range(1, Ssize_tMax
))},
3105 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3106 .Case({ReturnValueCondition(WithinRange
, SingleValue(0)),
3107 ArgumentCondition(2, WithinRange
, SingleValue(0))},
3108 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3109 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3110 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3111 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3112 /*BufSize=*/ArgNo(2)));
3113 if (!addToFunctionSummaryMap(
3115 // ssize_t recvfrom(int socket, void *restrict buffer,
3117 // int flags, struct sockaddr *restrict address,
3118 // socklen_t *restrict address_len);
3119 Signature(ArgTypes
{IntTy
, VoidPtrRestrictTy
, SizeTy
, IntTy
,
3120 StructSockaddrPtrRestrictTy
,
3121 Socklen_tPtrRestrictTy
},
3122 RetType
{Ssize_tTy
}),
3124 addToFunctionSummaryMap(
3126 Signature(ArgTypes
{IntTy
, VoidPtrRestrictTy
, SizeTy
, IntTy
,
3127 Irrelevant
, Socklen_tPtrRestrictTy
},
3128 RetType
{Ssize_tTy
}),
3133 .Case({ReturnValueCondition(LessThanOrEq
, ArgNo(2)),
3134 ReturnValueCondition(WithinRange
, Range(1, Ssize_tMax
))},
3135 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3136 .Case({ReturnValueCondition(WithinRange
, SingleValue(0)),
3137 ArgumentCondition(2, WithinRange
, SingleValue(0))},
3138 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3139 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3140 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3141 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3142 /*BufSize=*/ArgNo(2)));
3143 if (!addToFunctionSummaryMap(
3145 // ssize_t sendto(int socket, const void *message, size_t length,
3146 // int flags, const struct sockaddr *dest_addr,
3147 // socklen_t dest_len);
3148 Signature(ArgTypes
{IntTy
, ConstVoidPtrTy
, SizeTy
, IntTy
,
3149 ConstStructSockaddrPtrTy
, Socklen_tTy
},
3150 RetType
{Ssize_tTy
}),
3152 addToFunctionSummaryMap(
3154 Signature(ArgTypes
{IntTy
, ConstVoidPtrTy
, SizeTy
, IntTy
, Irrelevant
,
3156 RetType
{Ssize_tTy
}),
3159 // int listen(int sockfd, int backlog);
3160 addToFunctionSummaryMap(
3161 "listen", Signature(ArgTypes
{IntTy
, IntTy
}, RetType
{IntTy
}),
3163 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3164 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3166 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3168 // ssize_t recv(int sockfd, void *buf, size_t len, int flags);
3169 addToFunctionSummaryMap(
3171 Signature(ArgTypes
{IntTy
, VoidPtrTy
, SizeTy
, IntTy
},
3172 RetType
{Ssize_tTy
}),
3174 .Case({ReturnValueCondition(LessThanOrEq
, ArgNo(2)),
3175 ReturnValueCondition(WithinRange
, Range(1, Ssize_tMax
))},
3176 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3177 .Case({ReturnValueCondition(WithinRange
, SingleValue(0)),
3178 ArgumentCondition(2, WithinRange
, SingleValue(0))},
3179 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3180 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3181 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3182 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3183 /*BufSize=*/ArgNo(2))));
3185 std::optional
<QualType
> StructMsghdrTy
= lookupTy("msghdr");
3186 std::optional
<QualType
> StructMsghdrPtrTy
= getPointerTy(StructMsghdrTy
);
3187 std::optional
<QualType
> ConstStructMsghdrPtrTy
=
3188 getPointerTy(getConstTy(StructMsghdrTy
));
3190 // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
3191 addToFunctionSummaryMap(
3193 Signature(ArgTypes
{IntTy
, StructMsghdrPtrTy
, IntTy
},
3194 RetType
{Ssize_tTy
}),
3196 .Case({ReturnValueCondition(WithinRange
, Range(1, Ssize_tMax
))},
3197 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3198 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3200 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3202 // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
3203 addToFunctionSummaryMap(
3205 Signature(ArgTypes
{IntTy
, ConstStructMsghdrPtrTy
, IntTy
},
3206 RetType
{Ssize_tTy
}),
3208 .Case({ReturnValueCondition(WithinRange
, Range(1, Ssize_tMax
))},
3209 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3210 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3212 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3214 // int setsockopt(int socket, int level, int option_name,
3215 // const void *option_value, socklen_t option_len);
3216 addToFunctionSummaryMap(
3218 Signature(ArgTypes
{IntTy
, IntTy
, IntTy
, ConstVoidPtrTy
, Socklen_tTy
},
3221 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3222 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3223 .ArgConstraint(NotNull(ArgNo(3)))
3225 BufferSize(/*Buffer=*/ArgNo(3), /*BufSize=*/ArgNo(4)))
3227 ArgumentCondition(4, WithinRange
, Range(0, Socklen_tMax
))));
3229 // int getsockopt(int socket, int level, int option_name,
3230 // void *restrict option_value,
3231 // socklen_t *restrict option_len);
3232 addToFunctionSummaryMap(
3234 Signature(ArgTypes
{IntTy
, IntTy
, IntTy
, VoidPtrRestrictTy
,
3235 Socklen_tPtrRestrictTy
},
3238 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3239 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3240 .ArgConstraint(NotNull(ArgNo(3)))
3241 .ArgConstraint(NotNull(ArgNo(4))));
3243 // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
3244 addToFunctionSummaryMap(
3246 Signature(ArgTypes
{IntTy
, ConstVoidPtrTy
, SizeTy
, IntTy
},
3247 RetType
{Ssize_tTy
}),
3249 .Case({ReturnValueCondition(LessThanOrEq
, ArgNo(2)),
3250 ReturnValueCondition(WithinRange
, Range(1, Ssize_tMax
))},
3251 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3252 .Case({ReturnValueCondition(WithinRange
, SingleValue(0)),
3253 ArgumentCondition(2, WithinRange
, SingleValue(0))},
3254 ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3255 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3256 .ArgConstraint(ArgumentCondition(0, WithinRange
, Range(0, IntMax
)))
3257 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3258 /*BufSize=*/ArgNo(2))));
3260 // int socketpair(int domain, int type, int protocol, int sv[2]);
3261 addToFunctionSummaryMap(
3263 Signature(ArgTypes
{IntTy
, IntTy
, IntTy
, IntPtrTy
}, RetType
{IntTy
}),
3265 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3266 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3267 .ArgConstraint(NotNull(ArgNo(3))));
3269 // int shutdown(int socket, int how);
3270 addToFunctionSummaryMap(
3271 "shutdown", Signature(ArgTypes
{IntTy
, IntTy
}, RetType
{IntTy
}),
3273 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3274 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3276 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3278 // int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
3279 // char *restrict node, socklen_t nodelen,
3280 // char *restrict service,
3281 // socklen_t servicelen, int flags);
3283 // This is defined in netdb.h. And contrary to 'socket.h', the sockaddr
3284 // parameter is never handled as a transparent union in netdb.h
3285 addToFunctionSummaryMap(
3287 Signature(ArgTypes
{ConstStructSockaddrPtrRestrictTy
, Socklen_tTy
,
3288 CharPtrRestrictTy
, Socklen_tTy
, CharPtrRestrictTy
,
3289 Socklen_tTy
, IntTy
},
3293 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1)))
3295 ArgumentCondition(1, WithinRange
, Range(0, Socklen_tMax
)))
3297 BufferSize(/*Buffer=*/ArgNo(2), /*BufSize=*/ArgNo(3)))
3299 ArgumentCondition(3, WithinRange
, Range(0, Socklen_tMax
)))
3301 BufferSize(/*Buffer=*/ArgNo(4), /*BufSize=*/ArgNo(5)))
3303 ArgumentCondition(5, WithinRange
, Range(0, Socklen_tMax
))));
3305 std::optional
<QualType
> StructUtimbufTy
= lookupTy("utimbuf");
3306 std::optional
<QualType
> StructUtimbufPtrTy
= getPointerTy(StructUtimbufTy
);
3308 // int utime(const char *filename, struct utimbuf *buf);
3309 addToFunctionSummaryMap(
3311 Signature(ArgTypes
{ConstCharPtrTy
, StructUtimbufPtrTy
}, RetType
{IntTy
}),
3313 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3314 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3315 .ArgConstraint(NotNull(ArgNo(0))));
3317 std::optional
<QualType
> StructTimespecTy
= lookupTy("timespec");
3318 std::optional
<QualType
> StructTimespecPtrTy
=
3319 getPointerTy(StructTimespecTy
);
3320 std::optional
<QualType
> ConstStructTimespecPtrTy
=
3321 getPointerTy(getConstTy(StructTimespecTy
));
3323 // int futimens(int fd, const struct timespec times[2]);
3324 addToFunctionSummaryMap(
3326 Signature(ArgTypes
{IntTy
, ConstStructTimespecPtrTy
}, RetType
{IntTy
}),
3328 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3329 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3331 ArgumentCondition(0, WithinRange
, Range(0, IntMax
))));
3333 // int utimensat(int dirfd, const char *pathname,
3334 // const struct timespec times[2], int flags);
3335 addToFunctionSummaryMap(
3338 ArgTypes
{IntTy
, ConstCharPtrTy
, ConstStructTimespecPtrTy
, IntTy
},
3341 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3342 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3343 .ArgConstraint(NotNull(ArgNo(1))));
3345 std::optional
<QualType
> StructTimevalTy
= lookupTy("timeval");
3346 std::optional
<QualType
> ConstStructTimevalPtrTy
=
3347 getPointerTy(getConstTy(StructTimevalTy
));
3349 // int utimes(const char *filename, const struct timeval times[2]);
3350 addToFunctionSummaryMap(
3352 Signature(ArgTypes
{ConstCharPtrTy
, ConstStructTimevalPtrTy
},
3355 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3356 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3357 .ArgConstraint(NotNull(ArgNo(0))));
3359 // int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
3360 addToFunctionSummaryMap(
3362 Signature(ArgTypes
{ConstStructTimespecPtrTy
, StructTimespecPtrTy
},
3365 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3366 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3367 .ArgConstraint(NotNull(ArgNo(0))));
3369 std::optional
<QualType
> Time_tTy
= lookupTy("time_t");
3370 std::optional
<QualType
> ConstTime_tPtrTy
=
3371 getPointerTy(getConstTy(Time_tTy
));
3372 std::optional
<QualType
> ConstTime_tPtrRestrictTy
=
3373 getRestrictTy(ConstTime_tPtrTy
);
3375 std::optional
<QualType
> StructTmTy
= lookupTy("tm");
3376 std::optional
<QualType
> StructTmPtrTy
= getPointerTy(StructTmTy
);
3377 std::optional
<QualType
> StructTmPtrRestrictTy
=
3378 getRestrictTy(StructTmPtrTy
);
3379 std::optional
<QualType
> ConstStructTmPtrTy
=
3380 getPointerTy(getConstTy(StructTmTy
));
3381 std::optional
<QualType
> ConstStructTmPtrRestrictTy
=
3382 getRestrictTy(ConstStructTmPtrTy
);
3384 // struct tm * localtime(const time_t *tp);
3385 addToFunctionSummaryMap(
3387 Signature(ArgTypes
{ConstTime_tPtrTy
}, RetType
{StructTmPtrTy
}),
3388 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
3390 // struct tm *localtime_r(const time_t *restrict timer,
3391 // struct tm *restrict result);
3392 addToFunctionSummaryMap(
3394 Signature(ArgTypes
{ConstTime_tPtrRestrictTy
, StructTmPtrRestrictTy
},
3395 RetType
{StructTmPtrTy
}),
3397 .ArgConstraint(NotNull(ArgNo(0)))
3398 .ArgConstraint(NotNull(ArgNo(1))));
3400 // char *asctime_r(const struct tm *restrict tm, char *restrict buf);
3401 addToFunctionSummaryMap(
3403 Signature(ArgTypes
{ConstStructTmPtrRestrictTy
, CharPtrRestrictTy
},
3404 RetType
{CharPtrTy
}),
3406 .ArgConstraint(NotNull(ArgNo(0)))
3407 .ArgConstraint(NotNull(ArgNo(1)))
3408 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
3409 /*MinBufSize=*/BVF
.getValue(26, IntTy
))));
3411 // char *ctime_r(const time_t *timep, char *buf);
3412 addToFunctionSummaryMap(
3414 Signature(ArgTypes
{ConstTime_tPtrTy
, CharPtrTy
}, RetType
{CharPtrTy
}),
3416 .ArgConstraint(NotNull(ArgNo(0)))
3417 .ArgConstraint(NotNull(ArgNo(1)))
3418 .ArgConstraint(BufferSize(
3419 /*Buffer=*/ArgNo(1),
3420 /*MinBufSize=*/BVF
.getValue(26, IntTy
))));
3422 // struct tm *gmtime_r(const time_t *restrict timer,
3423 // struct tm *restrict result);
3424 addToFunctionSummaryMap(
3426 Signature(ArgTypes
{ConstTime_tPtrRestrictTy
, StructTmPtrRestrictTy
},
3427 RetType
{StructTmPtrTy
}),
3429 .ArgConstraint(NotNull(ArgNo(0)))
3430 .ArgConstraint(NotNull(ArgNo(1))));
3432 // struct tm * gmtime(const time_t *tp);
3433 addToFunctionSummaryMap(
3434 "gmtime", Signature(ArgTypes
{ConstTime_tPtrTy
}, RetType
{StructTmPtrTy
}),
3435 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
3437 std::optional
<QualType
> Clockid_tTy
= lookupTy("clockid_t");
3439 // int clock_gettime(clockid_t clock_id, struct timespec *tp);
3440 addToFunctionSummaryMap(
3442 Signature(ArgTypes
{Clockid_tTy
, StructTimespecPtrTy
}, RetType
{IntTy
}),
3444 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3445 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3446 .ArgConstraint(NotNull(ArgNo(1))));
3448 std::optional
<QualType
> StructItimervalTy
= lookupTy("itimerval");
3449 std::optional
<QualType
> StructItimervalPtrTy
=
3450 getPointerTy(StructItimervalTy
);
3452 // int getitimer(int which, struct itimerval *curr_value);
3453 addToFunctionSummaryMap(
3455 Signature(ArgTypes
{IntTy
, StructItimervalPtrTy
}, RetType
{IntTy
}),
3457 .Case(ReturnsZero
, ErrnoMustNotBeChecked
, GenericSuccessMsg
)
3458 .Case(ReturnsMinusOne
, ErrnoNEZeroIrrelevant
, GenericFailureMsg
)
3459 .ArgConstraint(NotNull(ArgNo(1))));
3461 std::optional
<QualType
> Pthread_cond_tTy
= lookupTy("pthread_cond_t");
3462 std::optional
<QualType
> Pthread_cond_tPtrTy
=
3463 getPointerTy(Pthread_cond_tTy
);
3464 std::optional
<QualType
> Pthread_tTy
= lookupTy("pthread_t");
3465 std::optional
<QualType
> Pthread_tPtrTy
= getPointerTy(Pthread_tTy
);
3466 std::optional
<QualType
> Pthread_tPtrRestrictTy
=
3467 getRestrictTy(Pthread_tPtrTy
);
3468 std::optional
<QualType
> Pthread_mutex_tTy
= lookupTy("pthread_mutex_t");
3469 std::optional
<QualType
> Pthread_mutex_tPtrTy
=
3470 getPointerTy(Pthread_mutex_tTy
);
3471 std::optional
<QualType
> Pthread_mutex_tPtrRestrictTy
=
3472 getRestrictTy(Pthread_mutex_tPtrTy
);
3473 std::optional
<QualType
> Pthread_attr_tTy
= lookupTy("pthread_attr_t");
3474 std::optional
<QualType
> Pthread_attr_tPtrTy
=
3475 getPointerTy(Pthread_attr_tTy
);
3476 std::optional
<QualType
> ConstPthread_attr_tPtrTy
=
3477 getPointerTy(getConstTy(Pthread_attr_tTy
));
3478 std::optional
<QualType
> ConstPthread_attr_tPtrRestrictTy
=
3479 getRestrictTy(ConstPthread_attr_tPtrTy
);
3480 std::optional
<QualType
> Pthread_mutexattr_tTy
=
3481 lookupTy("pthread_mutexattr_t");
3482 std::optional
<QualType
> ConstPthread_mutexattr_tPtrTy
=
3483 getPointerTy(getConstTy(Pthread_mutexattr_tTy
));
3484 std::optional
<QualType
> ConstPthread_mutexattr_tPtrRestrictTy
=
3485 getRestrictTy(ConstPthread_mutexattr_tPtrTy
);
3487 QualType PthreadStartRoutineTy
= getPointerTy(
3488 ACtx
.getFunctionType(/*ResultTy=*/VoidPtrTy
, /*Args=*/VoidPtrTy
,
3489 FunctionProtoType::ExtProtoInfo()));
3491 // int pthread_cond_signal(pthread_cond_t *cond);
3492 // int pthread_cond_broadcast(pthread_cond_t *cond);
3493 addToFunctionSummaryMap(
3494 {"pthread_cond_signal", "pthread_cond_broadcast"},
3495 Signature(ArgTypes
{Pthread_cond_tPtrTy
}, RetType
{IntTy
}),
3496 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
3498 // int pthread_create(pthread_t *restrict thread,
3499 // const pthread_attr_t *restrict attr,
3500 // void *(*start_routine)(void*), void *restrict arg);
3501 addToFunctionSummaryMap(
3503 Signature(ArgTypes
{Pthread_tPtrRestrictTy
,
3504 ConstPthread_attr_tPtrRestrictTy
,
3505 PthreadStartRoutineTy
, VoidPtrRestrictTy
},
3508 .ArgConstraint(NotNull(ArgNo(0)))
3509 .ArgConstraint(NotNull(ArgNo(2))));
3511 // int pthread_attr_destroy(pthread_attr_t *attr);
3512 // int pthread_attr_init(pthread_attr_t *attr);
3513 addToFunctionSummaryMap(
3514 {"pthread_attr_destroy", "pthread_attr_init"},
3515 Signature(ArgTypes
{Pthread_attr_tPtrTy
}, RetType
{IntTy
}),
3516 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
3518 // int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
3519 // size_t *restrict stacksize);
3520 // int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
3521 // size_t *restrict guardsize);
3522 addToFunctionSummaryMap(
3523 {"pthread_attr_getstacksize", "pthread_attr_getguardsize"},
3524 Signature(ArgTypes
{ConstPthread_attr_tPtrRestrictTy
, SizePtrRestrictTy
},
3527 .ArgConstraint(NotNull(ArgNo(0)))
3528 .ArgConstraint(NotNull(ArgNo(1))));
3530 // int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
3531 // int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
3532 addToFunctionSummaryMap(
3533 {"pthread_attr_setstacksize", "pthread_attr_setguardsize"},
3534 Signature(ArgTypes
{Pthread_attr_tPtrTy
, SizeTy
}, RetType
{IntTy
}),
3536 .ArgConstraint(NotNull(ArgNo(0)))
3538 ArgumentCondition(1, WithinRange
, Range(0, SizeMax
))));
3540 // int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
3541 // pthread_mutexattr_t *restrict attr);
3542 addToFunctionSummaryMap(
3543 "pthread_mutex_init",
3544 Signature(ArgTypes
{Pthread_mutex_tPtrRestrictTy
,
3545 ConstPthread_mutexattr_tPtrRestrictTy
},
3547 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
3549 // int pthread_mutex_destroy(pthread_mutex_t *mutex);
3550 // int pthread_mutex_lock(pthread_mutex_t *mutex);
3551 // int pthread_mutex_trylock(pthread_mutex_t *mutex);
3552 // int pthread_mutex_unlock(pthread_mutex_t *mutex);
3553 addToFunctionSummaryMap(
3554 {"pthread_mutex_destroy", "pthread_mutex_lock", "pthread_mutex_trylock",
3555 "pthread_mutex_unlock"},
3556 Signature(ArgTypes
{Pthread_mutex_tPtrTy
}, RetType
{IntTy
}),
3557 Summary(NoEvalCall
).ArgConstraint(NotNull(ArgNo(0))));
3560 // Functions for testing.
3561 if (AddTestFunctions
) {
3562 const RangeInt IntMin
= BVF
.getMinValue(IntTy
).getLimitedValue();
3564 addToFunctionSummaryMap(
3565 "__not_null", Signature(ArgTypes
{IntPtrTy
}, RetType
{IntTy
}),
3566 Summary(EvalCallAsPure
).ArgConstraint(NotNull(ArgNo(0))));
3568 addToFunctionSummaryMap(
3569 "__not_null_buffer",
3570 Signature(ArgTypes
{VoidPtrTy
, IntTy
, IntTy
}, RetType
{IntTy
}),
3571 Summary(EvalCallAsPure
)
3572 .ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2))));
3574 // Test inside range constraints.
3575 addToFunctionSummaryMap(
3576 "__single_val_0", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3577 Summary(EvalCallAsPure
)
3578 .ArgConstraint(ArgumentCondition(0U, WithinRange
, SingleValue(0))));
3579 addToFunctionSummaryMap(
3580 "__single_val_1", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3581 Summary(EvalCallAsPure
)
3582 .ArgConstraint(ArgumentCondition(0U, WithinRange
, SingleValue(1))));
3583 addToFunctionSummaryMap(
3584 "__range_1_2", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3585 Summary(EvalCallAsPure
)
3586 .ArgConstraint(ArgumentCondition(0U, WithinRange
, Range(1, 2))));
3587 addToFunctionSummaryMap(
3588 "__range_m1_1", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3589 Summary(EvalCallAsPure
)
3590 .ArgConstraint(ArgumentCondition(0U, WithinRange
, Range(-1, 1))));
3591 addToFunctionSummaryMap(
3592 "__range_m2_m1", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3593 Summary(EvalCallAsPure
)
3594 .ArgConstraint(ArgumentCondition(0U, WithinRange
, Range(-2, -1))));
3595 addToFunctionSummaryMap(
3596 "__range_m10_10", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3597 Summary(EvalCallAsPure
)
3598 .ArgConstraint(ArgumentCondition(0U, WithinRange
, Range(-10, 10))));
3599 addToFunctionSummaryMap("__range_m1_inf",
3600 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3601 Summary(EvalCallAsPure
)
3602 .ArgConstraint(ArgumentCondition(
3603 0U, WithinRange
, Range(-1, IntMax
))));
3604 addToFunctionSummaryMap("__range_0_inf",
3605 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3606 Summary(EvalCallAsPure
)
3607 .ArgConstraint(ArgumentCondition(
3608 0U, WithinRange
, Range(0, IntMax
))));
3609 addToFunctionSummaryMap("__range_1_inf",
3610 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3611 Summary(EvalCallAsPure
)
3612 .ArgConstraint(ArgumentCondition(
3613 0U, WithinRange
, Range(1, IntMax
))));
3614 addToFunctionSummaryMap("__range_minf_m1",
3615 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3616 Summary(EvalCallAsPure
)
3617 .ArgConstraint(ArgumentCondition(
3618 0U, WithinRange
, Range(IntMin
, -1))));
3619 addToFunctionSummaryMap("__range_minf_0",
3620 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3621 Summary(EvalCallAsPure
)
3622 .ArgConstraint(ArgumentCondition(
3623 0U, WithinRange
, Range(IntMin
, 0))));
3624 addToFunctionSummaryMap("__range_minf_1",
3625 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3626 Summary(EvalCallAsPure
)
3627 .ArgConstraint(ArgumentCondition(
3628 0U, WithinRange
, Range(IntMin
, 1))));
3629 addToFunctionSummaryMap("__range_1_2__4_6",
3630 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3631 Summary(EvalCallAsPure
)
3632 .ArgConstraint(ArgumentCondition(
3633 0U, WithinRange
, Range({1, 2}, {4, 6}))));
3634 addToFunctionSummaryMap(
3635 "__range_1_2__4_inf", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3636 Summary(EvalCallAsPure
)
3637 .ArgConstraint(ArgumentCondition(0U, WithinRange
,
3638 Range({1, 2}, {4, IntMax
}))));
3640 // Test out of range constraints.
3641 addToFunctionSummaryMap(
3642 "__single_val_out_0", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3643 Summary(EvalCallAsPure
)
3644 .ArgConstraint(ArgumentCondition(0U, OutOfRange
, SingleValue(0))));
3645 addToFunctionSummaryMap(
3646 "__single_val_out_1", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3647 Summary(EvalCallAsPure
)
3648 .ArgConstraint(ArgumentCondition(0U, OutOfRange
, SingleValue(1))));
3649 addToFunctionSummaryMap(
3650 "__range_out_1_2", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3651 Summary(EvalCallAsPure
)
3652 .ArgConstraint(ArgumentCondition(0U, OutOfRange
, Range(1, 2))));
3653 addToFunctionSummaryMap(
3654 "__range_out_m1_1", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3655 Summary(EvalCallAsPure
)
3656 .ArgConstraint(ArgumentCondition(0U, OutOfRange
, Range(-1, 1))));
3657 addToFunctionSummaryMap(
3658 "__range_out_m2_m1", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3659 Summary(EvalCallAsPure
)
3660 .ArgConstraint(ArgumentCondition(0U, OutOfRange
, Range(-2, -1))));
3661 addToFunctionSummaryMap(
3662 "__range_out_m10_10", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3663 Summary(EvalCallAsPure
)
3664 .ArgConstraint(ArgumentCondition(0U, OutOfRange
, Range(-10, 10))));
3665 addToFunctionSummaryMap("__range_out_m1_inf",
3666 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3667 Summary(EvalCallAsPure
)
3668 .ArgConstraint(ArgumentCondition(
3669 0U, OutOfRange
, Range(-1, IntMax
))));
3670 addToFunctionSummaryMap("__range_out_0_inf",
3671 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3672 Summary(EvalCallAsPure
)
3673 .ArgConstraint(ArgumentCondition(
3674 0U, OutOfRange
, Range(0, IntMax
))));
3675 addToFunctionSummaryMap("__range_out_1_inf",
3676 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3677 Summary(EvalCallAsPure
)
3678 .ArgConstraint(ArgumentCondition(
3679 0U, OutOfRange
, Range(1, IntMax
))));
3680 addToFunctionSummaryMap("__range_out_minf_m1",
3681 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3682 Summary(EvalCallAsPure
)
3683 .ArgConstraint(ArgumentCondition(
3684 0U, OutOfRange
, Range(IntMin
, -1))));
3685 addToFunctionSummaryMap("__range_out_minf_0",
3686 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3687 Summary(EvalCallAsPure
)
3688 .ArgConstraint(ArgumentCondition(
3689 0U, OutOfRange
, Range(IntMin
, 0))));
3690 addToFunctionSummaryMap("__range_out_minf_1",
3691 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3692 Summary(EvalCallAsPure
)
3693 .ArgConstraint(ArgumentCondition(
3694 0U, OutOfRange
, Range(IntMin
, 1))));
3695 addToFunctionSummaryMap("__range_out_1_2__4_6",
3696 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3697 Summary(EvalCallAsPure
)
3698 .ArgConstraint(ArgumentCondition(
3699 0U, OutOfRange
, Range({1, 2}, {4, 6}))));
3700 addToFunctionSummaryMap(
3701 "__range_out_1_2__4_inf", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3702 Summary(EvalCallAsPure
)
3704 ArgumentCondition(0U, OutOfRange
, Range({1, 2}, {4, IntMax
}))));
3707 addToFunctionSummaryMap(
3708 "__within", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3709 Summary(EvalCallAsPure
)
3710 .ArgConstraint(ArgumentCondition(0U, WithinRange
, SingleValue(1))));
3711 addToFunctionSummaryMap(
3712 "__out_of", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3713 Summary(EvalCallAsPure
)
3714 .ArgConstraint(ArgumentCondition(0U, OutOfRange
, SingleValue(1))));
3716 addToFunctionSummaryMap(
3717 "__two_constrained_args",
3718 Signature(ArgTypes
{IntTy
, IntTy
}, RetType
{IntTy
}),
3719 Summary(EvalCallAsPure
)
3720 .ArgConstraint(ArgumentCondition(0U, WithinRange
, SingleValue(1)))
3721 .ArgConstraint(ArgumentCondition(1U, WithinRange
, SingleValue(1))));
3722 addToFunctionSummaryMap(
3723 "__arg_constrained_twice", Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3724 Summary(EvalCallAsPure
)
3725 .ArgConstraint(ArgumentCondition(0U, OutOfRange
, SingleValue(1)))
3726 .ArgConstraint(ArgumentCondition(0U, OutOfRange
, SingleValue(2))));
3727 addToFunctionSummaryMap(
3729 Signature(ArgTypes
{Irrelevant
, IntTy
}, RetType
{IntTy
}),
3730 Summary(EvalCallAsPure
).ArgConstraint(NotNull(ArgNo(0))));
3731 addToFunctionSummaryMap(
3733 Signature(ArgTypes
{VoidPtrTy
, ConstCharPtrTy
}, RetType
{IntTy
}),
3734 Summary(EvalCallAsPure
)
3735 .ArgConstraint(NotNull(ArgNo(0)))
3736 .ArgConstraint(NotNull(ArgNo(1))));
3737 addToFunctionSummaryMap(
3738 "__buf_size_arg_constraint",
3739 Signature(ArgTypes
{ConstVoidPtrTy
, SizeTy
}, RetType
{IntTy
}),
3740 Summary(EvalCallAsPure
)
3742 BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))));
3743 addToFunctionSummaryMap(
3744 "__buf_size_arg_constraint_mul",
3745 Signature(ArgTypes
{ConstVoidPtrTy
, SizeTy
, SizeTy
}, RetType
{IntTy
}),
3746 Summary(EvalCallAsPure
)
3747 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
3748 /*BufSizeMultiplier=*/ArgNo(2))));
3749 addToFunctionSummaryMap(
3750 "__buf_size_arg_constraint_concrete",
3751 Signature(ArgTypes
{ConstVoidPtrTy
}, RetType
{IntTy
}),
3752 Summary(EvalCallAsPure
)
3753 .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0),
3754 /*BufSize=*/BVF
.getValue(10, IntTy
))));
3755 addToFunctionSummaryMap(
3756 {"__test_restrict_param_0", "__test_restrict_param_1",
3757 "__test_restrict_param_2"},
3758 Signature(ArgTypes
{VoidPtrRestrictTy
}, RetType
{VoidTy
}),
3759 Summary(EvalCallAsPure
));
3761 // Test the application of cases.
3762 addToFunctionSummaryMap(
3763 "__test_case_note", Signature(ArgTypes
{}, RetType
{IntTy
}),
3764 Summary(EvalCallAsPure
)
3765 .Case({ReturnValueCondition(WithinRange
, SingleValue(0))},
3766 ErrnoIrrelevant
, "Function returns 0")
3767 .Case({ReturnValueCondition(WithinRange
, SingleValue(1))},
3768 ErrnoIrrelevant
, "Function returns 1"));
3769 addToFunctionSummaryMap(
3770 "__test_case_range_1_2__4_6",
3771 Signature(ArgTypes
{IntTy
}, RetType
{IntTy
}),
3772 Summary(EvalCallAsPure
)
3773 .Case({ArgumentCondition(0U, WithinRange
,
3774 IntRangeVector
{{IntMin
, 0}, {3, 3}}),
3775 ReturnValueCondition(WithinRange
, SingleValue(1))},
3777 .Case({ArgumentCondition(0U, WithinRange
,
3778 IntRangeVector
{{3, 3}, {7, IntMax
}}),
3779 ReturnValueCondition(WithinRange
, SingleValue(2))},
3781 .Case({ArgumentCondition(0U, WithinRange
,
3782 IntRangeVector
{{IntMin
, 0}, {7, IntMax
}}),
3783 ReturnValueCondition(WithinRange
, SingleValue(3))},
3785 .Case({ArgumentCondition(
3787 IntRangeVector
{{IntMin
, 0}, {3, 3}, {7, IntMax
}}),
3788 ReturnValueCondition(WithinRange
, SingleValue(4))},
3793 void ento::registerStdCLibraryFunctionsChecker(CheckerManager
&mgr
) {
3794 auto *Checker
= mgr
.registerChecker
<StdLibraryFunctionsChecker
>();
3795 Checker
->CheckName
= mgr
.getCurrentCheckerName();
3796 const AnalyzerOptions
&Opts
= mgr
.getAnalyzerOptions();
3797 Checker
->DisplayLoadedSummaries
=
3798 Opts
.getCheckerBooleanOption(Checker
, "DisplayLoadedSummaries");
3799 Checker
->ModelPOSIX
= Opts
.getCheckerBooleanOption(Checker
, "ModelPOSIX");
3800 Checker
->ShouldAssumeControlledEnvironment
=
3801 Opts
.ShouldAssumeControlledEnvironment
;
3804 bool ento::shouldRegisterStdCLibraryFunctionsChecker(
3805 const CheckerManager
&mgr
) {
3809 void ento::registerStdCLibraryFunctionsTesterChecker(CheckerManager
&mgr
) {
3810 auto *Checker
= mgr
.getChecker
<StdLibraryFunctionsChecker
>();
3811 Checker
->AddTestFunctions
= true;
3814 bool ento::shouldRegisterStdCLibraryFunctionsTesterChecker(
3815 const CheckerManager
&mgr
) {