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
    |

Reply via email to