diff options
author | Balázs Kéri <balazs.keri@ericsson.com> | 2024-02-08 11:09:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-08 11:09:57 +0100 |
commit | b85fe40cb88a6b4f640c2b757bd0d254ff1d032c (patch) | |
tree | 8bcc033e48cd6afcdbe3b1920c63f4170d24251f /clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp | |
parent | 49ee2ffc65b7660bfe84cd842e083d6c0ee3e991 (diff) | |
download | llvm-b85fe40cb88a6b4f640c2b757bd0d254ff1d032c.zip llvm-b85fe40cb88a6b4f640c2b757bd0d254ff1d032c.tar.gz llvm-b85fe40cb88a6b4f640c2b757bd0d254ff1d032c.tar.bz2 |
[clang][analyzer] Add missing stream related functions to StdLibraryFunctionsChecker. (#76979)
Some stream functions were recently added to `StreamChecker` that were
not modeled by `StdCLibraryFunctionsChecker`. To ensure consistency
these functions are added to the other checker too.
Some of the related tests are re-organized.
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp | 79 |
1 files changed, 68 insertions, 11 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 0c6293e6..6b8ac26 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -2023,13 +2023,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( {{EOFv, EOFv}, {0, UCharRangeMax}}, "an unsigned char value or EOF"))); - // The getc() family of functions that returns either a char or an EOF. - addToFunctionSummaryMap( - {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), - Summary(NoEvalCall) - .Case({ReturnValueCondition(WithinRange, - {{EOFv, EOFv}, {0, UCharRangeMax}})}, - ErrnoIrrelevant)); addToFunctionSummaryMap( "getchar", Signature(ArgTypes{}, RetType{IntTy}), Summary(NoEvalCall) @@ -2139,7 +2132,17 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( std::move(GetenvSummary)); } - if (ModelPOSIX) { + if (!ModelPOSIX) { + // Without POSIX use of 'errno' is not specified (in these cases). + // Add these functions without 'errno' checks. + addToFunctionSummaryMap( + {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), + Summary(NoEvalCall) + .Case({ReturnValueCondition(WithinRange, + {{EOFv, EOFv}, {0, UCharRangeMax}})}, + ErrnoIrrelevant) + .ArgConstraint(NotNull(ArgNo(0)))); + } else { const auto ReturnsZeroOrMinusOne = ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))}; const auto ReturnsZero = @@ -2231,6 +2234,63 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) .ArgConstraint(NotNull(ArgNo(0)))); + std::optional<QualType> Off_tTy = lookupTy("off_t"); + std::optional<RangeInt> Off_tMax = getMaxValue(Off_tTy); + + // int fgetc(FILE *stream); + // 'getc' is the same as 'fgetc' but may be a macro + addToFunctionSummaryMap( + {"getc", "fgetc"}, Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), + Summary(NoEvalCall) + .Case({ReturnValueCondition(WithinRange, {{0, UCharRangeMax}})}, + ErrnoMustNotBeChecked, GenericSuccessMsg) + .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))}, + ErrnoIrrelevant, GenericFailureMsg) + .ArgConstraint(NotNull(ArgNo(0)))); + + // int fputc(int c, FILE *stream); + // 'putc' is the same as 'fputc' but may be a macro + addToFunctionSummaryMap( + {"putc", "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)))); + + // char *fgets(char *restrict s, int n, FILE *restrict stream); + addToFunctionSummaryMap( + "fgets", + Signature(ArgTypes{CharPtrRestrictTy, IntTy, FilePtrRestrictTy}, + RetType{CharPtrTy}), + Summary(NoEvalCall) + .Case({ReturnValueCondition(BO_EQ, ArgNo(0))}, + ErrnoMustNotBeChecked, GenericSuccessMsg) + .Case({IsNull(Ret)}, ErrnoIrrelevant, GenericFailureMsg) + .ArgConstraint(NotNull(ArgNo(0))) + .ArgConstraint(ArgumentCondition(1, WithinRange, Range(0, IntMax))) + .ArgConstraint( + BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1))) + .ArgConstraint(NotNull(ArgNo(2)))); + + // int fputs(const char *restrict s, FILE *restrict stream); + addToFunctionSummaryMap( + "fputs", + Signature(ArgTypes{ConstCharPtrRestrictTy, FilePtrRestrictTy}, + RetType{IntTy}), + Summary(NoEvalCall) + .Case(ReturnsNonnegative, ErrnoMustNotBeChecked, GenericSuccessMsg) + .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))}, + ErrnoNEZeroIrrelevant, GenericFailureMsg) + .ArgConstraint(NotNull(ArgNo(0))) + .ArgConstraint(NotNull(ArgNo(1)))); + // int ungetc(int c, FILE *stream); addToFunctionSummaryMap( "ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}), @@ -2250,9 +2310,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( 0, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})) .ArgConstraint(NotNull(ArgNo(1)))); - std::optional<QualType> Off_tTy = lookupTy("off_t"); - std::optional<RangeInt> Off_tMax = getMaxValue(Off_tTy); - // int fseek(FILE *stream, long offset, int whence); // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use // these for condition of arg 2. |