Skip to content

Commit 18c0f59

Browse files
authored
[clang][analyzer] Support 'fdopen' in the StreamChecker (#76776)
1 parent 75365b2 commit 18c0f59

File tree

8 files changed

+47
-5
lines changed

8 files changed

+47
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,8 +1162,9 @@ Improvements
11621162
`0954dc3fb921 <https://github.com/llvm/llvm-project/commit/0954dc3fb9214b994623f5306473de075f8e3593>`_)
11631163

11641164
- Improved the ``alpha.unix.Stream`` checker by modeling more functions like,
1165-
``fflush``, ``fputs``, ``fgetc``, ``fputc``, ``fopen``, ``fopen``, ``fgets``.
1166-
(`#74296 <https://github.com/llvm/llvm-project/pull/74296>`_,
1165+
``fflush``, ``fputs``, ``fgetc``, ``fputc``, ``fopen``, ``fdopen``, ``fgets``, ``tmpfile``.
1166+
(`#76776 <https://github.com/llvm/llvm-project/pull/76776>`_,
1167+
`#74296 <https://github.com/llvm/llvm-project/pull/74296>`_,
11671168
`#73335 <https://github.com/llvm/llvm-project/pull/73335>`_,
11681169
`#72627 <https://github.com/llvm/llvm-project/pull/72627>`_,
11691170
`#71518 <https://github.com/llvm/llvm-project/pull/71518>`_,

clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
239239
private:
240240
CallDescriptionMap<FnDescription> FnDescriptions = {
241241
{{{"fopen"}, 2}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
242+
{{{"fdopen"}, 2}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
242243
{{{"freopen"}, 3},
243244
{&StreamChecker::preFreopen, &StreamChecker::evalFreopen, 2}},
244245
{{{"tmpfile"}, 0}, {nullptr, &StreamChecker::evalFopen, ArgNone}},

clang/test/Analysis/Inputs/system-header-simulator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ FILE *funopen(const void *,
4343
int (*)(void *));
4444

4545
FILE *fopen(const char *restrict path, const char *restrict mode);
46+
FILE *fdopen(int fd, const char *mode);
4647
FILE *tmpfile(void);
4748
FILE *freopen(const char *restrict pathname, const char *restrict mode, FILE *restrict stream);
4849
int fclose(FILE *fp);

clang/test/Analysis/stream-error.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ void error_fopen(void) {
2121
fclose(F);
2222
}
2323

24+
void error_fdopen(int fd) {
25+
FILE *F = fdopen(fd, "r");
26+
if (!F)
27+
return;
28+
clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
29+
clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
30+
fclose(F);
31+
}
32+
2433
void error_freopen(void) {
2534
FILE *F = fopen("file", "r");
2635
if (!F)
@@ -146,8 +155,8 @@ void error_fgets(void) {
146155
fgets(Buf, sizeof(Buf), F); // expected-warning {{Stream might be already closed}}
147156
}
148157

149-
void error_fputc(void) {
150-
FILE *F = tmpfile();
158+
void error_fputc(int fd) {
159+
FILE *F = fdopen(fd, "w");
151160
if (!F)
152161
return;
153162
int Ret = fputc('X', F);

clang/test/Analysis/stream-non-posix-function.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@ typedef struct _FILE FILE;
88
// These functions are not standard C library functions.
99
FILE *tmpfile(const char *restrict path); // Real 'tmpfile' should have exactly 0 formal parameters.
1010
FILE *fopen(const char *restrict path); // Real 'fopen' should have exactly 2 formal parameters.
11+
FILE *fdopen(int fd); // Real 'fdopen' should have exactly 2 formal parameters.
1112

1213
void test_fopen_non_posix(void) {
1314
FILE *fp = fopen("file"); // no-leak: This isn't the standard POSIX `fopen`, we don't know the semantics of this call.
1415
}
1516

1617
void test_tmpfile_non_posix(void) {
17-
FILE *fp = tmpfile("file"); // // no-leak: This isn't the standard POSIX `tmpfile`, we don't know the semantics of this call.
18+
FILE *fp = tmpfile("file"); // no-leak: This isn't the standard POSIX `tmpfile`, we don't know the semantics of this call.
19+
}
20+
21+
void test_fdopen_non_posix(int fd) {
22+
FILE *fp = fdopen(fd); // no-leak: This isn't the standard POSIX `fdopen`, we don't know the semantics of this call.
1823
}

clang/test/Analysis/stream-note.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@ void check_note_freopen(void) {
5454
// expected-warning@-1 {{Opened stream never closed. Potential resource leak}}
5555
// expected-note@-2 {{Opened stream never closed. Potential resource leak}}
5656

57+
void check_note_fdopen(int fd) {
58+
FILE *F = fdopen(fd, "r"); // expected-note {{Stream opened here}}
59+
if (!F)
60+
// expected-note@-1 {{'F' is non-null}}
61+
// expected-note@-2 {{Taking false branch}}
62+
return;
63+
}
64+
// expected-warning@-1 {{Opened stream never closed. Potential resource leak}}
65+
// expected-note@-2 {{Opened stream never closed. Potential resource leak}}
66+
5767
void check_note_leak_2(int c) {
5868
FILE *F1 = fopen("foo1.c", "r"); // expected-note {{Stream opened here}}
5969
// stdargs-note@-1 {{'fopen' is successful}}

clang/test/Analysis/stream-stdlibraryfunctionargs.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ void test_fopen(void) {
2323
// stdfunc-warning{{should not be NULL}}
2424
}
2525

26+
void test_fdopen(int fd) {
27+
FILE *fp = fdopen(fd, "r");
28+
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}} any-warning{{FALSE}}
29+
fclose(fp); // \
30+
// stream-warning{{Stream pointer might be NULL}} \
31+
// stdfunc-warning{{should not be NULL}}
32+
}
33+
2634
void test_tmpfile(void) {
2735
FILE *fp = tmpfile();
2836
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}} any-warning{{FALSE}}

clang/test/Analysis/stream.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ void f_open(void) {
102102
fclose(p);
103103
}
104104

105+
void f_dopen(int fd) {
106+
FILE *F = fdopen(fd, "r");
107+
char buf[1024];
108+
fread(buf, 1, 1, F); // expected-warning {{Stream pointer might be NULL}}
109+
fclose(F);
110+
}
111+
105112
void f_seek(void) {
106113
FILE *p = fopen("foo", "r");
107114
if (!p)

0 commit comments

Comments
 (0)