[clang] [clang][analyzer] Support `fputs` in the StreamChecker (PR #73335)
Balázs Kéri via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 24 07:40:08 PST 2023
================
@@ -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
More information about the cfe-commits
mailing list