[clang] [clang][analyzer] Support `fgetc` in StreamChecker (PR #72627)

Balázs Kéri via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 23 01:46:18 PST 2023


================
@@ -768,26 +772,65 @@ void StreamChecker::evalFputc(const FnDescription *Desc, const CallEvent &Call,
 
   assertStreamStateOpened(OldSS);
 
+  // `fgetc` returns the read character on success, otherwise returns EOF.
   // `fputc` returns the written character on success, otherwise returns EOF.
 
-  // Generate a transition for the success state.
-  std::optional<NonLoc> PutVal = Call.getArgSVal(0).getAs<NonLoc>();
-  if (!PutVal)
-    return;
-  ProgramStateRef StateNotFailed =
-      State->BindExpr(CE, C.getLocationContext(), *PutVal);
-  StateNotFailed =
-      StateNotFailed->set<StreamMap>(StreamSym, StreamState::getOpened(Desc));
-  C.addTransition(StateNotFailed);
+  // Generate a transition for the success state of fputc.
+  if (!IsRead) {
+    std::optional<NonLoc> PutVal = Call.getArgSVal(0).getAs<NonLoc>();
+    if (!PutVal)
+      return;
+    ProgramStateRef StateNotFailed =
+        State->BindExpr(CE, C.getLocationContext(), *PutVal);
+    StateNotFailed =
+        StateNotFailed->set<StreamMap>(StreamSym, StreamState::getOpened(Desc));
+    C.addTransition(StateNotFailed);
+  }
+  // Generate a transition for the success state of fgetc.
+  // If we know the state to be FEOF at fgetc, do not add a success state.
+  else if (OldSS->ErrorState != ErrorFEof) {
+    NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
+    ProgramStateRef StateNotFailed =
+        State->BindExpr(CE, C.getLocationContext(), RetVal);
+    SValBuilder &SVB = C.getSValBuilder();
+    // The returned 'unsigned char' of `fgetc` is converted to 'int',
+    // so we need to check if it is in range [0, 255].
+    auto CondLow = SVB.evalBinOp(State, BO_GE, RetVal,
+                                 SVB.makeZeroVal(C.getASTContext().IntTy),
+                                 SVB.getConditionType())
+                       .getAs<DefinedOrUnknownSVal>();
+    auto CondHigh = SVB.evalBinOp(State, BO_LE, RetVal,
+                                  SVB.makeIntVal(255, C.getASTContext().IntTy),
+                                  SVB.getConditionType())
+                        .getAs<DefinedOrUnknownSVal>();
----------------
balazske wrote:

Value "255" can be replaced with `SVB.getBasicValueFactory().getMaxValue(C.getASTContext().UnsignedCharTy).getLimitedValue()` (this is probably not always 255). Probably ASTContext can be saved into a variable.

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


More information about the cfe-commits mailing list