diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 034825d88a44d..f160c464dc273 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -2277,6 +2277,20 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( .Case({}, ErrnoMustBeChecked) .ArgConstraint(NotNull(ArgNo(0)))); + // int fputc(int c, FILE *stream); + addToFunctionSummaryMap( + "fputc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}), + Summary(NoEvalCall) + .Case({ArgumentCondition(0, WithinRange, Range(0, UCharRangeMax)), + ReturnValueCondition(BO_EQ, ArgNo(0))}, + ErrnoMustNotBeChecked, GenericSuccessMsg) + .Case({ArgumentCondition(0, OutOfRange, Range(0, UCharRangeMax)), + ReturnValueCondition(WithinRange, Range(0, UCharRangeMax))}, + ErrnoMustNotBeChecked, GenericSuccessMsg) + .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))}, + ErrnoNEZeroIrrelevant, GenericFailureMsg) + .ArgConstraint(NotNull(ArgNo(1)))); + // void clearerr(FILE *stream); addToFunctionSummaryMap( "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}), diff --git a/clang/test/Analysis/Inputs/std-c-library-functions.h b/clang/test/Analysis/Inputs/std-c-library-functions.h index 7c86c359ee21d..6cb2d1be7a9b1 100644 --- a/clang/test/Analysis/Inputs/std-c-library-functions.h +++ b/clang/test/Analysis/Inputs/std-c-library-functions.h @@ -37,6 +37,7 @@ int toascii(int); int getc(FILE *); int fgetc(FILE *); +int fputc(int c, FILE *stream); int getchar(void); size_t fread(void *restrict, size_t, size_t, FILE *restrict); size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict); diff --git a/clang/test/Analysis/errno-stdlibraryfunctions.c b/clang/test/Analysis/errno-stdlibraryfunctions.c index 9e3d07e7aa88a..9ece662a93707 100644 --- a/clang/test/Analysis/errno-stdlibraryfunctions.c +++ b/clang/test/Analysis/errno-stdlibraryfunctions.c @@ -89,3 +89,17 @@ void errno_getcwd(char *Buf, size_t Sz) { if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}} } } + +void errno_fputc(int C, FILE *Fp) { + int Ret = fputc(C, Fp); + if (Ret == EOF) { + clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}} + if (errno) {} // no warning + } else if (C >= 0 && C <= 255) { + clang_analyzer_eval(Ret == C); // expected-warning{{TRUE}} + if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}} + } else { + clang_analyzer_eval(Ret != C); // expected-warning{{TRUE}} + if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}} + } +}