https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121377
Bug ID: 121377
Summary: False positive with -Wanalyzer-fd-phase-mismatch
Product: gcc
Version: 14.3.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: lminder at gmx dot net
Target Milestone: ---
Created attachment 62035
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=62035&action=edit
Preprocessed source file.
I'm creating a socket, binding it, then connecting. When using these steps, I
get, with -fanalyzer, a message as follows:
‘connect’ expects a new socket file descriptor but ‘sockfd’ is bound
That seems mistaken; I obviously need to bind() the socket before connect(), if
I want it to be effective. Indeed, presumably the compiler should instead
report a problem if I try to bind _after_ connect(). Relevant excerpt from the
ip(7) man page: "When connect(2) is called on an unbound socket, the socket is
automatically bound to a random free port or to a usable shared port with the
local address set to INADDR_ANY." Further, in the manual page to bind(), under
return codes: "EINVAL The socket is already bound to an address."
This is on linux. I've verified, using godbolt.org, that the bug is also
present in gcc trunk, not just 14.3.0.
gcc -v output:
Using built-in specs.
COLLECT_GCC=/nix/store/qnwxpk0in4bm43q2qnykvkjxa9qhqd0z-gcc-14.3.0/bin/gcc
COLLECT_LTO_WRAPPER=/nix/store/qnwxpk0in4bm43q2qnykvkjxa9qhqd0z-gcc-14.3.0/libexec/gcc/x86_64-unknown-linux-gnu/14.3.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ../gcc-14.3.0/configure
--prefix=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gcc-14.3.0
--with-gmp-include=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gmp-6.3.0-dev/include
--with-gmp-lib=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gmp-6.3.0/lib
--with-mpfr-include=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-mpfr-4.2.2-dev/include
--with-mpfr-lib=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-mpfr-4.2.2/lib
--with-mpc=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-libmpc-1.3.1
--with-native-system-header-dir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-glibc-2.40-66-dev/include
--with-build-sysroot=/
--with-gxx-include-dir=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-gcc-14.3.0/include/c++/14.3.0/
--program-prefix= --enable-lto --disable-libstdcxx-pch
--without-included-gettext --with-system-zlib --enable-static
--enable-languages=c,c++ --disable-multilib --enable-plugin --disable-libcc1
--with-isl=/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-isl-0.20
--disable-bootstrap --build=x86_64-unknown-linux-gnu
--host=x86_64-unknown-linux-gnu --target=x86_64-unknown-linux-gnu
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 14.3.0 (GCC)
Simple example (see attachment for preprocessed output):
#include <assert.h>
#include <arpa/inet.h> // for sockaddr_in, inet_pton()
#include <sys/socket.h> // for socket functions
typedef unsigned long size_t;
void* memset(void* s, int c, size_t n);
int close(int);
int main() {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
assert(sockfd >= 0);
// Bind to local port 1234
struct sockaddr_in local_addr;
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = htonl(INADDR_ANY); // or
inet_pton("127.0.0.1", ...)
local_addr.sin_port = htons(1234);
int e = bind(sockfd, (struct sockaddr *)&local_addr, sizeof(local_addr));
assert(e == 0);
// Connect to 127.0.0.1:4321
struct sockaddr_in remote_addr;
memset(&remote_addr, 0, sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(4321);
e = inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);
assert(e == 1);
e = connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(remote_addr));
assert(e == 0);
// Send packet using send()
const char message[] = "Hello, UDP";
send(sockfd, message, sizeof(message), 0);
close(sockfd);
return 0;
}
Compiler output:
analyzer_fd_min.c: In function ‘main’:
analyzer_fd_min.c:36:9: warning: ‘connect’ on file descriptor ‘sockfd’ in wrong
phase [CWE-666] [-Wanalyzer-fd-phase-mismatch]
36 | e = connect(sockfd, (struct sockaddr *)&remote_addr,
sizeof(remote_addr));
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
‘main’: event 1
|
|analyzer_fd_min.c:15:18:
| 15 | int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
‘main’: event 2
|
| 15 | int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
‘main’: event 3
|
|analyzer_fd_min.c:16:36:
| 16 | assert(sockfd >= 0);
| | ^
| | |
| | (3) following ‘true’ branch
(when ‘sockfd >= 0’)...
|
‘main’: event 4
|
|analyzer_fd_min.c:20:5:
| 20 | memset(&local_addr, 0, sizeof(local_addr));
| | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (4) ...to here
|
‘main’: events 5-6
|
|analyzer_fd_min.c:25:13:
| 25 | int e = bind(sockfd, (struct sockaddr *)&local_addr,
sizeof(local_addr));
| |
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (5) datagram socket bound here
| | (6) when ‘bind’ succeeds
|
‘main’: event 7
|
|analyzer_fd_min.c:26:36:
| 26 | assert(e == 0);
| | ^
| | |
| | (7) following ‘true’ branch
(when ‘e == 0’)...
|
‘main’: event 8
|
|analyzer_fd_min.c:30:5:
| 30 | memset(&remote_addr, 0, sizeof(remote_addr));
| | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (8) ...to here
|
‘main’: event 9
|
|analyzer_fd_min.c:34:36:
| 34 | assert(e == 1);
| | ^
| | |
| | (9) following ‘true’ branch
(when ‘e == 1’)...
|
‘main’: events 10-11
|
|analyzer_fd_min.c:36:9:
| 36 | e = connect(sockfd, (struct sockaddr *)&remote_addr,
sizeof(remote_addr));
| |
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (10) ...to here
| | (11) ‘connect’ expects a new socket file descriptor but
‘sockfd’ is bound
|