================ @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits