@@ -297,6 +297,9 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
297297 // / If true, evaluate special testing stream functions.
298298 bool TestMode = false ;
299299
300+ // / If true, generate failure branches for cases that are often not checked.
301+ bool PedanticMode = false ;
302+
300303private:
301304 CallDescriptionMap<FnDescription> FnDescriptions = {
302305 {{{" fopen" }, 2 }, {nullptr , &StreamChecker::evalFopen, ArgNone}},
@@ -945,6 +948,10 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
945948 }
946949
947950 // Add transition for the failed state.
951+ // At write, add failure case only if "pedantic mode" is on.
952+ if (!IsFread && !PedanticMode)
953+ return ;
954+
948955 NonLoc RetVal = makeRetVal (C, E.CE ).castAs <NonLoc>();
949956 ProgramStateRef StateFailed =
950957 State->BindExpr (E.CE , C.getLocationContext (), RetVal);
@@ -1057,6 +1064,9 @@ void StreamChecker::evalFputx(const FnDescription *Desc, const CallEvent &Call,
10571064 C.addTransition (StateNotFailed);
10581065 }
10591066
1067+ if (!PedanticMode)
1068+ return ;
1069+
10601070 // Add transition for the failed state. The resulting value of the file
10611071 // position indicator for the stream is indeterminate.
10621072 ProgramStateRef StateFailed = E.bindReturnValue (State, C, *EofVal);
@@ -1092,6 +1102,9 @@ void StreamChecker::evalFprintf(const FnDescription *Desc,
10921102 E.setStreamState (StateNotFailed, StreamState::getOpened (Desc));
10931103 C.addTransition (StateNotFailed);
10941104
1105+ if (!PedanticMode)
1106+ return ;
1107+
10951108 // Add transition for the failed state. The resulting value of the file
10961109 // position indicator for the stream is indeterminate.
10971110 StateFailed = E.setStreamState (
@@ -1264,21 +1277,23 @@ void StreamChecker::evalFseek(const FnDescription *Desc, const CallEvent &Call,
12641277 if (!E.Init (Desc, Call, C, State))
12651278 return ;
12661279
1267- // Bifurcate the state into failed and non-failed.
1268- // Return zero on success, -1 on error.
1280+ // Add success state.
12691281 ProgramStateRef StateNotFailed = E.bindReturnValue (State, C, 0 );
1270- ProgramStateRef StateFailed = E.bindReturnValue (State, C, -1 );
1271-
12721282 // No failure: Reset the state to opened with no error.
12731283 StateNotFailed =
12741284 E.setStreamState (StateNotFailed, StreamState::getOpened (Desc));
12751285 C.addTransition (StateNotFailed);
12761286
1287+ if (!PedanticMode)
1288+ return ;
1289+
1290+ // Add failure state.
12771291 // At error it is possible that fseek fails but sets none of the error flags.
12781292 // If fseek failed, assume that the file position becomes indeterminate in any
12791293 // case.
12801294 // It is allowed to set the position beyond the end of the file. EOF error
12811295 // should not occur.
1296+ ProgramStateRef StateFailed = E.bindReturnValue (State, C, -1 );
12821297 StateFailed = E.setStreamState (
12831298 StateFailed, StreamState::getOpened (Desc, ErrorNone | ErrorFError, true ));
12841299 C.addTransition (StateFailed, E.getFailureNoteTag (this , C));
@@ -1316,6 +1331,10 @@ void StreamChecker::evalFsetpos(const FnDescription *Desc,
13161331
13171332 StateNotFailed = E.setStreamState (
13181333 StateNotFailed, StreamState::getOpened (Desc, ErrorNone, false ));
1334+ C.addTransition (StateNotFailed);
1335+
1336+ if (!PedanticMode)
1337+ return ;
13191338
13201339 // At failure ferror could be set.
13211340 // The standards do not tell what happens with the file position at failure.
@@ -1324,7 +1343,6 @@ void StreamChecker::evalFsetpos(const FnDescription *Desc,
13241343 StateFailed = E.setStreamState (
13251344 StateFailed, StreamState::getOpened (Desc, ErrorNone | ErrorFError, true ));
13261345
1327- C.addTransition (StateNotFailed);
13281346 C.addTransition (StateFailed, E.getFailureNoteTag (this , C));
13291347}
13301348
@@ -1794,7 +1812,9 @@ ProgramStateRef StreamChecker::checkPointerEscape(
17941812// ===----------------------------------------------------------------------===//
17951813
17961814void ento::registerStreamChecker (CheckerManager &Mgr) {
1797- Mgr.registerChecker <StreamChecker>();
1815+ auto *Checker = Mgr.registerChecker <StreamChecker>();
1816+ Checker->PedanticMode =
1817+ Mgr.getAnalyzerOptions ().getCheckerBooleanOption (Checker, " Pedantic" );
17981818}
17991819
18001820bool ento::shouldRegisterStreamChecker (const CheckerManager &Mgr) {
0 commit comments