1 /* A state machine for detecting misuses of POSIX file descriptor APIs.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by Immad Mir <mir@sourceware.org>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
22 #define INCLUDE_MEMORY
24 #include "coretypes.h"
25 #include "make-unique.h"
28 #include "basic-block.h"
31 #include "diagnostic-path.h"
32 #include "diagnostic-metadata.h"
33 #include "analyzer/analyzer.h"
34 #include "diagnostic-event-id.h"
35 #include "analyzer/analyzer-logging.h"
36 #include "analyzer/sm.h"
37 #include "analyzer/pending-diagnostic.h"
38 #include "analyzer/function-set.h"
39 #include "analyzer/analyzer-selftests.h"
40 #include "stringpool.h"
42 #include "analyzer/call-string.h"
43 #include "analyzer/program-point.h"
44 #include "analyzer/store.h"
45 #include "analyzer/region-model.h"
47 #include "analyzer/program-state.h"
48 #include "analyzer/supergraph.h"
49 #include "analyzer/analyzer-language.h"
50 #include "analyzer/call-info.h"
58 /* An enum for distinguishing between three different access modes. */
67 enum access_directions
74 /* An enum for distinguishing between dup, dup2 and dup3. */
82 /* Enum for use by -Wanalyzer-fd-phase-mismatch. */
86 EXPECTED_PHASE_CAN_TRANSFER, /* can "read"/"write". */
87 EXPECTED_PHASE_CAN_BIND,
88 EXPECTED_PHASE_CAN_LISTEN,
89 EXPECTED_PHASE_CAN_ACCEPT,
90 EXPECTED_PHASE_CAN_CONNECT
93 class fd_state_machine : public state_machine
96 fd_state_machine (logger *logger);
99 inherited_state_p () const final override
104 state_machine::state_t
105 get_default_state (const svalue *sval) const final override
107 if (tree cst = sval->maybe_get_constant ())
109 if (TREE_CODE (cst) == INTEGER_CST)
111 int val = TREE_INT_CST_LOW (cst);
113 return m_constant_fd;
121 bool on_stmt (sm_context *sm_ctxt, const supernode *node,
122 const gimple *stmt) const final override;
124 void on_condition (sm_context *sm_ctxt, const supernode *node,
125 const gimple *stmt, const svalue *lhs, const tree_code op,
126 const svalue *rhs) const final override;
128 bool can_purge_p (state_t s) const final override;
129 std::unique_ptr<pending_diagnostic> on_leak (tree var) const final override;
131 bool is_unchecked_fd_p (state_t s) const;
132 bool is_valid_fd_p (state_t s) const;
133 bool is_socket_fd_p (state_t s) const;
134 bool is_datagram_socket_fd_p (state_t s) const;
135 bool is_stream_socket_fd_p (state_t s) const;
136 bool is_closed_fd_p (state_t s) const;
137 bool is_constant_fd_p (state_t s) const;
138 bool is_readonly_fd_p (state_t s) const;
139 bool is_writeonly_fd_p (state_t s) const;
140 enum access_mode get_access_mode_from_flag (int flag) const;
141 /* Function for one-to-one correspondence between valid
142 and unchecked states. */
143 state_t valid_to_unchecked_state (state_t state) const;
145 void mark_as_valid_fd (region_model *model,
147 const svalue *fd_sval,
148 const extrinsic_state &ext_state) const;
150 bool on_socket (const call_details &cd,
153 const extrinsic_state &ext_state) const;
154 bool on_bind (const call_details &cd,
157 const extrinsic_state &ext_state) const;
158 bool on_listen (const call_details &cd,
161 const extrinsic_state &ext_state) const;
162 bool on_accept (const call_details &cd,
165 const extrinsic_state &ext_state) const;
166 bool on_connect (const call_details &cd,
169 const extrinsic_state &ext_state) const;
171 /* State for a constant file descriptor (>= 0) */
172 state_t m_constant_fd;
174 /* States representing a file descriptor that hasn't yet been
175 checked for validity after opening, for three different
177 state_t m_unchecked_read_write;
179 state_t m_unchecked_read_only;
181 state_t m_unchecked_write_only;
183 /* States for representing a file descriptor that is known to be valid (>=
184 0), for three different access modes. */
185 state_t m_valid_read_write;
187 state_t m_valid_read_only;
189 state_t m_valid_write_only;
191 /* State for a file descriptor that is known to be invalid (< 0). */
194 /* State for a file descriptor that has been closed. */
197 /* States for FDs relating to socket APIs. */
199 /* Result of successful "socket" with SOCK_DGRAM. */
200 state_t m_new_datagram_socket;
201 /* Result of successful "socket" with SOCK_STREAM. */
202 state_t m_new_stream_socket;
203 /* Result of successful "socket" with unknown type. */
204 state_t m_new_unknown_socket;
206 /* The above after a successful call to "bind". */
207 state_t m_bound_datagram_socket;
208 state_t m_bound_stream_socket;
209 state_t m_bound_unknown_socket;
211 /* A bound socket after a successful call to "listen" (stream or unknown). */
212 state_t m_listening_stream_socket;
214 /* (i) the new FD as a result of a succesful call to "accept" on a
215 listening socket (via a passive open), or
216 (ii) an active socket after a successful call to "connect"
217 (via an active open). */
218 state_t m_connected_stream_socket;
220 /* State for a file descriptor that we do not want to track anymore . */
223 /* Stashed constant values from the frontend. These could be NULL. */
231 void on_open (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
232 const gcall *call) const;
233 void on_creat (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
234 const gcall *call) const;
235 void on_close (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
236 const gcall *call) const;
237 void on_read (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
238 const gcall *call, const tree callee_fndecl) const;
239 void on_write (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
240 const gcall *call, const tree callee_fndecl) const;
241 void check_for_open_fd (sm_context *sm_ctxt, const supernode *node,
242 const gimple *stmt, const gcall *call,
243 const tree callee_fndecl,
244 enum access_directions access_fn) const;
246 void make_valid_transitions_on_condition (sm_context *sm_ctxt,
247 const supernode *node,
249 const svalue *lhs) const;
250 void make_invalid_transitions_on_condition (sm_context *sm_ctxt,
251 const supernode *node,
253 const svalue *lhs) const;
254 void check_for_fd_attrs (sm_context *sm_ctxt, const supernode *node,
255 const gimple *stmt, const gcall *call,
256 const tree callee_fndecl, const char *attr_name,
257 access_directions fd_attr_access_dir) const;
258 void check_for_dup (sm_context *sm_ctxt, const supernode *node,
259 const gimple *stmt, const gcall *call, const tree callee_fndecl,
260 enum dup kind) const;
262 state_t get_state_for_socket_type (const svalue *socket_type_sval) const;
264 bool check_for_socket_fd (const call_details &cd,
267 const svalue *fd_sval,
268 const supernode *node,
270 bool *complained = NULL) const;
271 bool check_for_new_socket_fd (const call_details &cd,
274 const svalue *fd_sval,
275 const supernode *node,
277 enum expected_phase expected_phase) const;
280 /* Base diagnostic class relative to fd_state_machine. */
281 class fd_diagnostic : public pending_diagnostic
284 fd_diagnostic (const fd_state_machine &sm, tree arg) : m_sm (sm), m_arg (arg)
289 subclass_equal_p (const pending_diagnostic &base_other) const override
291 return same_tree_p (m_arg, ((const fd_diagnostic &)base_other).m_arg);
295 describe_state_change (const evdesc::state_change &change) override
297 if (change.m_old_state == m_sm.get_start_state ())
299 if (change.m_new_state == m_sm.m_unchecked_read_write
300 || change.m_new_state == m_sm.m_valid_read_write)
301 return change.formatted_print ("opened here as read-write");
303 if (change.m_new_state == m_sm.m_unchecked_read_only
304 || change.m_new_state == m_sm.m_valid_read_only)
305 return change.formatted_print ("opened here as read-only");
307 if (change.m_new_state == m_sm.m_unchecked_write_only
308 || change.m_new_state == m_sm.m_valid_write_only)
309 return change.formatted_print ("opened here as write-only");
311 if (change.m_new_state == m_sm.m_new_datagram_socket)
312 return change.formatted_print ("datagram socket created here");
314 if (change.m_new_state == m_sm.m_new_stream_socket)
315 return change.formatted_print ("stream socket created here");
317 if (change.m_new_state == m_sm.m_new_unknown_socket
318 || change.m_new_state == m_sm.m_connected_stream_socket)
319 return change.formatted_print ("socket created here");
322 if (change.m_new_state == m_sm.m_bound_datagram_socket)
323 return change.formatted_print ("datagram socket bound here");
325 if (change.m_new_state == m_sm.m_bound_stream_socket)
326 return change.formatted_print ("stream socket bound here");
328 if (change.m_new_state == m_sm.m_bound_unknown_socket
329 || change.m_new_state == m_sm.m_connected_stream_socket)
330 return change.formatted_print ("socket bound here");
332 if (change.m_new_state == m_sm.m_listening_stream_socket)
333 return change.formatted_print
334 ("stream socket marked as passive here via %qs", "listen");
336 if (change.m_new_state == m_sm.m_closed)
337 return change.formatted_print ("closed here");
339 if (m_sm.is_unchecked_fd_p (change.m_old_state)
340 && m_sm.is_valid_fd_p (change.m_new_state))
343 return change.formatted_print (
344 "assuming %qE is a valid file descriptor (>= 0)", change.m_expr);
346 return change.formatted_print ("assuming a valid file descriptor");
349 if (m_sm.is_unchecked_fd_p (change.m_old_state)
350 && change.m_new_state == m_sm.m_invalid)
353 return change.formatted_print (
354 "assuming %qE is an invalid file descriptor (< 0)",
357 return change.formatted_print ("assuming an invalid file descriptor");
360 return label_text ();
363 diagnostic_event::meaning
364 get_meaning_for_state_change (
365 const evdesc::state_change &change) const final override
367 if (change.m_old_state == m_sm.get_start_state ()
368 && (m_sm.is_unchecked_fd_p (change.m_new_state)
369 || change.m_new_state == m_sm.m_new_datagram_socket
370 || change.m_new_state == m_sm.m_new_stream_socket
371 || change.m_new_state == m_sm.m_new_unknown_socket))
372 return diagnostic_event::meaning (diagnostic_event::VERB_acquire,
373 diagnostic_event::NOUN_resource);
374 if (change.m_new_state == m_sm.m_closed)
375 return diagnostic_event::meaning (diagnostic_event::VERB_release,
376 diagnostic_event::NOUN_resource);
377 return diagnostic_event::meaning ();
381 const fd_state_machine &m_sm;
385 class fd_param_diagnostic : public fd_diagnostic
388 fd_param_diagnostic (const fd_state_machine &sm, tree arg, tree callee_fndecl,
389 const char *attr_name, int arg_idx)
390 : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl),
391 m_attr_name (attr_name), m_arg_idx (arg_idx)
395 fd_param_diagnostic (const fd_state_machine &sm, tree arg, tree callee_fndecl)
396 : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl),
397 m_attr_name (NULL), m_arg_idx (-1)
402 subclass_equal_p (const pending_diagnostic &base_other) const override
404 const fd_param_diagnostic &sub_other
405 = (const fd_param_diagnostic &)base_other;
406 return (same_tree_p (m_arg, sub_other.m_arg)
407 && same_tree_p (m_callee_fndecl, sub_other.m_callee_fndecl)
408 && m_arg_idx == sub_other.m_arg_idx
410 ? (strcmp (m_attr_name, sub_other.m_attr_name) == 0)
415 inform_filedescriptor_attribute (access_directions fd_dir)
421 case DIRS_READ_WRITE:
422 inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
423 "argument %d of %qD must be an open file descriptor, due to "
424 "%<__attribute__((%s(%d)))%>",
425 m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx + 1);
428 inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
429 "argument %d of %qD must be a readable file descriptor, due "
430 "to %<__attribute__((%s(%d)))%>",
431 m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx + 1);
434 inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
435 "argument %d of %qD must be a writable file descriptor, due "
436 "to %<__attribute__((%s(%d)))%>",
437 m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx + 1);
443 tree m_callee_fndecl;
444 const char *m_attr_name;
445 /* ARG_IDX is 0-based. */
449 class fd_leak : public fd_diagnostic
452 fd_leak (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm, arg) {}
455 get_kind () const final override
461 get_controlling_option () const final override
463 return OPT_Wanalyzer_fd_leak;
467 emit (rich_location *rich_loc) final override
469 /*CWE-775: Missing Release of File Descriptor or Handle after Effective
472 diagnostic_metadata m;
475 return warning_meta (rich_loc, m, get_controlling_option (),
476 "leak of file descriptor %qE", m_arg);
478 return warning_meta (rich_loc, m, get_controlling_option (),
479 "leak of file descriptor");
483 describe_state_change (const evdesc::state_change &change) final override
485 if (m_sm.is_unchecked_fd_p (change.m_new_state))
487 m_open_event = change.m_event_id;
488 return label_text::borrow ("opened here");
491 return fd_diagnostic::describe_state_change (change);
495 describe_final_event (const evdesc::final_event &ev) final override
497 if (m_open_event.known_p ())
500 return ev.formatted_print ("%qE leaks here; was opened at %@",
501 ev.m_expr, &m_open_event);
503 return ev.formatted_print ("leaks here; was opened at %@",
509 return ev.formatted_print ("%qE leaks here", ev.m_expr);
511 return ev.formatted_print ("leaks here");
516 diagnostic_event_id_t m_open_event;
519 class fd_access_mode_mismatch : public fd_param_diagnostic
522 fd_access_mode_mismatch (const fd_state_machine &sm, tree arg,
523 enum access_directions fd_dir,
524 const tree callee_fndecl, const char *attr_name,
526 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx),
532 fd_access_mode_mismatch (const fd_state_machine &sm, tree arg,
533 enum access_directions fd_dir,
534 const tree callee_fndecl)
535 : fd_param_diagnostic (sm, arg, callee_fndecl), m_fd_dir (fd_dir)
540 get_kind () const final override
542 return "fd_access_mode_mismatch";
546 get_controlling_option () const final override
548 return OPT_Wanalyzer_fd_access_mode_mismatch;
552 emit (rich_location *rich_loc) final override
558 warned = warning_at (rich_loc, get_controlling_option (),
559 "%qE on read-only file descriptor %qE",
560 m_callee_fndecl, m_arg);
563 warned = warning_at (rich_loc, get_controlling_option (),
564 "%qE on write-only file descriptor %qE",
565 m_callee_fndecl, m_arg);
571 inform_filedescriptor_attribute (m_fd_dir);
576 describe_final_event (const evdesc::final_event &ev) final override
581 return ev.formatted_print ("%qE on read-only file descriptor %qE",
582 m_callee_fndecl, m_arg);
584 return ev.formatted_print ("%qE on write-only file descriptor %qE",
585 m_callee_fndecl, m_arg);
592 enum access_directions m_fd_dir;
595 class fd_double_close : public fd_diagnostic
598 fd_double_close (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm, arg)
603 get_kind () const final override
605 return "fd_double_close";
609 get_controlling_option () const final override
611 return OPT_Wanalyzer_fd_double_close;
614 emit (rich_location *rich_loc) final override
616 diagnostic_metadata m;
617 // CWE-1341: Multiple Releases of Same Resource or Handle
619 return warning_meta (rich_loc, m, get_controlling_option (),
620 "double %<close%> of file descriptor %qE", m_arg);
624 describe_state_change (const evdesc::state_change &change) override
626 if (m_sm.is_unchecked_fd_p (change.m_new_state))
627 return label_text::borrow ("opened here");
629 if (change.m_new_state == m_sm.m_closed)
631 m_first_close_event = change.m_event_id;
632 return change.formatted_print ("first %qs here", "close");
634 return fd_diagnostic::describe_state_change (change);
638 describe_final_event (const evdesc::final_event &ev) final override
640 if (m_first_close_event.known_p ())
641 return ev.formatted_print ("second %qs here; first %qs was at %@",
642 "close", "close", &m_first_close_event);
643 return ev.formatted_print ("second %qs here", "close");
647 diagnostic_event_id_t m_first_close_event;
650 class fd_use_after_close : public fd_param_diagnostic
653 fd_use_after_close (const fd_state_machine &sm, tree arg,
654 const tree callee_fndecl, const char *attr_name,
656 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx)
660 fd_use_after_close (const fd_state_machine &sm, tree arg,
661 const tree callee_fndecl)
662 : fd_param_diagnostic (sm, arg, callee_fndecl)
667 get_kind () const final override
669 return "fd_use_after_close";
673 get_controlling_option () const final override
675 return OPT_Wanalyzer_fd_use_after_close;
679 emit (rich_location *rich_loc) final override
682 warned = warning_at (rich_loc, get_controlling_option (),
683 "%qE on closed file descriptor %qE", m_callee_fndecl,
686 inform_filedescriptor_attribute (DIRS_READ_WRITE);
691 describe_state_change (const evdesc::state_change &change) override
693 if (m_sm.is_unchecked_fd_p (change.m_new_state))
694 return label_text::borrow ("opened here");
696 if (change.m_new_state == m_sm.m_closed)
698 m_first_close_event = change.m_event_id;
699 return change.formatted_print ("closed here");
702 return fd_diagnostic::describe_state_change (change);
706 describe_final_event (const evdesc::final_event &ev) final override
708 if (m_first_close_event.known_p ())
709 return ev.formatted_print (
710 "%qE on closed file descriptor %qE; %qs was at %@", m_callee_fndecl,
711 m_arg, "close", &m_first_close_event);
713 return ev.formatted_print ("%qE on closed file descriptor %qE",
714 m_callee_fndecl, m_arg);
718 diagnostic_event_id_t m_first_close_event;
721 class fd_use_without_check : public fd_param_diagnostic
724 fd_use_without_check (const fd_state_machine &sm, tree arg,
725 const tree callee_fndecl, const char *attr_name,
727 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx)
731 fd_use_without_check (const fd_state_machine &sm, tree arg,
732 const tree callee_fndecl)
733 : fd_param_diagnostic (sm, arg, callee_fndecl)
738 get_kind () const final override
740 return "fd_use_without_check";
744 get_controlling_option () const final override
746 return OPT_Wanalyzer_fd_use_without_check;
750 emit (rich_location *rich_loc) final override
753 warned = warning_at (rich_loc, get_controlling_option (),
754 "%qE on possibly invalid file descriptor %qE",
755 m_callee_fndecl, m_arg);
757 inform_filedescriptor_attribute (DIRS_READ_WRITE);
762 describe_state_change (const evdesc::state_change &change) override
764 if (m_sm.is_unchecked_fd_p (change.m_new_state))
766 m_first_open_event = change.m_event_id;
767 return label_text::borrow ("opened here");
770 return fd_diagnostic::describe_state_change (change);
774 describe_final_event (const evdesc::final_event &ev) final override
776 if (m_first_open_event.known_p ())
777 return ev.formatted_print (
778 "%qE could be invalid: unchecked value from %@", m_arg,
779 &m_first_open_event);
781 return ev.formatted_print ("%qE could be invalid", m_arg);
785 diagnostic_event_id_t m_first_open_event;
788 /* Concrete pending_diagnostic subclass for -Wanalyzer-fd-phase-mismatch. */
790 class fd_phase_mismatch : public fd_param_diagnostic
793 fd_phase_mismatch (const fd_state_machine &sm, tree arg,
794 const tree callee_fndecl,
795 state_machine::state_t actual_state,
796 enum expected_phase expected_phase)
797 : fd_param_diagnostic (sm, arg, callee_fndecl),
798 m_actual_state (actual_state),
799 m_expected_phase (expected_phase)
801 gcc_assert (m_sm.is_socket_fd_p (actual_state));
802 switch (expected_phase)
804 case EXPECTED_PHASE_CAN_TRANSFER:
805 gcc_assert (actual_state == m_sm.m_new_stream_socket
806 || actual_state == m_sm.m_bound_stream_socket
807 || actual_state == m_sm.m_listening_stream_socket);
809 case EXPECTED_PHASE_CAN_BIND:
810 gcc_assert (actual_state == m_sm.m_bound_datagram_socket
811 || actual_state == m_sm.m_bound_stream_socket
812 || actual_state == m_sm.m_bound_unknown_socket
813 || actual_state == m_sm.m_connected_stream_socket
814 || actual_state == m_sm.m_listening_stream_socket);
816 case EXPECTED_PHASE_CAN_LISTEN:
817 gcc_assert (actual_state == m_sm.m_new_stream_socket
818 || actual_state == m_sm.m_new_unknown_socket
819 || actual_state == m_sm.m_connected_stream_socket);
821 case EXPECTED_PHASE_CAN_ACCEPT:
822 gcc_assert (actual_state == m_sm.m_new_stream_socket
823 || actual_state == m_sm.m_new_unknown_socket
824 || actual_state == m_sm.m_bound_stream_socket
825 || actual_state == m_sm.m_bound_unknown_socket
826 || actual_state == m_sm.m_connected_stream_socket);
828 case EXPECTED_PHASE_CAN_CONNECT:
829 gcc_assert (actual_state == m_sm.m_bound_datagram_socket
830 || actual_state == m_sm.m_bound_stream_socket
831 || actual_state == m_sm.m_bound_unknown_socket
832 || actual_state == m_sm.m_listening_stream_socket
833 || actual_state == m_sm.m_connected_stream_socket);
839 get_kind () const final override
841 return "fd_phase_mismatch";
845 subclass_equal_p (const pending_diagnostic &base_other) const final override
847 const fd_phase_mismatch &sub_other = (const fd_phase_mismatch &)base_other;
848 if (!fd_param_diagnostic ::subclass_equal_p (sub_other))
850 return (m_actual_state == sub_other.m_actual_state
851 && m_expected_phase == sub_other.m_expected_phase);
855 get_controlling_option () const final override
857 return OPT_Wanalyzer_fd_phase_mismatch;
861 emit (rich_location *rich_loc) final override
863 /* CWE-666: Operation on Resource in Wrong Phase of Lifetime. */
864 diagnostic_metadata m;
866 return warning_at (rich_loc, get_controlling_option (),
867 "%qE on file descriptor %qE in wrong phase",
868 m_callee_fndecl, m_arg);
872 describe_final_event (const evdesc::final_event &ev) final override
874 switch (m_expected_phase)
876 case EXPECTED_PHASE_CAN_TRANSFER:
878 if (m_actual_state == m_sm.m_new_stream_socket)
879 return ev.formatted_print
880 ("%qE expects a stream socket to be connected via %qs"
881 " but %qE has not yet been bound",
882 m_callee_fndecl, "accept", m_arg);
883 if (m_actual_state == m_sm.m_bound_stream_socket)
884 return ev.formatted_print
885 ("%qE expects a stream socket to be connected via %qs"
886 " but %qE is not yet listening",
887 m_callee_fndecl, "accept", m_arg);
888 if (m_actual_state == m_sm.m_listening_stream_socket)
889 return ev.formatted_print
890 ("%qE expects a stream socket to be connected via"
891 " the return value of %qs"
892 " but %qE is listening; wrong file descriptor?",
893 m_callee_fndecl, "accept", m_arg);
896 case EXPECTED_PHASE_CAN_BIND:
898 if (m_actual_state == m_sm.m_bound_datagram_socket
899 || m_actual_state == m_sm.m_bound_stream_socket
900 || m_actual_state == m_sm.m_bound_unknown_socket)
901 return ev.formatted_print
902 ("%qE expects a new socket file descriptor"
903 " but %qE has already been bound",
904 m_callee_fndecl, m_arg);
905 if (m_actual_state == m_sm.m_connected_stream_socket)
906 return ev.formatted_print
907 ("%qE expects a new socket file descriptor"
908 " but %qE is already connected",
909 m_callee_fndecl, m_arg);
910 if (m_actual_state == m_sm.m_listening_stream_socket)
911 return ev.formatted_print
912 ("%qE expects a new socket file descriptor"
913 " but %qE is already listening",
914 m_callee_fndecl, m_arg);
917 case EXPECTED_PHASE_CAN_LISTEN:
919 if (m_actual_state == m_sm.m_new_stream_socket
920 || m_actual_state == m_sm.m_new_unknown_socket)
921 return ev.formatted_print
922 ("%qE expects a bound stream socket file descriptor"
923 " but %qE has not yet been bound",
924 m_callee_fndecl, m_arg);
925 if (m_actual_state == m_sm.m_connected_stream_socket)
926 return ev.formatted_print
927 ("%qE expects a bound stream socket file descriptor"
928 " but %qE is connected",
929 m_callee_fndecl, m_arg);
932 case EXPECTED_PHASE_CAN_ACCEPT:
934 if (m_actual_state == m_sm.m_new_stream_socket
935 || m_actual_state == m_sm.m_new_unknown_socket)
936 return ev.formatted_print
937 ("%qE expects a listening stream socket file descriptor"
938 " but %qE has not yet been bound",
939 m_callee_fndecl, m_arg);
940 if (m_actual_state == m_sm.m_bound_stream_socket
941 || m_actual_state == m_sm.m_bound_unknown_socket)
942 return ev.formatted_print
943 ("%qE expects a listening stream socket file descriptor"
944 " whereas %qE is bound but not yet listening",
945 m_callee_fndecl, m_arg);
946 if (m_actual_state == m_sm.m_connected_stream_socket)
947 return ev.formatted_print
948 ("%qE expects a listening stream socket file descriptor"
949 " but %qE is connected",
950 m_callee_fndecl, m_arg);
953 case EXPECTED_PHASE_CAN_CONNECT:
955 if (m_actual_state == m_sm.m_bound_datagram_socket
956 || m_actual_state == m_sm.m_bound_stream_socket
957 || m_actual_state == m_sm.m_bound_unknown_socket)
958 return ev.formatted_print
959 ("%qE expects a new socket file descriptor but %qE is bound",
960 m_callee_fndecl, m_arg);
962 return ev.formatted_print
963 ("%qE expects a new socket file descriptor", m_callee_fndecl);
971 state_machine::state_t m_actual_state;
972 enum expected_phase m_expected_phase;
975 /* Enum for use by -Wanalyzer-fd-type-mismatch. */
979 EXPECTED_TYPE_SOCKET,
980 EXPECTED_TYPE_STREAM_SOCKET
983 /* Concrete pending_diagnostic subclass for -Wanalyzer-fd-type-mismatch. */
985 class fd_type_mismatch : public fd_param_diagnostic
988 fd_type_mismatch (const fd_state_machine &sm, tree arg,
989 const tree callee_fndecl,
990 state_machine::state_t actual_state,
991 enum expected_type expected_type)
992 : fd_param_diagnostic (sm, arg, callee_fndecl),
993 m_actual_state (actual_state),
994 m_expected_type (expected_type)
999 get_kind () const final override
1001 return "fd_type_mismatch";
1005 subclass_equal_p (const pending_diagnostic &base_other) const final override
1007 const fd_type_mismatch &sub_other = (const fd_type_mismatch &)base_other;
1008 if (!fd_param_diagnostic ::subclass_equal_p (sub_other))
1010 return (m_actual_state == sub_other.m_actual_state
1011 && m_expected_type == sub_other.m_expected_type);
1015 get_controlling_option () const final override
1017 return OPT_Wanalyzer_fd_type_mismatch;
1021 emit (rich_location *rich_loc) final override
1023 switch (m_expected_type)
1027 case EXPECTED_TYPE_SOCKET:
1028 return warning_at (rich_loc, get_controlling_option (),
1029 "%qE on non-socket file descriptor %qE",
1030 m_callee_fndecl, m_arg);
1031 case EXPECTED_TYPE_STREAM_SOCKET:
1032 if (m_sm.is_datagram_socket_fd_p (m_actual_state))
1033 return warning_at (rich_loc, get_controlling_option (),
1034 "%qE on datagram socket file descriptor %qE",
1035 m_callee_fndecl, m_arg);
1037 return warning_at (rich_loc, get_controlling_option (),
1038 "%qE on non-stream-socket file descriptor %qE",
1039 m_callee_fndecl, m_arg);
1044 describe_final_event (const evdesc::final_event &ev) final override
1046 switch (m_expected_type)
1051 case EXPECTED_TYPE_SOCKET:
1052 case EXPECTED_TYPE_STREAM_SOCKET:
1053 if (!m_sm.is_socket_fd_p (m_actual_state))
1054 return ev.formatted_print ("%qE expects a socket file descriptor"
1055 " but %qE is not a socket",
1056 m_callee_fndecl, m_arg);
1058 gcc_assert (m_expected_type == EXPECTED_TYPE_STREAM_SOCKET);
1059 gcc_assert (m_sm.is_datagram_socket_fd_p (m_actual_state));
1060 return ev.formatted_print
1061 ("%qE expects a stream socket file descriptor"
1062 " but %qE is a datagram socket",
1063 m_callee_fndecl, m_arg);
1067 state_machine::state_t m_actual_state;
1068 enum expected_type m_expected_type;
1071 fd_state_machine::fd_state_machine (logger *logger)
1072 : state_machine ("file-descriptor", logger),
1073 m_constant_fd (add_state ("fd-constant")),
1074 m_unchecked_read_write (add_state ("fd-unchecked-read-write")),
1075 m_unchecked_read_only (add_state ("fd-unchecked-read-only")),
1076 m_unchecked_write_only (add_state ("fd-unchecked-write-only")),
1077 m_valid_read_write (add_state ("fd-valid-read-write")),
1078 m_valid_read_only (add_state ("fd-valid-read-only")),
1079 m_valid_write_only (add_state ("fd-valid-write-only")),
1080 m_invalid (add_state ("fd-invalid")),
1081 m_closed (add_state ("fd-closed")),
1082 m_new_datagram_socket (add_state ("fd-new-datagram-socket")),
1083 m_new_stream_socket (add_state ("fd-new-stream-socket")),
1084 m_new_unknown_socket (add_state ("fd-new-unknown-socket")),
1085 m_bound_datagram_socket (add_state ("fd-bound-datagram-socket")),
1086 m_bound_stream_socket (add_state ("fd-bound-stream-socket")),
1087 m_bound_unknown_socket (add_state ("fd-bound-unknown-socket")),
1088 m_listening_stream_socket (add_state ("fd-listening-stream-socket")),
1089 m_connected_stream_socket (add_state ("fd-connected-stream-socket")),
1090 m_stop (add_state ("fd-stop")),
1091 m_O_ACCMODE (get_stashed_constant_by_name ("O_ACCMODE")),
1092 m_O_RDONLY (get_stashed_constant_by_name ("O_RDONLY")),
1093 m_O_WRONLY (get_stashed_constant_by_name ("O_WRONLY")),
1094 m_SOCK_STREAM (get_stashed_constant_by_name ("SOCK_STREAM")),
1095 m_SOCK_DGRAM (get_stashed_constant_by_name ("SOCK_DGRAM"))
1100 fd_state_machine::is_unchecked_fd_p (state_t s) const
1102 return (s == m_unchecked_read_write
1103 || s == m_unchecked_read_only
1104 || s == m_unchecked_write_only);
1108 fd_state_machine::is_valid_fd_p (state_t s) const
1110 return (s == m_valid_read_write
1111 || s == m_valid_read_only
1112 || s == m_valid_write_only);
1116 fd_state_machine::is_socket_fd_p (state_t s) const
1118 return (s == m_new_datagram_socket
1119 || s == m_new_stream_socket
1120 || s == m_new_unknown_socket
1121 || s == m_bound_datagram_socket
1122 || s == m_bound_stream_socket
1123 || s == m_bound_unknown_socket
1124 || s == m_listening_stream_socket
1125 || s == m_connected_stream_socket);
1129 fd_state_machine::is_datagram_socket_fd_p (state_t s) const
1131 return (s == m_new_datagram_socket
1132 || s == m_new_unknown_socket
1133 || s == m_bound_datagram_socket
1134 || s == m_bound_unknown_socket);
1138 fd_state_machine::is_stream_socket_fd_p (state_t s) const
1140 return (s == m_new_stream_socket
1141 || s == m_new_unknown_socket
1142 || s == m_bound_stream_socket
1143 || s == m_bound_unknown_socket
1144 || s == m_listening_stream_socket
1145 || s == m_connected_stream_socket);
1149 fd_state_machine::get_access_mode_from_flag (int flag) const
1151 if (m_O_ACCMODE && TREE_CODE (m_O_ACCMODE) == INTEGER_CST)
1153 const unsigned HOST_WIDE_INT mask_val = TREE_INT_CST_LOW (m_O_ACCMODE);
1154 const unsigned HOST_WIDE_INT masked_flag = flag & mask_val;
1156 if (m_O_RDONLY && TREE_CODE (m_O_RDONLY) == INTEGER_CST)
1157 if (masked_flag == TREE_INT_CST_LOW (m_O_RDONLY))
1160 if (m_O_WRONLY && TREE_CODE (m_O_WRONLY) == INTEGER_CST)
1161 if (masked_flag == TREE_INT_CST_LOW (m_O_WRONLY))
1168 fd_state_machine::is_readonly_fd_p (state_t state) const
1170 return (state == m_unchecked_read_only || state == m_valid_read_only);
1174 fd_state_machine::is_writeonly_fd_p (state_t state) const
1176 return (state == m_unchecked_write_only || state == m_valid_write_only);
1180 fd_state_machine::is_closed_fd_p (state_t state) const
1182 return (state == m_closed);
1186 fd_state_machine::is_constant_fd_p (state_t state) const
1188 return (state == m_constant_fd);
1191 fd_state_machine::state_t
1192 fd_state_machine::valid_to_unchecked_state (state_t state) const
1194 if (state == m_valid_read_write)
1195 return m_unchecked_read_write;
1196 else if (state == m_valid_write_only)
1197 return m_unchecked_write_only;
1198 else if (state == m_valid_read_only)
1199 return m_unchecked_read_only;
1206 fd_state_machine::mark_as_valid_fd (region_model *model,
1208 const svalue *fd_sval,
1209 const extrinsic_state &ext_state) const
1211 smap->set_state (model, fd_sval, m_valid_read_write, NULL, ext_state);
1215 fd_state_machine::on_stmt (sm_context *sm_ctxt, const supernode *node,
1216 const gimple *stmt) const
1218 if (const gcall *call = dyn_cast<const gcall *> (stmt))
1219 if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call))
1221 if (is_named_call_p (callee_fndecl, "open", call, 2))
1223 on_open (sm_ctxt, node, stmt, call);
1227 if (is_named_call_p (callee_fndecl, "creat", call, 2))
1229 on_creat (sm_ctxt, node, stmt, call);
1233 if (is_named_call_p (callee_fndecl, "close", call, 1))
1235 on_close (sm_ctxt, node, stmt, call);
1239 if (is_named_call_p (callee_fndecl, "write", call, 3))
1241 on_write (sm_ctxt, node, stmt, call, callee_fndecl);
1245 if (is_named_call_p (callee_fndecl, "read", call, 3))
1247 on_read (sm_ctxt, node, stmt, call, callee_fndecl);
1251 if (is_named_call_p (callee_fndecl, "dup", call, 1))
1253 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_1);
1257 if (is_named_call_p (callee_fndecl, "dup2", call, 2))
1259 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_2);
1263 if (is_named_call_p (callee_fndecl, "dup3", call, 3))
1265 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_3);
1270 // Handle __attribute__((fd_arg))
1272 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1273 "fd_arg", DIRS_READ_WRITE);
1275 // Handle __attribute__((fd_arg_read))
1277 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1278 "fd_arg_read", DIRS_READ);
1280 // Handle __attribute__((fd_arg_write))
1282 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1283 "fd_arg_write", DIRS_WRITE);
1291 fd_state_machine::check_for_fd_attrs (
1292 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
1293 const gcall *call, const tree callee_fndecl, const char *attr_name,
1294 access_directions fd_attr_access_dir) const
1297 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (callee_fndecl));
1298 attrs = lookup_attribute (attr_name, attrs);
1302 if (!TREE_VALUE (attrs))
1307 for (tree idx = TREE_VALUE (attrs); idx; idx = TREE_CHAIN (idx))
1309 unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (idx)) - 1;
1310 bitmap_set_bit (argmap, val);
1312 if (bitmap_empty_p (argmap))
1315 for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
1317 tree arg = gimple_call_arg (call, arg_idx);
1318 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1319 state_t state = sm_ctxt->get_state (stmt, arg);
1320 bool bit_set = bitmap_bit_p (argmap, arg_idx);
1321 if (TREE_CODE (TREE_TYPE (arg)) != INTEGER_TYPE)
1323 if (bit_set) // Check if arg_idx is marked by any of the file descriptor
1327 if (is_closed_fd_p (state))
1330 sm_ctxt->warn (node, stmt, arg,
1331 make_unique<fd_use_after_close>
1333 callee_fndecl, attr_name,
1338 if (!(is_valid_fd_p (state) || (state == m_stop)))
1340 if (!is_constant_fd_p (state))
1341 sm_ctxt->warn (node, stmt, arg,
1342 make_unique<fd_use_without_check>
1344 callee_fndecl, attr_name,
1348 switch (fd_attr_access_dir)
1350 case DIRS_READ_WRITE:
1354 if (is_writeonly_fd_p (state))
1358 make_unique<fd_access_mode_mismatch> (*this, diag_arg,
1368 if (is_readonly_fd_p (state))
1372 make_unique<fd_access_mode_mismatch> (*this, diag_arg,
1387 fd_state_machine::on_open (sm_context *sm_ctxt, const supernode *node,
1388 const gimple *stmt, const gcall *call) const
1390 tree lhs = gimple_call_lhs (call);
1393 tree arg = gimple_call_arg (call, 1);
1394 enum access_mode mode = READ_WRITE;
1395 if (TREE_CODE (arg) == INTEGER_CST)
1397 int flag = TREE_INT_CST_LOW (arg);
1398 mode = get_access_mode_from_flag (flag);
1403 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1404 m_unchecked_read_only);
1407 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1408 m_unchecked_write_only);
1411 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1412 m_unchecked_read_write);
1417 sm_ctxt->warn (node, stmt, NULL_TREE,
1418 make_unique<fd_leak> (*this, NULL_TREE));
1423 fd_state_machine::on_creat (sm_context *sm_ctxt, const supernode *node,
1424 const gimple *stmt, const gcall *call) const
1426 tree lhs = gimple_call_lhs (call);
1428 sm_ctxt->on_transition (node, stmt, lhs, m_start, m_unchecked_write_only);
1430 sm_ctxt->warn (node, stmt, NULL_TREE,
1431 make_unique<fd_leak> (*this, NULL_TREE));
1435 fd_state_machine::check_for_dup (sm_context *sm_ctxt, const supernode *node,
1436 const gimple *stmt, const gcall *call,
1437 const tree callee_fndecl, enum dup kind) const
1439 tree lhs = gimple_call_lhs (call);
1440 tree arg_1 = gimple_call_arg (call, 0);
1441 state_t state_arg_1 = sm_ctxt->get_state (stmt, arg_1);
1442 if (state_arg_1 == m_stop)
1444 if (!(is_constant_fd_p (state_arg_1) || is_valid_fd_p (state_arg_1)
1445 || state_arg_1 == m_start))
1447 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl,
1456 if (is_constant_fd_p (state_arg_1) || state_arg_1 == m_start)
1457 sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write);
1459 sm_ctxt->set_next_state (stmt, lhs,
1460 valid_to_unchecked_state (state_arg_1));
1466 tree arg_2 = gimple_call_arg (call, 1);
1467 state_t state_arg_2 = sm_ctxt->get_state (stmt, arg_2);
1468 tree diag_arg_2 = sm_ctxt->get_diagnostic_tree (arg_2);
1469 if (state_arg_2 == m_stop)
1471 /* Check if -1 was passed as second argument to dup2. */
1472 if (!(is_constant_fd_p (state_arg_2) || is_valid_fd_p (state_arg_2)
1473 || state_arg_2 == m_start))
1477 make_unique<fd_use_without_check> (*this, diag_arg_2,
1481 /* dup2 returns value of its second argument on success.But, the
1482 access mode of the returned file descriptor depends on the duplicated
1483 file descriptor i.e the first argument. */
1486 if (is_constant_fd_p (state_arg_1) || state_arg_1 == m_start)
1487 sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write);
1489 sm_ctxt->set_next_state (stmt, lhs,
1490 valid_to_unchecked_state (state_arg_1));
1498 fd_state_machine::on_close (sm_context *sm_ctxt, const supernode *node,
1499 const gimple *stmt, const gcall *call) const
1501 tree arg = gimple_call_arg (call, 0);
1502 state_t state = sm_ctxt->get_state (stmt, arg);
1503 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1505 sm_ctxt->on_transition (node, stmt, arg, m_start, m_closed);
1506 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_read_write, m_closed);
1507 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_read_only, m_closed);
1508 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_write_only, m_closed);
1509 sm_ctxt->on_transition (node, stmt, arg, m_valid_read_write, m_closed);
1510 sm_ctxt->on_transition (node, stmt, arg, m_valid_read_only, m_closed);
1511 sm_ctxt->on_transition (node, stmt, arg, m_valid_write_only, m_closed);
1512 sm_ctxt->on_transition (node, stmt, arg, m_constant_fd, m_closed);
1513 sm_ctxt->on_transition (node, stmt, arg, m_new_datagram_socket, m_closed);
1514 sm_ctxt->on_transition (node, stmt, arg, m_new_stream_socket, m_closed);
1515 sm_ctxt->on_transition (node, stmt, arg, m_new_unknown_socket, m_closed);
1516 sm_ctxt->on_transition (node, stmt, arg, m_bound_datagram_socket, m_closed);
1517 sm_ctxt->on_transition (node, stmt, arg, m_bound_stream_socket, m_closed);
1518 sm_ctxt->on_transition (node, stmt, arg, m_bound_unknown_socket, m_closed);
1519 sm_ctxt->on_transition (node, stmt, arg, m_listening_stream_socket, m_closed);
1520 sm_ctxt->on_transition (node, stmt, arg, m_connected_stream_socket, m_closed);
1522 if (is_closed_fd_p (state))
1524 sm_ctxt->warn (node, stmt, arg,
1525 make_unique<fd_double_close> (*this, diag_arg));
1526 sm_ctxt->set_next_state (stmt, arg, m_stop);
1530 fd_state_machine::on_read (sm_context *sm_ctxt, const supernode *node,
1531 const gimple *stmt, const gcall *call,
1532 const tree callee_fndecl) const
1534 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_READ);
1537 fd_state_machine::on_write (sm_context *sm_ctxt, const supernode *node,
1538 const gimple *stmt, const gcall *call,
1539 const tree callee_fndecl) const
1541 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_WRITE);
1545 fd_state_machine::check_for_open_fd (
1546 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
1547 const gcall *call, const tree callee_fndecl,
1548 enum access_directions callee_fndecl_dir) const
1550 tree arg = gimple_call_arg (call, 0);
1551 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1552 state_t state = sm_ctxt->get_state (stmt, arg);
1554 if (is_closed_fd_p (state))
1556 sm_ctxt->warn (node, stmt, arg,
1557 make_unique<fd_use_after_close> (*this, diag_arg,
1563 if (state == m_new_stream_socket
1564 || state == m_bound_stream_socket
1565 || state == m_listening_stream_socket)
1566 /* Complain about fncall on socket in wrong phase. */
1569 make_unique<fd_phase_mismatch> (*this, diag_arg,
1572 EXPECTED_PHASE_CAN_TRANSFER));
1573 else if (!(is_valid_fd_p (state)
1574 || state == m_new_datagram_socket
1575 || state == m_bound_unknown_socket
1576 || state == m_connected_stream_socket
1578 || state == m_stop))
1580 if (!is_constant_fd_p (state))
1583 make_unique<fd_use_without_check> (*this, diag_arg,
1586 switch (callee_fndecl_dir)
1588 case DIRS_READ_WRITE:
1591 if (is_writeonly_fd_p (state))
1593 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1594 sm_ctxt->warn (node, stmt, arg,
1595 make_unique<fd_access_mode_mismatch> (
1596 *this, diag_arg, DIRS_WRITE, callee_fndecl));
1602 if (is_readonly_fd_p (state))
1604 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1605 sm_ctxt->warn (node, stmt, arg,
1606 make_unique<fd_access_mode_mismatch> (
1607 *this, diag_arg, DIRS_READ, callee_fndecl));
1615 add_constraint_ge_zero (region_model *model,
1616 const svalue *fd_sval,
1617 region_model_context *ctxt)
1620 = model->get_manager ()->get_or_create_int_cst (integer_type_node, 0);
1621 return model->add_constraint (fd_sval, GE_EXPR, zero, ctxt);
1624 /* Get the state for a new socket type based on SOCKET_TYPE_SVAL,
1627 state_machine::state_t
1629 get_state_for_socket_type (const svalue *socket_type_sval) const
1631 if (tree socket_type_cst = socket_type_sval->maybe_get_constant ())
1633 /* Attempt to use SOCK_* constants stashed from the frontend. */
1634 if (tree_int_cst_equal (socket_type_cst, m_SOCK_STREAM))
1635 return m_new_stream_socket;
1636 if (tree_int_cst_equal (socket_type_cst, m_SOCK_DGRAM))
1637 return m_new_datagram_socket;
1640 /* Unrecognized constant, or a symbolic "type" value. */
1641 return m_new_unknown_socket;
1644 /* Update the model and fd state for an outcome of a call to "socket",
1645 where SUCCESSFUL indicate which of the two outcomes.
1646 Return true if the outcome is feasible, or false to reject it. */
1649 fd_state_machine::on_socket (const call_details &cd,
1651 sm_context *sm_ctxt,
1652 const extrinsic_state &ext_state) const
1654 const gcall *stmt = cd.get_call_stmt ();
1655 engine *eng = ext_state.get_engine ();
1656 const supergraph *sg = eng->get_supergraph ();
1657 const supernode *node = sg->get_supernode_for_stmt (stmt);
1658 region_model *model = cd.get_model ();
1662 if (gimple_call_lhs (stmt))
1664 conjured_purge p (model, cd.get_ctxt ());
1665 region_model_manager *mgr = model->get_manager ();
1666 const svalue *new_fd
1667 = mgr->get_or_create_conjured_svalue (integer_type_node,
1669 cd.get_lhs_region (),
1671 if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
1674 const svalue *socket_type_sval = cd.get_arg_svalue (1);
1675 state_machine::state_t new_state
1676 = get_state_for_socket_type (socket_type_sval);
1677 sm_ctxt->on_transition (node, stmt, new_fd, m_start, new_state);
1678 model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
1681 sm_ctxt->warn (node, stmt, NULL_TREE,
1682 make_unique<fd_leak> (*this, NULL_TREE));
1686 /* Return -1; set errno. */
1687 model->update_for_int_cst_return (cd, -1, true);
1688 model->set_errno (cd);
1694 /* Check that FD_SVAL is usable by socket APIs.
1695 Complain if it has been closed, if it is a non-socket,
1697 If COMPLAINED is non-NULL and a problem is found,
1698 write *COMPLAINED = true.
1700 If SUCCESSFUL is true, attempt to add the constraint that FD_SVAL >= 0.
1701 Return true if this outcome is feasible. */
1704 fd_state_machine::check_for_socket_fd (const call_details &cd,
1706 sm_context *sm_ctxt,
1707 const svalue *fd_sval,
1708 const supernode *node,
1710 bool *complained) const
1712 const gcall *stmt = cd.get_call_stmt ();
1714 if (is_closed_fd_p (old_state))
1716 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1718 (node, stmt, fd_sval,
1719 make_unique<fd_use_after_close> (*this, diag_arg,
1720 cd.get_fndecl_for_call ()));
1726 else if (is_unchecked_fd_p (old_state) || is_valid_fd_p (old_state))
1728 /* Complain about non-socket. */
1729 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1731 (node, stmt, fd_sval,
1732 make_unique<fd_type_mismatch> (*this, diag_arg,
1733 cd.get_fndecl_for_call (),
1735 EXPECTED_TYPE_SOCKET));
1741 else if (old_state == m_invalid)
1743 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1745 (node, stmt, fd_sval,
1746 make_unique<fd_use_without_check> (*this, diag_arg,
1747 cd.get_fndecl_for_call ()));
1755 if (!add_constraint_ge_zero (cd.get_model (), fd_sval, cd.get_ctxt ()))
1761 /* For use by "bind" and "connect".
1762 As per fd_state_machine::check_for_socket_fd above,
1763 but also complain if we don't have a new socket, and check that
1764 we can read up to the size bytes from the address. */
1767 fd_state_machine::check_for_new_socket_fd (const call_details &cd,
1769 sm_context *sm_ctxt,
1770 const svalue *fd_sval,
1771 const supernode *node,
1773 enum expected_phase expected_phase)
1776 bool complained = false;
1778 /* Check address and len. */
1779 const svalue *address_sval = cd.get_arg_svalue (1);
1780 const svalue *len_sval = cd.get_arg_svalue (2);
1782 /* Check that we can read the given number of bytes from the
1784 region_model *model = cd.get_model ();
1785 const region *address_reg
1786 = model->deref_rvalue (address_sval, cd.get_arg_tree (1),
1788 const region *sized_address_reg
1789 = model->get_manager ()->get_sized_region (address_reg,
1792 model->get_store_value (sized_address_reg, cd.get_ctxt ());
1794 if (!check_for_socket_fd (cd, successful, sm_ctxt,
1795 fd_sval, node, old_state, &complained))
1797 else if (!complained
1798 && !(old_state == m_new_stream_socket
1799 || old_state == m_new_datagram_socket
1800 || old_state == m_new_unknown_socket
1801 || old_state == m_start
1802 || old_state == m_stop
1803 || old_state == m_constant_fd))
1805 /* Complain about "bind" or "connect" in wrong phase. */
1806 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1808 (node, cd.get_call_stmt (), fd_sval,
1809 make_unique<fd_phase_mismatch> (*this, diag_arg,
1810 cd.get_fndecl_for_call (),
1816 else if (!successful)
1818 /* If we were in the start state, assume we had a new socket. */
1819 if (old_state == m_start)
1820 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1821 m_new_unknown_socket);
1824 /* Passing NULL as the address will lead to failure. */
1826 if (address_sval->all_zeroes_p ())
1832 /* Update the model and fd state for an outcome of a call to "bind",
1833 where SUCCESSFUL indicate which of the two outcomes.
1834 Return true if the outcome is feasible, or false to reject it. */
1837 fd_state_machine::on_bind (const call_details &cd,
1839 sm_context *sm_ctxt,
1840 const extrinsic_state &ext_state) const
1842 const gcall *stmt = cd.get_call_stmt ();
1843 engine *eng = ext_state.get_engine ();
1844 const supergraph *sg = eng->get_supergraph ();
1845 const supernode *node = sg->get_supernode_for_stmt (stmt);
1846 const svalue *fd_sval = cd.get_arg_svalue (0);
1847 region_model *model = cd.get_model ();
1848 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1850 if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
1851 fd_sval, node, old_state,
1852 EXPECTED_PHASE_CAN_BIND))
1857 state_t next_state = NULL;
1858 if (old_state == m_new_stream_socket)
1859 next_state = m_bound_stream_socket;
1860 else if (old_state == m_new_datagram_socket)
1861 next_state = m_bound_datagram_socket;
1862 else if (old_state == m_new_unknown_socket)
1863 next_state = m_bound_unknown_socket;
1864 else if (old_state == m_start)
1865 next_state = m_bound_unknown_socket;
1866 else if (old_state == m_stop)
1867 next_state = m_stop;
1870 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval, next_state);
1871 model->update_for_zero_return (cd, true);
1875 /* Return -1; set errno. */
1876 model->update_for_int_cst_return (cd, -1, true);
1877 model->set_errno (cd);
1883 /* Update the model and fd state for an outcome of a call to "listen",
1884 where SUCCESSFUL indicate which of the two outcomes.
1885 Return true if the outcome is feasible, or false to reject it. */
1888 fd_state_machine::on_listen (const call_details &cd,
1890 sm_context *sm_ctxt,
1891 const extrinsic_state &ext_state) const
1893 const gcall *stmt = cd.get_call_stmt ();
1894 engine *eng = ext_state.get_engine ();
1895 const supergraph *sg = eng->get_supergraph ();
1896 const supernode *node = sg->get_supernode_for_stmt (cd.get_call_stmt ());
1897 const svalue *fd_sval = cd.get_arg_svalue (0);
1898 region_model *model = cd.get_model ();
1899 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1901 /* We expect a stream socket that's had "bind" called on it. */
1902 if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
1904 if (!(old_state == m_start
1905 || old_state == m_constant_fd
1906 || old_state == m_stop
1907 || old_state == m_bound_stream_socket
1908 || old_state == m_bound_unknown_socket
1909 /* Assume it's OK to call "listen" more than once. */
1910 || old_state == m_listening_stream_socket))
1912 /* Complain about fncall on wrong type or in wrong phase. */
1913 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1914 if (is_stream_socket_fd_p (old_state))
1916 (node, stmt, fd_sval,
1917 make_unique<fd_phase_mismatch> (*this, diag_arg,
1918 cd.get_fndecl_for_call (),
1920 EXPECTED_PHASE_CAN_LISTEN));
1923 (node, stmt, fd_sval,
1924 make_unique<fd_type_mismatch> (*this, diag_arg,
1925 cd.get_fndecl_for_call (),
1927 EXPECTED_TYPE_STREAM_SOCKET));
1934 model->update_for_zero_return (cd, true);
1935 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1936 m_listening_stream_socket);
1940 /* Return -1; set errno. */
1941 model->update_for_int_cst_return (cd, -1, true);
1942 model->set_errno (cd);
1943 if (old_state == m_start)
1944 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1945 m_bound_stream_socket);
1951 /* Update the model and fd state for an outcome of a call to "accept",
1952 where SUCCESSFUL indicate which of the two outcomes.
1953 Return true if the outcome is feasible, or false to reject it. */
1956 fd_state_machine::on_accept (const call_details &cd,
1958 sm_context *sm_ctxt,
1959 const extrinsic_state &ext_state) const
1961 const gcall *stmt = cd.get_call_stmt ();
1962 engine *eng = ext_state.get_engine ();
1963 const supergraph *sg = eng->get_supergraph ();
1964 const supernode *node = sg->get_supernode_for_stmt (stmt);
1965 const svalue *fd_sval = cd.get_arg_svalue (0);
1966 const svalue *address_sval = cd.get_arg_svalue (1);
1967 const svalue *len_ptr_sval = cd.get_arg_svalue (2);
1968 region_model *model = cd.get_model ();
1969 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1971 if (!address_sval->all_zeroes_p ())
1973 region_model_manager *mgr = model->get_manager ();
1975 /* We might have a union of various pointer types, rather than a
1976 pointer type; cast to (void *) before dereferencing. */
1977 address_sval = mgr->get_or_create_cast (ptr_type_node, address_sval);
1979 const region *address_reg
1980 = model->deref_rvalue (address_sval, cd.get_arg_tree (1),
1982 const region *len_reg
1983 = model->deref_rvalue (len_ptr_sval, cd.get_arg_tree (2),
1985 const svalue *old_len_sval
1986 = model->get_store_value (len_reg, cd.get_ctxt ());
1987 tree len_ptr = cd.get_arg_tree (2);
1988 tree star_len_ptr = build2 (MEM_REF, TREE_TYPE (TREE_TYPE (len_ptr)),
1990 build_int_cst (TREE_TYPE (len_ptr), 0));
1991 old_len_sval = model->check_for_poison (old_len_sval,
1996 conjured_purge p (model, cd.get_ctxt ());
1997 const region *old_sized_address_reg
1998 = mgr->get_sized_region (address_reg,
2001 const svalue *new_addr_sval
2002 = mgr->get_or_create_conjured_svalue (NULL_TREE,
2004 old_sized_address_reg,
2006 model->set_value (old_sized_address_reg, new_addr_sval,
2008 const svalue *new_addr_len
2009 = mgr->get_or_create_conjured_svalue (NULL_TREE,
2013 model->set_value (len_reg, new_addr_len, cd.get_ctxt ());
2017 /* We expect a stream socket in the "listening" state. */
2018 if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
2021 if (old_state == m_start || old_state == m_constant_fd)
2022 /* If we were in the start state (or a constant), assume we had the
2024 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
2025 m_listening_stream_socket);
2026 else if (old_state == m_stop)
2028 /* No further complaints. */
2030 else if (old_state != m_listening_stream_socket)
2032 /* Complain about fncall on wrong type or in wrong phase. */
2033 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
2034 if (is_stream_socket_fd_p (old_state))
2036 (node, stmt, fd_sval,
2037 make_unique<fd_phase_mismatch> (*this, diag_arg,
2038 cd.get_fndecl_for_call (),
2040 EXPECTED_PHASE_CAN_ACCEPT));
2043 (node, stmt, fd_sval,
2044 make_unique<fd_type_mismatch> (*this, diag_arg,
2045 cd.get_fndecl_for_call (),
2047 EXPECTED_TYPE_STREAM_SOCKET));
2054 /* Return new conjured FD in "connected" state. */
2055 if (gimple_call_lhs (stmt))
2057 conjured_purge p (model, cd.get_ctxt ());
2058 region_model_manager *mgr = model->get_manager ();
2059 const svalue *new_fd
2060 = mgr->get_or_create_conjured_svalue (integer_type_node,
2062 cd.get_lhs_region (),
2064 if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
2066 sm_ctxt->on_transition (node, stmt, new_fd,
2067 m_start, m_connected_stream_socket);
2068 model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
2071 sm_ctxt->warn (node, stmt, NULL_TREE,
2072 make_unique<fd_leak> (*this, NULL_TREE));
2076 /* Return -1; set errno. */
2077 model->update_for_int_cst_return (cd, -1, true);
2078 model->set_errno (cd);
2084 /* Update the model and fd state for an outcome of a call to "connect",
2085 where SUCCESSFUL indicate which of the two outcomes.
2086 Return true if the outcome is feasible, or false to reject it. */
2089 fd_state_machine::on_connect (const call_details &cd,
2091 sm_context *sm_ctxt,
2092 const extrinsic_state &ext_state) const
2094 const gcall *stmt = cd.get_call_stmt ();
2095 engine *eng = ext_state.get_engine ();
2096 const supergraph *sg = eng->get_supergraph ();
2097 const supernode *node = sg->get_supernode_for_stmt (stmt);
2098 const svalue *fd_sval = cd.get_arg_svalue (0);
2099 region_model *model = cd.get_model ();
2100 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
2102 if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
2103 fd_sval, node, old_state,
2104 EXPECTED_PHASE_CAN_CONNECT))
2109 model->update_for_zero_return (cd, true);
2110 state_t next_state = NULL;
2111 if (old_state == m_new_stream_socket)
2112 next_state = m_connected_stream_socket;
2113 else if (old_state == m_new_datagram_socket)
2114 /* It's legal to call connect on a datagram socket, potentially
2115 more than once. We don't transition states for this. */
2116 next_state = m_new_datagram_socket;
2117 else if (old_state == m_new_unknown_socket)
2118 next_state = m_stop;
2119 else if (old_state == m_start)
2120 next_state = m_stop;
2121 else if (old_state == m_stop)
2122 next_state = m_stop;
2125 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval, next_state);
2129 /* Return -1; set errno. */
2130 model->update_for_int_cst_return (cd, -1, true);
2131 model->set_errno (cd);
2132 /* TODO: perhaps transition to a failed state, since the
2133 portable way to handle a failed "connect" is to close
2134 the socket and try again with a new socket. */
2141 fd_state_machine::on_condition (sm_context *sm_ctxt, const supernode *node,
2142 const gimple *stmt, const svalue *lhs,
2143 enum tree_code op, const svalue *rhs) const
2145 if (tree cst = rhs->maybe_get_constant ())
2147 if (TREE_CODE (cst) == INTEGER_CST)
2149 int val = TREE_INT_CST_LOW (cst);
2153 make_valid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2155 else if (op == EQ_EXPR)
2156 make_invalid_transitions_on_condition (sm_ctxt, node, stmt,
2162 if (rhs->all_zeroes_p ())
2165 make_valid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2166 else if (op == LT_EXPR)
2167 make_invalid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2172 fd_state_machine::make_valid_transitions_on_condition (sm_context *sm_ctxt,
2173 const supernode *node,
2175 const svalue *lhs) const
2177 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_write,
2178 m_valid_read_write);
2179 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_only,
2181 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_write_only,
2182 m_valid_write_only);
2186 fd_state_machine::make_invalid_transitions_on_condition (
2187 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
2188 const svalue *lhs) const
2190 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_write, m_invalid);
2191 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_only, m_invalid);
2192 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_write_only, m_invalid);
2196 fd_state_machine::can_purge_p (state_t s) const
2198 if (is_unchecked_fd_p (s)
2199 || is_valid_fd_p (s)
2200 || is_socket_fd_p (s))
2206 std::unique_ptr<pending_diagnostic>
2207 fd_state_machine::on_leak (tree var) const
2209 return make_unique<fd_leak> (*this, var);
2214 make_fd_state_machine (logger *logger)
2216 return new fd_state_machine (logger);
2220 get_fd_state (region_model_context *ctxt,
2221 sm_state_map **out_smap,
2222 const fd_state_machine **out_sm,
2223 unsigned *out_sm_idx,
2224 std::unique_ptr<sm_context> *out_sm_context)
2229 const state_machine *sm;
2230 if (!ctxt->get_fd_map (out_smap, &sm, out_sm_idx, out_sm_context))
2235 *out_sm = (const fd_state_machine *)sm;
2239 /* Specialcase hook for handling pipe, for use by
2240 kf_pipe::success::update_model. */
2243 region_model::mark_as_valid_fd (const svalue *sval, region_model_context *ctxt)
2246 const fd_state_machine *fd_sm;
2247 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, NULL))
2249 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2252 fd_sm->mark_as_valid_fd (this, smap, sval, *ext_state);
2255 /* Handle calls to "socket".
2256 See e.g. https://man7.org/linux/man-pages/man3/socket.3p.html */
2258 class kf_socket : public known_function
2261 class outcome_of_socket : public succeed_or_fail_call_info
2264 outcome_of_socket (const call_details &cd, bool success)
2265 : succeed_or_fail_call_info (cd, success)
2268 bool update_model (region_model *model,
2269 const exploded_edge *,
2270 region_model_context *ctxt) const final override
2272 const call_details cd (get_call_details (model, ctxt));
2274 const fd_state_machine *fd_sm;
2275 std::unique_ptr<sm_context> sm_ctxt;
2276 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2278 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2282 return fd_sm->on_socket (cd, m_success, sm_ctxt.get (), *ext_state);
2286 bool matches_call_types_p (const call_details &cd) const final override
2288 return cd.num_args () == 3;
2291 void impl_call_post (const call_details &cd) const final override
2295 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, false));
2296 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, true));
2297 cd.get_ctxt ()->terminate_path ();
2302 /* Handle calls to "bind".
2303 See e.g. https://man7.org/linux/man-pages/man3/bind.3p.html */
2305 class kf_bind : public known_function
2308 class outcome_of_bind : public succeed_or_fail_call_info
2311 outcome_of_bind (const call_details &cd, bool success)
2312 : succeed_or_fail_call_info (cd, success)
2315 bool update_model (region_model *model,
2316 const exploded_edge *,
2317 region_model_context *ctxt) const final override
2319 const call_details cd (get_call_details (model, ctxt));
2321 const fd_state_machine *fd_sm;
2322 std::unique_ptr<sm_context> sm_ctxt;
2323 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2325 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2328 return fd_sm->on_bind (cd, m_success, sm_ctxt.get (), *ext_state);
2332 bool matches_call_types_p (const call_details &cd) const final override
2334 return (cd.num_args () == 3 && cd.arg_is_pointer_p (1));
2337 void impl_call_post (const call_details &cd) const final override
2341 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, false));
2342 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, true));
2343 cd.get_ctxt ()->terminate_path ();
2348 /* Handle calls to "listen".
2349 See e.g. https://man7.org/linux/man-pages/man3/listen.3p.html */
2351 class kf_listen : public known_function
2353 class outcome_of_listen : public succeed_or_fail_call_info
2356 outcome_of_listen (const call_details &cd, bool success)
2357 : succeed_or_fail_call_info (cd, success)
2360 bool update_model (region_model *model,
2361 const exploded_edge *,
2362 region_model_context *ctxt) const final override
2364 const call_details cd (get_call_details (model, ctxt));
2366 const fd_state_machine *fd_sm;
2367 std::unique_ptr<sm_context> sm_ctxt;
2368 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2370 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2374 return fd_sm->on_listen (cd, m_success, sm_ctxt.get (), *ext_state);
2378 bool matches_call_types_p (const call_details &cd) const final override
2380 return cd.num_args () == 2;
2383 void impl_call_post (const call_details &cd) const final override
2387 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, false));
2388 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, true));
2389 cd.get_ctxt ()->terminate_path ();
2394 /* Handle calls to "accept".
2395 See e.g. https://man7.org/linux/man-pages/man3/accept.3p.html */
2397 class kf_accept : public known_function
2399 class outcome_of_accept : public succeed_or_fail_call_info
2402 outcome_of_accept (const call_details &cd, bool success)
2403 : succeed_or_fail_call_info (cd, success)
2406 bool update_model (region_model *model,
2407 const exploded_edge *,
2408 region_model_context *ctxt) const final override
2410 const call_details cd (get_call_details (model, ctxt));
2412 const fd_state_machine *fd_sm;
2413 std::unique_ptr<sm_context> sm_ctxt;
2414 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2416 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2420 return fd_sm->on_accept (cd, m_success, sm_ctxt.get (), *ext_state);
2424 bool matches_call_types_p (const call_details &cd) const final override
2426 return (cd.num_args () == 3
2427 && cd.arg_is_pointer_p (1)
2428 && cd.arg_is_pointer_p (2));
2431 void impl_call_post (const call_details &cd) const final override
2435 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, false));
2436 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, true));
2437 cd.get_ctxt ()->terminate_path ();
2442 /* Handle calls to "connect".
2443 See e.g. https://man7.org/linux/man-pages/man3/connect.3p.html */
2445 class kf_connect : public known_function
2448 class outcome_of_connect : public succeed_or_fail_call_info
2451 outcome_of_connect (const call_details &cd, bool success)
2452 : succeed_or_fail_call_info (cd, success)
2455 bool update_model (region_model *model,
2456 const exploded_edge *,
2457 region_model_context *ctxt) const final override
2459 const call_details cd (get_call_details (model, ctxt));
2461 const fd_state_machine *fd_sm;
2462 std::unique_ptr<sm_context> sm_ctxt;
2463 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2465 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2469 return fd_sm->on_connect (cd, m_success, sm_ctxt.get (), *ext_state);
2473 bool matches_call_types_p (const call_details &cd) const final override
2475 return (cd.num_args () == 3
2476 && cd.arg_is_pointer_p (1));
2479 void impl_call_post (const call_details &cd) const final override
2483 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, false));
2484 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, true));
2485 cd.get_ctxt ()->terminate_path ();
2490 /* Handler for calls to "pipe" and "pipe2".
2491 See e.g. https://www.man7.org/linux/man-pages/man2/pipe.2.html */
2493 class kf_pipe : public known_function
2495 class failure : public failed_call_info
2498 failure (const call_details &cd) : failed_call_info (cd) {}
2500 bool update_model (region_model *model,
2501 const exploded_edge *,
2502 region_model_context *ctxt) const final override
2504 /* Return -1; everything else is unchanged. */
2505 const call_details cd (get_call_details (model, ctxt));
2506 model->update_for_int_cst_return (cd, -1, true);
2511 class success : public success_call_info
2514 success (const call_details &cd) : success_call_info (cd) {}
2516 bool update_model (region_model *model,
2517 const exploded_edge *,
2518 region_model_context *ctxt) const final override
2520 const call_details cd (get_call_details (model, ctxt));
2523 model->update_for_zero_return (cd, true);
2525 /* Update fd array. */
2526 region_model_manager *mgr = cd.get_manager ();
2527 tree arr_tree = cd.get_arg_tree (0);
2528 const svalue *arr_sval = cd.get_arg_svalue (0);
2529 for (int idx = 0; idx < 2; idx++)
2531 const region *arr_reg
2532 = model->deref_rvalue (arr_sval, arr_tree, cd.get_ctxt ());
2533 const svalue *idx_sval
2534 = mgr->get_or_create_int_cst (integer_type_node, idx);
2535 const region *element_reg
2536 = mgr->get_element_region (arr_reg, integer_type_node, idx_sval);
2537 conjured_purge p (model, cd.get_ctxt ());
2538 const svalue *fd_sval
2539 = mgr->get_or_create_conjured_svalue (integer_type_node,
2540 cd.get_call_stmt (),
2543 model->set_value (element_reg, fd_sval, cd.get_ctxt ());
2544 model->mark_as_valid_fd (fd_sval, cd.get_ctxt ());
2551 kf_pipe (unsigned num_args)
2552 : m_num_args (num_args)
2554 gcc_assert (num_args > 0);
2557 bool matches_call_types_p (const call_details &cd) const final override
2559 return (cd.num_args () == m_num_args && cd.arg_is_pointer_p (0));
2562 void impl_call_post (const call_details &cd) const final override
2566 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
2567 cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
2568 cd.get_ctxt ()->terminate_path ();
2573 unsigned m_num_args;
2576 /* Populate KFM with instances of known functions relating to
2577 file descriptors. */
2580 register_known_fd_functions (known_function_manager &kfm)
2582 kfm.add ("accept", make_unique<kf_accept> ());
2583 kfm.add ("bind", make_unique<kf_bind> ());
2584 kfm.add ("connect", make_unique<kf_connect> ());
2585 kfm.add ("listen", make_unique<kf_listen> ());
2586 kfm.add ("pipe", make_unique<kf_pipe> (1));
2587 kfm.add ("pipe2", make_unique<kf_pipe> (2));
2588 kfm.add ("socket", make_unique<kf_socket> ());
2593 #endif // ENABLE_ANALYZER