[clang] [clang][analyzer] Support `fflush` in the StreamChecker (PR #74296)

Balázs Kéri via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 6 08:58:55 PST 2023


================
@@ -1191,6 +1199,49 @@ void StreamChecker::evalSetFeofFerror(const FnDescription *Desc,
   C.addTransition(State);
 }
 
+void StreamChecker::preFflush(const FnDescription *Desc, const CallEvent &Call,
+                              CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  SVal StreamVal = getStreamArg(Desc, Call);
+  std::optional<DefinedSVal> Stream = StreamVal.getAs<DefinedSVal>();
+  if (!Stream)
+    return;
+
+  ConstraintManager::ProgramStatePair SP =
+      C.getConstraintManager().assumeDual(State, *Stream);
+  if (State = SP.first)
+    if (State = ensureStreamOpened(StreamVal, C, State))
+      C.addTransition(State);
+}
+
+void StreamChecker::evalFflush(const FnDescription *Desc, const CallEvent &Call,
+                               CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+
+  // We will check the result even if the input is `NULL`,
+  // but do nothing if the input state is unknown.
+  SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
+  if (StreamSym) {
+    const StreamState *OldSS = State->get<StreamMap>(StreamSym);
+    if (!OldSS)
+      return;
+    assertStreamStateOpened(OldSS);
+  }
+
+  const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+  if (!CE)
+    return;
+
+  // `fflush` returns 0 on success, otherwise returns EOF.
+  ProgramStateRef StateNotFailed = bindInt(0, State, C, CE);
+  ProgramStateRef StateFailed = bindInt(*EofVal, State, C, CE);
+
+  // This function does not affect the stream state.
+  // Still we add success and failure state with the appropriate return value.
----------------
balazske wrote:

The stream state can be affected in some way, if the stream was in failed (`ferror`) state or the position is indeterminate, probably the `fflush` can be allowed but the error (and indeterminate position) should be reset to non-error. If the argument is null we can do this reset for all of the known streams. It is somewhat questionable what should happen at a failing `fflush`, but probably it is OK to leave the error flags as it was before.

https://github.com/llvm/llvm-project/pull/74296


More information about the cfe-commits mailing list