https://github.com/benshi001 updated https://github.com/llvm/llvm-project/pull/76776
>From 19122ac9df0e621ffb25fcb64bfad2336476b94b Mon Sep 17 00:00:00 2001 From: Ben Shi <benn...@tencent.com> Date: Wed, 3 Jan 2024 11:30:57 +0800 Subject: [PATCH] [clang][analyzer] Support 'fdopen' in the StreamChecker --- clang/docs/ReleaseNotes.rst | 5 +++-- clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp | 1 + .../test/Analysis/Inputs/system-header-simulator.h | 1 + clang/test/Analysis/stream-error.c | 13 +++++++++++-- clang/test/Analysis/stream-non-posix-function.c | 7 ++++++- clang/test/Analysis/stream-note.c | 10 ++++++++++ clang/test/Analysis/stream-stdlibraryfunctionargs.c | 8 ++++++++ clang/test/Analysis/stream.c | 7 +++++++ 8 files changed, 47 insertions(+), 5 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0c8fec691bf3c9..5aaa4436d21104 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1158,8 +1158,9 @@ Improvements `0954dc3fb921 <https://github.com/llvm/llvm-project/commit/0954dc3fb9214b994623f5306473de075f8e3593>`_) - Improved the ``alpha.unix.Stream`` checker by modeling more functions like, - ``fflush``, ``fputs``, ``fgetc``, ``fputc``, ``fopen``, ``fopen``, ``fgets``. - (`#74296 <https://github.com/llvm/llvm-project/pull/74296>`_, + ``fflush``, ``fputs``, ``fgetc``, ``fputc``, ``fopen``, ``fdopen``, ``fgets``, ``tmpfile``. + (`#76776 <https://github.com/llvm/llvm-project/pull/76776>`_, + `#74296 <https://github.com/llvm/llvm-project/pull/74296>`_, `#73335 <https://github.com/llvm/llvm-project/pull/73335>`_, `#72627 <https://github.com/llvm/llvm-project/pull/72627>`_, `#71518 <https://github.com/llvm/llvm-project/pull/71518>`_, diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 254b36ed03968d..25da3c18e8519f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -239,6 +239,7 @@ class StreamChecker : public Checker<check::PreCall, eval::Call, private: CallDescriptionMap<FnDescription> FnDescriptions = { {{{"fopen"}, 2}, {nullptr, &StreamChecker::evalFopen, ArgNone}}, + {{{"fdopen"}, 2}, {nullptr, &StreamChecker::evalFopen, ArgNone}}, {{{"freopen"}, 3}, {&StreamChecker::preFreopen, &StreamChecker::evalFreopen, 2}}, {{{"tmpfile"}, 0}, {nullptr, &StreamChecker::evalFopen, ArgNone}}, diff --git a/clang/test/Analysis/Inputs/system-header-simulator.h b/clang/test/Analysis/Inputs/system-header-simulator.h index 409a969a0d4cce..8c43c48c6a3e45 100644 --- a/clang/test/Analysis/Inputs/system-header-simulator.h +++ b/clang/test/Analysis/Inputs/system-header-simulator.h @@ -43,6 +43,7 @@ FILE *funopen(const void *, int (*)(void *)); FILE *fopen(const char *restrict path, const char *restrict mode); +FILE *fdopen(int fd, const char *mode); FILE *tmpfile(void); FILE *freopen(const char *restrict pathname, const char *restrict mode, FILE *restrict stream); int fclose(FILE *fp); diff --git a/clang/test/Analysis/stream-error.c b/clang/test/Analysis/stream-error.c index 37e1e54dfc89d5..13c6684b5840af 100644 --- a/clang/test/Analysis/stream-error.c +++ b/clang/test/Analysis/stream-error.c @@ -21,6 +21,15 @@ void error_fopen(void) { fclose(F); } +void error_fdopen(int fd) { + FILE *F = fdopen(fd, "r"); + if (!F) + return; + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + fclose(F); +} + void error_freopen(void) { FILE *F = fopen("file", "r"); if (!F) @@ -146,8 +155,8 @@ void error_fgets(void) { fgets(Buf, sizeof(Buf), F); // expected-warning {{Stream might be already closed}} } -void error_fputc(void) { - FILE *F = tmpfile(); +void error_fputc(int fd) { + FILE *F = fdopen(fd, "w"); if (!F) return; int Ret = fputc('X', F); diff --git a/clang/test/Analysis/stream-non-posix-function.c b/clang/test/Analysis/stream-non-posix-function.c index c6dc65afe788bb..091d95a573ddf9 100644 --- a/clang/test/Analysis/stream-non-posix-function.c +++ b/clang/test/Analysis/stream-non-posix-function.c @@ -8,11 +8,16 @@ typedef struct _FILE FILE; // These functions are not standard C library functions. FILE *tmpfile(const char *restrict path); // Real 'tmpfile' should have exactly 0 formal parameters. FILE *fopen(const char *restrict path); // Real 'fopen' should have exactly 2 formal parameters. +FILE *fdopen(int fd); // Real 'fdopen' should have exactly 2 formal parameters. void test_fopen_non_posix(void) { FILE *fp = fopen("file"); // no-leak: This isn't the standard POSIX `fopen`, we don't know the semantics of this call. } void test_tmpfile_non_posix(void) { - FILE *fp = tmpfile("file"); // // no-leak: This isn't the standard POSIX `tmpfile`, we don't know the semantics of this call. + FILE *fp = tmpfile("file"); // no-leak: This isn't the standard POSIX `tmpfile`, we don't know the semantics of this call. +} + +void test_fdopen_non_posix(int fd) { + FILE *fp = fdopen(fd); // no-leak: This isn't the standard POSIX `fdopen`, we don't know the semantics of this call. } diff --git a/clang/test/Analysis/stream-note.c b/clang/test/Analysis/stream-note.c index b9fdc16b19e55e..e412015eb68393 100644 --- a/clang/test/Analysis/stream-note.c +++ b/clang/test/Analysis/stream-note.c @@ -54,6 +54,16 @@ void check_note_freopen(void) { // expected-warning@-1 {{Opened stream never closed. Potential resource leak}} // expected-note@-2 {{Opened stream never closed. Potential resource leak}} +void check_note_fdopen(int fd) { + FILE *F = fdopen(fd, "r"); // expected-note {{Stream opened here}} + if (!F) + // expected-note@-1 {{'F' is non-null}} + // expected-note@-2 {{Taking false branch}} + return; +} +// expected-warning@-1 {{Opened stream never closed. Potential resource leak}} +// expected-note@-2 {{Opened stream never closed. Potential resource leak}} + void check_note_leak_2(int c) { FILE *F1 = fopen("foo1.c", "r"); // expected-note {{Stream opened here}} // stdargs-note@-1 {{'fopen' is successful}} diff --git a/clang/test/Analysis/stream-stdlibraryfunctionargs.c b/clang/test/Analysis/stream-stdlibraryfunctionargs.c index 938901ec088291..0053510163efc0 100644 --- a/clang/test/Analysis/stream-stdlibraryfunctionargs.c +++ b/clang/test/Analysis/stream-stdlibraryfunctionargs.c @@ -23,6 +23,14 @@ void test_fopen(void) { // stdfunc-warning{{should not be NULL}} } +void test_fdopen(int fd) { + FILE *fp = fdopen(fd, "r"); + clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}} any-warning{{FALSE}} + fclose(fp); // \ + // stream-warning{{Stream pointer might be NULL}} \ + // stdfunc-warning{{should not be NULL}} +} + void test_tmpfile(void) { FILE *fp = tmpfile(); clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}} any-warning{{FALSE}} diff --git a/clang/test/Analysis/stream.c b/clang/test/Analysis/stream.c index 0b655dbdc571fe..060d561c1fe1c2 100644 --- a/clang/test/Analysis/stream.c +++ b/clang/test/Analysis/stream.c @@ -102,6 +102,13 @@ void f_open(void) { fclose(p); } +void f_dopen(int fd) { + FILE *F = fdopen(fd, "r"); + char buf[1024]; + fread(buf, 1, 1, F); // expected-warning {{Stream pointer might be NULL}} + fclose(F); +} + void f_seek(void) { FILE *p = fopen("foo", "r"); if (!p) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits