================ @@ -768,26 +772,56 @@ 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(); + auto Cond = SVB.evalBinOp(State, BO_GE, RetVal, + SVB.makeZeroVal(C.getASTContext().IntTy), + SVB.getConditionType()) + .getAs<DefinedOrUnknownSVal>(); + if (!Cond) + return; ---------------- balazske wrote:
The function returns an `unsigned char` value converted to `int`, another condition should be added for the upper limit. https://github.com/llvm/llvm-project/pull/72627 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits