libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / analyzer / sm-fd.cc
blob3396b1d11228be356ddd5ee1b77c7d44c0eefb32
1 /* A state machine for detecting misuses of POSIX file descriptor APIs.
2 Copyright (C) 2019-2024 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)
10 any later version.
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/>. */
21 #include "config.h"
22 #define INCLUDE_MEMORY
23 #define INCLUDE_VECTOR
24 #include "system.h"
25 #include "coretypes.h"
26 #include "make-unique.h"
27 #include "tree.h"
28 #include "function.h"
29 #include "basic-block.h"
30 #include "gimple.h"
31 #include "options.h"
32 #include "diagnostic-path.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"
41 #include "attribs.h"
42 #include "analyzer/call-string.h"
43 #include "analyzer/program-point.h"
44 #include "analyzer/store.h"
45 #include "analyzer/region-model.h"
46 #include "bitmap.h"
47 #include "analyzer/program-state.h"
48 #include "analyzer/supergraph.h"
49 #include "analyzer/analyzer-language.h"
50 #include "analyzer/call-details.h"
51 #include "analyzer/call-info.h"
53 #if ENABLE_ANALYZER
55 namespace ana {
57 namespace {
59 /* An enum for distinguishing between three different access modes. */
61 enum access_mode
63 READ_WRITE,
64 READ_ONLY,
65 WRITE_ONLY
68 enum access_directions
70 DIRS_READ_WRITE,
71 DIRS_READ,
72 DIRS_WRITE
75 /* An enum for distinguishing between dup, dup2 and dup3. */
76 enum dup
78 DUP_1,
79 DUP_2,
80 DUP_3
83 /* Enum for use by -Wanalyzer-fd-phase-mismatch. */
85 enum expected_phase
87 EXPECTED_PHASE_CAN_TRANSFER, /* can "read"/"write". */
88 EXPECTED_PHASE_CAN_BIND,
89 EXPECTED_PHASE_CAN_LISTEN,
90 EXPECTED_PHASE_CAN_ACCEPT,
91 EXPECTED_PHASE_CAN_CONNECT
94 class fd_state_machine : public state_machine
96 public:
97 fd_state_machine (logger *logger);
99 bool
100 inherited_state_p () const final override
102 return false;
105 state_machine::state_t
106 get_default_state (const svalue *sval) const final override
108 if (tree cst = sval->maybe_get_constant ())
110 if (TREE_CODE (cst) == INTEGER_CST)
112 int val = TREE_INT_CST_LOW (cst);
113 if (val >= 0)
114 return m_constant_fd;
115 else
116 return m_invalid;
119 return m_start;
122 bool on_stmt (sm_context &sm_ctxt, const supernode *node,
123 const gimple *stmt) const final override;
125 void on_condition (sm_context &sm_ctxt, const supernode *node,
126 const gimple *stmt, const svalue *lhs, const tree_code op,
127 const svalue *rhs) const final override;
129 bool can_purge_p (state_t s) const final override;
130 std::unique_ptr<pending_diagnostic> on_leak (tree var) const final override;
132 bool is_unchecked_fd_p (state_t s) const;
133 bool is_valid_fd_p (state_t s) const;
134 bool is_socket_fd_p (state_t s) const;
135 bool is_datagram_socket_fd_p (state_t s) const;
136 bool is_stream_socket_fd_p (state_t s) const;
137 bool is_closed_fd_p (state_t s) const;
138 bool is_constant_fd_p (state_t s) const;
139 bool is_readonly_fd_p (state_t s) const;
140 bool is_writeonly_fd_p (state_t s) const;
141 enum access_mode get_access_mode_from_flag (int flag) const;
142 /* Function for one-to-one correspondence between valid
143 and unchecked states. */
144 state_t valid_to_unchecked_state (state_t state) const;
146 void mark_as_valid_fd (region_model *model,
147 sm_state_map *smap,
148 const svalue *fd_sval,
149 const extrinsic_state &ext_state) const;
151 bool on_socket (const call_details &cd,
152 bool successful,
153 sm_context &sm_ctxt,
154 const extrinsic_state &ext_state) const;
155 bool on_bind (const call_details &cd,
156 bool successful,
157 sm_context &sm_ctxt,
158 const extrinsic_state &ext_state) const;
159 bool on_listen (const call_details &cd,
160 bool successful,
161 sm_context &sm_ctxt,
162 const extrinsic_state &ext_state) const;
163 bool on_accept (const call_details &cd,
164 bool successful,
165 sm_context &sm_ctxt,
166 const extrinsic_state &ext_state) const;
167 bool on_connect (const call_details &cd,
168 bool successful,
169 sm_context &sm_ctxt,
170 const extrinsic_state &ext_state) const;
172 /* State for a constant file descriptor (>= 0) */
173 state_t m_constant_fd;
175 /* States representing a file descriptor that hasn't yet been
176 checked for validity after opening, for three different
177 access modes. */
178 state_t m_unchecked_read_write;
180 state_t m_unchecked_read_only;
182 state_t m_unchecked_write_only;
184 /* States for representing a file descriptor that is known to be valid (>=
185 0), for three different access modes. */
186 state_t m_valid_read_write;
188 state_t m_valid_read_only;
190 state_t m_valid_write_only;
192 /* State for a file descriptor that is known to be invalid (< 0). */
193 state_t m_invalid;
195 /* State for a file descriptor that has been closed. */
196 state_t m_closed;
198 /* States for FDs relating to socket APIs. */
200 /* Result of successful "socket" with SOCK_DGRAM. */
201 state_t m_new_datagram_socket;
202 /* Result of successful "socket" with SOCK_STREAM. */
203 state_t m_new_stream_socket;
204 /* Result of successful "socket" with unknown type. */
205 state_t m_new_unknown_socket;
207 /* The above after a successful call to "bind". */
208 state_t m_bound_datagram_socket;
209 state_t m_bound_stream_socket;
210 state_t m_bound_unknown_socket;
212 /* A bound socket after a successful call to "listen" (stream or unknown). */
213 state_t m_listening_stream_socket;
215 /* (i) the new FD as a result of a succesful call to "accept" on a
216 listening socket (via a passive open), or
217 (ii) an active socket after a successful call to "connect"
218 (via an active open). */
219 state_t m_connected_stream_socket;
221 /* State for a file descriptor that we do not want to track anymore . */
222 state_t m_stop;
224 /* Stashed constant values from the frontend. These could be NULL. */
225 tree m_O_ACCMODE;
226 tree m_O_RDONLY;
227 tree m_O_WRONLY;
228 tree m_SOCK_STREAM;
229 tree m_SOCK_DGRAM;
231 private:
232 void on_open (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
233 const gcall *call) const;
234 void on_creat (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
235 const gcall *call) const;
236 void on_close (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
237 const gcall *call) const;
238 void on_read (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
239 const gcall *call, const tree callee_fndecl) const;
240 void on_write (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
241 const gcall *call, const tree callee_fndecl) const;
242 void check_for_open_fd (sm_context &sm_ctxt, const supernode *node,
243 const gimple *stmt, const gcall *call,
244 const tree callee_fndecl,
245 enum access_directions access_fn) const;
247 void make_valid_transitions_on_condition (sm_context &sm_ctxt,
248 const supernode *node,
249 const gimple *stmt,
250 const svalue *lhs) const;
251 void make_invalid_transitions_on_condition (sm_context &sm_ctxt,
252 const supernode *node,
253 const gimple *stmt,
254 const svalue *lhs) const;
255 void check_for_fd_attrs (sm_context &sm_ctxt, const supernode *node,
256 const gimple *stmt, const gcall *call,
257 const tree callee_fndecl, const char *attr_name,
258 access_directions fd_attr_access_dir) const;
259 void check_for_dup (sm_context &sm_ctxt, const supernode *node,
260 const gimple *stmt, const gcall *call, const tree callee_fndecl,
261 enum dup kind) const;
263 state_t get_state_for_socket_type (const svalue *socket_type_sval) const;
265 bool check_for_socket_fd (const call_details &cd,
266 bool successful,
267 sm_context &sm_ctxt,
268 const svalue *fd_sval,
269 const supernode *node,
270 state_t old_state,
271 bool *complained = NULL) const;
272 bool check_for_new_socket_fd (const call_details &cd,
273 bool successful,
274 sm_context &sm_ctxt,
275 const svalue *fd_sval,
276 const supernode *node,
277 state_t old_state,
278 enum expected_phase expected_phase) const;
281 /* Base diagnostic class relative to fd_state_machine. */
282 class fd_diagnostic : public pending_diagnostic
284 public:
285 fd_diagnostic (const fd_state_machine &sm, tree arg) : m_sm (sm), m_arg (arg)
289 bool
290 subclass_equal_p (const pending_diagnostic &base_other) const override
292 return same_tree_p (m_arg, ((const fd_diagnostic &)base_other).m_arg);
295 label_text
296 describe_state_change (const evdesc::state_change &change) override
298 if (change.m_old_state == m_sm.get_start_state ())
300 if (change.m_new_state == m_sm.m_unchecked_read_write
301 || change.m_new_state == m_sm.m_valid_read_write)
302 return change.formatted_print ("opened here as read-write");
304 if (change.m_new_state == m_sm.m_unchecked_read_only
305 || change.m_new_state == m_sm.m_valid_read_only)
306 return change.formatted_print ("opened here as read-only");
308 if (change.m_new_state == m_sm.m_unchecked_write_only
309 || change.m_new_state == m_sm.m_valid_write_only)
310 return change.formatted_print ("opened here as write-only");
312 if (change.m_new_state == m_sm.m_new_datagram_socket)
313 return change.formatted_print ("datagram socket created here");
315 if (change.m_new_state == m_sm.m_new_stream_socket)
316 return change.formatted_print ("stream socket created here");
318 if (change.m_new_state == m_sm.m_new_unknown_socket
319 || change.m_new_state == m_sm.m_connected_stream_socket)
320 return change.formatted_print ("socket created here");
323 if (change.m_new_state == m_sm.m_bound_datagram_socket)
324 return change.formatted_print ("datagram socket bound here");
326 if (change.m_new_state == m_sm.m_bound_stream_socket)
327 return change.formatted_print ("stream socket bound here");
329 if (change.m_new_state == m_sm.m_bound_unknown_socket
330 || change.m_new_state == m_sm.m_connected_stream_socket)
331 return change.formatted_print ("socket bound here");
333 if (change.m_new_state == m_sm.m_listening_stream_socket)
334 return change.formatted_print
335 ("stream socket marked as passive here via %qs", "listen");
337 if (change.m_new_state == m_sm.m_closed)
338 return change.formatted_print ("closed here");
340 if (m_sm.is_unchecked_fd_p (change.m_old_state)
341 && m_sm.is_valid_fd_p (change.m_new_state))
343 if (change.m_expr)
344 return change.formatted_print (
345 "assuming %qE is a valid file descriptor (>= 0)", change.m_expr);
346 else
347 return change.formatted_print ("assuming a valid file descriptor");
350 if (m_sm.is_unchecked_fd_p (change.m_old_state)
351 && change.m_new_state == m_sm.m_invalid)
353 if (change.m_expr)
354 return change.formatted_print (
355 "assuming %qE is an invalid file descriptor (< 0)",
356 change.m_expr);
357 else
358 return change.formatted_print ("assuming an invalid file descriptor");
361 return label_text ();
364 diagnostic_event::meaning
365 get_meaning_for_state_change (
366 const evdesc::state_change &change) const final override
368 if (change.m_old_state == m_sm.get_start_state ()
369 && (m_sm.is_unchecked_fd_p (change.m_new_state)
370 || change.m_new_state == m_sm.m_new_datagram_socket
371 || change.m_new_state == m_sm.m_new_stream_socket
372 || change.m_new_state == m_sm.m_new_unknown_socket))
373 return diagnostic_event::meaning (diagnostic_event::VERB_acquire,
374 diagnostic_event::NOUN_resource);
375 if (change.m_new_state == m_sm.m_closed)
376 return diagnostic_event::meaning (diagnostic_event::VERB_release,
377 diagnostic_event::NOUN_resource);
378 return diagnostic_event::meaning ();
381 protected:
382 const fd_state_machine &m_sm;
383 tree m_arg;
386 class fd_param_diagnostic : public fd_diagnostic
388 public:
389 fd_param_diagnostic (const fd_state_machine &sm, tree arg, tree callee_fndecl,
390 const char *attr_name, int arg_idx)
391 : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl),
392 m_attr_name (attr_name), m_arg_idx (arg_idx)
396 fd_param_diagnostic (const fd_state_machine &sm, tree arg, tree callee_fndecl)
397 : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl),
398 m_attr_name (NULL), m_arg_idx (-1)
402 bool
403 subclass_equal_p (const pending_diagnostic &base_other) const override
405 const fd_param_diagnostic &sub_other
406 = (const fd_param_diagnostic &)base_other;
407 return (same_tree_p (m_arg, sub_other.m_arg)
408 && same_tree_p (m_callee_fndecl, sub_other.m_callee_fndecl)
409 && m_arg_idx == sub_other.m_arg_idx
410 && ((m_attr_name)
411 ? (strcmp (m_attr_name, sub_other.m_attr_name) == 0)
412 : true));
415 void
416 inform_filedescriptor_attribute (access_directions fd_dir)
419 if (m_attr_name)
420 switch (fd_dir)
422 case DIRS_READ_WRITE:
423 inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
424 "argument %d of %qD must be an open file descriptor, due to "
425 "%<__attribute__((%s(%d)))%>",
426 m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx + 1);
427 break;
428 case DIRS_WRITE:
429 inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
430 "argument %d of %qD must be a readable file descriptor, due "
431 "to %<__attribute__((%s(%d)))%>",
432 m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx + 1);
433 break;
434 case DIRS_READ:
435 inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
436 "argument %d of %qD must be a writable file descriptor, due "
437 "to %<__attribute__((%s(%d)))%>",
438 m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx + 1);
439 break;
443 protected:
444 tree m_callee_fndecl;
445 const char *m_attr_name;
446 /* ARG_IDX is 0-based. */
447 int m_arg_idx;
450 class fd_leak : public fd_diagnostic
452 public:
453 fd_leak (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm, arg) {}
455 const char *
456 get_kind () const final override
458 return "fd_leak";
462 get_controlling_option () const final override
464 return OPT_Wanalyzer_fd_leak;
467 bool
468 emit (diagnostic_emission_context &ctxt) final override
470 /*CWE-775: Missing Release of File Descriptor or Handle after Effective
471 Lifetime
473 ctxt.add_cwe (775);
474 if (m_arg)
475 return ctxt.warn ("leak of file descriptor %qE", m_arg);
476 else
477 return ctxt.warn ("leak of file descriptor");
480 label_text
481 describe_state_change (const evdesc::state_change &change) final override
483 if (m_sm.is_unchecked_fd_p (change.m_new_state))
485 m_open_event = change.m_event_id;
486 return label_text::borrow ("opened here");
489 return fd_diagnostic::describe_state_change (change);
492 label_text
493 describe_final_event (const evdesc::final_event &ev) final override
495 if (m_open_event.known_p ())
497 if (ev.m_expr)
498 return ev.formatted_print ("%qE leaks here; was opened at %@",
499 ev.m_expr, &m_open_event);
500 else
501 return ev.formatted_print ("leaks here; was opened at %@",
502 &m_open_event);
504 else
506 if (ev.m_expr)
507 return ev.formatted_print ("%qE leaks here", ev.m_expr);
508 else
509 return ev.formatted_print ("leaks here");
513 private:
514 diagnostic_event_id_t m_open_event;
517 class fd_access_mode_mismatch : public fd_param_diagnostic
519 public:
520 fd_access_mode_mismatch (const fd_state_machine &sm, tree arg,
521 enum access_directions fd_dir,
522 const tree callee_fndecl, const char *attr_name,
523 int arg_idx)
524 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx),
525 m_fd_dir (fd_dir)
530 fd_access_mode_mismatch (const fd_state_machine &sm, tree arg,
531 enum access_directions fd_dir,
532 const tree callee_fndecl)
533 : fd_param_diagnostic (sm, arg, callee_fndecl), m_fd_dir (fd_dir)
537 const char *
538 get_kind () const final override
540 return "fd_access_mode_mismatch";
544 get_controlling_option () const final override
546 return OPT_Wanalyzer_fd_access_mode_mismatch;
549 bool
550 emit (diagnostic_emission_context &ctxt) final override
552 bool warned;
553 switch (m_fd_dir)
555 case DIRS_READ:
556 warned = ctxt.warn ("%qE on read-only file descriptor %qE",
557 m_callee_fndecl, m_arg);
558 break;
559 case DIRS_WRITE:
560 warned = ctxt.warn ("%qE on write-only file descriptor %qE",
561 m_callee_fndecl, m_arg);
562 break;
563 default:
564 gcc_unreachable ();
566 if (warned)
567 inform_filedescriptor_attribute (m_fd_dir);
568 return warned;
571 label_text
572 describe_final_event (const evdesc::final_event &ev) final override
574 switch (m_fd_dir)
576 case DIRS_READ:
577 return ev.formatted_print ("%qE on read-only file descriptor %qE",
578 m_callee_fndecl, m_arg);
579 case DIRS_WRITE:
580 return ev.formatted_print ("%qE on write-only file descriptor %qE",
581 m_callee_fndecl, m_arg);
582 default:
583 gcc_unreachable ();
587 private:
588 enum access_directions m_fd_dir;
591 class fd_double_close : public fd_diagnostic
593 public:
594 fd_double_close (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm, arg)
598 const char *
599 get_kind () const final override
601 return "fd_double_close";
605 get_controlling_option () const final override
607 return OPT_Wanalyzer_fd_double_close;
609 bool
610 emit (diagnostic_emission_context &ctxt) final override
612 // CWE-1341: Multiple Releases of Same Resource or Handle
613 ctxt.add_cwe (1341);
614 return ctxt.warn ("double %<close%> of file descriptor %qE", m_arg);
617 label_text
618 describe_state_change (const evdesc::state_change &change) override
620 if (m_sm.is_unchecked_fd_p (change.m_new_state))
621 return label_text::borrow ("opened here");
623 if (change.m_new_state == m_sm.m_closed)
625 m_first_close_event = change.m_event_id;
626 return change.formatted_print ("first %qs here", "close");
628 return fd_diagnostic::describe_state_change (change);
631 label_text
632 describe_final_event (const evdesc::final_event &ev) final override
634 if (m_first_close_event.known_p ())
635 return ev.formatted_print ("second %qs here; first %qs was at %@",
636 "close", "close", &m_first_close_event);
637 return ev.formatted_print ("second %qs here", "close");
640 private:
641 diagnostic_event_id_t m_first_close_event;
644 class fd_use_after_close : public fd_param_diagnostic
646 public:
647 fd_use_after_close (const fd_state_machine &sm, tree arg,
648 const tree callee_fndecl, const char *attr_name,
649 int arg_idx)
650 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx)
654 fd_use_after_close (const fd_state_machine &sm, tree arg,
655 const tree callee_fndecl)
656 : fd_param_diagnostic (sm, arg, callee_fndecl)
660 const char *
661 get_kind () const final override
663 return "fd_use_after_close";
667 get_controlling_option () const final override
669 return OPT_Wanalyzer_fd_use_after_close;
672 bool
673 emit (diagnostic_emission_context &ctxt) final override
675 bool warned = ctxt.warn ("%qE on closed file descriptor %qE",
676 m_callee_fndecl, m_arg);
677 if (warned)
678 inform_filedescriptor_attribute (DIRS_READ_WRITE);
679 return warned;
682 label_text
683 describe_state_change (const evdesc::state_change &change) override
685 if (m_sm.is_unchecked_fd_p (change.m_new_state))
686 return label_text::borrow ("opened here");
688 if (change.m_new_state == m_sm.m_closed)
690 m_first_close_event = change.m_event_id;
691 return change.formatted_print ("closed here");
694 return fd_diagnostic::describe_state_change (change);
697 label_text
698 describe_final_event (const evdesc::final_event &ev) final override
700 if (m_first_close_event.known_p ())
701 return ev.formatted_print (
702 "%qE on closed file descriptor %qE; %qs was at %@", m_callee_fndecl,
703 m_arg, "close", &m_first_close_event);
704 else
705 return ev.formatted_print ("%qE on closed file descriptor %qE",
706 m_callee_fndecl, m_arg);
709 private:
710 diagnostic_event_id_t m_first_close_event;
713 class fd_use_without_check : public fd_param_diagnostic
715 public:
716 fd_use_without_check (const fd_state_machine &sm, tree arg,
717 const tree callee_fndecl, const char *attr_name,
718 int arg_idx)
719 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx)
723 fd_use_without_check (const fd_state_machine &sm, tree arg,
724 const tree callee_fndecl)
725 : fd_param_diagnostic (sm, arg, callee_fndecl)
729 const char *
730 get_kind () const final override
732 return "fd_use_without_check";
736 get_controlling_option () const final override
738 return OPT_Wanalyzer_fd_use_without_check;
741 bool
742 emit (diagnostic_emission_context &ctxt) final override
744 bool warned = ctxt.warn ("%qE on possibly invalid file descriptor %qE",
745 m_callee_fndecl, m_arg);
746 if (warned)
747 inform_filedescriptor_attribute (DIRS_READ_WRITE);
748 return warned;
751 label_text
752 describe_state_change (const evdesc::state_change &change) override
754 if (m_sm.is_unchecked_fd_p (change.m_new_state))
756 m_first_open_event = change.m_event_id;
757 return label_text::borrow ("opened here");
760 return fd_diagnostic::describe_state_change (change);
763 label_text
764 describe_final_event (const evdesc::final_event &ev) final override
766 if (m_first_open_event.known_p ())
767 return ev.formatted_print (
768 "%qE could be invalid: unchecked value from %@", m_arg,
769 &m_first_open_event);
770 else
771 return ev.formatted_print ("%qE could be invalid", m_arg);
774 private:
775 diagnostic_event_id_t m_first_open_event;
778 /* Concrete pending_diagnostic subclass for -Wanalyzer-fd-phase-mismatch. */
780 class fd_phase_mismatch : public fd_param_diagnostic
782 public:
783 fd_phase_mismatch (const fd_state_machine &sm, tree arg,
784 const tree callee_fndecl,
785 state_machine::state_t actual_state,
786 enum expected_phase expected_phase)
787 : fd_param_diagnostic (sm, arg, callee_fndecl),
788 m_actual_state (actual_state),
789 m_expected_phase (expected_phase)
791 gcc_assert (m_sm.is_socket_fd_p (actual_state));
792 switch (expected_phase)
794 case EXPECTED_PHASE_CAN_TRANSFER:
795 gcc_assert (actual_state == m_sm.m_new_stream_socket
796 || actual_state == m_sm.m_bound_stream_socket
797 || actual_state == m_sm.m_listening_stream_socket);
798 break;
799 case EXPECTED_PHASE_CAN_BIND:
800 gcc_assert (actual_state == m_sm.m_bound_datagram_socket
801 || actual_state == m_sm.m_bound_stream_socket
802 || actual_state == m_sm.m_bound_unknown_socket
803 || actual_state == m_sm.m_connected_stream_socket
804 || actual_state == m_sm.m_listening_stream_socket);
805 break;
806 case EXPECTED_PHASE_CAN_LISTEN:
807 gcc_assert (actual_state == m_sm.m_new_stream_socket
808 || actual_state == m_sm.m_new_unknown_socket
809 || actual_state == m_sm.m_connected_stream_socket);
810 break;
811 case EXPECTED_PHASE_CAN_ACCEPT:
812 gcc_assert (actual_state == m_sm.m_new_stream_socket
813 || actual_state == m_sm.m_new_unknown_socket
814 || actual_state == m_sm.m_bound_stream_socket
815 || actual_state == m_sm.m_bound_unknown_socket
816 || actual_state == m_sm.m_connected_stream_socket);
817 break;
818 case EXPECTED_PHASE_CAN_CONNECT:
819 gcc_assert (actual_state == m_sm.m_bound_datagram_socket
820 || actual_state == m_sm.m_bound_stream_socket
821 || actual_state == m_sm.m_bound_unknown_socket
822 || actual_state == m_sm.m_listening_stream_socket
823 || actual_state == m_sm.m_connected_stream_socket);
824 break;
828 const char *
829 get_kind () const final override
831 return "fd_phase_mismatch";
834 bool
835 subclass_equal_p (const pending_diagnostic &base_other) const final override
837 const fd_phase_mismatch &sub_other = (const fd_phase_mismatch &)base_other;
838 if (!fd_param_diagnostic ::subclass_equal_p (sub_other))
839 return false;
840 return (m_actual_state == sub_other.m_actual_state
841 && m_expected_phase == sub_other.m_expected_phase);
845 get_controlling_option () const final override
847 return OPT_Wanalyzer_fd_phase_mismatch;
850 bool
851 emit (diagnostic_emission_context &ctxt) final override
853 /* CWE-666: Operation on Resource in Wrong Phase of Lifetime. */
854 ctxt.add_cwe (666);
855 return ctxt.warn ("%qE on file descriptor %qE in wrong phase",
856 m_callee_fndecl, m_arg);
859 label_text
860 describe_final_event (const evdesc::final_event &ev) final override
862 switch (m_expected_phase)
864 case EXPECTED_PHASE_CAN_TRANSFER:
866 if (m_actual_state == m_sm.m_new_stream_socket)
867 return ev.formatted_print
868 ("%qE expects a stream socket to be connected via %qs"
869 " but %qE has not yet been bound",
870 m_callee_fndecl, "accept", m_arg);
871 if (m_actual_state == m_sm.m_bound_stream_socket)
872 return ev.formatted_print
873 ("%qE expects a stream socket to be connected via %qs"
874 " but %qE is not yet listening",
875 m_callee_fndecl, "accept", m_arg);
876 if (m_actual_state == m_sm.m_listening_stream_socket)
877 return ev.formatted_print
878 ("%qE expects a stream socket to be connected via"
879 " the return value of %qs"
880 " but %qE is listening; wrong file descriptor?",
881 m_callee_fndecl, "accept", m_arg);
883 break;
884 case EXPECTED_PHASE_CAN_BIND:
886 if (m_actual_state == m_sm.m_bound_datagram_socket
887 || m_actual_state == m_sm.m_bound_stream_socket
888 || m_actual_state == m_sm.m_bound_unknown_socket)
889 return ev.formatted_print
890 ("%qE expects a new socket file descriptor"
891 " but %qE has already been bound",
892 m_callee_fndecl, m_arg);
893 if (m_actual_state == m_sm.m_connected_stream_socket)
894 return ev.formatted_print
895 ("%qE expects a new socket file descriptor"
896 " but %qE is already connected",
897 m_callee_fndecl, m_arg);
898 if (m_actual_state == m_sm.m_listening_stream_socket)
899 return ev.formatted_print
900 ("%qE expects a new socket file descriptor"
901 " but %qE is already listening",
902 m_callee_fndecl, m_arg);
904 break;
905 case EXPECTED_PHASE_CAN_LISTEN:
907 if (m_actual_state == m_sm.m_new_stream_socket
908 || m_actual_state == m_sm.m_new_unknown_socket)
909 return ev.formatted_print
910 ("%qE expects a bound stream socket file descriptor"
911 " but %qE has not yet been bound",
912 m_callee_fndecl, m_arg);
913 if (m_actual_state == m_sm.m_connected_stream_socket)
914 return ev.formatted_print
915 ("%qE expects a bound stream socket file descriptor"
916 " but %qE is connected",
917 m_callee_fndecl, m_arg);
919 break;
920 case EXPECTED_PHASE_CAN_ACCEPT:
922 if (m_actual_state == m_sm.m_new_stream_socket
923 || m_actual_state == m_sm.m_new_unknown_socket)
924 return ev.formatted_print
925 ("%qE expects a listening stream socket file descriptor"
926 " but %qE has not yet been bound",
927 m_callee_fndecl, m_arg);
928 if (m_actual_state == m_sm.m_bound_stream_socket
929 || m_actual_state == m_sm.m_bound_unknown_socket)
930 return ev.formatted_print
931 ("%qE expects a listening stream socket file descriptor"
932 " whereas %qE is bound but not yet listening",
933 m_callee_fndecl, m_arg);
934 if (m_actual_state == m_sm.m_connected_stream_socket)
935 return ev.formatted_print
936 ("%qE expects a listening stream socket file descriptor"
937 " but %qE is connected",
938 m_callee_fndecl, m_arg);
940 break;
941 case EXPECTED_PHASE_CAN_CONNECT:
943 if (m_actual_state == m_sm.m_bound_datagram_socket
944 || m_actual_state == m_sm.m_bound_stream_socket
945 || m_actual_state == m_sm.m_bound_unknown_socket)
946 return ev.formatted_print
947 ("%qE expects a new socket file descriptor but %qE is bound",
948 m_callee_fndecl, m_arg);
949 else
950 return ev.formatted_print
951 ("%qE expects a new socket file descriptor", m_callee_fndecl);
953 break;
955 gcc_unreachable ();
958 private:
959 state_machine::state_t m_actual_state;
960 enum expected_phase m_expected_phase;
963 /* Enum for use by -Wanalyzer-fd-type-mismatch. */
965 enum expected_type
967 EXPECTED_TYPE_SOCKET,
968 EXPECTED_TYPE_STREAM_SOCKET
971 /* Concrete pending_diagnostic subclass for -Wanalyzer-fd-type-mismatch. */
973 class fd_type_mismatch : public fd_param_diagnostic
975 public:
976 fd_type_mismatch (const fd_state_machine &sm, tree arg,
977 const tree callee_fndecl,
978 state_machine::state_t actual_state,
979 enum expected_type expected_type)
980 : fd_param_diagnostic (sm, arg, callee_fndecl),
981 m_actual_state (actual_state),
982 m_expected_type (expected_type)
986 const char *
987 get_kind () const final override
989 return "fd_type_mismatch";
992 bool
993 subclass_equal_p (const pending_diagnostic &base_other) const final override
995 const fd_type_mismatch &sub_other = (const fd_type_mismatch &)base_other;
996 if (!fd_param_diagnostic ::subclass_equal_p (sub_other))
997 return false;
998 return (m_actual_state == sub_other.m_actual_state
999 && m_expected_type == sub_other.m_expected_type);
1003 get_controlling_option () const final override
1005 return OPT_Wanalyzer_fd_type_mismatch;
1008 bool
1009 emit (diagnostic_emission_context &ctxt) final override
1011 switch (m_expected_type)
1013 default:
1014 gcc_unreachable ();
1015 case EXPECTED_TYPE_SOCKET:
1016 return ctxt.warn ("%qE on non-socket file descriptor %qE",
1017 m_callee_fndecl, m_arg);
1018 case EXPECTED_TYPE_STREAM_SOCKET:
1019 if (m_sm.is_datagram_socket_fd_p (m_actual_state))
1020 return ctxt.warn ("%qE on datagram socket file descriptor %qE",
1021 m_callee_fndecl, m_arg);
1022 else
1023 return ctxt.warn ("%qE on non-stream-socket file descriptor %qE",
1024 m_callee_fndecl, m_arg);
1028 label_text
1029 describe_final_event (const evdesc::final_event &ev) final override
1031 switch (m_expected_type)
1033 default:
1034 break;
1035 gcc_unreachable ();
1036 case EXPECTED_TYPE_SOCKET:
1037 case EXPECTED_TYPE_STREAM_SOCKET:
1038 if (!m_sm.is_socket_fd_p (m_actual_state))
1039 return ev.formatted_print ("%qE expects a socket file descriptor"
1040 " but %qE is not a socket",
1041 m_callee_fndecl, m_arg);
1043 gcc_assert (m_expected_type == EXPECTED_TYPE_STREAM_SOCKET);
1044 gcc_assert (m_sm.is_datagram_socket_fd_p (m_actual_state));
1045 return ev.formatted_print
1046 ("%qE expects a stream socket file descriptor"
1047 " but %qE is a datagram socket",
1048 m_callee_fndecl, m_arg);
1051 private:
1052 state_machine::state_t m_actual_state;
1053 enum expected_type m_expected_type;
1056 fd_state_machine::fd_state_machine (logger *logger)
1057 : state_machine ("file-descriptor", logger),
1058 m_constant_fd (add_state ("fd-constant")),
1059 m_unchecked_read_write (add_state ("fd-unchecked-read-write")),
1060 m_unchecked_read_only (add_state ("fd-unchecked-read-only")),
1061 m_unchecked_write_only (add_state ("fd-unchecked-write-only")),
1062 m_valid_read_write (add_state ("fd-valid-read-write")),
1063 m_valid_read_only (add_state ("fd-valid-read-only")),
1064 m_valid_write_only (add_state ("fd-valid-write-only")),
1065 m_invalid (add_state ("fd-invalid")),
1066 m_closed (add_state ("fd-closed")),
1067 m_new_datagram_socket (add_state ("fd-new-datagram-socket")),
1068 m_new_stream_socket (add_state ("fd-new-stream-socket")),
1069 m_new_unknown_socket (add_state ("fd-new-unknown-socket")),
1070 m_bound_datagram_socket (add_state ("fd-bound-datagram-socket")),
1071 m_bound_stream_socket (add_state ("fd-bound-stream-socket")),
1072 m_bound_unknown_socket (add_state ("fd-bound-unknown-socket")),
1073 m_listening_stream_socket (add_state ("fd-listening-stream-socket")),
1074 m_connected_stream_socket (add_state ("fd-connected-stream-socket")),
1075 m_stop (add_state ("fd-stop")),
1076 m_O_ACCMODE (get_stashed_constant_by_name ("O_ACCMODE")),
1077 m_O_RDONLY (get_stashed_constant_by_name ("O_RDONLY")),
1078 m_O_WRONLY (get_stashed_constant_by_name ("O_WRONLY")),
1079 m_SOCK_STREAM (get_stashed_constant_by_name ("SOCK_STREAM")),
1080 m_SOCK_DGRAM (get_stashed_constant_by_name ("SOCK_DGRAM"))
1084 bool
1085 fd_state_machine::is_unchecked_fd_p (state_t s) const
1087 return (s == m_unchecked_read_write
1088 || s == m_unchecked_read_only
1089 || s == m_unchecked_write_only);
1092 bool
1093 fd_state_machine::is_valid_fd_p (state_t s) const
1095 return (s == m_valid_read_write
1096 || s == m_valid_read_only
1097 || s == m_valid_write_only);
1100 bool
1101 fd_state_machine::is_socket_fd_p (state_t s) const
1103 return (s == m_new_datagram_socket
1104 || s == m_new_stream_socket
1105 || s == m_new_unknown_socket
1106 || s == m_bound_datagram_socket
1107 || s == m_bound_stream_socket
1108 || s == m_bound_unknown_socket
1109 || s == m_listening_stream_socket
1110 || s == m_connected_stream_socket);
1113 bool
1114 fd_state_machine::is_datagram_socket_fd_p (state_t s) const
1116 return (s == m_new_datagram_socket
1117 || s == m_new_unknown_socket
1118 || s == m_bound_datagram_socket
1119 || s == m_bound_unknown_socket);
1122 bool
1123 fd_state_machine::is_stream_socket_fd_p (state_t s) const
1125 return (s == m_new_stream_socket
1126 || s == m_new_unknown_socket
1127 || s == m_bound_stream_socket
1128 || s == m_bound_unknown_socket
1129 || s == m_listening_stream_socket
1130 || s == m_connected_stream_socket);
1133 enum access_mode
1134 fd_state_machine::get_access_mode_from_flag (int flag) const
1136 if (m_O_ACCMODE && TREE_CODE (m_O_ACCMODE) == INTEGER_CST)
1138 const unsigned HOST_WIDE_INT mask_val = TREE_INT_CST_LOW (m_O_ACCMODE);
1139 const unsigned HOST_WIDE_INT masked_flag = flag & mask_val;
1141 if (m_O_RDONLY && TREE_CODE (m_O_RDONLY) == INTEGER_CST)
1142 if (masked_flag == TREE_INT_CST_LOW (m_O_RDONLY))
1143 return READ_ONLY;
1145 if (m_O_WRONLY && TREE_CODE (m_O_WRONLY) == INTEGER_CST)
1146 if (masked_flag == TREE_INT_CST_LOW (m_O_WRONLY))
1147 return WRITE_ONLY;
1149 return READ_WRITE;
1152 bool
1153 fd_state_machine::is_readonly_fd_p (state_t state) const
1155 return (state == m_unchecked_read_only || state == m_valid_read_only);
1158 bool
1159 fd_state_machine::is_writeonly_fd_p (state_t state) const
1161 return (state == m_unchecked_write_only || state == m_valid_write_only);
1164 bool
1165 fd_state_machine::is_closed_fd_p (state_t state) const
1167 return (state == m_closed);
1170 bool
1171 fd_state_machine::is_constant_fd_p (state_t state) const
1173 return (state == m_constant_fd);
1176 fd_state_machine::state_t
1177 fd_state_machine::valid_to_unchecked_state (state_t state) const
1179 if (state == m_valid_read_write)
1180 return m_unchecked_read_write;
1181 else if (state == m_valid_write_only)
1182 return m_unchecked_write_only;
1183 else if (state == m_valid_read_only)
1184 return m_unchecked_read_only;
1185 else
1186 gcc_unreachable ();
1187 return NULL;
1190 void
1191 fd_state_machine::mark_as_valid_fd (region_model *model,
1192 sm_state_map *smap,
1193 const svalue *fd_sval,
1194 const extrinsic_state &ext_state) const
1196 smap->set_state (model, fd_sval, m_valid_read_write, NULL, ext_state);
1199 bool
1200 fd_state_machine::on_stmt (sm_context &sm_ctxt, const supernode *node,
1201 const gimple *stmt) const
1203 if (const gcall *call = dyn_cast<const gcall *> (stmt))
1204 if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
1206 if (is_named_call_p (callee_fndecl, "open", call, 2))
1208 on_open (sm_ctxt, node, stmt, call);
1209 return true;
1210 } // "open"
1212 if (is_named_call_p (callee_fndecl, "creat", call, 2))
1214 on_creat (sm_ctxt, node, stmt, call);
1215 return true;
1216 } // "creat"
1218 if (is_named_call_p (callee_fndecl, "close", call, 1))
1220 on_close (sm_ctxt, node, stmt, call);
1221 return true;
1222 } // "close"
1224 if (is_named_call_p (callee_fndecl, "write", call, 3))
1226 on_write (sm_ctxt, node, stmt, call, callee_fndecl);
1227 return true;
1228 } // "write"
1230 if (is_named_call_p (callee_fndecl, "read", call, 3))
1232 on_read (sm_ctxt, node, stmt, call, callee_fndecl);
1233 return true;
1234 } // "read"
1236 if (is_named_call_p (callee_fndecl, "dup", call, 1))
1238 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_1);
1239 return true;
1242 if (is_named_call_p (callee_fndecl, "dup2", call, 2))
1244 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_2);
1245 return true;
1248 if (is_named_call_p (callee_fndecl, "dup3", call, 3))
1250 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_3);
1251 return true;
1255 // Handle __attribute__((fd_arg))
1257 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1258 "fd_arg", DIRS_READ_WRITE);
1260 // Handle __attribute__((fd_arg_read))
1262 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1263 "fd_arg_read", DIRS_READ);
1265 // Handle __attribute__((fd_arg_write))
1267 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1268 "fd_arg_write", DIRS_WRITE);
1272 return false;
1275 void
1276 fd_state_machine::check_for_fd_attrs (
1277 sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
1278 const gcall *call, const tree callee_fndecl, const char *attr_name,
1279 access_directions fd_attr_access_dir) const
1281 /* Handle interesting fd attributes of the callee_fndecl,
1282 or prioritize those of the builtin that callee_fndecl is
1283 expected to be.
1284 Might want this to be controlled by a flag. */
1285 tree fndecl = callee_fndecl;
1286 /* If call is recognized as a builtin known_function,
1287 use that builtin's function_decl. */
1288 if (const region_model *old_model = sm_ctxt.get_old_region_model ())
1289 if (const builtin_known_function *builtin_kf
1290 = old_model->get_builtin_kf (call))
1291 fndecl = builtin_kf->builtin_decl ();
1293 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (fndecl));
1294 attrs = lookup_attribute (attr_name, attrs);
1295 if (!attrs)
1296 return;
1298 if (!TREE_VALUE (attrs))
1299 return;
1301 auto_bitmap argmap;
1303 for (tree idx = TREE_VALUE (attrs); idx; idx = TREE_CHAIN (idx))
1305 unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (idx)) - 1;
1306 bitmap_set_bit (argmap, val);
1308 if (bitmap_empty_p (argmap))
1309 return;
1311 for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
1313 tree arg = gimple_call_arg (call, arg_idx);
1314 tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
1315 state_t state = sm_ctxt.get_state (stmt, arg);
1316 bool bit_set = bitmap_bit_p (argmap, arg_idx);
1317 if (TREE_CODE (TREE_TYPE (arg)) != INTEGER_TYPE)
1318 continue;
1319 if (bit_set) // Check if arg_idx is marked by any of the file descriptor
1320 // attributes
1323 /* Do use the fndecl that caused the warning so that the
1324 misused attributes are printed and the user not confused. */
1325 if (is_closed_fd_p (state))
1328 sm_ctxt.warn (node, stmt, arg,
1329 make_unique<fd_use_after_close>
1330 (*this, diag_arg,
1331 fndecl, attr_name,
1332 arg_idx));
1333 continue;
1336 if (!(is_valid_fd_p (state) || (state == m_stop)))
1338 if (!is_constant_fd_p (state))
1340 sm_ctxt.warn (node, stmt, arg,
1341 make_unique<fd_use_without_check>
1342 (*this, diag_arg,
1343 fndecl, attr_name,
1344 arg_idx));
1345 continue;
1349 switch (fd_attr_access_dir)
1351 case DIRS_READ_WRITE:
1352 break;
1353 case DIRS_READ:
1355 if (is_writeonly_fd_p (state))
1357 sm_ctxt.warn (
1358 node, stmt, arg,
1359 make_unique<fd_access_mode_mismatch> (*this, diag_arg,
1360 DIRS_WRITE,
1361 fndecl,
1362 attr_name,
1363 arg_idx));
1366 break;
1367 case DIRS_WRITE:
1369 if (is_readonly_fd_p (state))
1371 sm_ctxt.warn (
1372 node, stmt, arg,
1373 make_unique<fd_access_mode_mismatch> (*this, diag_arg,
1374 DIRS_READ,
1375 fndecl,
1376 attr_name,
1377 arg_idx));
1380 break;
1387 void
1388 fd_state_machine::on_open (sm_context &sm_ctxt, const supernode *node,
1389 const gimple *stmt, const gcall *call) const
1391 tree lhs = gimple_call_lhs (call);
1392 if (lhs)
1394 tree arg = gimple_call_arg (call, 1);
1395 enum access_mode mode = READ_WRITE;
1396 if (TREE_CODE (arg) == INTEGER_CST)
1398 int flag = TREE_INT_CST_LOW (arg);
1399 mode = get_access_mode_from_flag (flag);
1401 switch (mode)
1403 case READ_ONLY:
1404 sm_ctxt.on_transition (node, stmt, lhs, m_start,
1405 m_unchecked_read_only);
1406 break;
1407 case WRITE_ONLY:
1408 sm_ctxt.on_transition (node, stmt, lhs, m_start,
1409 m_unchecked_write_only);
1410 break;
1411 default:
1412 sm_ctxt.on_transition (node, stmt, lhs, m_start,
1413 m_unchecked_read_write);
1416 else
1418 sm_ctxt.warn (node, stmt, NULL_TREE,
1419 make_unique<fd_leak> (*this, NULL_TREE));
1423 void
1424 fd_state_machine::on_creat (sm_context &sm_ctxt, const supernode *node,
1425 const gimple *stmt, const gcall *call) const
1427 tree lhs = gimple_call_lhs (call);
1428 if (lhs)
1429 sm_ctxt.on_transition (node, stmt, lhs, m_start, m_unchecked_write_only);
1430 else
1431 sm_ctxt.warn (node, stmt, NULL_TREE,
1432 make_unique<fd_leak> (*this, NULL_TREE));
1435 void
1436 fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node,
1437 const gimple *stmt, const gcall *call,
1438 const tree callee_fndecl, enum dup kind) const
1440 tree lhs = gimple_call_lhs (call);
1441 tree arg_1 = gimple_call_arg (call, 0);
1442 state_t state_arg_1 = sm_ctxt.get_state (stmt, arg_1);
1443 if (state_arg_1 == m_stop)
1444 return;
1445 if (!(is_constant_fd_p (state_arg_1) || is_valid_fd_p (state_arg_1)
1446 || state_arg_1 == m_start))
1448 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl,
1449 DIRS_READ_WRITE);
1450 return;
1452 switch (kind)
1454 case DUP_1:
1455 if (lhs)
1457 if (is_constant_fd_p (state_arg_1) || state_arg_1 == m_start)
1458 sm_ctxt.set_next_state (stmt, lhs, m_unchecked_read_write);
1459 else
1460 sm_ctxt.set_next_state (stmt, lhs,
1461 valid_to_unchecked_state (state_arg_1));
1463 break;
1465 case DUP_2:
1466 case DUP_3:
1467 tree arg_2 = gimple_call_arg (call, 1);
1468 state_t state_arg_2 = sm_ctxt.get_state (stmt, arg_2);
1469 tree diag_arg_2 = sm_ctxt.get_diagnostic_tree (arg_2);
1470 if (state_arg_2 == m_stop)
1471 return;
1472 /* Check if -1 was passed as second argument to dup2. */
1473 if (!(is_constant_fd_p (state_arg_2) || is_valid_fd_p (state_arg_2)
1474 || state_arg_2 == m_start))
1476 sm_ctxt.warn (
1477 node, stmt, arg_2,
1478 make_unique<fd_use_without_check> (*this, diag_arg_2,
1479 callee_fndecl));
1480 return;
1482 /* dup2 returns value of its second argument on success.But, the
1483 access mode of the returned file descriptor depends on the duplicated
1484 file descriptor i.e the first argument. */
1485 if (lhs)
1487 if (is_constant_fd_p (state_arg_1) || state_arg_1 == m_start)
1488 sm_ctxt.set_next_state (stmt, lhs, m_unchecked_read_write);
1489 else
1490 sm_ctxt.set_next_state (stmt, lhs,
1491 valid_to_unchecked_state (state_arg_1));
1494 break;
1498 void
1499 fd_state_machine::on_close (sm_context &sm_ctxt, const supernode *node,
1500 const gimple *stmt, const gcall *call) const
1502 tree arg = gimple_call_arg (call, 0);
1503 state_t state = sm_ctxt.get_state (stmt, arg);
1504 tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
1506 sm_ctxt.on_transition (node, stmt, arg, m_start, m_closed);
1507 sm_ctxt.on_transition (node, stmt, arg, m_unchecked_read_write, m_closed);
1508 sm_ctxt.on_transition (node, stmt, arg, m_unchecked_read_only, m_closed);
1509 sm_ctxt.on_transition (node, stmt, arg, m_unchecked_write_only, m_closed);
1510 sm_ctxt.on_transition (node, stmt, arg, m_valid_read_write, m_closed);
1511 sm_ctxt.on_transition (node, stmt, arg, m_valid_read_only, m_closed);
1512 sm_ctxt.on_transition (node, stmt, arg, m_valid_write_only, m_closed);
1513 sm_ctxt.on_transition (node, stmt, arg, m_constant_fd, m_closed);
1514 sm_ctxt.on_transition (node, stmt, arg, m_new_datagram_socket, m_closed);
1515 sm_ctxt.on_transition (node, stmt, arg, m_new_stream_socket, m_closed);
1516 sm_ctxt.on_transition (node, stmt, arg, m_new_unknown_socket, m_closed);
1517 sm_ctxt.on_transition (node, stmt, arg, m_bound_datagram_socket, m_closed);
1518 sm_ctxt.on_transition (node, stmt, arg, m_bound_stream_socket, m_closed);
1519 sm_ctxt.on_transition (node, stmt, arg, m_bound_unknown_socket, m_closed);
1520 sm_ctxt.on_transition (node, stmt, arg, m_listening_stream_socket, m_closed);
1521 sm_ctxt.on_transition (node, stmt, arg, m_connected_stream_socket, m_closed);
1523 if (is_closed_fd_p (state))
1525 sm_ctxt.warn (node, stmt, arg,
1526 make_unique<fd_double_close> (*this, diag_arg));
1527 sm_ctxt.set_next_state (stmt, arg, m_stop);
1530 void
1531 fd_state_machine::on_read (sm_context &sm_ctxt, const supernode *node,
1532 const gimple *stmt, const gcall *call,
1533 const tree callee_fndecl) const
1535 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_READ);
1537 void
1538 fd_state_machine::on_write (sm_context &sm_ctxt, const supernode *node,
1539 const gimple *stmt, const gcall *call,
1540 const tree callee_fndecl) const
1542 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_WRITE);
1545 void
1546 fd_state_machine::check_for_open_fd (
1547 sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
1548 const gcall *call, const tree callee_fndecl,
1549 enum access_directions callee_fndecl_dir) const
1551 tree arg = gimple_call_arg (call, 0);
1552 tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
1553 state_t state = sm_ctxt.get_state (stmt, arg);
1555 if (is_closed_fd_p (state))
1557 sm_ctxt.warn (node, stmt, arg,
1558 make_unique<fd_use_after_close> (*this, diag_arg,
1559 callee_fndecl));
1562 else
1564 if (state == m_new_stream_socket
1565 || state == m_bound_stream_socket
1566 || state == m_listening_stream_socket)
1567 /* Complain about fncall on socket in wrong phase. */
1568 sm_ctxt.warn
1569 (node, stmt, arg,
1570 make_unique<fd_phase_mismatch> (*this, diag_arg,
1571 callee_fndecl,
1572 state,
1573 EXPECTED_PHASE_CAN_TRANSFER));
1574 else if (!(is_valid_fd_p (state)
1575 || state == m_new_datagram_socket
1576 || state == m_bound_unknown_socket
1577 || state == m_connected_stream_socket
1578 || state == m_start
1579 || state == m_stop))
1581 if (!is_constant_fd_p (state))
1582 sm_ctxt.warn (
1583 node, stmt, arg,
1584 make_unique<fd_use_without_check> (*this, diag_arg,
1585 callee_fndecl));
1587 switch (callee_fndecl_dir)
1589 case DIRS_READ_WRITE:
1590 break;
1591 case DIRS_READ:
1592 if (is_writeonly_fd_p (state))
1594 tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
1595 sm_ctxt.warn (node, stmt, arg,
1596 make_unique<fd_access_mode_mismatch> (
1597 *this, diag_arg, DIRS_WRITE, callee_fndecl));
1600 break;
1601 case DIRS_WRITE:
1603 if (is_readonly_fd_p (state))
1605 tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
1606 sm_ctxt.warn (node, stmt, arg,
1607 make_unique<fd_access_mode_mismatch> (
1608 *this, diag_arg, DIRS_READ, callee_fndecl));
1610 break;
1615 static bool
1616 add_constraint_ge_zero (region_model *model,
1617 const svalue *fd_sval,
1618 region_model_context *ctxt)
1620 const svalue *zero
1621 = model->get_manager ()->get_or_create_int_cst (integer_type_node, 0);
1622 return model->add_constraint (fd_sval, GE_EXPR, zero, ctxt);
1625 /* Get the state for a new socket type based on SOCKET_TYPE_SVAL,
1626 a SOCK_* value. */
1628 state_machine::state_t
1629 fd_state_machine::
1630 get_state_for_socket_type (const svalue *socket_type_sval) const
1632 if (tree socket_type_cst = socket_type_sval->maybe_get_constant ())
1634 /* Attempt to use SOCK_* constants stashed from the frontend. */
1635 if (tree_int_cst_equal (socket_type_cst, m_SOCK_STREAM))
1636 return m_new_stream_socket;
1637 if (tree_int_cst_equal (socket_type_cst, m_SOCK_DGRAM))
1638 return m_new_datagram_socket;
1641 /* Unrecognized constant, or a symbolic "type" value. */
1642 return m_new_unknown_socket;
1645 /* Update the model and fd state for an outcome of a call to "socket",
1646 where SUCCESSFUL indicate which of the two outcomes.
1647 Return true if the outcome is feasible, or false to reject it. */
1649 bool
1650 fd_state_machine::on_socket (const call_details &cd,
1651 bool successful,
1652 sm_context &sm_ctxt,
1653 const extrinsic_state &ext_state) const
1655 const gcall *stmt = cd.get_call_stmt ();
1656 engine *eng = ext_state.get_engine ();
1657 const supergraph *sg = eng->get_supergraph ();
1658 const supernode *node = sg->get_supernode_for_stmt (stmt);
1659 region_model *model = cd.get_model ();
1661 if (successful)
1663 if (gimple_call_lhs (stmt))
1665 conjured_purge p (model, cd.get_ctxt ());
1666 region_model_manager *mgr = model->get_manager ();
1667 const svalue *new_fd
1668 = mgr->get_or_create_conjured_svalue (integer_type_node,
1669 stmt,
1670 cd.get_lhs_region (),
1672 if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
1673 return false;
1675 const svalue *socket_type_sval = cd.get_arg_svalue (1);
1676 state_machine::state_t new_state
1677 = get_state_for_socket_type (socket_type_sval);
1678 sm_ctxt.on_transition (node, stmt, new_fd, m_start, new_state);
1679 model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
1681 else
1682 sm_ctxt.warn (node, stmt, NULL_TREE,
1683 make_unique<fd_leak> (*this, NULL_TREE));
1685 else
1687 /* Return -1; set errno. */
1688 model->update_for_int_cst_return (cd, -1, true);
1689 model->set_errno (cd);
1692 return true;
1695 /* Check that FD_SVAL is usable by socket APIs.
1696 Complain if it has been closed, if it is a non-socket,
1697 or is invalid.
1698 If COMPLAINED is non-NULL and a problem is found,
1699 write *COMPLAINED = true.
1701 If SUCCESSFUL is true, attempt to add the constraint that FD_SVAL >= 0.
1702 Return true if this outcome is feasible. */
1704 bool
1705 fd_state_machine::check_for_socket_fd (const call_details &cd,
1706 bool successful,
1707 sm_context &sm_ctxt,
1708 const svalue *fd_sval,
1709 const supernode *node,
1710 state_t old_state,
1711 bool *complained) const
1713 const gcall *stmt = cd.get_call_stmt ();
1715 if (is_closed_fd_p (old_state))
1717 tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
1718 sm_ctxt.warn
1719 (node, stmt, fd_sval,
1720 make_unique<fd_use_after_close> (*this, diag_arg,
1721 cd.get_fndecl_for_call ()));
1722 if (complained)
1723 *complained = true;
1724 if (successful)
1725 return false;
1727 else if (is_unchecked_fd_p (old_state) || is_valid_fd_p (old_state))
1729 /* Complain about non-socket. */
1730 tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
1731 sm_ctxt.warn
1732 (node, stmt, fd_sval,
1733 make_unique<fd_type_mismatch> (*this, diag_arg,
1734 cd.get_fndecl_for_call (),
1735 old_state,
1736 EXPECTED_TYPE_SOCKET));
1737 if (complained)
1738 *complained = true;
1739 if (successful)
1740 return false;
1742 else if (old_state == m_invalid)
1744 tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
1745 sm_ctxt.warn
1746 (node, stmt, fd_sval,
1747 make_unique<fd_use_without_check> (*this, diag_arg,
1748 cd.get_fndecl_for_call ()));
1749 if (complained)
1750 *complained = true;
1751 if (successful)
1752 return false;
1755 if (successful)
1756 if (!add_constraint_ge_zero (cd.get_model (), fd_sval, cd.get_ctxt ()))
1757 return false;
1759 return true;
1762 /* For use by "bind" and "connect".
1763 As per fd_state_machine::check_for_socket_fd above,
1764 but also complain if we don't have a new socket, and check that
1765 we can read up to the size bytes from the address. */
1767 bool
1768 fd_state_machine::check_for_new_socket_fd (const call_details &cd,
1769 bool successful,
1770 sm_context &sm_ctxt,
1771 const svalue *fd_sval,
1772 const supernode *node,
1773 state_t old_state,
1774 enum expected_phase expected_phase)
1775 const
1777 bool complained = false;
1779 /* Check address and len. */
1780 const svalue *address_sval = cd.get_arg_svalue (1);
1781 const svalue *len_sval = cd.get_arg_svalue (2);
1783 /* Check that we can read the given number of bytes from the
1784 address. */
1785 region_model *model = cd.get_model ();
1786 const region *address_reg
1787 = model->deref_rvalue (address_sval, cd.get_arg_tree (1),
1788 cd.get_ctxt ());
1789 const region *sized_address_reg
1790 = model->get_manager ()->get_sized_region (address_reg,
1791 NULL_TREE,
1792 len_sval);
1793 model->get_store_value (sized_address_reg, cd.get_ctxt ());
1795 if (!check_for_socket_fd (cd, successful, sm_ctxt,
1796 fd_sval, node, old_state, &complained))
1797 return false;
1798 else if (!complained
1799 && !(old_state == m_new_stream_socket
1800 || old_state == m_new_datagram_socket
1801 || old_state == m_new_unknown_socket
1802 || old_state == m_start
1803 || old_state == m_stop
1804 || old_state == m_constant_fd))
1806 /* Complain about "bind" or "connect" in wrong phase. */
1807 tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
1808 sm_ctxt.warn
1809 (node, cd.get_call_stmt (), fd_sval,
1810 make_unique<fd_phase_mismatch> (*this, diag_arg,
1811 cd.get_fndecl_for_call (),
1812 old_state,
1813 expected_phase));
1814 if (successful)
1815 return false;
1817 else if (!successful)
1819 /* If we were in the start state, assume we had a new socket. */
1820 if (old_state == m_start)
1821 sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
1822 m_new_unknown_socket);
1825 /* Passing NULL as the address will lead to failure. */
1826 if (successful)
1827 if (address_sval->all_zeroes_p ())
1828 return false;
1830 return true;
1833 /* Update the model and fd state for an outcome of a call to "bind",
1834 where SUCCESSFUL indicate which of the two outcomes.
1835 Return true if the outcome is feasible, or false to reject it. */
1837 bool
1838 fd_state_machine::on_bind (const call_details &cd,
1839 bool successful,
1840 sm_context &sm_ctxt,
1841 const extrinsic_state &ext_state) const
1843 const gcall *stmt = cd.get_call_stmt ();
1844 engine *eng = ext_state.get_engine ();
1845 const supergraph *sg = eng->get_supergraph ();
1846 const supernode *node = sg->get_supernode_for_stmt (stmt);
1847 const svalue *fd_sval = cd.get_arg_svalue (0);
1848 region_model *model = cd.get_model ();
1849 state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
1851 if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
1852 fd_sval, node, old_state,
1853 EXPECTED_PHASE_CAN_BIND))
1854 return false;
1856 if (successful)
1858 state_t next_state = NULL;
1859 if (old_state == m_new_stream_socket)
1860 next_state = m_bound_stream_socket;
1861 else if (old_state == m_new_datagram_socket)
1862 next_state = m_bound_datagram_socket;
1863 else if (old_state == m_new_unknown_socket)
1864 next_state = m_bound_unknown_socket;
1865 else if (old_state == m_start
1866 || old_state == m_constant_fd)
1867 next_state = m_bound_unknown_socket;
1868 else if (old_state == m_stop)
1869 next_state = m_stop;
1870 else
1871 gcc_unreachable ();
1872 sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, next_state);
1873 model->update_for_zero_return (cd, true);
1875 else
1877 /* Return -1; set errno. */
1878 model->update_for_int_cst_return (cd, -1, true);
1879 model->set_errno (cd);
1882 return true;
1885 /* Update the model and fd state for an outcome of a call to "listen",
1886 where SUCCESSFUL indicate which of the two outcomes.
1887 Return true if the outcome is feasible, or false to reject it. */
1889 bool
1890 fd_state_machine::on_listen (const call_details &cd,
1891 bool successful,
1892 sm_context &sm_ctxt,
1893 const extrinsic_state &ext_state) const
1895 const gcall *stmt = cd.get_call_stmt ();
1896 engine *eng = ext_state.get_engine ();
1897 const supergraph *sg = eng->get_supergraph ();
1898 const supernode *node = sg->get_supernode_for_stmt (cd.get_call_stmt ());
1899 const svalue *fd_sval = cd.get_arg_svalue (0);
1900 region_model *model = cd.get_model ();
1901 state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
1903 /* We expect a stream socket that's had "bind" called on it. */
1904 if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
1905 return false;
1906 if (!(old_state == m_start
1907 || old_state == m_constant_fd
1908 || old_state == m_stop
1909 || old_state == m_invalid
1910 || old_state == m_bound_stream_socket
1911 || old_state == m_bound_unknown_socket
1912 /* Assume it's OK to call "listen" more than once. */
1913 || old_state == m_listening_stream_socket))
1915 /* Complain about fncall on wrong type or in wrong phase. */
1916 tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
1917 if (is_stream_socket_fd_p (old_state))
1918 sm_ctxt.warn
1919 (node, stmt, fd_sval,
1920 make_unique<fd_phase_mismatch> (*this, diag_arg,
1921 cd.get_fndecl_for_call (),
1922 old_state,
1923 EXPECTED_PHASE_CAN_LISTEN));
1924 else
1925 sm_ctxt.warn
1926 (node, stmt, fd_sval,
1927 make_unique<fd_type_mismatch> (*this, diag_arg,
1928 cd.get_fndecl_for_call (),
1929 old_state,
1930 EXPECTED_TYPE_STREAM_SOCKET));
1931 if (successful)
1932 return false;
1935 if (successful)
1937 model->update_for_zero_return (cd, true);
1938 sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
1939 m_listening_stream_socket);
1941 else
1943 /* Return -1; set errno. */
1944 model->update_for_int_cst_return (cd, -1, true);
1945 model->set_errno (cd);
1946 if (old_state == m_start)
1947 sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
1948 m_bound_stream_socket);
1951 return true;
1954 /* Update the model and fd state for an outcome of a call to "accept",
1955 where SUCCESSFUL indicate which of the two outcomes.
1956 Return true if the outcome is feasible, or false to reject it. */
1958 bool
1959 fd_state_machine::on_accept (const call_details &cd,
1960 bool successful,
1961 sm_context &sm_ctxt,
1962 const extrinsic_state &ext_state) const
1964 const gcall *stmt = cd.get_call_stmt ();
1965 engine *eng = ext_state.get_engine ();
1966 const supergraph *sg = eng->get_supergraph ();
1967 const supernode *node = sg->get_supernode_for_stmt (stmt);
1968 const svalue *fd_sval = cd.get_arg_svalue (0);
1969 const svalue *address_sval = cd.get_arg_svalue (1);
1970 const svalue *len_ptr_sval = cd.get_arg_svalue (2);
1971 region_model *model = cd.get_model ();
1972 state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
1974 if (!address_sval->all_zeroes_p ())
1976 region_model_manager *mgr = model->get_manager ();
1978 /* We might have a union of various pointer types, rather than a
1979 pointer type; cast to (void *) before dereferencing. */
1980 address_sval = mgr->get_or_create_cast (ptr_type_node, address_sval);
1982 const region *address_reg
1983 = model->deref_rvalue (address_sval, cd.get_arg_tree (1),
1984 cd.get_ctxt ());
1985 const region *len_reg
1986 = model->deref_rvalue (len_ptr_sval, cd.get_arg_tree (2),
1987 cd.get_ctxt ());
1988 const svalue *old_len_sval
1989 = model->get_store_value (len_reg, cd.get_ctxt ());
1990 tree len_ptr = cd.get_arg_tree (2);
1991 tree star_len_ptr = build2 (MEM_REF, TREE_TYPE (TREE_TYPE (len_ptr)),
1992 len_ptr,
1993 build_int_cst (TREE_TYPE (len_ptr), 0));
1994 old_len_sval = model->check_for_poison (old_len_sval,
1995 star_len_ptr,
1996 len_reg,
1997 cd.get_ctxt ());
1998 if (successful)
2000 conjured_purge p (model, cd.get_ctxt ());
2001 const region *old_sized_address_reg
2002 = mgr->get_sized_region (address_reg,
2003 NULL_TREE,
2004 old_len_sval);
2005 const svalue *new_addr_sval
2006 = mgr->get_or_create_conjured_svalue (NULL_TREE,
2007 stmt,
2008 old_sized_address_reg,
2010 model->set_value (old_sized_address_reg, new_addr_sval,
2011 cd.get_ctxt ());
2012 const svalue *new_addr_len
2013 = mgr->get_or_create_conjured_svalue (NULL_TREE,
2014 stmt,
2015 len_reg,
2017 model->set_value (len_reg, new_addr_len, cd.get_ctxt ());
2021 /* We expect a stream socket in the "listening" state. */
2022 if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
2023 return false;
2025 if (old_state == m_start || old_state == m_constant_fd)
2026 /* If we were in the start state (or a constant), assume we had the
2027 expected state. */
2028 sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
2029 m_listening_stream_socket);
2030 else if (old_state == m_stop)
2032 /* No further complaints. */
2034 else if (old_state != m_listening_stream_socket)
2036 /* Complain about fncall on wrong type or in wrong phase. */
2037 tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
2038 if (is_stream_socket_fd_p (old_state))
2039 sm_ctxt.warn
2040 (node, stmt, fd_sval,
2041 make_unique<fd_phase_mismatch> (*this, diag_arg,
2042 cd.get_fndecl_for_call (),
2043 old_state,
2044 EXPECTED_PHASE_CAN_ACCEPT));
2045 else
2046 sm_ctxt.warn
2047 (node, stmt, fd_sval,
2048 make_unique<fd_type_mismatch> (*this, diag_arg,
2049 cd.get_fndecl_for_call (),
2050 old_state,
2051 EXPECTED_TYPE_STREAM_SOCKET));
2052 if (successful)
2053 return false;
2056 if (successful)
2058 /* Return new conjured FD in "connected" state. */
2059 if (gimple_call_lhs (stmt))
2061 conjured_purge p (model, cd.get_ctxt ());
2062 region_model_manager *mgr = model->get_manager ();
2063 const svalue *new_fd
2064 = mgr->get_or_create_conjured_svalue (integer_type_node,
2065 stmt,
2066 cd.get_lhs_region (),
2068 if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
2069 return false;
2070 sm_ctxt.on_transition (node, stmt, new_fd,
2071 m_start, m_connected_stream_socket);
2072 model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
2074 else
2075 sm_ctxt.warn (node, stmt, NULL_TREE,
2076 make_unique<fd_leak> (*this, NULL_TREE));
2078 else
2080 /* Return -1; set errno. */
2081 model->update_for_int_cst_return (cd, -1, true);
2082 model->set_errno (cd);
2085 return true;
2088 /* Update the model and fd state for an outcome of a call to "connect",
2089 where SUCCESSFUL indicate which of the two outcomes.
2090 Return true if the outcome is feasible, or false to reject it. */
2092 bool
2093 fd_state_machine::on_connect (const call_details &cd,
2094 bool successful,
2095 sm_context &sm_ctxt,
2096 const extrinsic_state &ext_state) const
2098 const gcall *stmt = cd.get_call_stmt ();
2099 engine *eng = ext_state.get_engine ();
2100 const supergraph *sg = eng->get_supergraph ();
2101 const supernode *node = sg->get_supernode_for_stmt (stmt);
2102 const svalue *fd_sval = cd.get_arg_svalue (0);
2103 region_model *model = cd.get_model ();
2104 state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
2106 if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
2107 fd_sval, node, old_state,
2108 EXPECTED_PHASE_CAN_CONNECT))
2109 return false;
2111 if (successful)
2113 model->update_for_zero_return (cd, true);
2114 state_t next_state = NULL;
2115 if (old_state == m_new_stream_socket)
2116 next_state = m_connected_stream_socket;
2117 else if (old_state == m_new_datagram_socket)
2118 /* It's legal to call connect on a datagram socket, potentially
2119 more than once. We don't transition states for this. */
2120 next_state = m_new_datagram_socket;
2121 else if (old_state == m_new_unknown_socket)
2122 next_state = m_stop;
2123 else if (old_state == m_start
2124 || old_state == m_constant_fd)
2125 next_state = m_stop;
2126 else if (old_state == m_stop)
2127 next_state = m_stop;
2128 else
2129 gcc_unreachable ();
2130 sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, next_state);
2132 else
2134 /* Return -1; set errno. */
2135 model->update_for_int_cst_return (cd, -1, true);
2136 model->set_errno (cd);
2137 /* TODO: perhaps transition to a failed state, since the
2138 portable way to handle a failed "connect" is to close
2139 the socket and try again with a new socket. */
2142 return true;
2145 void
2146 fd_state_machine::on_condition (sm_context &sm_ctxt, const supernode *node,
2147 const gimple *stmt, const svalue *lhs,
2148 enum tree_code op, const svalue *rhs) const
2150 if (tree cst = rhs->maybe_get_constant ())
2152 if (TREE_CODE (cst) == INTEGER_CST)
2154 int val = TREE_INT_CST_LOW (cst);
2155 if (val == -1)
2157 if (op == NE_EXPR)
2158 make_valid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2160 else if (op == EQ_EXPR)
2161 make_invalid_transitions_on_condition (sm_ctxt, node, stmt,
2162 lhs);
2167 if (rhs->all_zeroes_p ())
2169 if (op == GE_EXPR)
2170 make_valid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2171 else if (op == LT_EXPR)
2172 make_invalid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2176 void
2177 fd_state_machine::make_valid_transitions_on_condition (sm_context &sm_ctxt,
2178 const supernode *node,
2179 const gimple *stmt,
2180 const svalue *lhs) const
2182 sm_ctxt.on_transition (node, stmt, lhs, m_unchecked_read_write,
2183 m_valid_read_write);
2184 sm_ctxt.on_transition (node, stmt, lhs, m_unchecked_read_only,
2185 m_valid_read_only);
2186 sm_ctxt.on_transition (node, stmt, lhs, m_unchecked_write_only,
2187 m_valid_write_only);
2190 void
2191 fd_state_machine::make_invalid_transitions_on_condition (
2192 sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
2193 const svalue *lhs) const
2195 sm_ctxt.on_transition (node, stmt, lhs, m_unchecked_read_write, m_invalid);
2196 sm_ctxt.on_transition (node, stmt, lhs, m_unchecked_read_only, m_invalid);
2197 sm_ctxt.on_transition (node, stmt, lhs, m_unchecked_write_only, m_invalid);
2200 bool
2201 fd_state_machine::can_purge_p (state_t s) const
2203 if (is_unchecked_fd_p (s)
2204 || is_valid_fd_p (s)
2205 || is_socket_fd_p (s))
2206 return false;
2207 else
2208 return true;
2211 std::unique_ptr<pending_diagnostic>
2212 fd_state_machine::on_leak (tree var) const
2214 return make_unique<fd_leak> (*this, var);
2216 } // namespace
2218 state_machine *
2219 make_fd_state_machine (logger *logger)
2221 return new fd_state_machine (logger);
2224 static bool
2225 get_fd_state (region_model_context *ctxt,
2226 sm_state_map **out_smap,
2227 const fd_state_machine **out_sm,
2228 unsigned *out_sm_idx,
2229 std::unique_ptr<sm_context> *out_sm_context)
2231 if (!ctxt)
2232 return false;
2234 const state_machine *sm;
2235 if (!ctxt->get_fd_map (out_smap, &sm, out_sm_idx, out_sm_context))
2236 return false;
2238 gcc_assert (sm);
2240 *out_sm = (const fd_state_machine *)sm;
2241 return true;
2244 /* Specialcase hook for handling pipe, for use by
2245 kf_pipe::success::update_model. */
2247 void
2248 region_model::mark_as_valid_fd (const svalue *sval, region_model_context *ctxt)
2250 sm_state_map *smap;
2251 const fd_state_machine *fd_sm;
2252 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, NULL))
2253 return;
2254 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2255 if (!ext_state)
2256 return;
2257 fd_sm->mark_as_valid_fd (this, smap, sval, *ext_state);
2260 /* Handle calls to "socket".
2261 See e.g. https://man7.org/linux/man-pages/man3/socket.3p.html */
2263 class kf_socket : public known_function
2265 public:
2266 class outcome_of_socket : public succeed_or_fail_call_info
2268 public:
2269 outcome_of_socket (const call_details &cd, bool success)
2270 : succeed_or_fail_call_info (cd, success)
2273 bool update_model (region_model *model,
2274 const exploded_edge *,
2275 region_model_context *ctxt) const final override
2277 const call_details cd (get_call_details (model, ctxt));
2278 sm_state_map *smap;
2279 const fd_state_machine *fd_sm;
2280 std::unique_ptr<sm_context> sm_ctxt;
2281 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2283 cd.set_any_lhs_with_defaults ();
2284 return true;
2286 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2287 if (!ext_state)
2289 cd.set_any_lhs_with_defaults ();
2290 return true;
2293 return fd_sm->on_socket (cd, m_success, *(sm_ctxt.get ()), *ext_state);
2297 bool matches_call_types_p (const call_details &cd) const final override
2299 return cd.num_args () == 3;
2302 void impl_call_post (const call_details &cd) const final override
2304 if (cd.get_ctxt ())
2306 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, false));
2307 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, true));
2308 cd.get_ctxt ()->terminate_path ();
2313 /* Handle calls to "bind".
2314 See e.g. https://man7.org/linux/man-pages/man3/bind.3p.html */
2316 class kf_bind : public known_function
2318 public:
2319 class outcome_of_bind : public succeed_or_fail_call_info
2321 public:
2322 outcome_of_bind (const call_details &cd, bool success)
2323 : succeed_or_fail_call_info (cd, success)
2326 bool update_model (region_model *model,
2327 const exploded_edge *,
2328 region_model_context *ctxt) const final override
2330 const call_details cd (get_call_details (model, ctxt));
2331 sm_state_map *smap;
2332 const fd_state_machine *fd_sm;
2333 std::unique_ptr<sm_context> sm_ctxt;
2334 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2336 cd.set_any_lhs_with_defaults ();
2337 return true;
2339 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2340 if (!ext_state)
2342 cd.set_any_lhs_with_defaults ();
2343 return true;
2345 return fd_sm->on_bind (cd, m_success, *sm_ctxt.get (), *ext_state);
2349 bool matches_call_types_p (const call_details &cd) const final override
2351 return (cd.num_args () == 3 && cd.arg_is_pointer_p (1));
2354 void impl_call_post (const call_details &cd) const final override
2356 if (cd.get_ctxt ())
2358 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, false));
2359 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, true));
2360 cd.get_ctxt ()->terminate_path ();
2365 /* Handle calls to "listen".
2366 See e.g. https://man7.org/linux/man-pages/man3/listen.3p.html */
2368 class kf_listen : public known_function
2370 class outcome_of_listen : public succeed_or_fail_call_info
2372 public:
2373 outcome_of_listen (const call_details &cd, bool success)
2374 : succeed_or_fail_call_info (cd, success)
2377 bool update_model (region_model *model,
2378 const exploded_edge *,
2379 region_model_context *ctxt) const final override
2381 const call_details cd (get_call_details (model, ctxt));
2382 sm_state_map *smap;
2383 const fd_state_machine *fd_sm;
2384 std::unique_ptr<sm_context> sm_ctxt;
2385 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2387 cd.set_any_lhs_with_defaults ();
2388 return true;
2390 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2391 if (!ext_state)
2393 cd.set_any_lhs_with_defaults ();
2394 return true;
2397 return fd_sm->on_listen (cd, m_success, *sm_ctxt.get (), *ext_state);
2401 bool matches_call_types_p (const call_details &cd) const final override
2403 return cd.num_args () == 2;
2406 void impl_call_post (const call_details &cd) const final override
2408 if (cd.get_ctxt ())
2410 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, false));
2411 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, true));
2412 cd.get_ctxt ()->terminate_path ();
2417 /* Handle calls to "accept".
2418 See e.g. https://man7.org/linux/man-pages/man3/accept.3p.html */
2420 class kf_accept : public known_function
2422 class outcome_of_accept : public succeed_or_fail_call_info
2424 public:
2425 outcome_of_accept (const call_details &cd, bool success)
2426 : succeed_or_fail_call_info (cd, success)
2429 bool update_model (region_model *model,
2430 const exploded_edge *,
2431 region_model_context *ctxt) const final override
2433 const call_details cd (get_call_details (model, ctxt));
2434 sm_state_map *smap;
2435 const fd_state_machine *fd_sm;
2436 std::unique_ptr<sm_context> sm_ctxt;
2437 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2439 cd.set_any_lhs_with_defaults ();
2440 return true;
2442 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2443 if (!ext_state)
2445 cd.set_any_lhs_with_defaults ();
2446 return true;
2449 return fd_sm->on_accept (cd, m_success, *sm_ctxt.get (), *ext_state);
2453 bool matches_call_types_p (const call_details &cd) const final override
2455 return (cd.num_args () == 3
2456 && cd.arg_is_pointer_p (1)
2457 && cd.arg_is_pointer_p (2));
2460 void impl_call_post (const call_details &cd) const final override
2462 if (cd.get_ctxt ())
2464 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, false));
2465 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, true));
2466 cd.get_ctxt ()->terminate_path ();
2471 /* Handle calls to "connect".
2472 See e.g. https://man7.org/linux/man-pages/man3/connect.3p.html */
2474 class kf_connect : public known_function
2476 public:
2477 class outcome_of_connect : public succeed_or_fail_call_info
2479 public:
2480 outcome_of_connect (const call_details &cd, bool success)
2481 : succeed_or_fail_call_info (cd, success)
2484 bool update_model (region_model *model,
2485 const exploded_edge *,
2486 region_model_context *ctxt) const final override
2488 const call_details cd (get_call_details (model, ctxt));
2489 sm_state_map *smap;
2490 const fd_state_machine *fd_sm;
2491 std::unique_ptr<sm_context> sm_ctxt;
2492 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2494 cd.set_any_lhs_with_defaults ();
2495 return true;
2497 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2498 if (!ext_state)
2500 cd.set_any_lhs_with_defaults ();
2501 return true;
2504 return fd_sm->on_connect (cd, m_success, *sm_ctxt.get (), *ext_state);
2508 bool matches_call_types_p (const call_details &cd) const final override
2510 return (cd.num_args () == 3
2511 && cd.arg_is_pointer_p (1));
2514 void impl_call_post (const call_details &cd) const final override
2516 if (cd.get_ctxt ())
2518 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, false));
2519 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, true));
2520 cd.get_ctxt ()->terminate_path ();
2525 /* Handler for "isatty"".
2526 See e.g. https://man7.org/linux/man-pages/man3/isatty.3.html */
2528 class kf_isatty : public known_function
2530 class outcome_of_isatty : public succeed_or_fail_call_info
2532 public:
2533 outcome_of_isatty (const call_details &cd, bool success)
2534 : succeed_or_fail_call_info (cd, success)
2537 bool update_model (region_model *model,
2538 const exploded_edge *,
2539 region_model_context *ctxt) const final override
2541 const call_details cd (get_call_details (model, ctxt));
2543 if (m_success)
2545 /* Return 1. */
2546 model->update_for_int_cst_return (cd, 1, true);
2548 else
2550 /* Return 0; set errno. */
2551 model->update_for_int_cst_return (cd, 0, true);
2552 model->set_errno (cd);
2555 return feasible_p (cd, ctxt);
2558 private:
2559 bool feasible_p (const call_details &cd,
2560 region_model_context *ctxt) const
2562 if (m_success)
2564 /* Can't be "success" on a closed/invalid fd. */
2565 sm_state_map *smap;
2566 const fd_state_machine *fd_sm;
2567 std::unique_ptr<sm_context> sm_ctxt;
2568 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2569 return true;
2570 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2571 if (!ext_state)
2572 return true;
2574 const svalue *fd_sval = cd.get_arg_svalue (0);
2575 state_machine::state_t old_state
2576 = sm_ctxt->get_state (cd.get_call_stmt (), fd_sval);
2578 if (fd_sm->is_closed_fd_p (old_state)
2579 || old_state == fd_sm->m_invalid)
2580 return false;
2582 return true;
2584 }; // class outcome_of_isatty
2586 public:
2587 bool matches_call_types_p (const call_details &cd) const final override
2589 return cd.num_args () == 1;
2592 void impl_call_post (const call_details &cd) const final override
2594 if (cd.get_ctxt ())
2596 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, false));
2597 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, true));
2598 cd.get_ctxt ()->terminate_path ();
2603 /* Handler for calls to "pipe" and "pipe2".
2604 See e.g. https://www.man7.org/linux/man-pages/man2/pipe.2.html */
2606 class kf_pipe : public known_function
2608 class failure : public failed_call_info
2610 public:
2611 failure (const call_details &cd) : failed_call_info (cd) {}
2613 bool update_model (region_model *model,
2614 const exploded_edge *,
2615 region_model_context *ctxt) const final override
2617 /* Return -1; everything else is unchanged. */
2618 const call_details cd (get_call_details (model, ctxt));
2619 model->update_for_int_cst_return (cd, -1, true);
2620 return true;
2624 class success : public success_call_info
2626 public:
2627 success (const call_details &cd) : success_call_info (cd) {}
2629 bool update_model (region_model *model,
2630 const exploded_edge *,
2631 region_model_context *ctxt) const final override
2633 const call_details cd (get_call_details (model, ctxt));
2635 /* Return 0. */
2636 model->update_for_zero_return (cd, true);
2638 /* Update fd array. */
2639 region_model_manager *mgr = cd.get_manager ();
2640 tree arr_tree = cd.get_arg_tree (0);
2641 const svalue *arr_sval = cd.get_arg_svalue (0);
2642 for (int idx = 0; idx < 2; idx++)
2644 const region *arr_reg
2645 = model->deref_rvalue (arr_sval, arr_tree, cd.get_ctxt ());
2646 const svalue *idx_sval
2647 = mgr->get_or_create_int_cst (integer_type_node, idx);
2648 const region *element_reg
2649 = mgr->get_element_region (arr_reg, integer_type_node, idx_sval);
2650 conjured_purge p (model, cd.get_ctxt ());
2651 const svalue *fd_sval
2652 = mgr->get_or_create_conjured_svalue (integer_type_node,
2653 cd.get_call_stmt (),
2654 element_reg,
2656 model->set_value (element_reg, fd_sval, cd.get_ctxt ());
2657 model->mark_as_valid_fd (fd_sval, cd.get_ctxt ());
2659 return true;
2663 public:
2664 kf_pipe (unsigned num_args)
2665 : m_num_args (num_args)
2667 gcc_assert (num_args > 0);
2670 bool matches_call_types_p (const call_details &cd) const final override
2672 return (cd.num_args () == m_num_args && cd.arg_is_pointer_p (0));
2675 void impl_call_post (const call_details &cd) const final override
2677 if (cd.get_ctxt ())
2679 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
2680 cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
2681 cd.get_ctxt ()->terminate_path ();
2685 private:
2686 unsigned m_num_args;
2689 /* Handler for "read".
2690 ssize_t read(int fildes, void *buf, size_t nbyte);
2691 See e.g. https://man7.org/linux/man-pages/man2/read.2.html */
2693 class kf_read : public known_function
2695 public:
2696 bool matches_call_types_p (const call_details &cd) const final override
2698 return (cd.num_args () == 3
2699 && cd.arg_is_pointer_p (1)
2700 && cd.arg_is_size_p (2));
2703 /* For now, assume that any call to "read" fully clobbers the buffer
2704 passed in. This isn't quite correct (e.g. errors, partial reads;
2705 see PR analyzer/108689), but at least stops us falsely complaining
2706 about the buffer being uninitialized. */
2707 void impl_call_pre (const call_details &cd) const final override
2709 region_model *model = cd.get_model ();
2710 const svalue *ptr_sval = cd.get_arg_svalue (1);
2711 if (const region *reg = ptr_sval->maybe_get_region ())
2713 const region *base_reg = reg->get_base_region ();
2714 const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
2715 model->set_value (base_reg, new_sval, cd.get_ctxt ());
2717 cd.set_any_lhs_with_defaults ();
2722 /* Populate KFM with instances of known functions relating to
2723 file descriptors. */
2725 void
2726 register_known_fd_functions (known_function_manager &kfm)
2728 kfm.add ("accept", make_unique<kf_accept> ());
2729 kfm.add ("bind", make_unique<kf_bind> ());
2730 kfm.add ("connect", make_unique<kf_connect> ());
2731 kfm.add ("isatty", make_unique<kf_isatty> ());
2732 kfm.add ("listen", make_unique<kf_listen> ());
2733 kfm.add ("pipe", make_unique<kf_pipe> (1));
2734 kfm.add ("pipe2", make_unique<kf_pipe> (2));
2735 kfm.add ("read", make_unique<kf_read> ());
2736 kfm.add ("socket", make_unique<kf_socket> ());
2739 } // namespace ana
2741 #endif // ENABLE_ANALYZER