c++: indirect change of active union member in constexpr [PR101631,PR102286]
[official-gcc.git] / gcc / analyzer / sm-fd.cc
blob34bbd84f6e7e2e8a413f0731086a8be7b88450e1
1 /* A state machine for detecting misuses of POSIX file descriptor APIs.
2 Copyright (C) 2019-2023 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 #include "system.h"
24 #include "coretypes.h"
25 #include "make-unique.h"
26 #include "tree.h"
27 #include "function.h"
28 #include "basic-block.h"
29 #include "gimple.h"
30 #include "options.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"
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 (rich_location *rich_loc, logger *) final override
470 /*CWE-775: Missing Release of File Descriptor or Handle after Effective
471 Lifetime
473 diagnostic_metadata m;
474 m.add_cwe (775);
475 if (m_arg)
476 return warning_meta (rich_loc, m, get_controlling_option (),
477 "leak of file descriptor %qE", m_arg);
478 else
479 return warning_meta (rich_loc, m, get_controlling_option (),
480 "leak of file descriptor");
483 label_text
484 describe_state_change (const evdesc::state_change &change) final override
486 if (m_sm.is_unchecked_fd_p (change.m_new_state))
488 m_open_event = change.m_event_id;
489 return label_text::borrow ("opened here");
492 return fd_diagnostic::describe_state_change (change);
495 label_text
496 describe_final_event (const evdesc::final_event &ev) final override
498 if (m_open_event.known_p ())
500 if (ev.m_expr)
501 return ev.formatted_print ("%qE leaks here; was opened at %@",
502 ev.m_expr, &m_open_event);
503 else
504 return ev.formatted_print ("leaks here; was opened at %@",
505 &m_open_event);
507 else
509 if (ev.m_expr)
510 return ev.formatted_print ("%qE leaks here", ev.m_expr);
511 else
512 return ev.formatted_print ("leaks here");
516 private:
517 diagnostic_event_id_t m_open_event;
520 class fd_access_mode_mismatch : public fd_param_diagnostic
522 public:
523 fd_access_mode_mismatch (const fd_state_machine &sm, tree arg,
524 enum access_directions fd_dir,
525 const tree callee_fndecl, const char *attr_name,
526 int arg_idx)
527 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx),
528 m_fd_dir (fd_dir)
533 fd_access_mode_mismatch (const fd_state_machine &sm, tree arg,
534 enum access_directions fd_dir,
535 const tree callee_fndecl)
536 : fd_param_diagnostic (sm, arg, callee_fndecl), m_fd_dir (fd_dir)
540 const char *
541 get_kind () const final override
543 return "fd_access_mode_mismatch";
547 get_controlling_option () const final override
549 return OPT_Wanalyzer_fd_access_mode_mismatch;
552 bool
553 emit (rich_location *rich_loc, logger *) final override
555 bool warned;
556 switch (m_fd_dir)
558 case DIRS_READ:
559 warned = warning_at (rich_loc, get_controlling_option (),
560 "%qE on read-only file descriptor %qE",
561 m_callee_fndecl, m_arg);
562 break;
563 case DIRS_WRITE:
564 warned = warning_at (rich_loc, get_controlling_option (),
565 "%qE on write-only file descriptor %qE",
566 m_callee_fndecl, m_arg);
567 break;
568 default:
569 gcc_unreachable ();
571 if (warned)
572 inform_filedescriptor_attribute (m_fd_dir);
573 return warned;
576 label_text
577 describe_final_event (const evdesc::final_event &ev) final override
579 switch (m_fd_dir)
581 case DIRS_READ:
582 return ev.formatted_print ("%qE on read-only file descriptor %qE",
583 m_callee_fndecl, m_arg);
584 case DIRS_WRITE:
585 return ev.formatted_print ("%qE on write-only file descriptor %qE",
586 m_callee_fndecl, m_arg);
587 default:
588 gcc_unreachable ();
592 private:
593 enum access_directions m_fd_dir;
596 class fd_double_close : public fd_diagnostic
598 public:
599 fd_double_close (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm, arg)
603 const char *
604 get_kind () const final override
606 return "fd_double_close";
610 get_controlling_option () const final override
612 return OPT_Wanalyzer_fd_double_close;
614 bool
615 emit (rich_location *rich_loc, logger *) final override
617 diagnostic_metadata m;
618 // CWE-1341: Multiple Releases of Same Resource or Handle
619 m.add_cwe (1341);
620 return warning_meta (rich_loc, m, get_controlling_option (),
621 "double %<close%> of file descriptor %qE", m_arg);
624 label_text
625 describe_state_change (const evdesc::state_change &change) override
627 if (m_sm.is_unchecked_fd_p (change.m_new_state))
628 return label_text::borrow ("opened here");
630 if (change.m_new_state == m_sm.m_closed)
632 m_first_close_event = change.m_event_id;
633 return change.formatted_print ("first %qs here", "close");
635 return fd_diagnostic::describe_state_change (change);
638 label_text
639 describe_final_event (const evdesc::final_event &ev) final override
641 if (m_first_close_event.known_p ())
642 return ev.formatted_print ("second %qs here; first %qs was at %@",
643 "close", "close", &m_first_close_event);
644 return ev.formatted_print ("second %qs here", "close");
647 private:
648 diagnostic_event_id_t m_first_close_event;
651 class fd_use_after_close : public fd_param_diagnostic
653 public:
654 fd_use_after_close (const fd_state_machine &sm, tree arg,
655 const tree callee_fndecl, const char *attr_name,
656 int arg_idx)
657 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx)
661 fd_use_after_close (const fd_state_machine &sm, tree arg,
662 const tree callee_fndecl)
663 : fd_param_diagnostic (sm, arg, callee_fndecl)
667 const char *
668 get_kind () const final override
670 return "fd_use_after_close";
674 get_controlling_option () const final override
676 return OPT_Wanalyzer_fd_use_after_close;
679 bool
680 emit (rich_location *rich_loc, logger *) final override
682 bool warned;
683 warned = warning_at (rich_loc, get_controlling_option (),
684 "%qE on closed file descriptor %qE", m_callee_fndecl,
685 m_arg);
686 if (warned)
687 inform_filedescriptor_attribute (DIRS_READ_WRITE);
688 return warned;
691 label_text
692 describe_state_change (const evdesc::state_change &change) override
694 if (m_sm.is_unchecked_fd_p (change.m_new_state))
695 return label_text::borrow ("opened here");
697 if (change.m_new_state == m_sm.m_closed)
699 m_first_close_event = change.m_event_id;
700 return change.formatted_print ("closed here");
703 return fd_diagnostic::describe_state_change (change);
706 label_text
707 describe_final_event (const evdesc::final_event &ev) final override
709 if (m_first_close_event.known_p ())
710 return ev.formatted_print (
711 "%qE on closed file descriptor %qE; %qs was at %@", m_callee_fndecl,
712 m_arg, "close", &m_first_close_event);
713 else
714 return ev.formatted_print ("%qE on closed file descriptor %qE",
715 m_callee_fndecl, m_arg);
718 private:
719 diagnostic_event_id_t m_first_close_event;
722 class fd_use_without_check : public fd_param_diagnostic
724 public:
725 fd_use_without_check (const fd_state_machine &sm, tree arg,
726 const tree callee_fndecl, const char *attr_name,
727 int arg_idx)
728 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx)
732 fd_use_without_check (const fd_state_machine &sm, tree arg,
733 const tree callee_fndecl)
734 : fd_param_diagnostic (sm, arg, callee_fndecl)
738 const char *
739 get_kind () const final override
741 return "fd_use_without_check";
745 get_controlling_option () const final override
747 return OPT_Wanalyzer_fd_use_without_check;
750 bool
751 emit (rich_location *rich_loc, logger *) final override
753 bool warned;
754 warned = warning_at (rich_loc, get_controlling_option (),
755 "%qE on possibly invalid file descriptor %qE",
756 m_callee_fndecl, m_arg);
757 if (warned)
758 inform_filedescriptor_attribute (DIRS_READ_WRITE);
759 return warned;
762 label_text
763 describe_state_change (const evdesc::state_change &change) override
765 if (m_sm.is_unchecked_fd_p (change.m_new_state))
767 m_first_open_event = change.m_event_id;
768 return label_text::borrow ("opened here");
771 return fd_diagnostic::describe_state_change (change);
774 label_text
775 describe_final_event (const evdesc::final_event &ev) final override
777 if (m_first_open_event.known_p ())
778 return ev.formatted_print (
779 "%qE could be invalid: unchecked value from %@", m_arg,
780 &m_first_open_event);
781 else
782 return ev.formatted_print ("%qE could be invalid", m_arg);
785 private:
786 diagnostic_event_id_t m_first_open_event;
789 /* Concrete pending_diagnostic subclass for -Wanalyzer-fd-phase-mismatch. */
791 class fd_phase_mismatch : public fd_param_diagnostic
793 public:
794 fd_phase_mismatch (const fd_state_machine &sm, tree arg,
795 const tree callee_fndecl,
796 state_machine::state_t actual_state,
797 enum expected_phase expected_phase)
798 : fd_param_diagnostic (sm, arg, callee_fndecl),
799 m_actual_state (actual_state),
800 m_expected_phase (expected_phase)
802 gcc_assert (m_sm.is_socket_fd_p (actual_state));
803 switch (expected_phase)
805 case EXPECTED_PHASE_CAN_TRANSFER:
806 gcc_assert (actual_state == m_sm.m_new_stream_socket
807 || actual_state == m_sm.m_bound_stream_socket
808 || actual_state == m_sm.m_listening_stream_socket);
809 break;
810 case EXPECTED_PHASE_CAN_BIND:
811 gcc_assert (actual_state == m_sm.m_bound_datagram_socket
812 || actual_state == m_sm.m_bound_stream_socket
813 || actual_state == m_sm.m_bound_unknown_socket
814 || actual_state == m_sm.m_connected_stream_socket
815 || actual_state == m_sm.m_listening_stream_socket);
816 break;
817 case EXPECTED_PHASE_CAN_LISTEN:
818 gcc_assert (actual_state == m_sm.m_new_stream_socket
819 || actual_state == m_sm.m_new_unknown_socket
820 || actual_state == m_sm.m_connected_stream_socket);
821 break;
822 case EXPECTED_PHASE_CAN_ACCEPT:
823 gcc_assert (actual_state == m_sm.m_new_stream_socket
824 || actual_state == m_sm.m_new_unknown_socket
825 || actual_state == m_sm.m_bound_stream_socket
826 || actual_state == m_sm.m_bound_unknown_socket
827 || actual_state == m_sm.m_connected_stream_socket);
828 break;
829 case EXPECTED_PHASE_CAN_CONNECT:
830 gcc_assert (actual_state == m_sm.m_bound_datagram_socket
831 || actual_state == m_sm.m_bound_stream_socket
832 || actual_state == m_sm.m_bound_unknown_socket
833 || actual_state == m_sm.m_listening_stream_socket
834 || actual_state == m_sm.m_connected_stream_socket);
835 break;
839 const char *
840 get_kind () const final override
842 return "fd_phase_mismatch";
845 bool
846 subclass_equal_p (const pending_diagnostic &base_other) const final override
848 const fd_phase_mismatch &sub_other = (const fd_phase_mismatch &)base_other;
849 if (!fd_param_diagnostic ::subclass_equal_p (sub_other))
850 return false;
851 return (m_actual_state == sub_other.m_actual_state
852 && m_expected_phase == sub_other.m_expected_phase);
856 get_controlling_option () const final override
858 return OPT_Wanalyzer_fd_phase_mismatch;
861 bool
862 emit (rich_location *rich_loc, logger *) final override
864 /* CWE-666: Operation on Resource in Wrong Phase of Lifetime. */
865 diagnostic_metadata m;
866 m.add_cwe (666);
867 return warning_at (rich_loc, get_controlling_option (),
868 "%qE on file descriptor %qE in wrong phase",
869 m_callee_fndecl, m_arg);
872 label_text
873 describe_final_event (const evdesc::final_event &ev) final override
875 switch (m_expected_phase)
877 case EXPECTED_PHASE_CAN_TRANSFER:
879 if (m_actual_state == m_sm.m_new_stream_socket)
880 return ev.formatted_print
881 ("%qE expects a stream socket to be connected via %qs"
882 " but %qE has not yet been bound",
883 m_callee_fndecl, "accept", m_arg);
884 if (m_actual_state == m_sm.m_bound_stream_socket)
885 return ev.formatted_print
886 ("%qE expects a stream socket to be connected via %qs"
887 " but %qE is not yet listening",
888 m_callee_fndecl, "accept", m_arg);
889 if (m_actual_state == m_sm.m_listening_stream_socket)
890 return ev.formatted_print
891 ("%qE expects a stream socket to be connected via"
892 " the return value of %qs"
893 " but %qE is listening; wrong file descriptor?",
894 m_callee_fndecl, "accept", m_arg);
896 break;
897 case EXPECTED_PHASE_CAN_BIND:
899 if (m_actual_state == m_sm.m_bound_datagram_socket
900 || m_actual_state == m_sm.m_bound_stream_socket
901 || m_actual_state == m_sm.m_bound_unknown_socket)
902 return ev.formatted_print
903 ("%qE expects a new socket file descriptor"
904 " but %qE has already been bound",
905 m_callee_fndecl, m_arg);
906 if (m_actual_state == m_sm.m_connected_stream_socket)
907 return ev.formatted_print
908 ("%qE expects a new socket file descriptor"
909 " but %qE is already connected",
910 m_callee_fndecl, m_arg);
911 if (m_actual_state == m_sm.m_listening_stream_socket)
912 return ev.formatted_print
913 ("%qE expects a new socket file descriptor"
914 " but %qE is already listening",
915 m_callee_fndecl, m_arg);
917 break;
918 case EXPECTED_PHASE_CAN_LISTEN:
920 if (m_actual_state == m_sm.m_new_stream_socket
921 || m_actual_state == m_sm.m_new_unknown_socket)
922 return ev.formatted_print
923 ("%qE expects a bound stream socket file descriptor"
924 " but %qE has not yet been bound",
925 m_callee_fndecl, m_arg);
926 if (m_actual_state == m_sm.m_connected_stream_socket)
927 return ev.formatted_print
928 ("%qE expects a bound stream socket file descriptor"
929 " but %qE is connected",
930 m_callee_fndecl, m_arg);
932 break;
933 case EXPECTED_PHASE_CAN_ACCEPT:
935 if (m_actual_state == m_sm.m_new_stream_socket
936 || m_actual_state == m_sm.m_new_unknown_socket)
937 return ev.formatted_print
938 ("%qE expects a listening stream socket file descriptor"
939 " but %qE has not yet been bound",
940 m_callee_fndecl, m_arg);
941 if (m_actual_state == m_sm.m_bound_stream_socket
942 || m_actual_state == m_sm.m_bound_unknown_socket)
943 return ev.formatted_print
944 ("%qE expects a listening stream socket file descriptor"
945 " whereas %qE is bound but not yet listening",
946 m_callee_fndecl, m_arg);
947 if (m_actual_state == m_sm.m_connected_stream_socket)
948 return ev.formatted_print
949 ("%qE expects a listening stream socket file descriptor"
950 " but %qE is connected",
951 m_callee_fndecl, m_arg);
953 break;
954 case EXPECTED_PHASE_CAN_CONNECT:
956 if (m_actual_state == m_sm.m_bound_datagram_socket
957 || m_actual_state == m_sm.m_bound_stream_socket
958 || m_actual_state == m_sm.m_bound_unknown_socket)
959 return ev.formatted_print
960 ("%qE expects a new socket file descriptor but %qE is bound",
961 m_callee_fndecl, m_arg);
962 else
963 return ev.formatted_print
964 ("%qE expects a new socket file descriptor", m_callee_fndecl);
966 break;
968 gcc_unreachable ();
971 private:
972 state_machine::state_t m_actual_state;
973 enum expected_phase m_expected_phase;
976 /* Enum for use by -Wanalyzer-fd-type-mismatch. */
978 enum expected_type
980 EXPECTED_TYPE_SOCKET,
981 EXPECTED_TYPE_STREAM_SOCKET
984 /* Concrete pending_diagnostic subclass for -Wanalyzer-fd-type-mismatch. */
986 class fd_type_mismatch : public fd_param_diagnostic
988 public:
989 fd_type_mismatch (const fd_state_machine &sm, tree arg,
990 const tree callee_fndecl,
991 state_machine::state_t actual_state,
992 enum expected_type expected_type)
993 : fd_param_diagnostic (sm, arg, callee_fndecl),
994 m_actual_state (actual_state),
995 m_expected_type (expected_type)
999 const char *
1000 get_kind () const final override
1002 return "fd_type_mismatch";
1005 bool
1006 subclass_equal_p (const pending_diagnostic &base_other) const final override
1008 const fd_type_mismatch &sub_other = (const fd_type_mismatch &)base_other;
1009 if (!fd_param_diagnostic ::subclass_equal_p (sub_other))
1010 return false;
1011 return (m_actual_state == sub_other.m_actual_state
1012 && m_expected_type == sub_other.m_expected_type);
1016 get_controlling_option () const final override
1018 return OPT_Wanalyzer_fd_type_mismatch;
1021 bool
1022 emit (rich_location *rich_loc, logger *) final override
1024 switch (m_expected_type)
1026 default:
1027 gcc_unreachable ();
1028 case EXPECTED_TYPE_SOCKET:
1029 return warning_at (rich_loc, get_controlling_option (),
1030 "%qE on non-socket file descriptor %qE",
1031 m_callee_fndecl, m_arg);
1032 case EXPECTED_TYPE_STREAM_SOCKET:
1033 if (m_sm.is_datagram_socket_fd_p (m_actual_state))
1034 return warning_at (rich_loc, get_controlling_option (),
1035 "%qE on datagram socket file descriptor %qE",
1036 m_callee_fndecl, m_arg);
1037 else
1038 return warning_at (rich_loc, get_controlling_option (),
1039 "%qE on non-stream-socket file descriptor %qE",
1040 m_callee_fndecl, m_arg);
1044 label_text
1045 describe_final_event (const evdesc::final_event &ev) final override
1047 switch (m_expected_type)
1049 default:
1050 break;
1051 gcc_unreachable ();
1052 case EXPECTED_TYPE_SOCKET:
1053 case EXPECTED_TYPE_STREAM_SOCKET:
1054 if (!m_sm.is_socket_fd_p (m_actual_state))
1055 return ev.formatted_print ("%qE expects a socket file descriptor"
1056 " but %qE is not a socket",
1057 m_callee_fndecl, m_arg);
1059 gcc_assert (m_expected_type == EXPECTED_TYPE_STREAM_SOCKET);
1060 gcc_assert (m_sm.is_datagram_socket_fd_p (m_actual_state));
1061 return ev.formatted_print
1062 ("%qE expects a stream socket file descriptor"
1063 " but %qE is a datagram socket",
1064 m_callee_fndecl, m_arg);
1067 private:
1068 state_machine::state_t m_actual_state;
1069 enum expected_type m_expected_type;
1072 fd_state_machine::fd_state_machine (logger *logger)
1073 : state_machine ("file-descriptor", logger),
1074 m_constant_fd (add_state ("fd-constant")),
1075 m_unchecked_read_write (add_state ("fd-unchecked-read-write")),
1076 m_unchecked_read_only (add_state ("fd-unchecked-read-only")),
1077 m_unchecked_write_only (add_state ("fd-unchecked-write-only")),
1078 m_valid_read_write (add_state ("fd-valid-read-write")),
1079 m_valid_read_only (add_state ("fd-valid-read-only")),
1080 m_valid_write_only (add_state ("fd-valid-write-only")),
1081 m_invalid (add_state ("fd-invalid")),
1082 m_closed (add_state ("fd-closed")),
1083 m_new_datagram_socket (add_state ("fd-new-datagram-socket")),
1084 m_new_stream_socket (add_state ("fd-new-stream-socket")),
1085 m_new_unknown_socket (add_state ("fd-new-unknown-socket")),
1086 m_bound_datagram_socket (add_state ("fd-bound-datagram-socket")),
1087 m_bound_stream_socket (add_state ("fd-bound-stream-socket")),
1088 m_bound_unknown_socket (add_state ("fd-bound-unknown-socket")),
1089 m_listening_stream_socket (add_state ("fd-listening-stream-socket")),
1090 m_connected_stream_socket (add_state ("fd-connected-stream-socket")),
1091 m_stop (add_state ("fd-stop")),
1092 m_O_ACCMODE (get_stashed_constant_by_name ("O_ACCMODE")),
1093 m_O_RDONLY (get_stashed_constant_by_name ("O_RDONLY")),
1094 m_O_WRONLY (get_stashed_constant_by_name ("O_WRONLY")),
1095 m_SOCK_STREAM (get_stashed_constant_by_name ("SOCK_STREAM")),
1096 m_SOCK_DGRAM (get_stashed_constant_by_name ("SOCK_DGRAM"))
1100 bool
1101 fd_state_machine::is_unchecked_fd_p (state_t s) const
1103 return (s == m_unchecked_read_write
1104 || s == m_unchecked_read_only
1105 || s == m_unchecked_write_only);
1108 bool
1109 fd_state_machine::is_valid_fd_p (state_t s) const
1111 return (s == m_valid_read_write
1112 || s == m_valid_read_only
1113 || s == m_valid_write_only);
1116 bool
1117 fd_state_machine::is_socket_fd_p (state_t s) const
1119 return (s == m_new_datagram_socket
1120 || s == m_new_stream_socket
1121 || s == m_new_unknown_socket
1122 || s == m_bound_datagram_socket
1123 || s == m_bound_stream_socket
1124 || s == m_bound_unknown_socket
1125 || s == m_listening_stream_socket
1126 || s == m_connected_stream_socket);
1129 bool
1130 fd_state_machine::is_datagram_socket_fd_p (state_t s) const
1132 return (s == m_new_datagram_socket
1133 || s == m_new_unknown_socket
1134 || s == m_bound_datagram_socket
1135 || s == m_bound_unknown_socket);
1138 bool
1139 fd_state_machine::is_stream_socket_fd_p (state_t s) const
1141 return (s == m_new_stream_socket
1142 || s == m_new_unknown_socket
1143 || s == m_bound_stream_socket
1144 || s == m_bound_unknown_socket
1145 || s == m_listening_stream_socket
1146 || s == m_connected_stream_socket);
1149 enum access_mode
1150 fd_state_machine::get_access_mode_from_flag (int flag) const
1152 if (m_O_ACCMODE && TREE_CODE (m_O_ACCMODE) == INTEGER_CST)
1154 const unsigned HOST_WIDE_INT mask_val = TREE_INT_CST_LOW (m_O_ACCMODE);
1155 const unsigned HOST_WIDE_INT masked_flag = flag & mask_val;
1157 if (m_O_RDONLY && TREE_CODE (m_O_RDONLY) == INTEGER_CST)
1158 if (masked_flag == TREE_INT_CST_LOW (m_O_RDONLY))
1159 return READ_ONLY;
1161 if (m_O_WRONLY && TREE_CODE (m_O_WRONLY) == INTEGER_CST)
1162 if (masked_flag == TREE_INT_CST_LOW (m_O_WRONLY))
1163 return WRITE_ONLY;
1165 return READ_WRITE;
1168 bool
1169 fd_state_machine::is_readonly_fd_p (state_t state) const
1171 return (state == m_unchecked_read_only || state == m_valid_read_only);
1174 bool
1175 fd_state_machine::is_writeonly_fd_p (state_t state) const
1177 return (state == m_unchecked_write_only || state == m_valid_write_only);
1180 bool
1181 fd_state_machine::is_closed_fd_p (state_t state) const
1183 return (state == m_closed);
1186 bool
1187 fd_state_machine::is_constant_fd_p (state_t state) const
1189 return (state == m_constant_fd);
1192 fd_state_machine::state_t
1193 fd_state_machine::valid_to_unchecked_state (state_t state) const
1195 if (state == m_valid_read_write)
1196 return m_unchecked_read_write;
1197 else if (state == m_valid_write_only)
1198 return m_unchecked_write_only;
1199 else if (state == m_valid_read_only)
1200 return m_unchecked_read_only;
1201 else
1202 gcc_unreachable ();
1203 return NULL;
1206 void
1207 fd_state_machine::mark_as_valid_fd (region_model *model,
1208 sm_state_map *smap,
1209 const svalue *fd_sval,
1210 const extrinsic_state &ext_state) const
1212 smap->set_state (model, fd_sval, m_valid_read_write, NULL, ext_state);
1215 bool
1216 fd_state_machine::on_stmt (sm_context *sm_ctxt, const supernode *node,
1217 const gimple *stmt) const
1219 if (const gcall *call = dyn_cast<const gcall *> (stmt))
1220 if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call))
1222 if (is_named_call_p (callee_fndecl, "open", call, 2))
1224 on_open (sm_ctxt, node, stmt, call);
1225 return true;
1226 } // "open"
1228 if (is_named_call_p (callee_fndecl, "creat", call, 2))
1230 on_creat (sm_ctxt, node, stmt, call);
1231 return true;
1232 } // "creat"
1234 if (is_named_call_p (callee_fndecl, "close", call, 1))
1236 on_close (sm_ctxt, node, stmt, call);
1237 return true;
1238 } // "close"
1240 if (is_named_call_p (callee_fndecl, "write", call, 3))
1242 on_write (sm_ctxt, node, stmt, call, callee_fndecl);
1243 return true;
1244 } // "write"
1246 if (is_named_call_p (callee_fndecl, "read", call, 3))
1248 on_read (sm_ctxt, node, stmt, call, callee_fndecl);
1249 return true;
1250 } // "read"
1252 if (is_named_call_p (callee_fndecl, "dup", call, 1))
1254 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_1);
1255 return true;
1258 if (is_named_call_p (callee_fndecl, "dup2", call, 2))
1260 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_2);
1261 return true;
1264 if (is_named_call_p (callee_fndecl, "dup3", call, 3))
1266 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_3);
1267 return true;
1271 // Handle __attribute__((fd_arg))
1273 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1274 "fd_arg", DIRS_READ_WRITE);
1276 // Handle __attribute__((fd_arg_read))
1278 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1279 "fd_arg_read", DIRS_READ);
1281 // Handle __attribute__((fd_arg_write))
1283 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1284 "fd_arg_write", DIRS_WRITE);
1288 return false;
1291 void
1292 fd_state_machine::check_for_fd_attrs (
1293 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
1294 const gcall *call, const tree callee_fndecl, const char *attr_name,
1295 access_directions fd_attr_access_dir) const
1297 /* Handle interesting fd attributes of the callee_fndecl,
1298 or prioritize those of the builtin that callee_fndecl is
1299 expected to be.
1300 Might want this to be controlled by a flag. */
1301 tree fndecl = callee_fndecl;
1302 /* If call is recognized as a builtin known_function,
1303 use that builtin's function_decl. */
1304 if (const region_model *old_model = sm_ctxt->get_old_region_model ())
1305 if (const builtin_known_function *builtin_kf
1306 = old_model->get_builtin_kf (call))
1307 fndecl = builtin_kf->builtin_decl ();
1309 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (fndecl));
1310 attrs = lookup_attribute (attr_name, attrs);
1311 if (!attrs)
1312 return;
1314 if (!TREE_VALUE (attrs))
1315 return;
1317 auto_bitmap argmap;
1319 for (tree idx = TREE_VALUE (attrs); idx; idx = TREE_CHAIN (idx))
1321 unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (idx)) - 1;
1322 bitmap_set_bit (argmap, val);
1324 if (bitmap_empty_p (argmap))
1325 return;
1327 for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
1329 tree arg = gimple_call_arg (call, arg_idx);
1330 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1331 state_t state = sm_ctxt->get_state (stmt, arg);
1332 bool bit_set = bitmap_bit_p (argmap, arg_idx);
1333 if (TREE_CODE (TREE_TYPE (arg)) != INTEGER_TYPE)
1334 continue;
1335 if (bit_set) // Check if arg_idx is marked by any of the file descriptor
1336 // attributes
1339 /* Do use the fndecl that caused the warning so that the
1340 misused attributes are printed and the user not confused. */
1341 if (is_closed_fd_p (state))
1344 sm_ctxt->warn (node, stmt, arg,
1345 make_unique<fd_use_after_close>
1346 (*this, diag_arg,
1347 fndecl, attr_name,
1348 arg_idx));
1349 continue;
1352 if (!(is_valid_fd_p (state) || (state == m_stop)))
1354 if (!is_constant_fd_p (state))
1356 sm_ctxt->warn (node, stmt, arg,
1357 make_unique<fd_use_without_check>
1358 (*this, diag_arg,
1359 fndecl, attr_name,
1360 arg_idx));
1361 continue;
1365 switch (fd_attr_access_dir)
1367 case DIRS_READ_WRITE:
1368 break;
1369 case DIRS_READ:
1371 if (is_writeonly_fd_p (state))
1373 sm_ctxt->warn (
1374 node, stmt, arg,
1375 make_unique<fd_access_mode_mismatch> (*this, diag_arg,
1376 DIRS_WRITE,
1377 fndecl,
1378 attr_name,
1379 arg_idx));
1382 break;
1383 case DIRS_WRITE:
1385 if (is_readonly_fd_p (state))
1387 sm_ctxt->warn (
1388 node, stmt, arg,
1389 make_unique<fd_access_mode_mismatch> (*this, diag_arg,
1390 DIRS_READ,
1391 fndecl,
1392 attr_name,
1393 arg_idx));
1396 break;
1403 void
1404 fd_state_machine::on_open (sm_context *sm_ctxt, const supernode *node,
1405 const gimple *stmt, const gcall *call) const
1407 tree lhs = gimple_call_lhs (call);
1408 if (lhs)
1410 tree arg = gimple_call_arg (call, 1);
1411 enum access_mode mode = READ_WRITE;
1412 if (TREE_CODE (arg) == INTEGER_CST)
1414 int flag = TREE_INT_CST_LOW (arg);
1415 mode = get_access_mode_from_flag (flag);
1417 switch (mode)
1419 case READ_ONLY:
1420 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1421 m_unchecked_read_only);
1422 break;
1423 case WRITE_ONLY:
1424 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1425 m_unchecked_write_only);
1426 break;
1427 default:
1428 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1429 m_unchecked_read_write);
1432 else
1434 sm_ctxt->warn (node, stmt, NULL_TREE,
1435 make_unique<fd_leak> (*this, NULL_TREE));
1439 void
1440 fd_state_machine::on_creat (sm_context *sm_ctxt, const supernode *node,
1441 const gimple *stmt, const gcall *call) const
1443 tree lhs = gimple_call_lhs (call);
1444 if (lhs)
1445 sm_ctxt->on_transition (node, stmt, lhs, m_start, m_unchecked_write_only);
1446 else
1447 sm_ctxt->warn (node, stmt, NULL_TREE,
1448 make_unique<fd_leak> (*this, NULL_TREE));
1451 void
1452 fd_state_machine::check_for_dup (sm_context *sm_ctxt, const supernode *node,
1453 const gimple *stmt, const gcall *call,
1454 const tree callee_fndecl, enum dup kind) const
1456 tree lhs = gimple_call_lhs (call);
1457 tree arg_1 = gimple_call_arg (call, 0);
1458 state_t state_arg_1 = sm_ctxt->get_state (stmt, arg_1);
1459 if (state_arg_1 == m_stop)
1460 return;
1461 if (!(is_constant_fd_p (state_arg_1) || is_valid_fd_p (state_arg_1)
1462 || state_arg_1 == m_start))
1464 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl,
1465 DIRS_READ_WRITE);
1466 return;
1468 switch (kind)
1470 case DUP_1:
1471 if (lhs)
1473 if (is_constant_fd_p (state_arg_1) || state_arg_1 == m_start)
1474 sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write);
1475 else
1476 sm_ctxt->set_next_state (stmt, lhs,
1477 valid_to_unchecked_state (state_arg_1));
1479 break;
1481 case DUP_2:
1482 case DUP_3:
1483 tree arg_2 = gimple_call_arg (call, 1);
1484 state_t state_arg_2 = sm_ctxt->get_state (stmt, arg_2);
1485 tree diag_arg_2 = sm_ctxt->get_diagnostic_tree (arg_2);
1486 if (state_arg_2 == m_stop)
1487 return;
1488 /* Check if -1 was passed as second argument to dup2. */
1489 if (!(is_constant_fd_p (state_arg_2) || is_valid_fd_p (state_arg_2)
1490 || state_arg_2 == m_start))
1492 sm_ctxt->warn (
1493 node, stmt, arg_2,
1494 make_unique<fd_use_without_check> (*this, diag_arg_2,
1495 callee_fndecl));
1496 return;
1498 /* dup2 returns value of its second argument on success.But, the
1499 access mode of the returned file descriptor depends on the duplicated
1500 file descriptor i.e the first argument. */
1501 if (lhs)
1503 if (is_constant_fd_p (state_arg_1) || state_arg_1 == m_start)
1504 sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write);
1505 else
1506 sm_ctxt->set_next_state (stmt, lhs,
1507 valid_to_unchecked_state (state_arg_1));
1510 break;
1514 void
1515 fd_state_machine::on_close (sm_context *sm_ctxt, const supernode *node,
1516 const gimple *stmt, const gcall *call) const
1518 tree arg = gimple_call_arg (call, 0);
1519 state_t state = sm_ctxt->get_state (stmt, arg);
1520 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1522 sm_ctxt->on_transition (node, stmt, arg, m_start, m_closed);
1523 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_read_write, m_closed);
1524 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_read_only, m_closed);
1525 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_write_only, m_closed);
1526 sm_ctxt->on_transition (node, stmt, arg, m_valid_read_write, m_closed);
1527 sm_ctxt->on_transition (node, stmt, arg, m_valid_read_only, m_closed);
1528 sm_ctxt->on_transition (node, stmt, arg, m_valid_write_only, m_closed);
1529 sm_ctxt->on_transition (node, stmt, arg, m_constant_fd, m_closed);
1530 sm_ctxt->on_transition (node, stmt, arg, m_new_datagram_socket, m_closed);
1531 sm_ctxt->on_transition (node, stmt, arg, m_new_stream_socket, m_closed);
1532 sm_ctxt->on_transition (node, stmt, arg, m_new_unknown_socket, m_closed);
1533 sm_ctxt->on_transition (node, stmt, arg, m_bound_datagram_socket, m_closed);
1534 sm_ctxt->on_transition (node, stmt, arg, m_bound_stream_socket, m_closed);
1535 sm_ctxt->on_transition (node, stmt, arg, m_bound_unknown_socket, m_closed);
1536 sm_ctxt->on_transition (node, stmt, arg, m_listening_stream_socket, m_closed);
1537 sm_ctxt->on_transition (node, stmt, arg, m_connected_stream_socket, m_closed);
1539 if (is_closed_fd_p (state))
1541 sm_ctxt->warn (node, stmt, arg,
1542 make_unique<fd_double_close> (*this, diag_arg));
1543 sm_ctxt->set_next_state (stmt, arg, m_stop);
1546 void
1547 fd_state_machine::on_read (sm_context *sm_ctxt, const supernode *node,
1548 const gimple *stmt, const gcall *call,
1549 const tree callee_fndecl) const
1551 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_READ);
1553 void
1554 fd_state_machine::on_write (sm_context *sm_ctxt, const supernode *node,
1555 const gimple *stmt, const gcall *call,
1556 const tree callee_fndecl) const
1558 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_WRITE);
1561 void
1562 fd_state_machine::check_for_open_fd (
1563 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
1564 const gcall *call, const tree callee_fndecl,
1565 enum access_directions callee_fndecl_dir) const
1567 tree arg = gimple_call_arg (call, 0);
1568 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1569 state_t state = sm_ctxt->get_state (stmt, arg);
1571 if (is_closed_fd_p (state))
1573 sm_ctxt->warn (node, stmt, arg,
1574 make_unique<fd_use_after_close> (*this, diag_arg,
1575 callee_fndecl));
1578 else
1580 if (state == m_new_stream_socket
1581 || state == m_bound_stream_socket
1582 || state == m_listening_stream_socket)
1583 /* Complain about fncall on socket in wrong phase. */
1584 sm_ctxt->warn
1585 (node, stmt, arg,
1586 make_unique<fd_phase_mismatch> (*this, diag_arg,
1587 callee_fndecl,
1588 state,
1589 EXPECTED_PHASE_CAN_TRANSFER));
1590 else if (!(is_valid_fd_p (state)
1591 || state == m_new_datagram_socket
1592 || state == m_bound_unknown_socket
1593 || state == m_connected_stream_socket
1594 || state == m_start
1595 || state == m_stop))
1597 if (!is_constant_fd_p (state))
1598 sm_ctxt->warn (
1599 node, stmt, arg,
1600 make_unique<fd_use_without_check> (*this, diag_arg,
1601 callee_fndecl));
1603 switch (callee_fndecl_dir)
1605 case DIRS_READ_WRITE:
1606 break;
1607 case DIRS_READ:
1608 if (is_writeonly_fd_p (state))
1610 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1611 sm_ctxt->warn (node, stmt, arg,
1612 make_unique<fd_access_mode_mismatch> (
1613 *this, diag_arg, DIRS_WRITE, callee_fndecl));
1616 break;
1617 case DIRS_WRITE:
1619 if (is_readonly_fd_p (state))
1621 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1622 sm_ctxt->warn (node, stmt, arg,
1623 make_unique<fd_access_mode_mismatch> (
1624 *this, diag_arg, DIRS_READ, callee_fndecl));
1626 break;
1631 static bool
1632 add_constraint_ge_zero (region_model *model,
1633 const svalue *fd_sval,
1634 region_model_context *ctxt)
1636 const svalue *zero
1637 = model->get_manager ()->get_or_create_int_cst (integer_type_node, 0);
1638 return model->add_constraint (fd_sval, GE_EXPR, zero, ctxt);
1641 /* Get the state for a new socket type based on SOCKET_TYPE_SVAL,
1642 a SOCK_* value. */
1644 state_machine::state_t
1645 fd_state_machine::
1646 get_state_for_socket_type (const svalue *socket_type_sval) const
1648 if (tree socket_type_cst = socket_type_sval->maybe_get_constant ())
1650 /* Attempt to use SOCK_* constants stashed from the frontend. */
1651 if (tree_int_cst_equal (socket_type_cst, m_SOCK_STREAM))
1652 return m_new_stream_socket;
1653 if (tree_int_cst_equal (socket_type_cst, m_SOCK_DGRAM))
1654 return m_new_datagram_socket;
1657 /* Unrecognized constant, or a symbolic "type" value. */
1658 return m_new_unknown_socket;
1661 /* Update the model and fd state for an outcome of a call to "socket",
1662 where SUCCESSFUL indicate which of the two outcomes.
1663 Return true if the outcome is feasible, or false to reject it. */
1665 bool
1666 fd_state_machine::on_socket (const call_details &cd,
1667 bool successful,
1668 sm_context *sm_ctxt,
1669 const extrinsic_state &ext_state) const
1671 const gcall *stmt = cd.get_call_stmt ();
1672 engine *eng = ext_state.get_engine ();
1673 const supergraph *sg = eng->get_supergraph ();
1674 const supernode *node = sg->get_supernode_for_stmt (stmt);
1675 region_model *model = cd.get_model ();
1677 if (successful)
1679 if (gimple_call_lhs (stmt))
1681 conjured_purge p (model, cd.get_ctxt ());
1682 region_model_manager *mgr = model->get_manager ();
1683 const svalue *new_fd
1684 = mgr->get_or_create_conjured_svalue (integer_type_node,
1685 stmt,
1686 cd.get_lhs_region (),
1688 if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
1689 return false;
1691 const svalue *socket_type_sval = cd.get_arg_svalue (1);
1692 state_machine::state_t new_state
1693 = get_state_for_socket_type (socket_type_sval);
1694 sm_ctxt->on_transition (node, stmt, new_fd, m_start, new_state);
1695 model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
1697 else
1698 sm_ctxt->warn (node, stmt, NULL_TREE,
1699 make_unique<fd_leak> (*this, NULL_TREE));
1701 else
1703 /* Return -1; set errno. */
1704 model->update_for_int_cst_return (cd, -1, true);
1705 model->set_errno (cd);
1708 return true;
1711 /* Check that FD_SVAL is usable by socket APIs.
1712 Complain if it has been closed, if it is a non-socket,
1713 or is invalid.
1714 If COMPLAINED is non-NULL and a problem is found,
1715 write *COMPLAINED = true.
1717 If SUCCESSFUL is true, attempt to add the constraint that FD_SVAL >= 0.
1718 Return true if this outcome is feasible. */
1720 bool
1721 fd_state_machine::check_for_socket_fd (const call_details &cd,
1722 bool successful,
1723 sm_context *sm_ctxt,
1724 const svalue *fd_sval,
1725 const supernode *node,
1726 state_t old_state,
1727 bool *complained) const
1729 const gcall *stmt = cd.get_call_stmt ();
1731 if (is_closed_fd_p (old_state))
1733 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1734 sm_ctxt->warn
1735 (node, stmt, fd_sval,
1736 make_unique<fd_use_after_close> (*this, diag_arg,
1737 cd.get_fndecl_for_call ()));
1738 if (complained)
1739 *complained = true;
1740 if (successful)
1741 return false;
1743 else if (is_unchecked_fd_p (old_state) || is_valid_fd_p (old_state))
1745 /* Complain about non-socket. */
1746 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1747 sm_ctxt->warn
1748 (node, stmt, fd_sval,
1749 make_unique<fd_type_mismatch> (*this, diag_arg,
1750 cd.get_fndecl_for_call (),
1751 old_state,
1752 EXPECTED_TYPE_SOCKET));
1753 if (complained)
1754 *complained = true;
1755 if (successful)
1756 return false;
1758 else if (old_state == m_invalid)
1760 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1761 sm_ctxt->warn
1762 (node, stmt, fd_sval,
1763 make_unique<fd_use_without_check> (*this, diag_arg,
1764 cd.get_fndecl_for_call ()));
1765 if (complained)
1766 *complained = true;
1767 if (successful)
1768 return false;
1771 if (successful)
1772 if (!add_constraint_ge_zero (cd.get_model (), fd_sval, cd.get_ctxt ()))
1773 return false;
1775 return true;
1778 /* For use by "bind" and "connect".
1779 As per fd_state_machine::check_for_socket_fd above,
1780 but also complain if we don't have a new socket, and check that
1781 we can read up to the size bytes from the address. */
1783 bool
1784 fd_state_machine::check_for_new_socket_fd (const call_details &cd,
1785 bool successful,
1786 sm_context *sm_ctxt,
1787 const svalue *fd_sval,
1788 const supernode *node,
1789 state_t old_state,
1790 enum expected_phase expected_phase)
1791 const
1793 bool complained = false;
1795 /* Check address and len. */
1796 const svalue *address_sval = cd.get_arg_svalue (1);
1797 const svalue *len_sval = cd.get_arg_svalue (2);
1799 /* Check that we can read the given number of bytes from the
1800 address. */
1801 region_model *model = cd.get_model ();
1802 const region *address_reg
1803 = model->deref_rvalue (address_sval, cd.get_arg_tree (1),
1804 cd.get_ctxt ());
1805 const region *sized_address_reg
1806 = model->get_manager ()->get_sized_region (address_reg,
1807 NULL_TREE,
1808 len_sval);
1809 model->get_store_value (sized_address_reg, cd.get_ctxt ());
1811 if (!check_for_socket_fd (cd, successful, sm_ctxt,
1812 fd_sval, node, old_state, &complained))
1813 return false;
1814 else if (!complained
1815 && !(old_state == m_new_stream_socket
1816 || old_state == m_new_datagram_socket
1817 || old_state == m_new_unknown_socket
1818 || old_state == m_start
1819 || old_state == m_stop
1820 || old_state == m_constant_fd))
1822 /* Complain about "bind" or "connect" in wrong phase. */
1823 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1824 sm_ctxt->warn
1825 (node, cd.get_call_stmt (), fd_sval,
1826 make_unique<fd_phase_mismatch> (*this, diag_arg,
1827 cd.get_fndecl_for_call (),
1828 old_state,
1829 expected_phase));
1830 if (successful)
1831 return false;
1833 else if (!successful)
1835 /* If we were in the start state, assume we had a new socket. */
1836 if (old_state == m_start)
1837 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1838 m_new_unknown_socket);
1841 /* Passing NULL as the address will lead to failure. */
1842 if (successful)
1843 if (address_sval->all_zeroes_p ())
1844 return false;
1846 return true;
1849 /* Update the model and fd state for an outcome of a call to "bind",
1850 where SUCCESSFUL indicate which of the two outcomes.
1851 Return true if the outcome is feasible, or false to reject it. */
1853 bool
1854 fd_state_machine::on_bind (const call_details &cd,
1855 bool successful,
1856 sm_context *sm_ctxt,
1857 const extrinsic_state &ext_state) const
1859 const gcall *stmt = cd.get_call_stmt ();
1860 engine *eng = ext_state.get_engine ();
1861 const supergraph *sg = eng->get_supergraph ();
1862 const supernode *node = sg->get_supernode_for_stmt (stmt);
1863 const svalue *fd_sval = cd.get_arg_svalue (0);
1864 region_model *model = cd.get_model ();
1865 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1867 if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
1868 fd_sval, node, old_state,
1869 EXPECTED_PHASE_CAN_BIND))
1870 return false;
1872 if (successful)
1874 state_t next_state = NULL;
1875 if (old_state == m_new_stream_socket)
1876 next_state = m_bound_stream_socket;
1877 else if (old_state == m_new_datagram_socket)
1878 next_state = m_bound_datagram_socket;
1879 else if (old_state == m_new_unknown_socket)
1880 next_state = m_bound_unknown_socket;
1881 else if (old_state == m_start
1882 || old_state == m_constant_fd)
1883 next_state = m_bound_unknown_socket;
1884 else if (old_state == m_stop)
1885 next_state = m_stop;
1886 else
1887 gcc_unreachable ();
1888 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval, next_state);
1889 model->update_for_zero_return (cd, true);
1891 else
1893 /* Return -1; set errno. */
1894 model->update_for_int_cst_return (cd, -1, true);
1895 model->set_errno (cd);
1898 return true;
1901 /* Update the model and fd state for an outcome of a call to "listen",
1902 where SUCCESSFUL indicate which of the two outcomes.
1903 Return true if the outcome is feasible, or false to reject it. */
1905 bool
1906 fd_state_machine::on_listen (const call_details &cd,
1907 bool successful,
1908 sm_context *sm_ctxt,
1909 const extrinsic_state &ext_state) const
1911 const gcall *stmt = cd.get_call_stmt ();
1912 engine *eng = ext_state.get_engine ();
1913 const supergraph *sg = eng->get_supergraph ();
1914 const supernode *node = sg->get_supernode_for_stmt (cd.get_call_stmt ());
1915 const svalue *fd_sval = cd.get_arg_svalue (0);
1916 region_model *model = cd.get_model ();
1917 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1919 /* We expect a stream socket that's had "bind" called on it. */
1920 if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
1921 return false;
1922 if (!(old_state == m_start
1923 || old_state == m_constant_fd
1924 || old_state == m_stop
1925 || old_state == m_invalid
1926 || old_state == m_bound_stream_socket
1927 || old_state == m_bound_unknown_socket
1928 /* Assume it's OK to call "listen" more than once. */
1929 || old_state == m_listening_stream_socket))
1931 /* Complain about fncall on wrong type or in wrong phase. */
1932 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1933 if (is_stream_socket_fd_p (old_state))
1934 sm_ctxt->warn
1935 (node, stmt, fd_sval,
1936 make_unique<fd_phase_mismatch> (*this, diag_arg,
1937 cd.get_fndecl_for_call (),
1938 old_state,
1939 EXPECTED_PHASE_CAN_LISTEN));
1940 else
1941 sm_ctxt->warn
1942 (node, stmt, fd_sval,
1943 make_unique<fd_type_mismatch> (*this, diag_arg,
1944 cd.get_fndecl_for_call (),
1945 old_state,
1946 EXPECTED_TYPE_STREAM_SOCKET));
1947 if (successful)
1948 return false;
1951 if (successful)
1953 model->update_for_zero_return (cd, true);
1954 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1955 m_listening_stream_socket);
1957 else
1959 /* Return -1; set errno. */
1960 model->update_for_int_cst_return (cd, -1, true);
1961 model->set_errno (cd);
1962 if (old_state == m_start)
1963 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1964 m_bound_stream_socket);
1967 return true;
1970 /* Update the model and fd state for an outcome of a call to "accept",
1971 where SUCCESSFUL indicate which of the two outcomes.
1972 Return true if the outcome is feasible, or false to reject it. */
1974 bool
1975 fd_state_machine::on_accept (const call_details &cd,
1976 bool successful,
1977 sm_context *sm_ctxt,
1978 const extrinsic_state &ext_state) const
1980 const gcall *stmt = cd.get_call_stmt ();
1981 engine *eng = ext_state.get_engine ();
1982 const supergraph *sg = eng->get_supergraph ();
1983 const supernode *node = sg->get_supernode_for_stmt (stmt);
1984 const svalue *fd_sval = cd.get_arg_svalue (0);
1985 const svalue *address_sval = cd.get_arg_svalue (1);
1986 const svalue *len_ptr_sval = cd.get_arg_svalue (2);
1987 region_model *model = cd.get_model ();
1988 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1990 if (!address_sval->all_zeroes_p ())
1992 region_model_manager *mgr = model->get_manager ();
1994 /* We might have a union of various pointer types, rather than a
1995 pointer type; cast to (void *) before dereferencing. */
1996 address_sval = mgr->get_or_create_cast (ptr_type_node, address_sval);
1998 const region *address_reg
1999 = model->deref_rvalue (address_sval, cd.get_arg_tree (1),
2000 cd.get_ctxt ());
2001 const region *len_reg
2002 = model->deref_rvalue (len_ptr_sval, cd.get_arg_tree (2),
2003 cd.get_ctxt ());
2004 const svalue *old_len_sval
2005 = model->get_store_value (len_reg, cd.get_ctxt ());
2006 tree len_ptr = cd.get_arg_tree (2);
2007 tree star_len_ptr = build2 (MEM_REF, TREE_TYPE (TREE_TYPE (len_ptr)),
2008 len_ptr,
2009 build_int_cst (TREE_TYPE (len_ptr), 0));
2010 old_len_sval = model->check_for_poison (old_len_sval,
2011 star_len_ptr,
2012 len_reg,
2013 cd.get_ctxt ());
2014 if (successful)
2016 conjured_purge p (model, cd.get_ctxt ());
2017 const region *old_sized_address_reg
2018 = mgr->get_sized_region (address_reg,
2019 NULL_TREE,
2020 old_len_sval);
2021 const svalue *new_addr_sval
2022 = mgr->get_or_create_conjured_svalue (NULL_TREE,
2023 stmt,
2024 old_sized_address_reg,
2026 model->set_value (old_sized_address_reg, new_addr_sval,
2027 cd.get_ctxt ());
2028 const svalue *new_addr_len
2029 = mgr->get_or_create_conjured_svalue (NULL_TREE,
2030 stmt,
2031 len_reg,
2033 model->set_value (len_reg, new_addr_len, cd.get_ctxt ());
2037 /* We expect a stream socket in the "listening" state. */
2038 if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
2039 return false;
2041 if (old_state == m_start || old_state == m_constant_fd)
2042 /* If we were in the start state (or a constant), assume we had the
2043 expected state. */
2044 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
2045 m_listening_stream_socket);
2046 else if (old_state == m_stop)
2048 /* No further complaints. */
2050 else if (old_state != m_listening_stream_socket)
2052 /* Complain about fncall on wrong type or in wrong phase. */
2053 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
2054 if (is_stream_socket_fd_p (old_state))
2055 sm_ctxt->warn
2056 (node, stmt, fd_sval,
2057 make_unique<fd_phase_mismatch> (*this, diag_arg,
2058 cd.get_fndecl_for_call (),
2059 old_state,
2060 EXPECTED_PHASE_CAN_ACCEPT));
2061 else
2062 sm_ctxt->warn
2063 (node, stmt, fd_sval,
2064 make_unique<fd_type_mismatch> (*this, diag_arg,
2065 cd.get_fndecl_for_call (),
2066 old_state,
2067 EXPECTED_TYPE_STREAM_SOCKET));
2068 if (successful)
2069 return false;
2072 if (successful)
2074 /* Return new conjured FD in "connected" state. */
2075 if (gimple_call_lhs (stmt))
2077 conjured_purge p (model, cd.get_ctxt ());
2078 region_model_manager *mgr = model->get_manager ();
2079 const svalue *new_fd
2080 = mgr->get_or_create_conjured_svalue (integer_type_node,
2081 stmt,
2082 cd.get_lhs_region (),
2084 if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
2085 return false;
2086 sm_ctxt->on_transition (node, stmt, new_fd,
2087 m_start, m_connected_stream_socket);
2088 model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
2090 else
2091 sm_ctxt->warn (node, stmt, NULL_TREE,
2092 make_unique<fd_leak> (*this, NULL_TREE));
2094 else
2096 /* Return -1; set errno. */
2097 model->update_for_int_cst_return (cd, -1, true);
2098 model->set_errno (cd);
2101 return true;
2104 /* Update the model and fd state for an outcome of a call to "connect",
2105 where SUCCESSFUL indicate which of the two outcomes.
2106 Return true if the outcome is feasible, or false to reject it. */
2108 bool
2109 fd_state_machine::on_connect (const call_details &cd,
2110 bool successful,
2111 sm_context *sm_ctxt,
2112 const extrinsic_state &ext_state) const
2114 const gcall *stmt = cd.get_call_stmt ();
2115 engine *eng = ext_state.get_engine ();
2116 const supergraph *sg = eng->get_supergraph ();
2117 const supernode *node = sg->get_supernode_for_stmt (stmt);
2118 const svalue *fd_sval = cd.get_arg_svalue (0);
2119 region_model *model = cd.get_model ();
2120 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
2122 if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
2123 fd_sval, node, old_state,
2124 EXPECTED_PHASE_CAN_CONNECT))
2125 return false;
2127 if (successful)
2129 model->update_for_zero_return (cd, true);
2130 state_t next_state = NULL;
2131 if (old_state == m_new_stream_socket)
2132 next_state = m_connected_stream_socket;
2133 else if (old_state == m_new_datagram_socket)
2134 /* It's legal to call connect on a datagram socket, potentially
2135 more than once. We don't transition states for this. */
2136 next_state = m_new_datagram_socket;
2137 else if (old_state == m_new_unknown_socket)
2138 next_state = m_stop;
2139 else if (old_state == m_start
2140 || old_state == m_constant_fd)
2141 next_state = m_stop;
2142 else if (old_state == m_stop)
2143 next_state = m_stop;
2144 else
2145 gcc_unreachable ();
2146 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval, next_state);
2148 else
2150 /* Return -1; set errno. */
2151 model->update_for_int_cst_return (cd, -1, true);
2152 model->set_errno (cd);
2153 /* TODO: perhaps transition to a failed state, since the
2154 portable way to handle a failed "connect" is to close
2155 the socket and try again with a new socket. */
2158 return true;
2161 void
2162 fd_state_machine::on_condition (sm_context *sm_ctxt, const supernode *node,
2163 const gimple *stmt, const svalue *lhs,
2164 enum tree_code op, const svalue *rhs) const
2166 if (tree cst = rhs->maybe_get_constant ())
2168 if (TREE_CODE (cst) == INTEGER_CST)
2170 int val = TREE_INT_CST_LOW (cst);
2171 if (val == -1)
2173 if (op == NE_EXPR)
2174 make_valid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2176 else if (op == EQ_EXPR)
2177 make_invalid_transitions_on_condition (sm_ctxt, node, stmt,
2178 lhs);
2183 if (rhs->all_zeroes_p ())
2185 if (op == GE_EXPR)
2186 make_valid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2187 else if (op == LT_EXPR)
2188 make_invalid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2192 void
2193 fd_state_machine::make_valid_transitions_on_condition (sm_context *sm_ctxt,
2194 const supernode *node,
2195 const gimple *stmt,
2196 const svalue *lhs) const
2198 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_write,
2199 m_valid_read_write);
2200 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_only,
2201 m_valid_read_only);
2202 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_write_only,
2203 m_valid_write_only);
2206 void
2207 fd_state_machine::make_invalid_transitions_on_condition (
2208 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
2209 const svalue *lhs) const
2211 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_write, m_invalid);
2212 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_only, m_invalid);
2213 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_write_only, m_invalid);
2216 bool
2217 fd_state_machine::can_purge_p (state_t s) const
2219 if (is_unchecked_fd_p (s)
2220 || is_valid_fd_p (s)
2221 || is_socket_fd_p (s))
2222 return false;
2223 else
2224 return true;
2227 std::unique_ptr<pending_diagnostic>
2228 fd_state_machine::on_leak (tree var) const
2230 return make_unique<fd_leak> (*this, var);
2232 } // namespace
2234 state_machine *
2235 make_fd_state_machine (logger *logger)
2237 return new fd_state_machine (logger);
2240 static bool
2241 get_fd_state (region_model_context *ctxt,
2242 sm_state_map **out_smap,
2243 const fd_state_machine **out_sm,
2244 unsigned *out_sm_idx,
2245 std::unique_ptr<sm_context> *out_sm_context)
2247 if (!ctxt)
2248 return false;
2250 const state_machine *sm;
2251 if (!ctxt->get_fd_map (out_smap, &sm, out_sm_idx, out_sm_context))
2252 return false;
2254 gcc_assert (sm);
2256 *out_sm = (const fd_state_machine *)sm;
2257 return true;
2260 /* Specialcase hook for handling pipe, for use by
2261 kf_pipe::success::update_model. */
2263 void
2264 region_model::mark_as_valid_fd (const svalue *sval, region_model_context *ctxt)
2266 sm_state_map *smap;
2267 const fd_state_machine *fd_sm;
2268 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, NULL))
2269 return;
2270 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2271 if (!ext_state)
2272 return;
2273 fd_sm->mark_as_valid_fd (this, smap, sval, *ext_state);
2276 /* Handle calls to "socket".
2277 See e.g. https://man7.org/linux/man-pages/man3/socket.3p.html */
2279 class kf_socket : public known_function
2281 public:
2282 class outcome_of_socket : public succeed_or_fail_call_info
2284 public:
2285 outcome_of_socket (const call_details &cd, bool success)
2286 : succeed_or_fail_call_info (cd, success)
2289 bool update_model (region_model *model,
2290 const exploded_edge *,
2291 region_model_context *ctxt) const final override
2293 const call_details cd (get_call_details (model, ctxt));
2294 sm_state_map *smap;
2295 const fd_state_machine *fd_sm;
2296 std::unique_ptr<sm_context> sm_ctxt;
2297 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2299 cd.set_any_lhs_with_defaults ();
2300 return true;
2302 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2303 if (!ext_state)
2305 cd.set_any_lhs_with_defaults ();
2306 return true;
2309 return fd_sm->on_socket (cd, m_success, sm_ctxt.get (), *ext_state);
2313 bool matches_call_types_p (const call_details &cd) const final override
2315 return cd.num_args () == 3;
2318 void impl_call_post (const call_details &cd) const final override
2320 if (cd.get_ctxt ())
2322 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, false));
2323 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, true));
2324 cd.get_ctxt ()->terminate_path ();
2329 /* Handle calls to "bind".
2330 See e.g. https://man7.org/linux/man-pages/man3/bind.3p.html */
2332 class kf_bind : public known_function
2334 public:
2335 class outcome_of_bind : public succeed_or_fail_call_info
2337 public:
2338 outcome_of_bind (const call_details &cd, bool success)
2339 : succeed_or_fail_call_info (cd, success)
2342 bool update_model (region_model *model,
2343 const exploded_edge *,
2344 region_model_context *ctxt) const final override
2346 const call_details cd (get_call_details (model, ctxt));
2347 sm_state_map *smap;
2348 const fd_state_machine *fd_sm;
2349 std::unique_ptr<sm_context> sm_ctxt;
2350 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2352 cd.set_any_lhs_with_defaults ();
2353 return true;
2355 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2356 if (!ext_state)
2358 cd.set_any_lhs_with_defaults ();
2359 return true;
2361 return fd_sm->on_bind (cd, m_success, sm_ctxt.get (), *ext_state);
2365 bool matches_call_types_p (const call_details &cd) const final override
2367 return (cd.num_args () == 3 && cd.arg_is_pointer_p (1));
2370 void impl_call_post (const call_details &cd) const final override
2372 if (cd.get_ctxt ())
2374 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, false));
2375 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, true));
2376 cd.get_ctxt ()->terminate_path ();
2381 /* Handle calls to "listen".
2382 See e.g. https://man7.org/linux/man-pages/man3/listen.3p.html */
2384 class kf_listen : public known_function
2386 class outcome_of_listen : public succeed_or_fail_call_info
2388 public:
2389 outcome_of_listen (const call_details &cd, bool success)
2390 : succeed_or_fail_call_info (cd, success)
2393 bool update_model (region_model *model,
2394 const exploded_edge *,
2395 region_model_context *ctxt) const final override
2397 const call_details cd (get_call_details (model, ctxt));
2398 sm_state_map *smap;
2399 const fd_state_machine *fd_sm;
2400 std::unique_ptr<sm_context> sm_ctxt;
2401 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2403 cd.set_any_lhs_with_defaults ();
2404 return true;
2406 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2407 if (!ext_state)
2409 cd.set_any_lhs_with_defaults ();
2410 return true;
2413 return fd_sm->on_listen (cd, m_success, sm_ctxt.get (), *ext_state);
2417 bool matches_call_types_p (const call_details &cd) const final override
2419 return cd.num_args () == 2;
2422 void impl_call_post (const call_details &cd) const final override
2424 if (cd.get_ctxt ())
2426 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, false));
2427 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, true));
2428 cd.get_ctxt ()->terminate_path ();
2433 /* Handle calls to "accept".
2434 See e.g. https://man7.org/linux/man-pages/man3/accept.3p.html */
2436 class kf_accept : public known_function
2438 class outcome_of_accept : public succeed_or_fail_call_info
2440 public:
2441 outcome_of_accept (const call_details &cd, bool success)
2442 : succeed_or_fail_call_info (cd, success)
2445 bool update_model (region_model *model,
2446 const exploded_edge *,
2447 region_model_context *ctxt) const final override
2449 const call_details cd (get_call_details (model, ctxt));
2450 sm_state_map *smap;
2451 const fd_state_machine *fd_sm;
2452 std::unique_ptr<sm_context> sm_ctxt;
2453 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2455 cd.set_any_lhs_with_defaults ();
2456 return true;
2458 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2459 if (!ext_state)
2461 cd.set_any_lhs_with_defaults ();
2462 return true;
2465 return fd_sm->on_accept (cd, m_success, sm_ctxt.get (), *ext_state);
2469 bool matches_call_types_p (const call_details &cd) const final override
2471 return (cd.num_args () == 3
2472 && cd.arg_is_pointer_p (1)
2473 && cd.arg_is_pointer_p (2));
2476 void impl_call_post (const call_details &cd) const final override
2478 if (cd.get_ctxt ())
2480 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, false));
2481 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, true));
2482 cd.get_ctxt ()->terminate_path ();
2487 /* Handle calls to "connect".
2488 See e.g. https://man7.org/linux/man-pages/man3/connect.3p.html */
2490 class kf_connect : public known_function
2492 public:
2493 class outcome_of_connect : public succeed_or_fail_call_info
2495 public:
2496 outcome_of_connect (const call_details &cd, bool success)
2497 : succeed_or_fail_call_info (cd, success)
2500 bool update_model (region_model *model,
2501 const exploded_edge *,
2502 region_model_context *ctxt) const final override
2504 const call_details cd (get_call_details (model, ctxt));
2505 sm_state_map *smap;
2506 const fd_state_machine *fd_sm;
2507 std::unique_ptr<sm_context> sm_ctxt;
2508 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2510 cd.set_any_lhs_with_defaults ();
2511 return true;
2513 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2514 if (!ext_state)
2516 cd.set_any_lhs_with_defaults ();
2517 return true;
2520 return fd_sm->on_connect (cd, m_success, sm_ctxt.get (), *ext_state);
2524 bool matches_call_types_p (const call_details &cd) const final override
2526 return (cd.num_args () == 3
2527 && cd.arg_is_pointer_p (1));
2530 void impl_call_post (const call_details &cd) const final override
2532 if (cd.get_ctxt ())
2534 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, false));
2535 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, true));
2536 cd.get_ctxt ()->terminate_path ();
2541 /* Handler for "isatty"".
2542 See e.g. https://man7.org/linux/man-pages/man3/isatty.3.html */
2544 class kf_isatty : public known_function
2546 class outcome_of_isatty : public succeed_or_fail_call_info
2548 public:
2549 outcome_of_isatty (const call_details &cd, bool success)
2550 : succeed_or_fail_call_info (cd, success)
2553 bool update_model (region_model *model,
2554 const exploded_edge *,
2555 region_model_context *ctxt) const final override
2557 const call_details cd (get_call_details (model, ctxt));
2559 if (m_success)
2561 /* Return 1. */
2562 model->update_for_int_cst_return (cd, 1, true);
2564 else
2566 /* Return 0; set errno. */
2567 model->update_for_int_cst_return (cd, 0, true);
2568 model->set_errno (cd);
2571 return feasible_p (cd, ctxt);
2574 private:
2575 bool feasible_p (const call_details &cd,
2576 region_model_context *ctxt) const
2578 if (m_success)
2580 /* Can't be "success" on a closed/invalid fd. */
2581 sm_state_map *smap;
2582 const fd_state_machine *fd_sm;
2583 std::unique_ptr<sm_context> sm_ctxt;
2584 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2585 return true;
2586 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2587 if (!ext_state)
2588 return true;
2590 const svalue *fd_sval = cd.get_arg_svalue (0);
2591 state_machine::state_t old_state
2592 = sm_ctxt->get_state (cd.get_call_stmt (), fd_sval);
2594 if (fd_sm->is_closed_fd_p (old_state)
2595 || old_state == fd_sm->m_invalid)
2596 return false;
2598 return true;
2600 }; // class outcome_of_isatty
2602 public:
2603 bool matches_call_types_p (const call_details &cd) const final override
2605 return cd.num_args () == 1;
2608 void impl_call_post (const call_details &cd) const final override
2610 if (cd.get_ctxt ())
2612 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, false));
2613 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, true));
2614 cd.get_ctxt ()->terminate_path ();
2619 /* Handler for calls to "pipe" and "pipe2".
2620 See e.g. https://www.man7.org/linux/man-pages/man2/pipe.2.html */
2622 class kf_pipe : public known_function
2624 class failure : public failed_call_info
2626 public:
2627 failure (const call_details &cd) : failed_call_info (cd) {}
2629 bool update_model (region_model *model,
2630 const exploded_edge *,
2631 region_model_context *ctxt) const final override
2633 /* Return -1; everything else is unchanged. */
2634 const call_details cd (get_call_details (model, ctxt));
2635 model->update_for_int_cst_return (cd, -1, true);
2636 return true;
2640 class success : public success_call_info
2642 public:
2643 success (const call_details &cd) : success_call_info (cd) {}
2645 bool update_model (region_model *model,
2646 const exploded_edge *,
2647 region_model_context *ctxt) const final override
2649 const call_details cd (get_call_details (model, ctxt));
2651 /* Return 0. */
2652 model->update_for_zero_return (cd, true);
2654 /* Update fd array. */
2655 region_model_manager *mgr = cd.get_manager ();
2656 tree arr_tree = cd.get_arg_tree (0);
2657 const svalue *arr_sval = cd.get_arg_svalue (0);
2658 for (int idx = 0; idx < 2; idx++)
2660 const region *arr_reg
2661 = model->deref_rvalue (arr_sval, arr_tree, cd.get_ctxt ());
2662 const svalue *idx_sval
2663 = mgr->get_or_create_int_cst (integer_type_node, idx);
2664 const region *element_reg
2665 = mgr->get_element_region (arr_reg, integer_type_node, idx_sval);
2666 conjured_purge p (model, cd.get_ctxt ());
2667 const svalue *fd_sval
2668 = mgr->get_or_create_conjured_svalue (integer_type_node,
2669 cd.get_call_stmt (),
2670 element_reg,
2672 model->set_value (element_reg, fd_sval, cd.get_ctxt ());
2673 model->mark_as_valid_fd (fd_sval, cd.get_ctxt ());
2675 return true;
2679 public:
2680 kf_pipe (unsigned num_args)
2681 : m_num_args (num_args)
2683 gcc_assert (num_args > 0);
2686 bool matches_call_types_p (const call_details &cd) const final override
2688 return (cd.num_args () == m_num_args && cd.arg_is_pointer_p (0));
2691 void impl_call_post (const call_details &cd) const final override
2693 if (cd.get_ctxt ())
2695 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
2696 cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
2697 cd.get_ctxt ()->terminate_path ();
2701 private:
2702 unsigned m_num_args;
2705 /* Handler for "read".
2706 ssize_t read(int fildes, void *buf, size_t nbyte);
2707 See e.g. https://man7.org/linux/man-pages/man2/read.2.html */
2709 class kf_read : public known_function
2711 public:
2712 bool matches_call_types_p (const call_details &cd) const final override
2714 return (cd.num_args () == 3
2715 && cd.arg_is_pointer_p (1)
2716 && cd.arg_is_size_p (2));
2719 /* For now, assume that any call to "read" fully clobbers the buffer
2720 passed in. This isn't quite correct (e.g. errors, partial reads;
2721 see PR analyzer/108689), but at least stops us falsely complaining
2722 about the buffer being uninitialized. */
2723 void impl_call_pre (const call_details &cd) const final override
2725 region_model *model = cd.get_model ();
2726 const svalue *ptr_sval = cd.get_arg_svalue (1);
2727 if (const region *reg = ptr_sval->maybe_get_region ())
2729 const region *base_reg = reg->get_base_region ();
2730 const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
2731 model->set_value (base_reg, new_sval, cd.get_ctxt ());
2733 cd.set_any_lhs_with_defaults ();
2738 /* Populate KFM with instances of known functions relating to
2739 file descriptors. */
2741 void
2742 register_known_fd_functions (known_function_manager &kfm)
2744 kfm.add ("accept", make_unique<kf_accept> ());
2745 kfm.add ("bind", make_unique<kf_bind> ());
2746 kfm.add ("connect", make_unique<kf_connect> ());
2747 kfm.add ("isatty", make_unique<kf_isatty> ());
2748 kfm.add ("listen", make_unique<kf_listen> ());
2749 kfm.add ("pipe", make_unique<kf_pipe> (1));
2750 kfm.add ("pipe2", make_unique<kf_pipe> (2));
2751 kfm.add ("read", make_unique<kf_read> ());
2752 kfm.add ("socket", make_unique<kf_socket> ());
2755 } // namespace ana
2757 #endif // ENABLE_ANALYZER