https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128374
Bug ID: 128374
Summary: analyzer: sm-fd ignores 3-arg open(), rejects valid
socket() fds in fd_arg, and drops mode checks on
unchecked/non-literal fds
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: analyzer
Assignee: dmalcolm at gcc dot gnu.org
Reporter: 220245569 at seu dot edu.cn
CC: 220255623 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
Target Milestone: ---
Target: *-*-*
Reproducer
----------
$ cat trigger.c
#define O_RDONLY 0
#define O_WRONLY 1
#define O_CREAT 0100
#define SOCK_STREAM 1
int open (const char *, int, ...);
int socket (int, int, int);
int close (int);
void use_fd (int fd) __attribute__((fd_arg (1)));
void write_fd (int fd) __attribute__((fd_arg_write (1)));
void bug_3arg_open (const char *path)
{
int fd = open (path, O_RDONLY | O_CREAT, 0644);
if (fd >= 0)
write_fd (fd); /* false-positive fd-use-without-check; misses mode mismatch
& leak */
}
void bug_checked_socket (void)
{
int s = socket (2, SOCK_STREAM, 0);
if (s >= 0)
{
use_fd (s); /* false-positive fd-use-without-check after socket()
succeeds */
close (s);
}
}
void bug_unchecked_mode_mismatch (const char *path)
{
int fd = open (path, O_RDONLY);
write_fd (fd); /* warns fd-use-without-check, but misses access-mode-mismatch
*/
close (fd);
}
Compile flag: x86_64-linux-gnu-gcc -O0 -fanalyzer -S trigger.c
trigger.c: In function 'bug_3arg_open':
trigger.c:17:5: warning: 'write_fd' on possibly invalid file descriptor 'fd'
[-Wanalyzer-fd-use-without-check]
trigger.c: In function 'bug_checked_socket':
trigger.c:25:7: warning: 'use_fd' on possibly invalid file descriptor 's'
[-Wanalyzer-fd-use-without-check]
22 | int s = socket (2, SOCK_STREAM, 0);
| (1) stream socket created here
| (2) when 'socket' succeeds
23 | if (s >= 0)
| (3) following 'true' branch (when 's >= 0')...
25 | use_fd (s);
| (5) 's' could be invalid
# bug_unchecked_mode_mismatch warns fd-use-without-check at line 33 but misses
-Wanalyzer-fd-access-mode-mismatch
Root cause
----------
1. fd_state_machine::on_stmt (gcc/analyzer/sm-fd.cc:1333) matches open via
is_named_call_p (callee_fndecl, "open", *call, 2), which requires exactly
2 arguments. Any 3-argument open (path, O_RDONLY | O_CREAT, mode) is left
in m_start, causing false-positive -Wanalyzer-fd-use-without-check after
if (fd >= 0) and missing mode-mismatch / leak warnings.
2. check_for_fd_attrs (sm-fd.cc:1463) checks
!(is_valid_fd_p (state) || (state == m_stop)) and omits
is_socket_fd_p (state) (unlike check_for_open_fd at line 1911), so checked
socket() descriptors trigger a false-positive
-Wanalyzer-fd-use-without-check.
3. check_for_fd_attrs executes 'continue;' at line 1472 after warning on an
unchecked descriptor, skipping the DIRS_READ / DIRS_WRITE mode check; and
on_open (line 1522) checks TREE_CODE (arg) == INTEGER_CST on the raw GIMPLE
operand instead of querying the region model's constant svalue.
Suggested Fix
-------------
1. Accept both 2-argument and 3-argument open() calls in
fd_state_machine::on_stmt
(sm-fd.cc:1333).
2. Add is_socket_fd_p (state) to check_for_fd_attrs (sm-fd.cc:1463) and remove
the 'continue;' at line 1472.
3. In fd_state_machine::on_open (sm-fd.cc:1522), resolve non-INTEGER_CST flag
operands via the region model's maybe_get_constant ().