@@ -533,13 +533,11 @@ class StdLibraryFunctionsChecker
533
533
virtual ProgramStateRef apply (ProgramStateRef State, const CallEvent &Call,
534
534
const Summary &Summary,
535
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
538
- // / expected).
539
- virtual const NoteTag *describe (CheckerContext &C,
540
- StringRef FunctionName) const {
541
- return nullptr ;
542
- }
536
+ // / Get a description about what happens with 'errno' here and how it causes
537
+ // / a later bug report created by ErrnoChecker.
538
+ // / Empty return value means that 'errno' related bug may not happen from
539
+ // / the current analyzed function.
540
+ virtual const std::string describe (CheckerContext &C) const { return " " ; }
543
541
544
542
virtual ~ErrnoConstraintBase () {}
545
543
@@ -596,7 +594,8 @@ class StdLibraryFunctionsChecker
596
594
};
597
595
598
596
// / Set errno constraint at success cases of standard functions.
599
- // / Success case: 'errno' is not allowed to be used.
597
+ // / Success case: 'errno' is not allowed to be used because the value is
598
+ // / undefined after successful call.
600
599
// / \c ErrnoChecker can emit bug report after such a function call if errno
601
600
// / is used.
602
601
class SuccessErrnoConstraint : public ErrnoConstraintBase {
@@ -607,12 +606,15 @@ class StdLibraryFunctionsChecker
607
606
return errno_modeling::setErrnoForStdSuccess (State, C);
608
607
}
609
608
610
- const NoteTag *describe (CheckerContext &C,
611
- StringRef FunctionName) const override {
612
- return errno_modeling::getNoteTagForStdSuccess (C, FunctionName);
609
+ const std::string describe (CheckerContext &C) const {
610
+ return " 'errno' becomes undefined after the call" ;
613
611
}
614
612
};
615
613
614
+ // / Set errno constraint at functions that indicate failure only with 'errno'.
615
+ // / In this case 'errno' is required to be observed.
616
+ // / \c ErrnoChecker can emit bug report after such a function call if errno
617
+ // / is overwritten without a read before.
616
618
class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {
617
619
public:
618
620
ProgramStateRef apply (ProgramStateRef State, const CallEvent &Call,
@@ -622,9 +624,8 @@ class StdLibraryFunctionsChecker
622
624
Call.getOriginExpr ());
623
625
}
624
626
625
- const NoteTag *describe (CheckerContext &C,
626
- StringRef FunctionName) const override {
627
- return errno_modeling::getNoteTagForStdMustBeChecked (C, FunctionName);
627
+ const std::string describe (CheckerContext &C) const {
628
+ return " reading 'errno' is required to find out if the call has failed" ;
628
629
}
629
630
};
630
631
@@ -1392,17 +1393,28 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
1392
1393
// Still add these note tags, the other checker should add only its
1393
1394
// specialized note tags. These general note tags are handled always by
1394
1395
// StdLibraryFunctionsChecker.
1396
+
1395
1397
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.
1400
- std::string Note =
1401
- llvm::formatv (Case.getNote ().str ().c_str (),
1402
- cast<NamedDecl>(Call.getDecl ())->getDeclName ());
1403
- if (Summary.getInvalidationKd () == EvalCallAsPure) {
1398
+ DeclarationName FunctionName =
1399
+ cast<NamedDecl>(Call.getDecl ())->getDeclName ();
1400
+
1401
+ std::string ErrnoNote = Case.getErrnoConstraint ().describe (C);
1402
+ std::string CaseNote;
1403
+ if (Case.getNote ().empty ()) {
1404
+ if (!ErrnoNote.empty ())
1405
+ ErrnoNote =
1406
+ llvm::formatv (" After calling '{0}' {1}" , FunctionName, ErrnoNote);
1407
+ } else {
1408
+ CaseNote = llvm::formatv (Case.getNote ().str ().c_str (), FunctionName);
1409
+ }
1410
+ const SVal RV = Call.getReturnValue ();
1411
+
1412
+ if (Summary.getInvalidationKd () == EvalCallAsPure) {
1413
+ // Do not expect that errno is interesting (the "pure" functions do not
1414
+ // affect it).
1415
+ if (!CaseNote.empty ()) {
1404
1416
const NoteTag *Tag = C.getNoteTag (
1405
- [Node, Note , RV](PathSensitiveBugReport &BR) -> std::string {
1417
+ [Node, CaseNote , RV](PathSensitiveBugReport &BR) -> std::string {
1406
1418
// Try to omit the note if we know in advance which branch is
1407
1419
// taken (this means, only one branch exists).
1408
1420
// This check is performed inside the lambda, after other
@@ -1414,37 +1426,42 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
1414
1426
// the successors). This is why this check is only used in the
1415
1427
// EvalCallAsPure case.
1416
1428
if (BR.isInteresting (RV) && Node->succ_size () > 1 )
1417
- return Note ;
1429
+ return CaseNote ;
1418
1430
return " " ;
1419
1431
});
1420
1432
Pred = C.addTransition (NewState, Pred, Tag);
1421
- } else {
1433
+ }
1434
+ } else {
1435
+ if (!CaseNote.empty () || !ErrnoNote.empty ()) {
1422
1436
const NoteTag *Tag =
1423
- C.getNoteTag ([Note, RV](PathSensitiveBugReport &BR) -> std::string {
1424
- if (BR.isInteresting (RV))
1425
- return Note;
1437
+ C.getNoteTag ([CaseNote, ErrnoNote,
1438
+ RV](PathSensitiveBugReport &BR) -> std::string {
1439
+ // If 'errno' is interesting, show the user a note about the case
1440
+ // (what happened at the function call) and about how 'errno'
1441
+ // causes the problem. ErrnoChecker sets the errno (but not RV) to
1442
+ // interesting.
1443
+ // If only the return value is interesting, show only the case
1444
+ // note.
1445
+ std::optional<Loc> ErrnoLoc =
1446
+ errno_modeling::getErrnoLoc (BR.getErrorNode ()->getState ());
1447
+ bool ErrnoImportant = !ErrnoNote.empty () && ErrnoLoc &&
1448
+ BR.isInteresting (ErrnoLoc->getAsRegion ());
1449
+ if (ErrnoImportant) {
1450
+ BR.markNotInteresting (ErrnoLoc->getAsRegion ());
1451
+ if (CaseNote.empty ())
1452
+ return ErrnoNote;
1453
+ return llvm::formatv (" {0}; {1}" , CaseNote, ErrnoNote);
1454
+ } else {
1455
+ if (BR.isInteresting (RV))
1456
+ return CaseNote;
1457
+ }
1426
1458
return " " ;
1427
1459
});
1428
1460
Pred = C.addTransition (NewState, Pred, Tag);
1429
1461
}
1430
-
1431
- // Pred may be:
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 ())
1436
- continue ;
1437
1462
}
1438
1463
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);
1446
-
1447
- // Add the transition if no note tag could be added.
1464
+ // Add the transition if no note tag was added.
1448
1465
if (Pred == Node && NewState != State)
1449
1466
C.addTransition (NewState);
1450
1467
}
@@ -2038,7 +2055,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
2038
2055
ErrnoMustNotBeChecked, GenericSuccessMsg)
2039
2056
.Case ({ArgumentCondition (1U , WithinRange, SingleValue (0 )),
2040
2057
ReturnValueCondition (WithinRange, SingleValue (0 ))},
2041
- ErrnoMustNotBeChecked, GenericSuccessMsg)
2058
+ ErrnoMustNotBeChecked,
2059
+ " Assuming that argument 'size' to '{0}' is 0" )
2042
2060
.ArgConstraint (NotNullBuffer (ArgNo (0 ), ArgNo (1 ), ArgNo (2 )))
2043
2061
.ArgConstraint (NotNull (ArgNo (3 )))
2044
2062
.ArgConstraint (BufferSize (/* Buffer=*/ ArgNo (0 ), /* BufSize=*/ ArgNo (1 ),
0 commit comments