================
@@ -774,26 +780,45 @@ void StreamChecker::evalFgetcFputc(const FnDescription 
*Desc,
 
   // `fgetc` returns the read character on success, otherwise returns EOF.
   // `fputc` returns the written character on success, otherwise returns EOF.
+  // `fputs` returns a non negative value on sucecess, otherwise returns EOF.
 
-  // Generate a transition for the success state of fputc.
+  SValBuilder &SVB = C.getSValBuilder();
+  auto &ASTC = C.getASTContext();
   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);
+    // Generddate a transition for the success state of `fputc`.
+    if (SingleChar) {
+      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);
+    }
+    // Generddate a transition for the success state of `fputs`.
+    else {
+      NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
+      ProgramStateRef StateNotFailed =
+          State->BindExpr(CE, C.getLocationContext(), RetVal);
+      auto Cond =
+          SVB.evalBinOp(State, BO_GE, RetVal, SVB.makeZeroVal(ASTC.IntTy),
+                        SVB.getConditionType())
+              .getAs<DefinedOrUnknownSVal>();
+      if (!Cond)
+        return;
+      StateNotFailed = StateNotFailed->assume(*Cond, true);
+      if (!StateNotFailed)
+        return;
+      C.addTransition(StateNotFailed);
+    }
----------------
balazske wrote:

This function is becoming too large. Here almost all code for `fputs` is in a 
new branch and really there are 4 condition branches for all 4 functions (if 
`fgets` is added) with not much common code. It looks better to make an 
`evalFputX` and `evalFgetX` function (but `fgets` can be too much different 
than the other). Functions for the common code at begin and end of these `eval` 
functions (that can be reused by the others too) could be good too (and 
separate eval functions for all get and put cases), but this belongs into a 
separate PR. Probably I can improve the code, my next plans contain anyway to 
work with `StreamChecker`.

https://github.com/llvm/llvm-project/pull/73335
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to