https://github.com/benshi001 updated https://github.com/llvm/llvm-project/pull/77902
>From 97d753446ffc8eb9c701effb52dd671afc73e1dd Mon Sep 17 00:00:00 2001 From: Ben Shi <benn...@tencent.com> Date: Fri, 12 Jan 2024 18:17:39 +0800 Subject: [PATCH 1/2] [clang][analyzer] Improve modeling of 'fseeko' and 'ftello' in StdLibraryFunctionsChecker --- .../Checkers/StdLibraryFunctionsChecker.cpp | 12 +++++-- clang/test/Analysis/stream-errno.c | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 3b36565681a7f3..f934444eb4bf48 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -2859,13 +2859,19 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( "fseeko", Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}), Summary(NoEvalCall) - .Case(ReturnsZeroOrMinusOne, ErrnoIrrelevant) - .ArgConstraint(NotNull(ArgNo(0)))); + .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) + .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) + .ArgConstraint(NotNull(ArgNo(0))) + .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}}))); // off_t ftello(FILE *stream); addToFunctionSummaryMap( "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}), - Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); + Summary(NoEvalCall) + .Case({ReturnValueCondition(WithinRange, Range(0, LongMax))}, + ErrnoUnchanged, GenericSuccessMsg) + .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) + .ArgConstraint(NotNull(ArgNo(0)))); // void *mmap(void *addr, size_t length, int prot, int flags, int fd, // off_t offset); diff --git a/clang/test/Analysis/stream-errno.c b/clang/test/Analysis/stream-errno.c index f44ee6070708b2..bc184d5ce018d3 100644 --- a/clang/test/Analysis/stream-errno.c +++ b/clang/test/Analysis/stream-errno.c @@ -129,6 +129,7 @@ void check_fseek(void) { int S = fseek(F, 11, SEEK_SET); if (S != 0) { clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}} + clang_analyzer_eval(S == -1); // expected-warning{{TRUE}} if (errno) {} // no-warning fclose(F); return; @@ -136,6 +137,21 @@ void check_fseek(void) { if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}} } +void check_fseeko(void) { + FILE *F = tmpfile(); + if (!F) + return; + int S = fseeko(F, 11, SEEK_SET); + if (S == -1) { + clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}} + if (errno) {} // no-warning + } else { + clang_analyzer_eval(S == 0); // expected-warning{{TRUE}} + if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}} + } + fclose(F); +} + void check_no_errno_change(void) { FILE *F = tmpfile(); if (!F) @@ -197,6 +213,22 @@ void check_ftell(void) { fclose(F); } +void check_ftello(void) { + FILE *F = tmpfile(); + if (!F) + return; + errno = 0; + off_t Ret = ftello(F); + if (Ret >= 0) { + clang_analyzer_eval(errno == 0); // expected-warning{{TRUE}} + } else { + clang_analyzer_eval(Ret == -1); // expected-warning{{TRUE}} + clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}} + } + if (errno) {} // no-warning + fclose(F); +} + void check_rewind(void) { FILE *F = tmpfile(); if (!F) >From abf8a48d6c188f83d05ce7ae1604767b18a27490 Mon Sep 17 00:00:00 2001 From: Ben Shi <benn...@tencent.com> Date: Sat, 13 Jan 2024 12:33:35 +0800 Subject: [PATCH 2/2] [clang][analyzer] Improve modeling of 'fseeko' and 'ftello' in StdLibraryFunctionsChecker --- .../Checkers/StdLibraryFunctionsChecker.cpp | 43 ++++++++++--------- .../Analysis/std-c-library-functions-POSIX.c | 4 +- clang/test/Analysis/stream-errno.c | 5 +-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index f934444eb4bf48..641ebe90f88e2e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -2220,6 +2220,9 @@ 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. @@ -2232,6 +2235,16 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( .ArgConstraint(NotNull(ArgNo(0))) .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}}))); + // int fseeko(FILE *stream, off_t offset, int whence); + addToFunctionSummaryMap( + "fseeko", + Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}), + Summary(NoEvalCall) + .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) + .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) + .ArgConstraint(NotNull(ArgNo(0))) + .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}}))); + // int fgetpos(FILE *restrict stream, fpos_t *restrict pos); // From 'The Open Group Base Specifications Issue 7, 2018 edition': // "The fgetpos() function shall not change the setting of errno if @@ -2279,6 +2292,15 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) .ArgConstraint(NotNull(ArgNo(0)))); + // off_t ftello(FILE *stream); + addToFunctionSummaryMap( + "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}), + Summary(NoEvalCall) + .Case({ReturnValueCondition(WithinRange, Range(0, Off_tMax))}, + ErrnoMustNotBeChecked, GenericSuccessMsg) + .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) + .ArgConstraint(NotNull(ArgNo(0)))); + // int fileno(FILE *stream); addToFunctionSummaryMap( "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}), @@ -2410,8 +2432,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( .ArgConstraint( ArgumentCondition(0, WithinRange, Range(0, IntMax)))); - std::optional<QualType> Off_tTy = lookupTy("off_t"); - // int truncate(const char *path, off_t length); addToFunctionSummaryMap( "truncate", @@ -2854,25 +2874,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( "rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}), Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0)))); - // int fseeko(FILE *stream, off_t offset, int whence); - addToFunctionSummaryMap( - "fseeko", - Signature(ArgTypes{FilePtrTy, Off_tTy, IntTy}, RetType{IntTy}), - Summary(NoEvalCall) - .Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg) - .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) - .ArgConstraint(NotNull(ArgNo(0))) - .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}}))); - - // off_t ftello(FILE *stream); - addToFunctionSummaryMap( - "ftello", Signature(ArgTypes{FilePtrTy}, RetType{Off_tTy}), - Summary(NoEvalCall) - .Case({ReturnValueCondition(WithinRange, Range(0, LongMax))}, - ErrnoUnchanged, GenericSuccessMsg) - .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) - .ArgConstraint(NotNull(ArgNo(0)))); - // void *mmap(void *addr, size_t length, int prot, int flags, int fd, // off_t offset); // FIXME: Improve for errno modeling. diff --git a/clang/test/Analysis/std-c-library-functions-POSIX.c b/clang/test/Analysis/std-c-library-functions-POSIX.c index daa4d904c3ac5e..8a26e0b0f27286 100644 --- a/clang/test/Analysis/std-c-library-functions-POSIX.c +++ b/clang/test/Analysis/std-c-library-functions-POSIX.c @@ -21,6 +21,8 @@ // CHECK: Loaded summary for: FILE *freopen(const char *restrict pathname, const char *restrict mode, FILE *restrict stream) // CHECK: Loaded summary for: int fclose(FILE *stream) // CHECK: Loaded summary for: int fseek(FILE *stream, long offset, int whence) +// CHECK: Loaded summary for: int fseeko(FILE *stream, off_t offset, int whence) +// CHECK: Loaded summary for: off_t ftello(FILE *stream) // CHECK: Loaded summary for: int fileno(FILE *stream) // CHECK: Loaded summary for: long a64l(const char *str64) // CHECK: Loaded summary for: char *l64a(long value) @@ -80,8 +82,6 @@ // CHECK: Loaded summary for: void rewinddir(DIR *dir) // CHECK: Loaded summary for: void seekdir(DIR *dirp, long loc) // CHECK: Loaded summary for: int rand_r(unsigned int *seedp) -// CHECK: Loaded summary for: int fseeko(FILE *stream, off_t offset, int whence) -// CHECK: Loaded summary for: off_t ftello(FILE *stream) // CHECK: Loaded summary for: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) // CHECK: Loaded summary for: void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off64_t offset) // CHECK: Loaded summary for: int pipe(int fildes[2]) diff --git a/clang/test/Analysis/stream-errno.c b/clang/test/Analysis/stream-errno.c index bc184d5ce018d3..13981e9094d1c9 100644 --- a/clang/test/Analysis/stream-errno.c +++ b/clang/test/Analysis/stream-errno.c @@ -217,15 +217,14 @@ void check_ftello(void) { FILE *F = tmpfile(); if (!F) return; - errno = 0; off_t Ret = ftello(F); if (Ret >= 0) { - clang_analyzer_eval(errno == 0); // expected-warning{{TRUE}} + if (errno) {} // expected-warning{{An undefined value may be read from 'errno'}} } else { clang_analyzer_eval(Ret == -1); // expected-warning{{TRUE}} clang_analyzer_eval(errno != 0); // expected-warning{{TRUE}} + if (errno) {} // no-warning } - if (errno) {} // no-warning fclose(F); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits