mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 12:00:11 -05:00
180 lines
7.6 KiB
Plaintext
180 lines
7.6 KiB
Plaintext
/* An overview of the state machine from sm-fd.cc.
|
|
Copyright (C) 2022-2026 Free Software Foundation, Inc.
|
|
Contributed by David Malcolm <dmalcolm@redhat.com>.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
/* Keep this in-sync with sm-fd.cc */
|
|
|
|
digraph "fd" {
|
|
|
|
/* STATES. */
|
|
|
|
/* 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. */
|
|
unchecked_read_write;
|
|
unchecked_read_only;
|
|
unchecked_write_only;
|
|
|
|
/* States for representing a file descriptor that is known to be valid (>=
|
|
0), for three different access modes. */
|
|
valid_read_write;
|
|
valid_read_only;
|
|
valid_write_only;
|
|
|
|
/* State for a file descriptor that is known to be invalid (< 0). */
|
|
invalid;
|
|
|
|
/* State for a file descriptor that has been closed. */
|
|
closed;
|
|
|
|
/* States for FDs relating to socket APIs. */
|
|
|
|
/* Result of successful "socket" with SOCK_DGRAM. */
|
|
new_datagram_socket;
|
|
/* Result of successful "socket" with SOCK_STREAM. */
|
|
new_stream_socket;
|
|
/* Result of successful "socket" with unknown type. */
|
|
new_unknown_socket;
|
|
|
|
/* The above after a successful call to "bind". */
|
|
bound_datagram_socket;
|
|
bound_stream_socket;
|
|
bound_unknown_socket;
|
|
|
|
/* A bound socket after a successful call to "listen" (stream or unknown). */
|
|
listening_stream_socket;
|
|
|
|
/* (i) the new FD as a result of a succesful call to "accept" on a
|
|
listening socket (via a passive open), or
|
|
(ii) an active socket after a successful call to "connect"
|
|
(via an active open). */
|
|
connected_stream_socket;
|
|
|
|
/* State for a file descriptor that we do not want to track anymore . */
|
|
stop;
|
|
|
|
/* TRANSITIONS. */
|
|
|
|
/* On "open". */
|
|
start -> unchecked_read_only [label="on 'X = open(..., O_RDONLY);'"];
|
|
start -> unchecked_write_only [label="on 'X = open(..., O_WRONLY);'"];
|
|
start -> unchecked_read_write [label="on 'X = open(..., ...);'"];
|
|
|
|
/* On "creat". */
|
|
start -> unchecked_write_only [label="on 'X = create(...);'"];
|
|
|
|
/* On "close". */
|
|
start -> closed [label="on 'close(X);'"];
|
|
unchecked_read_write -> closed [label="on 'close(X);'"];
|
|
unchecked_read_only -> closed [label="on 'close(X);'"];
|
|
unchecked_write_only -> closed [label="on 'close(X);'"];
|
|
valid_read_write -> closed [label="on 'close(X);'"];
|
|
valid_read_only -> closed [label="on 'close(X);'"];
|
|
valid_write_only -> closed [label="on 'close(X);'"];
|
|
constant_fd -> closed [label="on 'close(X);'"];
|
|
new_datagram_socket -> closed [label="on 'close(X);'"];
|
|
new_stream_socket -> closed [label="on 'close(X);'"];
|
|
new_unknown_socket -> closed [label="on 'close(X);'"];
|
|
bound_datagram_socket -> closed [label="on 'close(X);'"];
|
|
bound_stream_socket -> closed [label="on 'close(X);'"];
|
|
bound_unknown_socket -> closed [label="on 'close(X);'"];
|
|
listening_stream_socket -> closed [label="on 'close(X);'"];
|
|
connected_stream_socket -> closed [label="on 'close(X);'"];
|
|
closed -> stop [label="on 'close(X);':\nWarn('double close')"];
|
|
|
|
/* On "read". */
|
|
closed -> closed [label="on 'read(X);':\nWarn('use after close')"];
|
|
unchecked_read_write -> unchecked_read_write [label="on 'read(X);:\nWarn('use without check')'"];
|
|
unchecked_read_only -> unchecked_read_only [label="on 'read(X);:\nWarn('use without check')'"];
|
|
unchecked_write_only -> unchecked_write_only [label="on 'read(X);:\nWarn('use without check')'"];
|
|
valid_write_only -> valid_write_only [label="on 'read(X);:\nWarn('access mode mismatch')'"];
|
|
|
|
/* On "write". */
|
|
closed -> closed [label="on 'write(X);':\nWarn('use after close')"];
|
|
unchecked_read_write -> unchecked_read_write [label="on 'write(X);:\nWarn('use without check')'"];
|
|
unchecked_read_only -> unchecked_read_only [label="on 'write(X);:\nWarn('use without check')'"];
|
|
unchecked_write_only -> unchecked_write_only [label="on 'write(X);:\nWarn('use without check')'"];
|
|
valid_read_only -> valid_read_only [label="on 'write(X);:\nWarn('access mode mismatch')'"];
|
|
|
|
/* On "dup". */
|
|
closed -> closed [label="on 'dup(X);':\nWarn('use after close')"];
|
|
/* plus stuff for the new fd. */
|
|
|
|
/* On "pipe". */
|
|
start -> valid_read_write [label="when 'pipe()' succeeds"];
|
|
|
|
/* On "socket". */
|
|
start -> new_datagram_socket [label="when 'socket(..., SOCK_DGRAM, ...)' succeeds"];
|
|
start -> new_stream_socket [label="when 'socket(..., SOCK_STREAM, ...)' succeeds"];
|
|
start -> new_unknown_socket [label="when 'socket(..., ..., ...)' succeeds"];
|
|
|
|
/* 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"];
|
|
|
|
/* On "listen". */
|
|
start -> listening_stream_socket [label="when 'listen(X, ...)' succeeds"];
|
|
bound_stream_socket -> listening_stream_socket [label="when 'listen(X, ...)' succeeds"];
|
|
bound_unknown_socket -> listening_stream_socket [label="when 'listen(X, ...)' succeeds"];
|
|
|
|
/* 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'"];
|
|
unchecked_read_only -> valid_read_only [label="on 'X >= 0'"];
|
|
unchecked_write_only -> valid_write_only [label="on 'X >= 0'"];
|
|
unchecked_read_write -> invalid [label="on 'X < 0'"];
|
|
unchecked_read_only -> invalid [label="on 'X < 0'"];
|
|
unchecked_write_only -> invalid [label="on 'X < 0'"];
|
|
|
|
/* Leaks. */
|
|
unchecked_read_write -> stop [label="on leak:\nWarn('leak')"];
|
|
unchecked_read_only -> stop [label="on leak:\nWarn('leak')"];
|
|
unchecked_write_only -> stop [label="on leak:\nWarn('leak')"];
|
|
valid_read_write -> stop [label="on leak:\nWarn('leak')"];
|
|
valid_read_only -> stop [label="on leak:\nWarn('leak')"];
|
|
valid_write_only -> stop [label="on leak:\nWarn('leak')"];
|
|
new_datagram_socket -> stop [label="on leak:\nWarn('leak')"];
|
|
new_stream_socket -> stop [label="on leak:\nWarn('leak')"];
|
|
new_unknown_socket -> stop [label="on leak:\nWarn('leak')"];
|
|
bound_datagram_socket -> stop [label="on leak:\nWarn('leak')"];
|
|
bound_stream_socket -> stop [label="on leak:\nWarn('leak')"];
|
|
bound_unknown_socket -> stop [label="on leak:\nWarn('leak')"];
|
|
listening_stream_socket -> stop [label="on leak:\nWarn('leak')"];
|
|
connected_stream_socket -> stop [label="on leak:\nWarn('leak')"];
|
|
}
|