================ @@ -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