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 |