[committed] analyzer: fix ICE on bind/connect with a constant fd [PR107928]

Message ID 20221201023317.3722715-1-dmalcolm@redhat.com
State Committed
Commit 45a75fd3d31265e43aa3ce7a5e851083d534b00b
Headers
Series [committed] analyzer: fix ICE on bind/connect with a constant fd [PR107928] |

Commit Message

David Malcolm Dec. 1, 2022, 2:33 a.m. UTC
  Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r13-4424-g45a75fd3d31265.

gcc/analyzer/ChangeLog:
	PR analyzer/107928
	* sm-fd.cc (fd_state_machine::on_bind): Handle m_constant_fd in
	the "success" outcome.
	(fd_state_machine::on_connect): Likewise.
	* sm-fd.dot: Add "constant_fd" state and its transitions.

gcc/testsuite/ChangeLog:
	PR analyzer/107928
	* gcc.dg/analyzer/fd-bind-pr107928.c: New test.
	* gcc.dg/analyzer/fd-connect-pr107928.c: New test.
	* gcc.dg/analyzer/fd-stream-socket-active-open.c
	(test_active_open_from_connect_constant): New, adapted from
	test_active_open_from_connect.
	* gcc.dg/analyzer/fd-stream-socket-passive-open.c
	(test_passive_open_from_bind_constant): New, adapted from
	test_passive_open_from_bind.
	(test_passive_open_from_listen_constant): New, adapted from
	test_passive_open_from_listen.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
---
 gcc/analyzer/sm-fd.cc                         |  6 +-
 gcc/analyzer/sm-fd.dot                        |  6 ++
 .../gcc.dg/analyzer/fd-bind-pr107928.c        | 10 ++
 .../gcc.dg/analyzer/fd-connect-pr107928.c     | 10 ++
 .../analyzer/fd-stream-socket-active-open.c   | 31 ++++++
 .../analyzer/fd-stream-socket-passive-open.c  | 98 +++++++++++++++++++
 6 files changed, 159 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/fd-bind-pr107928.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/fd-connect-pr107928.c
  

Patch

diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc
index 794733e55ca..799847cb8e8 100644
--- a/gcc/analyzer/sm-fd.cc
+++ b/gcc/analyzer/sm-fd.cc
@@ -1861,7 +1861,8 @@  fd_state_machine::on_bind (const call_details &cd,
 	next_state = m_bound_datagram_socket;
       else if (old_state == m_new_unknown_socket)
 	next_state = m_bound_unknown_socket;
-      else if (old_state == m_start)
+      else if (old_state == m_start
+	       || old_state == m_constant_fd)
 	next_state = m_bound_unknown_socket;
       else if (old_state == m_stop)
 	next_state = m_stop;
@@ -2116,7 +2117,8 @@  fd_state_machine::on_connect (const call_details &cd,
 	next_state = m_new_datagram_socket;
       else if (old_state == m_new_unknown_socket)
 	next_state = m_stop;
-      else if (old_state == m_start)
+      else if (old_state == m_start
+	       || old_state == m_constant_fd)
 	next_state = m_stop;
       else if (old_state == m_stop)
 	next_state = m_stop;
diff --git a/gcc/analyzer/sm-fd.dot b/gcc/analyzer/sm-fd.dot
index da925b0989f..d7676b1f779 100644
--- a/gcc/analyzer/sm-fd.dot
+++ b/gcc/analyzer/sm-fd.dot
@@ -27,6 +27,9 @@  digraph "fd" {
   /* Start state.  */
   start;
 
+  /* State for a constant file descriptor (>= 0).  */
+  constant_fd;
+
   /* States representing a file descriptor that hasn't yet been
     checked for validity after opening, for three different
     access modes.  */
@@ -129,6 +132,7 @@  digraph "fd" {
 
   /* On "bind".  */
   start -> bound_unknown_socket [label="when 'bind(X, ...)' succeeds"];
+  constant_fd -> bound_unknown_socket [label="when 'bind(X, ...)' succeeds"];
   new_stream_socket -> bound_stream_socket [label="when 'bind(X, ...)' succeeds"];
   new_datagram_socket -> bound_datagram_socket [label="when 'bind(X, ...)' succeeds"];
   new_unknown_socket -> bound_unknown_socket [label="when 'bind(X, ...)' succeeds"];
@@ -140,12 +144,14 @@  digraph "fd" {
 
   /* On "accept".  */
   start -> connected_stream_socket [label="when 'accept(OTHER, ...)' succeeds on a listening_stream_socket"];
+  constant_fd -> connected_stream_socket [label="when 'accept(OTHER, ...)' succeeds on a listening_stream_socket"];
 
   /* On "connect".  */
   new_stream_socket -> connected_stream_socket [label="when 'connect(X, ...)' succeeds"];
   new_datagram_socket -> new_datagram_socket [label="when 'connect(X, ...)' succeeds"];
   new_unknown_socket -> stop [label="when 'connect(X, ...)' succeeds"];
   start -> stop [label="when 'connect(X, ...)' succeeds"];
+  constant_fd -> stop [label="when 'connect(X, ...)' succeeds"];
 
   /* on_condition.  */
   unchecked_read_write -> valid_read_write [label="on 'X >= 0'"];
diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-bind-pr107928.c b/gcc/testsuite/gcc.dg/analyzer/fd-bind-pr107928.c
new file mode 100644
index 00000000000..acc1a1df8e0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/fd-bind-pr107928.c
@@ -0,0 +1,10 @@ 
+struct sa {};
+
+int
+bind (int, struct sa *, int);
+
+int
+foo (struct sa sa)
+{
+  return bind (1, &sa, sizeof sa);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-connect-pr107928.c b/gcc/testsuite/gcc.dg/analyzer/fd-connect-pr107928.c
new file mode 100644
index 00000000000..f3bdc87c210
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/fd-connect-pr107928.c
@@ -0,0 +1,10 @@ 
+struct sa {};
+
+int
+connect (int, struct sa *, int);
+
+int
+foo (struct sa sa)
+{
+  return connect (1, &sa, sizeof sa);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c
index 841894cc1bd..89ea82e59c9 100644
--- a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c
+++ b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c
@@ -74,3 +74,34 @@  void test_active_open_from_connect (int fd, const char *sockname, void *buf)
   close (fd);
   __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-stop'" } */
 }
+
+void test_active_open_from_connect_constant (const char *sockname, void *buf)
+{
+  const int fd = 42;
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+
+  struct sockaddr_un addr;
+  memset (&addr, 0, sizeof (addr));
+  addr.sun_family = AF_UNIX;
+  strncpy (addr.sun_path, sockname, sizeof(addr.sun_path) - 1);
+
+  errno = 0;
+  if (connect (fd, (struct sockaddr *)&addr, sizeof (addr)) == -1)
+    {
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+      __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+      close (fd);
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+      return;
+    }
+
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-stop'" } */
+  __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+
+  write (fd, "hello", 6);
+  read (fd, buf, 100);
+
+  close (fd);
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-stop'" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c
index a61091101ed..8af52904d7e 100644
--- a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c
+++ b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c
@@ -129,6 +129,62 @@  void test_passive_open_from_bind (int fd, const char *sockname, void *buf)
   __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
 }
 
+void test_passive_open_from_bind_constant (const char *sockname, void *buf)
+{
+  const int fd = 42;
+  struct sockaddr_un addr;
+  int afd;
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+  memset (&addr, 0, sizeof (addr));
+  addr.sun_family = AF_UNIX;
+  strncpy (addr.sun_path, sockname, sizeof(addr.sun_path) - 1);
+  errno = 0;
+  if (bind (fd, (struct sockaddr *)&addr, sizeof (addr)) == -1)
+    {
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+      __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+      close (fd);
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+      return;
+    }
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-bound-unknown-socket'" } */
+  __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+  if (listen (fd, 5) == -1)
+    {
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-bound-unknown-socket'" } */
+      __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+      close (fd);
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+      return;
+    }
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+  __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+  afd = accept (fd, NULL, NULL);
+  if (afd == -1)
+    {
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+      __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+      close (fd);
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+      return;
+    }
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+  __analyzer_dump_state ("file-descriptor", afd); /* { dg-warning "state: 'fd-connected-stream-socket'" } */
+  __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (afd >= 0); /* { dg-warning "TRUE" } */
+
+  write (afd, "hello", 6);  
+  read (afd, buf, 100);
+
+  close (afd);
+  close (fd);
+  __analyzer_dump_state ("file-descriptor", afd); /* { dg-warning "state: 'fd-closed'" } */
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+}
+
 void test_passive_open_from_listen (int fd, void *buf)
 {
   int afd;
@@ -169,6 +225,48 @@  void test_passive_open_from_listen (int fd, void *buf)
   __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
 }
 
+
+void test_passive_open_from_listen_constant (void *buf)
+{
+  const int fd = 42;
+  int afd;
+  errno = 0;
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+  if (listen (fd, 5) == -1)
+    {
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+      __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+      close (fd);
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+      return;
+    }
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+  __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+  afd = accept (fd, NULL, NULL);
+  if (afd == -1)
+    {
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+      __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+      close (fd);
+      __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+      return;
+    }
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+  __analyzer_dump_state ("file-descriptor", afd); /* { dg-warning "state: 'fd-connected-stream-socket'" } */
+  __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (afd >= 0); /* { dg-warning "TRUE" } */
+
+  write (afd, "hello", 6);
+  read (afd, buf, 100);
+
+  close (afd);
+  close (fd);
+  __analyzer_dump_state ("file-descriptor", afd); /* { dg-warning "state: 'fd-closed'" } */
+  __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+}
+
 void test_passive_open_from_accept (int fd, void *buf)
 {
   int afd;