]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/analyzer/sm-fd.cc
analyzer: move known funs for fds to sm-fd.cc
[thirdparty/gcc.git] / gcc / analyzer / sm-fd.cc
CommitLineData
9365b2bf
ML
1/* A state machine for detecting misuses of POSIX file descriptor APIs.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by Immad Mir <mir@sourceware.org>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
6341f14e 22#define INCLUDE_MEMORY
9365b2bf
ML
23#include "system.h"
24#include "coretypes.h"
6341f14e 25#include "make-unique.h"
9365b2bf
ML
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"
9365b2bf
ML
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"
9365b2bf
ML
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"
792f039f 47#include "analyzer/program-state.h"
86a90006
DM
48#include "analyzer/supergraph.h"
49#include "analyzer/analyzer-language.h"
50d5b240 50#include "analyzer/call-info.h"
9365b2bf
ML
51
52#if ENABLE_ANALYZER
53
54namespace ana {
55
56namespace {
57
58/* An enum for distinguishing between three different access modes. */
59
60enum access_mode
61{
62 READ_WRITE,
63 READ_ONLY,
64 WRITE_ONLY
65};
66
67enum access_directions
68{
69 DIRS_READ_WRITE,
70 DIRS_READ,
71 DIRS_WRITE
72};
73
6a11f2d9
IM
74/* An enum for distinguishing between dup, dup2 and dup3. */
75enum dup
76{
77 DUP_1,
78 DUP_2,
79 DUP_3
80};
81
86a90006
DM
82/* Enum for use by -Wanalyzer-fd-phase-mismatch. */
83
84enum expected_phase
85{
86 EXPECTED_PHASE_CAN_TRANSFER, /* can "read"/"write". */
87 EXPECTED_PHASE_CAN_BIND,
88 EXPECTED_PHASE_CAN_LISTEN,
89 EXPECTED_PHASE_CAN_ACCEPT,
90 EXPECTED_PHASE_CAN_CONNECT
91};
92
9365b2bf
ML
93class fd_state_machine : public state_machine
94{
95public:
96 fd_state_machine (logger *logger);
97
98 bool
99 inherited_state_p () const final override
100 {
101 return false;
102 }
103
104 state_machine::state_t
105 get_default_state (const svalue *sval) const final override
106 {
107 if (tree cst = sval->maybe_get_constant ())
108 {
109 if (TREE_CODE (cst) == INTEGER_CST)
110 {
111 int val = TREE_INT_CST_LOW (cst);
112 if (val >= 0)
113 return m_constant_fd;
114 else
115 return m_invalid;
116 }
117 }
118 return m_start;
119 }
120
121 bool on_stmt (sm_context *sm_ctxt, const supernode *node,
122 const gimple *stmt) const final override;
123
124 void on_condition (sm_context *sm_ctxt, const supernode *node,
125 const gimple *stmt, const svalue *lhs, const tree_code op,
126 const svalue *rhs) const final override;
127
128 bool can_purge_p (state_t s) const final override;
6341f14e 129 std::unique_ptr<pending_diagnostic> on_leak (tree var) const final override;
9365b2bf
ML
130
131 bool is_unchecked_fd_p (state_t s) const;
132 bool is_valid_fd_p (state_t s) const;
86a90006
DM
133 bool is_socket_fd_p (state_t s) const;
134 bool is_datagram_socket_fd_p (state_t s) const;
135 bool is_stream_socket_fd_p (state_t s) const;
9365b2bf
ML
136 bool is_closed_fd_p (state_t s) const;
137 bool is_constant_fd_p (state_t s) const;
138 bool is_readonly_fd_p (state_t s) const;
139 bool is_writeonly_fd_p (state_t s) const;
140 enum access_mode get_access_mode_from_flag (int flag) const;
6a11f2d9
IM
141 /* Function for one-to-one correspondence between valid
142 and unchecked states. */
143 state_t valid_to_unchecked_state (state_t state) const;
792f039f
DM
144
145 void mark_as_valid_fd (region_model *model,
146 sm_state_map *smap,
147 const svalue *fd_sval,
148 const extrinsic_state &ext_state) const;
149
86a90006
DM
150 bool on_socket (const call_details &cd,
151 bool successful,
152 sm_context *sm_ctxt,
153 const extrinsic_state &ext_state) const;
154 bool on_bind (const call_details &cd,
155 bool successful,
156 sm_context *sm_ctxt,
157 const extrinsic_state &ext_state) const;
158 bool on_listen (const call_details &cd,
159 bool successful,
160 sm_context *sm_ctxt,
161 const extrinsic_state &ext_state) const;
162 bool on_accept (const call_details &cd,
163 bool successful,
164 sm_context *sm_ctxt,
165 const extrinsic_state &ext_state) const;
166 bool on_connect (const call_details &cd,
167 bool successful,
168 sm_context *sm_ctxt,
169 const extrinsic_state &ext_state) const;
170
9365b2bf
ML
171 /* State for a constant file descriptor (>= 0) */
172 state_t m_constant_fd;
173
174 /* States representing a file descriptor that hasn't yet been
175 checked for validity after opening, for three different
176 access modes. */
177 state_t m_unchecked_read_write;
178
179 state_t m_unchecked_read_only;
180
181 state_t m_unchecked_write_only;
182
183 /* States for representing a file descriptor that is known to be valid (>=
184 0), for three different access modes. */
185 state_t m_valid_read_write;
186
187 state_t m_valid_read_only;
188
189 state_t m_valid_write_only;
190
191 /* State for a file descriptor that is known to be invalid (< 0). */
192 state_t m_invalid;
193
194 /* State for a file descriptor that has been closed. */
195 state_t m_closed;
196
86a90006
DM
197 /* States for FDs relating to socket APIs. */
198
199 /* Result of successful "socket" with SOCK_DGRAM. */
200 state_t m_new_datagram_socket;
201 /* Result of successful "socket" with SOCK_STREAM. */
202 state_t m_new_stream_socket;
203 /* Result of successful "socket" with unknown type. */
204 state_t m_new_unknown_socket;
205
206 /* The above after a successful call to "bind". */
207 state_t m_bound_datagram_socket;
208 state_t m_bound_stream_socket;
209 state_t m_bound_unknown_socket;
210
211 /* A bound socket after a successful call to "listen" (stream or unknown). */
212 state_t m_listening_stream_socket;
213
214 /* (i) the new FD as a result of a succesful call to "accept" on a
215 listening socket (via a passive open), or
216 (ii) an active socket after a successful call to "connect"
217 (via an active open). */
218 state_t m_connected_stream_socket;
219
9365b2bf
ML
220 /* State for a file descriptor that we do not want to track anymore . */
221 state_t m_stop;
222
d8aba860
DM
223 /* Stashed constant values from the frontend. These could be NULL. */
224 tree m_O_ACCMODE;
225 tree m_O_RDONLY;
226 tree m_O_WRONLY;
86a90006
DM
227 tree m_SOCK_STREAM;
228 tree m_SOCK_DGRAM;
d8aba860 229
9365b2bf
ML
230private:
231 void on_open (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
232 const gcall *call) const;
6a11f2d9
IM
233 void on_creat (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
234 const gcall *call) const;
9365b2bf
ML
235 void on_close (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
236 const gcall *call) const;
237 void on_read (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
238 const gcall *call, const tree callee_fndecl) const;
239 void on_write (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
240 const gcall *call, const tree callee_fndecl) const;
241 void check_for_open_fd (sm_context *sm_ctxt, const supernode *node,
242 const gimple *stmt, const gcall *call,
243 const tree callee_fndecl,
244 enum access_directions access_fn) const;
245
246 void make_valid_transitions_on_condition (sm_context *sm_ctxt,
247 const supernode *node,
248 const gimple *stmt,
249 const svalue *lhs) const;
250 void make_invalid_transitions_on_condition (sm_context *sm_ctxt,
251 const supernode *node,
252 const gimple *stmt,
253 const svalue *lhs) const;
254 void check_for_fd_attrs (sm_context *sm_ctxt, const supernode *node,
255 const gimple *stmt, const gcall *call,
256 const tree callee_fndecl, const char *attr_name,
257 access_directions fd_attr_access_dir) const;
6a11f2d9
IM
258 void check_for_dup (sm_context *sm_ctxt, const supernode *node,
259 const gimple *stmt, const gcall *call, const tree callee_fndecl,
260 enum dup kind) const;
86a90006
DM
261
262 state_t get_state_for_socket_type (const svalue *socket_type_sval) const;
263
264 bool check_for_socket_fd (const call_details &cd,
265 bool successful,
266 sm_context *sm_ctxt,
267 const svalue *fd_sval,
268 const supernode *node,
269 state_t old_state,
270 bool *complained = NULL) const;
271 bool check_for_new_socket_fd (const call_details &cd,
272 bool successful,
273 sm_context *sm_ctxt,
274 const svalue *fd_sval,
275 const supernode *node,
276 state_t old_state,
277 enum expected_phase expected_phase) const;
9365b2bf
ML
278};
279
280/* Base diagnostic class relative to fd_state_machine. */
281class fd_diagnostic : public pending_diagnostic
282{
283public:
284 fd_diagnostic (const fd_state_machine &sm, tree arg) : m_sm (sm), m_arg (arg)
285 {
286 }
287
288 bool
289 subclass_equal_p (const pending_diagnostic &base_other) const override
290 {
291 return same_tree_p (m_arg, ((const fd_diagnostic &)base_other).m_arg);
292 }
293
294 label_text
295 describe_state_change (const evdesc::state_change &change) override
296 {
86a90006 297 if (change.m_old_state == m_sm.get_start_state ())
9365b2bf 298 {
792f039f
DM
299 if (change.m_new_state == m_sm.m_unchecked_read_write
300 || change.m_new_state == m_sm.m_valid_read_write)
9365b2bf
ML
301 return change.formatted_print ("opened here as read-write");
302
792f039f
DM
303 if (change.m_new_state == m_sm.m_unchecked_read_only
304 || change.m_new_state == m_sm.m_valid_read_only)
9365b2bf
ML
305 return change.formatted_print ("opened here as read-only");
306
792f039f
DM
307 if (change.m_new_state == m_sm.m_unchecked_write_only
308 || change.m_new_state == m_sm.m_valid_write_only)
9365b2bf 309 return change.formatted_print ("opened here as write-only");
86a90006
DM
310
311 if (change.m_new_state == m_sm.m_new_datagram_socket)
312 return change.formatted_print ("datagram socket created here");
313
314 if (change.m_new_state == m_sm.m_new_stream_socket)
315 return change.formatted_print ("stream socket created here");
316
317 if (change.m_new_state == m_sm.m_new_unknown_socket
318 || change.m_new_state == m_sm.m_connected_stream_socket)
319 return change.formatted_print ("socket created here");
9365b2bf
ML
320 }
321
86a90006
DM
322 if (change.m_new_state == m_sm.m_bound_datagram_socket)
323 return change.formatted_print ("datagram socket bound here");
324
325 if (change.m_new_state == m_sm.m_bound_stream_socket)
326 return change.formatted_print ("stream socket bound here");
327
328 if (change.m_new_state == m_sm.m_bound_unknown_socket
329 || change.m_new_state == m_sm.m_connected_stream_socket)
330 return change.formatted_print ("socket bound here");
331
332 if (change.m_new_state == m_sm.m_listening_stream_socket)
333 return change.formatted_print
334 ("stream socket marked as passive here via %qs", "listen");
335
9365b2bf
ML
336 if (change.m_new_state == m_sm.m_closed)
337 return change.formatted_print ("closed here");
338
339 if (m_sm.is_unchecked_fd_p (change.m_old_state)
340 && m_sm.is_valid_fd_p (change.m_new_state))
341 {
342 if (change.m_expr)
343 return change.formatted_print (
344 "assuming %qE is a valid file descriptor (>= 0)", change.m_expr);
345 else
346 return change.formatted_print ("assuming a valid file descriptor");
347 }
348
349 if (m_sm.is_unchecked_fd_p (change.m_old_state)
350 && change.m_new_state == m_sm.m_invalid)
351 {
352 if (change.m_expr)
353 return change.formatted_print (
354 "assuming %qE is an invalid file descriptor (< 0)",
355 change.m_expr);
356 else
357 return change.formatted_print ("assuming an invalid file descriptor");
358 }
359
360 return label_text ();
361 }
362
0f82c0ea
IM
363 diagnostic_event::meaning
364 get_meaning_for_state_change (
365 const evdesc::state_change &change) const final override
366 {
367 if (change.m_old_state == m_sm.get_start_state ()
86a90006
DM
368 && (m_sm.is_unchecked_fd_p (change.m_new_state)
369 || change.m_new_state == m_sm.m_new_datagram_socket
370 || change.m_new_state == m_sm.m_new_stream_socket
371 || change.m_new_state == m_sm.m_new_unknown_socket))
0f82c0ea
IM
372 return diagnostic_event::meaning (diagnostic_event::VERB_acquire,
373 diagnostic_event::NOUN_resource);
374 if (change.m_new_state == m_sm.m_closed)
375 return diagnostic_event::meaning (diagnostic_event::VERB_release,
376 diagnostic_event::NOUN_resource);
377 return diagnostic_event::meaning ();
378 }
379
9365b2bf
ML
380protected:
381 const fd_state_machine &m_sm;
382 tree m_arg;
383};
384
385class fd_param_diagnostic : public fd_diagnostic
386{
387public:
388 fd_param_diagnostic (const fd_state_machine &sm, tree arg, tree callee_fndecl,
389 const char *attr_name, int arg_idx)
390 : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl),
391 m_attr_name (attr_name), m_arg_idx (arg_idx)
392 {
393 }
394
395 fd_param_diagnostic (const fd_state_machine &sm, tree arg, tree callee_fndecl)
396 : fd_diagnostic (sm, arg), m_callee_fndecl (callee_fndecl),
397 m_attr_name (NULL), m_arg_idx (-1)
398 {
399 }
400
401 bool
402 subclass_equal_p (const pending_diagnostic &base_other) const override
403 {
404 const fd_param_diagnostic &sub_other
405 = (const fd_param_diagnostic &)base_other;
406 return (same_tree_p (m_arg, sub_other.m_arg)
407 && same_tree_p (m_callee_fndecl, sub_other.m_callee_fndecl)
408 && m_arg_idx == sub_other.m_arg_idx
409 && ((m_attr_name)
410 ? (strcmp (m_attr_name, sub_other.m_attr_name) == 0)
411 : true));
412 }
413
414 void
415 inform_filedescriptor_attribute (access_directions fd_dir)
416 {
417
418 if (m_attr_name)
419 switch (fd_dir)
420 {
421 case DIRS_READ_WRITE:
422 inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
423 "argument %d of %qD must be an open file descriptor, due to "
424 "%<__attribute__((%s(%d)))%>",
425 m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx + 1);
426 break;
427 case DIRS_WRITE:
428 inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
429 "argument %d of %qD must be a readable file descriptor, due "
430 "to %<__attribute__((%s(%d)))%>",
431 m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx + 1);
432 break;
433 case DIRS_READ:
434 inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
435 "argument %d of %qD must be a writable file descriptor, due "
436 "to %<__attribute__((%s(%d)))%>",
437 m_arg_idx + 1, m_callee_fndecl, m_attr_name, m_arg_idx + 1);
438 break;
439 }
440 }
441
442protected:
443 tree m_callee_fndecl;
444 const char *m_attr_name;
445 /* ARG_IDX is 0-based. */
446 int m_arg_idx;
447};
448
449class fd_leak : public fd_diagnostic
450{
451public:
452 fd_leak (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm, arg) {}
453
454 const char *
455 get_kind () const final override
456 {
457 return "fd_leak";
458 }
459
460 int
461 get_controlling_option () const final override
462 {
463 return OPT_Wanalyzer_fd_leak;
464 }
465
466 bool
467 emit (rich_location *rich_loc) final override
468 {
469 /*CWE-775: Missing Release of File Descriptor or Handle after Effective
470 Lifetime
471 */
472 diagnostic_metadata m;
473 m.add_cwe (775);
474 if (m_arg)
475 return warning_meta (rich_loc, m, get_controlling_option (),
476 "leak of file descriptor %qE", m_arg);
477 else
478 return warning_meta (rich_loc, m, get_controlling_option (),
479 "leak of file descriptor");
480 }
481
482 label_text
483 describe_state_change (const evdesc::state_change &change) final override
484 {
485 if (m_sm.is_unchecked_fd_p (change.m_new_state))
486 {
487 m_open_event = change.m_event_id;
488 return label_text::borrow ("opened here");
489 }
490
491 return fd_diagnostic::describe_state_change (change);
492 }
493
494 label_text
495 describe_final_event (const evdesc::final_event &ev) final override
496 {
497 if (m_open_event.known_p ())
498 {
499 if (ev.m_expr)
500 return ev.formatted_print ("%qE leaks here; was opened at %@",
501 ev.m_expr, &m_open_event);
502 else
503 return ev.formatted_print ("leaks here; was opened at %@",
504 &m_open_event);
505 }
506 else
507 {
508 if (ev.m_expr)
509 return ev.formatted_print ("%qE leaks here", ev.m_expr);
510 else
511 return ev.formatted_print ("leaks here");
512 }
513 }
514
515private:
516 diagnostic_event_id_t m_open_event;
517};
518
519class fd_access_mode_mismatch : public fd_param_diagnostic
520{
521public:
522 fd_access_mode_mismatch (const fd_state_machine &sm, tree arg,
523 enum access_directions fd_dir,
524 const tree callee_fndecl, const char *attr_name,
525 int arg_idx)
526 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx),
527 m_fd_dir (fd_dir)
528
529 {
530 }
531
532 fd_access_mode_mismatch (const fd_state_machine &sm, tree arg,
533 enum access_directions fd_dir,
534 const tree callee_fndecl)
535 : fd_param_diagnostic (sm, arg, callee_fndecl), m_fd_dir (fd_dir)
536 {
537 }
538
539 const char *
540 get_kind () const final override
541 {
542 return "fd_access_mode_mismatch";
543 }
544
545 int
546 get_controlling_option () const final override
547 {
548 return OPT_Wanalyzer_fd_access_mode_mismatch;
549 }
550
551 bool
552 emit (rich_location *rich_loc) final override
553 {
554 bool warned;
555 switch (m_fd_dir)
556 {
557 case DIRS_READ:
558 warned = warning_at (rich_loc, get_controlling_option (),
559 "%qE on read-only file descriptor %qE",
560 m_callee_fndecl, m_arg);
561 break;
562 case DIRS_WRITE:
563 warned = warning_at (rich_loc, get_controlling_option (),
564 "%qE on write-only file descriptor %qE",
565 m_callee_fndecl, m_arg);
566 break;
567 default:
568 gcc_unreachable ();
569 }
570 if (warned)
571 inform_filedescriptor_attribute (m_fd_dir);
572 return warned;
573 }
574
575 label_text
576 describe_final_event (const evdesc::final_event &ev) final override
577 {
578 switch (m_fd_dir)
579 {
580 case DIRS_READ:
581 return ev.formatted_print ("%qE on read-only file descriptor %qE",
582 m_callee_fndecl, m_arg);
583 case DIRS_WRITE:
584 return ev.formatted_print ("%qE on write-only file descriptor %qE",
585 m_callee_fndecl, m_arg);
586 default:
587 gcc_unreachable ();
588 }
589 }
590
591private:
592 enum access_directions m_fd_dir;
593};
594
595class fd_double_close : public fd_diagnostic
596{
597public:
598 fd_double_close (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm, arg)
599 {
600 }
601
602 const char *
603 get_kind () const final override
604 {
605 return "fd_double_close";
606 }
607
608 int
609 get_controlling_option () const final override
610 {
611 return OPT_Wanalyzer_fd_double_close;
612 }
613 bool
614 emit (rich_location *rich_loc) final override
615 {
616 diagnostic_metadata m;
617 // CWE-1341: Multiple Releases of Same Resource or Handle
618 m.add_cwe (1341);
619 return warning_meta (rich_loc, m, get_controlling_option (),
620 "double %<close%> of file descriptor %qE", m_arg);
621 }
622
623 label_text
624 describe_state_change (const evdesc::state_change &change) override
625 {
626 if (m_sm.is_unchecked_fd_p (change.m_new_state))
627 return label_text::borrow ("opened here");
628
629 if (change.m_new_state == m_sm.m_closed)
630 {
631 m_first_close_event = change.m_event_id;
632 return change.formatted_print ("first %qs here", "close");
633 }
634 return fd_diagnostic::describe_state_change (change);
635 }
636
637 label_text
638 describe_final_event (const evdesc::final_event &ev) final override
639 {
640 if (m_first_close_event.known_p ())
641 return ev.formatted_print ("second %qs here; first %qs was at %@",
642 "close", "close", &m_first_close_event);
643 return ev.formatted_print ("second %qs here", "close");
644 }
645
646private:
647 diagnostic_event_id_t m_first_close_event;
648};
649
650class fd_use_after_close : public fd_param_diagnostic
651{
652public:
653 fd_use_after_close (const fd_state_machine &sm, tree arg,
654 const tree callee_fndecl, const char *attr_name,
655 int arg_idx)
656 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx)
657 {
658 }
659
660 fd_use_after_close (const fd_state_machine &sm, tree arg,
661 const tree callee_fndecl)
662 : fd_param_diagnostic (sm, arg, callee_fndecl)
663 {
664 }
665
666 const char *
667 get_kind () const final override
668 {
669 return "fd_use_after_close";
670 }
671
672 int
673 get_controlling_option () const final override
674 {
675 return OPT_Wanalyzer_fd_use_after_close;
676 }
677
678 bool
679 emit (rich_location *rich_loc) final override
680 {
681 bool warned;
682 warned = warning_at (rich_loc, get_controlling_option (),
683 "%qE on closed file descriptor %qE", m_callee_fndecl,
684 m_arg);
685 if (warned)
686 inform_filedescriptor_attribute (DIRS_READ_WRITE);
687 return warned;
688 }
689
690 label_text
691 describe_state_change (const evdesc::state_change &change) override
692 {
693 if (m_sm.is_unchecked_fd_p (change.m_new_state))
694 return label_text::borrow ("opened here");
695
696 if (change.m_new_state == m_sm.m_closed)
697 {
698 m_first_close_event = change.m_event_id;
699 return change.formatted_print ("closed here");
700 }
701
702 return fd_diagnostic::describe_state_change (change);
703 }
704
705 label_text
706 describe_final_event (const evdesc::final_event &ev) final override
707 {
708 if (m_first_close_event.known_p ())
709 return ev.formatted_print (
710 "%qE on closed file descriptor %qE; %qs was at %@", m_callee_fndecl,
711 m_arg, "close", &m_first_close_event);
712 else
713 return ev.formatted_print ("%qE on closed file descriptor %qE",
714 m_callee_fndecl, m_arg);
715 }
716
717private:
718 diagnostic_event_id_t m_first_close_event;
719};
720
721class fd_use_without_check : public fd_param_diagnostic
722{
723public:
724 fd_use_without_check (const fd_state_machine &sm, tree arg,
725 const tree callee_fndecl, const char *attr_name,
726 int arg_idx)
727 : fd_param_diagnostic (sm, arg, callee_fndecl, attr_name, arg_idx)
728 {
729 }
730
731 fd_use_without_check (const fd_state_machine &sm, tree arg,
732 const tree callee_fndecl)
733 : fd_param_diagnostic (sm, arg, callee_fndecl)
734 {
735 }
736
737 const char *
738 get_kind () const final override
739 {
740 return "fd_use_without_check";
741 }
742
743 int
744 get_controlling_option () const final override
745 {
746 return OPT_Wanalyzer_fd_use_without_check;
747 }
748
749 bool
750 emit (rich_location *rich_loc) final override
751 {
752 bool warned;
753 warned = warning_at (rich_loc, get_controlling_option (),
754 "%qE on possibly invalid file descriptor %qE",
755 m_callee_fndecl, m_arg);
756 if (warned)
757 inform_filedescriptor_attribute (DIRS_READ_WRITE);
758 return warned;
759 }
760
761 label_text
762 describe_state_change (const evdesc::state_change &change) override
763 {
764 if (m_sm.is_unchecked_fd_p (change.m_new_state))
765 {
766 m_first_open_event = change.m_event_id;
767 return label_text::borrow ("opened here");
768 }
769
770 return fd_diagnostic::describe_state_change (change);
771 }
772
773 label_text
774 describe_final_event (const evdesc::final_event &ev) final override
775 {
776 if (m_first_open_event.known_p ())
777 return ev.formatted_print (
778 "%qE could be invalid: unchecked value from %@", m_arg,
779 &m_first_open_event);
780 else
781 return ev.formatted_print ("%qE could be invalid", m_arg);
782 }
783
784private:
785 diagnostic_event_id_t m_first_open_event;
786};
787
86a90006
DM
788/* Concrete pending_diagnostic subclass for -Wanalyzer-fd-phase-mismatch. */
789
790class fd_phase_mismatch : public fd_param_diagnostic
791{
792public:
793 fd_phase_mismatch (const fd_state_machine &sm, tree arg,
794 const tree callee_fndecl,
795 state_machine::state_t actual_state,
796 enum expected_phase expected_phase)
797 : fd_param_diagnostic (sm, arg, callee_fndecl),
798 m_actual_state (actual_state),
799 m_expected_phase (expected_phase)
800 {
801 gcc_assert (m_sm.is_socket_fd_p (actual_state));
802 switch (expected_phase)
803 {
804 case EXPECTED_PHASE_CAN_TRANSFER:
805 gcc_assert (actual_state == m_sm.m_new_stream_socket
806 || actual_state == m_sm.m_bound_stream_socket
807 || actual_state == m_sm.m_listening_stream_socket);
808 break;
809 case EXPECTED_PHASE_CAN_BIND:
810 gcc_assert (actual_state == m_sm.m_bound_datagram_socket
811 || actual_state == m_sm.m_bound_stream_socket
812 || actual_state == m_sm.m_bound_unknown_socket
813 || actual_state == m_sm.m_connected_stream_socket
814 || actual_state == m_sm.m_listening_stream_socket);
815 break;
816 case EXPECTED_PHASE_CAN_LISTEN:
817 gcc_assert (actual_state == m_sm.m_new_stream_socket
818 || actual_state == m_sm.m_new_unknown_socket
819 || actual_state == m_sm.m_connected_stream_socket);
820 break;
821 case EXPECTED_PHASE_CAN_ACCEPT:
822 gcc_assert (actual_state == m_sm.m_new_stream_socket
823 || actual_state == m_sm.m_new_unknown_socket
824 || actual_state == m_sm.m_bound_stream_socket
825 || actual_state == m_sm.m_bound_unknown_socket
826 || actual_state == m_sm.m_connected_stream_socket);
827 break;
828 case EXPECTED_PHASE_CAN_CONNECT:
829 gcc_assert (actual_state == m_sm.m_bound_datagram_socket
830 || actual_state == m_sm.m_bound_stream_socket
831 || actual_state == m_sm.m_bound_unknown_socket
832 || actual_state == m_sm.m_listening_stream_socket
833 || actual_state == m_sm.m_connected_stream_socket);
834 break;
835 }
836 }
837
838 const char *
839 get_kind () const final override
840 {
841 return "fd_phase_mismatch";
842 }
843
844 bool
845 subclass_equal_p (const pending_diagnostic &base_other) const final override
846 {
847 const fd_phase_mismatch &sub_other = (const fd_phase_mismatch &)base_other;
848 if (!fd_param_diagnostic ::subclass_equal_p (sub_other))
849 return false;
850 return (m_actual_state == sub_other.m_actual_state
851 && m_expected_phase == sub_other.m_expected_phase);
852 }
853
854 int
855 get_controlling_option () const final override
856 {
857 return OPT_Wanalyzer_fd_phase_mismatch;
858 }
859
860 bool
861 emit (rich_location *rich_loc) final override
862 {
863 /* CWE-666: Operation on Resource in Wrong Phase of Lifetime. */
864 diagnostic_metadata m;
865 m.add_cwe (666);
866 return warning_at (rich_loc, get_controlling_option (),
867 "%qE on file descriptor %qE in wrong phase",
868 m_callee_fndecl, m_arg);
869 }
870
871 label_text
872 describe_final_event (const evdesc::final_event &ev) final override
873 {
874 switch (m_expected_phase)
875 {
876 case EXPECTED_PHASE_CAN_TRANSFER:
877 {
878 if (m_actual_state == m_sm.m_new_stream_socket)
879 return ev.formatted_print
880 ("%qE expects a stream socket to be connected via %qs"
881 " but %qE has not yet been bound",
882 m_callee_fndecl, "accept", m_arg);
883 if (m_actual_state == m_sm.m_bound_stream_socket)
884 return ev.formatted_print
885 ("%qE expects a stream socket to be connected via %qs"
886 " but %qE is not yet listening",
887 m_callee_fndecl, "accept", m_arg);
888 if (m_actual_state == m_sm.m_listening_stream_socket)
889 return ev.formatted_print
890 ("%qE expects a stream socket to be connected via"
891 " the return value of %qs"
892 " but %qE is listening; wrong file descriptor?",
893 m_callee_fndecl, "accept", m_arg);
894 }
895 break;
896 case EXPECTED_PHASE_CAN_BIND:
897 {
898 if (m_actual_state == m_sm.m_bound_datagram_socket
899 || m_actual_state == m_sm.m_bound_stream_socket
900 || m_actual_state == m_sm.m_bound_unknown_socket)
901 return ev.formatted_print
902 ("%qE expects a new socket file descriptor"
903 " but %qE has already been bound",
904 m_callee_fndecl, m_arg);
905 if (m_actual_state == m_sm.m_connected_stream_socket)
906 return ev.formatted_print
907 ("%qE expects a new socket file descriptor"
908 " but %qE is already connected",
909 m_callee_fndecl, m_arg);
910 if (m_actual_state == m_sm.m_listening_stream_socket)
911 return ev.formatted_print
912 ("%qE expects a new socket file descriptor"
913 " but %qE is already listening",
914 m_callee_fndecl, m_arg);
915 }
916 break;
917 case EXPECTED_PHASE_CAN_LISTEN:
918 {
919 if (m_actual_state == m_sm.m_new_stream_socket
920 || m_actual_state == m_sm.m_new_unknown_socket)
921 return ev.formatted_print
922 ("%qE expects a bound stream socket file descriptor"
923 " but %qE has not yet been bound",
924 m_callee_fndecl, m_arg);
925 if (m_actual_state == m_sm.m_connected_stream_socket)
926 return ev.formatted_print
927 ("%qE expects a bound stream socket file descriptor"
928 " but %qE is connected",
929 m_callee_fndecl, m_arg);
930 }
931 break;
932 case EXPECTED_PHASE_CAN_ACCEPT:
933 {
934 if (m_actual_state == m_sm.m_new_stream_socket
935 || m_actual_state == m_sm.m_new_unknown_socket)
936 return ev.formatted_print
937 ("%qE expects a listening stream socket file descriptor"
938 " but %qE has not yet been bound",
939 m_callee_fndecl, m_arg);
940 if (m_actual_state == m_sm.m_bound_stream_socket
941 || m_actual_state == m_sm.m_bound_unknown_socket)
942 return ev.formatted_print
943 ("%qE expects a listening stream socket file descriptor"
944 " whereas %qE is bound but not yet listening",
945 m_callee_fndecl, m_arg);
946 if (m_actual_state == m_sm.m_connected_stream_socket)
947 return ev.formatted_print
948 ("%qE expects a listening stream socket file descriptor"
949 " but %qE is connected",
950 m_callee_fndecl, m_arg);
951 }
952 break;
953 case EXPECTED_PHASE_CAN_CONNECT:
954 {
955 if (m_actual_state == m_sm.m_bound_datagram_socket
956 || m_actual_state == m_sm.m_bound_stream_socket
957 || m_actual_state == m_sm.m_bound_unknown_socket)
958 return ev.formatted_print
959 ("%qE expects a new socket file descriptor but %qE is bound",
960 m_callee_fndecl, m_arg);
961 else
962 return ev.formatted_print
963 ("%qE expects a new socket file descriptor", m_callee_fndecl);
964 }
965 break;
966 }
967 gcc_unreachable ();
968 }
969
970private:
971 state_machine::state_t m_actual_state;
972 enum expected_phase m_expected_phase;
973};
974
975/* Enum for use by -Wanalyzer-fd-type-mismatch. */
976
977enum expected_type
978{
979 EXPECTED_TYPE_SOCKET,
980 EXPECTED_TYPE_STREAM_SOCKET
981};
982
983/* Concrete pending_diagnostic subclass for -Wanalyzer-fd-type-mismatch. */
984
985class fd_type_mismatch : public fd_param_diagnostic
986{
987public:
988 fd_type_mismatch (const fd_state_machine &sm, tree arg,
989 const tree callee_fndecl,
990 state_machine::state_t actual_state,
991 enum expected_type expected_type)
992 : fd_param_diagnostic (sm, arg, callee_fndecl),
993 m_actual_state (actual_state),
994 m_expected_type (expected_type)
995 {
996 }
997
998 const char *
999 get_kind () const final override
1000 {
1001 return "fd_type_mismatch";
1002 }
1003
1004 bool
1005 subclass_equal_p (const pending_diagnostic &base_other) const final override
1006 {
1007 const fd_type_mismatch &sub_other = (const fd_type_mismatch &)base_other;
1008 if (!fd_param_diagnostic ::subclass_equal_p (sub_other))
1009 return false;
1010 return (m_actual_state == sub_other.m_actual_state
1011 && m_expected_type == sub_other.m_expected_type);
1012 }
1013
1014 int
1015 get_controlling_option () const final override
1016 {
1017 return OPT_Wanalyzer_fd_type_mismatch;
1018 }
1019
1020 bool
1021 emit (rich_location *rich_loc) final override
1022 {
1023 switch (m_expected_type)
1024 {
1025 default:
1026 gcc_unreachable ();
1027 case EXPECTED_TYPE_SOCKET:
1028 return warning_at (rich_loc, get_controlling_option (),
1029 "%qE on non-socket file descriptor %qE",
1030 m_callee_fndecl, m_arg);
1031 case EXPECTED_TYPE_STREAM_SOCKET:
1032 if (m_sm.is_datagram_socket_fd_p (m_actual_state))
1033 return warning_at (rich_loc, get_controlling_option (),
1034 "%qE on datagram socket file descriptor %qE",
1035 m_callee_fndecl, m_arg);
1036 else
1037 return warning_at (rich_loc, get_controlling_option (),
1038 "%qE on non-stream-socket file descriptor %qE",
1039 m_callee_fndecl, m_arg);
1040 }
1041 }
1042
1043 label_text
1044 describe_final_event (const evdesc::final_event &ev) final override
1045 {
1046 switch (m_expected_type)
1047 {
1048 default:
1049 break;
1050 gcc_unreachable ();
1051 case EXPECTED_TYPE_SOCKET:
1052 case EXPECTED_TYPE_STREAM_SOCKET:
1053 if (!m_sm.is_socket_fd_p (m_actual_state))
1054 return ev.formatted_print ("%qE expects a socket file descriptor"
1055 " but %qE is not a socket",
1056 m_callee_fndecl, m_arg);
1057 }
1058 gcc_assert (m_expected_type == EXPECTED_TYPE_STREAM_SOCKET);
1059 gcc_assert (m_sm.is_datagram_socket_fd_p (m_actual_state));
1060 return ev.formatted_print
1061 ("%qE expects a stream socket file descriptor"
1062 " but %qE is a datagram socket",
1063 m_callee_fndecl, m_arg);
1064 }
1065
1066private:
1067 state_machine::state_t m_actual_state;
1068 enum expected_type m_expected_type;
1069};
1070
9365b2bf
ML
1071fd_state_machine::fd_state_machine (logger *logger)
1072 : state_machine ("file-descriptor", logger),
1073 m_constant_fd (add_state ("fd-constant")),
1074 m_unchecked_read_write (add_state ("fd-unchecked-read-write")),
1075 m_unchecked_read_only (add_state ("fd-unchecked-read-only")),
1076 m_unchecked_write_only (add_state ("fd-unchecked-write-only")),
1077 m_valid_read_write (add_state ("fd-valid-read-write")),
1078 m_valid_read_only (add_state ("fd-valid-read-only")),
1079 m_valid_write_only (add_state ("fd-valid-write-only")),
1080 m_invalid (add_state ("fd-invalid")),
1081 m_closed (add_state ("fd-closed")),
86a90006
DM
1082 m_new_datagram_socket (add_state ("fd-new-datagram-socket")),
1083 m_new_stream_socket (add_state ("fd-new-stream-socket")),
1084 m_new_unknown_socket (add_state ("fd-new-unknown-socket")),
1085 m_bound_datagram_socket (add_state ("fd-bound-datagram-socket")),
1086 m_bound_stream_socket (add_state ("fd-bound-stream-socket")),
1087 m_bound_unknown_socket (add_state ("fd-bound-unknown-socket")),
1088 m_listening_stream_socket (add_state ("fd-listening-stream-socket")),
1089 m_connected_stream_socket (add_state ("fd-connected-stream-socket")),
d8aba860
DM
1090 m_stop (add_state ("fd-stop")),
1091 m_O_ACCMODE (get_stashed_constant_by_name ("O_ACCMODE")),
1092 m_O_RDONLY (get_stashed_constant_by_name ("O_RDONLY")),
86a90006
DM
1093 m_O_WRONLY (get_stashed_constant_by_name ("O_WRONLY")),
1094 m_SOCK_STREAM (get_stashed_constant_by_name ("SOCK_STREAM")),
1095 m_SOCK_DGRAM (get_stashed_constant_by_name ("SOCK_DGRAM"))
9365b2bf
ML
1096{
1097}
1098
1099bool
1100fd_state_machine::is_unchecked_fd_p (state_t s) const
1101{
1102 return (s == m_unchecked_read_write
1103 || s == m_unchecked_read_only
1104 || s == m_unchecked_write_only);
1105}
1106
1107bool
1108fd_state_machine::is_valid_fd_p (state_t s) const
1109{
1110 return (s == m_valid_read_write
1111 || s == m_valid_read_only
1112 || s == m_valid_write_only);
1113}
1114
86a90006
DM
1115bool
1116fd_state_machine::is_socket_fd_p (state_t s) const
1117{
1118 return (s == m_new_datagram_socket
1119 || s == m_new_stream_socket
1120 || s == m_new_unknown_socket
1121 || s == m_bound_datagram_socket
1122 || s == m_bound_stream_socket
1123 || s == m_bound_unknown_socket
1124 || s == m_listening_stream_socket
1125 || s == m_connected_stream_socket);
1126}
1127
1128bool
1129fd_state_machine::is_datagram_socket_fd_p (state_t s) const
1130{
1131 return (s == m_new_datagram_socket
1132 || s == m_new_unknown_socket
1133 || s == m_bound_datagram_socket
1134 || s == m_bound_unknown_socket);
1135}
1136
1137bool
1138fd_state_machine::is_stream_socket_fd_p (state_t s) const
1139{
1140 return (s == m_new_stream_socket
1141 || s == m_new_unknown_socket
1142 || s == m_bound_stream_socket
1143 || s == m_bound_unknown_socket
1144 || s == m_listening_stream_socket
1145 || s == m_connected_stream_socket);
1146}
1147
9365b2bf
ML
1148enum access_mode
1149fd_state_machine::get_access_mode_from_flag (int flag) const
1150{
d8aba860 1151 if (m_O_ACCMODE && TREE_CODE (m_O_ACCMODE) == INTEGER_CST)
9365b2bf 1152 {
d8aba860
DM
1153 const unsigned HOST_WIDE_INT mask_val = TREE_INT_CST_LOW (m_O_ACCMODE);
1154 const unsigned HOST_WIDE_INT masked_flag = flag & mask_val;
1155
1156 if (m_O_RDONLY && TREE_CODE (m_O_RDONLY) == INTEGER_CST)
1157 if (masked_flag == TREE_INT_CST_LOW (m_O_RDONLY))
1158 return READ_ONLY;
1159
1160 if (m_O_WRONLY && TREE_CODE (m_O_WRONLY) == INTEGER_CST)
1161 if (masked_flag == TREE_INT_CST_LOW (m_O_WRONLY))
1162 return WRITE_ONLY;
9365b2bf
ML
1163 }
1164 return READ_WRITE;
1165}
1166
1167bool
1168fd_state_machine::is_readonly_fd_p (state_t state) const
1169{
1170 return (state == m_unchecked_read_only || state == m_valid_read_only);
1171}
1172
1173bool
1174fd_state_machine::is_writeonly_fd_p (state_t state) const
1175{
1176 return (state == m_unchecked_write_only || state == m_valid_write_only);
1177}
1178
1179bool
1180fd_state_machine::is_closed_fd_p (state_t state) const
1181{
1182 return (state == m_closed);
1183}
1184
1185bool
1186fd_state_machine::is_constant_fd_p (state_t state) const
1187{
1188 return (state == m_constant_fd);
1189}
1190
6a11f2d9
IM
1191fd_state_machine::state_t
1192fd_state_machine::valid_to_unchecked_state (state_t state) const
1193{
1194 if (state == m_valid_read_write)
1195 return m_unchecked_read_write;
1196 else if (state == m_valid_write_only)
1197 return m_unchecked_write_only;
1198 else if (state == m_valid_read_only)
1199 return m_unchecked_read_only;
1200 else
1201 gcc_unreachable ();
1202 return NULL;
1203}
1204
792f039f
DM
1205void
1206fd_state_machine::mark_as_valid_fd (region_model *model,
1207 sm_state_map *smap,
1208 const svalue *fd_sval,
1209 const extrinsic_state &ext_state) const
1210{
1211 smap->set_state (model, fd_sval, m_valid_read_write, NULL, ext_state);
1212}
1213
9365b2bf
ML
1214bool
1215fd_state_machine::on_stmt (sm_context *sm_ctxt, const supernode *node,
1216 const gimple *stmt) const
1217{
1218 if (const gcall *call = dyn_cast<const gcall *> (stmt))
1219 if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call))
1220 {
1221 if (is_named_call_p (callee_fndecl, "open", call, 2))
1222 {
1223 on_open (sm_ctxt, node, stmt, call);
1224 return true;
1225 } // "open"
1226
6a11f2d9
IM
1227 if (is_named_call_p (callee_fndecl, "creat", call, 2))
1228 {
1229 on_creat (sm_ctxt, node, stmt, call);
792f039f 1230 return true;
6a11f2d9
IM
1231 } // "creat"
1232
9365b2bf
ML
1233 if (is_named_call_p (callee_fndecl, "close", call, 1))
1234 {
1235 on_close (sm_ctxt, node, stmt, call);
1236 return true;
1237 } // "close"
1238
1239 if (is_named_call_p (callee_fndecl, "write", call, 3))
1240 {
1241 on_write (sm_ctxt, node, stmt, call, callee_fndecl);
1242 return true;
1243 } // "write"
1244
1245 if (is_named_call_p (callee_fndecl, "read", call, 3))
1246 {
1247 on_read (sm_ctxt, node, stmt, call, callee_fndecl);
1248 return true;
1249 } // "read"
1250
6a11f2d9
IM
1251 if (is_named_call_p (callee_fndecl, "dup", call, 1))
1252 {
1253 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_1);
1254 return true;
1255 }
1256
1257 if (is_named_call_p (callee_fndecl, "dup2", call, 2))
1258 {
1259 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_2);
1260 return true;
1261 }
1262
1263 if (is_named_call_p (callee_fndecl, "dup3", call, 3))
1264 {
1265 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_3);
1266 return true;
1267 }
9365b2bf
ML
1268
1269 {
1270 // Handle __attribute__((fd_arg))
1271
1272 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1273 "fd_arg", DIRS_READ_WRITE);
1274
1275 // Handle __attribute__((fd_arg_read))
1276
1277 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1278 "fd_arg_read", DIRS_READ);
1279
1280 // Handle __attribute__((fd_arg_write))
1281
1282 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1283 "fd_arg_write", DIRS_WRITE);
1284 }
1285 }
1286
1287 return false;
1288}
1289
1290void
1291fd_state_machine::check_for_fd_attrs (
1292 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
1293 const gcall *call, const tree callee_fndecl, const char *attr_name,
1294 access_directions fd_attr_access_dir) const
1295{
1296
1297 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (callee_fndecl));
1298 attrs = lookup_attribute (attr_name, attrs);
1299 if (!attrs)
1300 return;
1301
1302 if (!TREE_VALUE (attrs))
1303 return;
1304
1305 auto_bitmap argmap;
1306
1307 for (tree idx = TREE_VALUE (attrs); idx; idx = TREE_CHAIN (idx))
1308 {
1309 unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (idx)) - 1;
1310 bitmap_set_bit (argmap, val);
1311 }
1312 if (bitmap_empty_p (argmap))
1313 return;
1314
1315 for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
1316 {
1317 tree arg = gimple_call_arg (call, arg_idx);
1318 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1319 state_t state = sm_ctxt->get_state (stmt, arg);
1320 bool bit_set = bitmap_bit_p (argmap, arg_idx);
1321 if (TREE_CODE (TREE_TYPE (arg)) != INTEGER_TYPE)
1322 continue;
1323 if (bit_set) // Check if arg_idx is marked by any of the file descriptor
1324 // attributes
1325 {
1326
1327 if (is_closed_fd_p (state))
1328 {
1329
1330 sm_ctxt->warn (node, stmt, arg,
6341f14e
DM
1331 make_unique<fd_use_after_close>
1332 (*this, diag_arg,
1333 callee_fndecl, attr_name,
1334 arg_idx));
9365b2bf
ML
1335 continue;
1336 }
1337
1338 if (!(is_valid_fd_p (state) || (state == m_stop)))
1339 {
1340 if (!is_constant_fd_p (state))
1341 sm_ctxt->warn (node, stmt, arg,
6341f14e
DM
1342 make_unique<fd_use_without_check>
1343 (*this, diag_arg,
1344 callee_fndecl, attr_name,
1345 arg_idx));
9365b2bf
ML
1346 }
1347
1348 switch (fd_attr_access_dir)
1349 {
1350 case DIRS_READ_WRITE:
1351 break;
1352 case DIRS_READ:
1353
1354 if (is_writeonly_fd_p (state))
1355 {
1356 sm_ctxt->warn (
1357 node, stmt, arg,
6341f14e
DM
1358 make_unique<fd_access_mode_mismatch> (*this, diag_arg,
1359 DIRS_WRITE,
1360 callee_fndecl,
1361 attr_name,
1362 arg_idx));
9365b2bf
ML
1363 }
1364
1365 break;
1366 case DIRS_WRITE:
1367
1368 if (is_readonly_fd_p (state))
1369 {
1370 sm_ctxt->warn (
1371 node, stmt, arg,
6341f14e
DM
1372 make_unique<fd_access_mode_mismatch> (*this, diag_arg,
1373 DIRS_READ,
1374 callee_fndecl,
1375 attr_name,
1376 arg_idx));
9365b2bf
ML
1377 }
1378
1379 break;
1380 }
1381 }
1382 }
1383}
1384
1385
1386void
1387fd_state_machine::on_open (sm_context *sm_ctxt, const supernode *node,
1388 const gimple *stmt, const gcall *call) const
1389{
1390 tree lhs = gimple_call_lhs (call);
1391 if (lhs)
1392 {
1393 tree arg = gimple_call_arg (call, 1);
57bbf3a4 1394 enum access_mode mode = READ_WRITE;
9365b2bf
ML
1395 if (TREE_CODE (arg) == INTEGER_CST)
1396 {
1397 int flag = TREE_INT_CST_LOW (arg);
57bbf3a4
DM
1398 mode = get_access_mode_from_flag (flag);
1399 }
1400 switch (mode)
1401 {
1402 case READ_ONLY:
1403 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1404 m_unchecked_read_only);
1405 break;
1406 case WRITE_ONLY:
1407 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1408 m_unchecked_write_only);
1409 break;
1410 default:
1411 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1412 m_unchecked_read_write);
9365b2bf
ML
1413 }
1414 }
1415 else
1416 {
6341f14e
DM
1417 sm_ctxt->warn (node, stmt, NULL_TREE,
1418 make_unique<fd_leak> (*this, NULL_TREE));
9365b2bf
ML
1419 }
1420}
1421
6a11f2d9
IM
1422void
1423fd_state_machine::on_creat (sm_context *sm_ctxt, const supernode *node,
1424 const gimple *stmt, const gcall *call) const
1425{
1426 tree lhs = gimple_call_lhs (call);
1427 if (lhs)
1428 sm_ctxt->on_transition (node, stmt, lhs, m_start, m_unchecked_write_only);
1429 else
6341f14e
DM
1430 sm_ctxt->warn (node, stmt, NULL_TREE,
1431 make_unique<fd_leak> (*this, NULL_TREE));
6a11f2d9
IM
1432}
1433
1434void
1435fd_state_machine::check_for_dup (sm_context *sm_ctxt, const supernode *node,
1436 const gimple *stmt, const gcall *call,
1437 const tree callee_fndecl, enum dup kind) const
1438{
1439 tree lhs = gimple_call_lhs (call);
1440 tree arg_1 = gimple_call_arg (call, 0);
1441 state_t state_arg_1 = sm_ctxt->get_state (stmt, arg_1);
1442 if (state_arg_1 == m_stop)
1443 return;
83714225
IM
1444 if (!(is_constant_fd_p (state_arg_1) || is_valid_fd_p (state_arg_1)
1445 || state_arg_1 == m_start))
6a11f2d9
IM
1446 {
1447 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl,
1448 DIRS_READ_WRITE);
ed7e7620 1449 return;
6a11f2d9
IM
1450 }
1451 switch (kind)
1452 {
1453 case DUP_1:
1454 if (lhs)
1455 {
83714225 1456 if (is_constant_fd_p (state_arg_1) || state_arg_1 == m_start)
6a11f2d9
IM
1457 sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write);
1458 else
1459 sm_ctxt->set_next_state (stmt, lhs,
1460 valid_to_unchecked_state (state_arg_1));
1461 }
1462 break;
1463
1464 case DUP_2:
1465 case DUP_3:
1466 tree arg_2 = gimple_call_arg (call, 1);
1467 state_t state_arg_2 = sm_ctxt->get_state (stmt, arg_2);
1468 tree diag_arg_2 = sm_ctxt->get_diagnostic_tree (arg_2);
1469 if (state_arg_2 == m_stop)
1470 return;
1471 /* Check if -1 was passed as second argument to dup2. */
83714225
IM
1472 if (!(is_constant_fd_p (state_arg_2) || is_valid_fd_p (state_arg_2)
1473 || state_arg_2 == m_start))
6a11f2d9
IM
1474 {
1475 sm_ctxt->warn (
1476 node, stmt, arg_2,
6341f14e
DM
1477 make_unique<fd_use_without_check> (*this, diag_arg_2,
1478 callee_fndecl));
6a11f2d9
IM
1479 return;
1480 }
1481 /* dup2 returns value of its second argument on success.But, the
1482 access mode of the returned file descriptor depends on the duplicated
1483 file descriptor i.e the first argument. */
1484 if (lhs)
1485 {
83714225 1486 if (is_constant_fd_p (state_arg_1) || state_arg_1 == m_start)
6a11f2d9
IM
1487 sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write);
1488 else
1489 sm_ctxt->set_next_state (stmt, lhs,
1490 valid_to_unchecked_state (state_arg_1));
1491 }
1492
1493 break;
1494 }
1495}
1496
9365b2bf
ML
1497void
1498fd_state_machine::on_close (sm_context *sm_ctxt, const supernode *node,
1499 const gimple *stmt, const gcall *call) const
1500{
1501 tree arg = gimple_call_arg (call, 0);
1502 state_t state = sm_ctxt->get_state (stmt, arg);
1503 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1504
1505 sm_ctxt->on_transition (node, stmt, arg, m_start, m_closed);
1506 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_read_write, m_closed);
1507 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_read_only, m_closed);
1508 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_write_only, m_closed);
1509 sm_ctxt->on_transition (node, stmt, arg, m_valid_read_write, m_closed);
1510 sm_ctxt->on_transition (node, stmt, arg, m_valid_read_only, m_closed);
1511 sm_ctxt->on_transition (node, stmt, arg, m_valid_write_only, m_closed);
1512 sm_ctxt->on_transition (node, stmt, arg, m_constant_fd, m_closed);
86a90006
DM
1513 sm_ctxt->on_transition (node, stmt, arg, m_new_datagram_socket, m_closed);
1514 sm_ctxt->on_transition (node, stmt, arg, m_new_stream_socket, m_closed);
1515 sm_ctxt->on_transition (node, stmt, arg, m_new_unknown_socket, m_closed);
1516 sm_ctxt->on_transition (node, stmt, arg, m_bound_datagram_socket, m_closed);
1517 sm_ctxt->on_transition (node, stmt, arg, m_bound_stream_socket, m_closed);
1518 sm_ctxt->on_transition (node, stmt, arg, m_bound_unknown_socket, m_closed);
1519 sm_ctxt->on_transition (node, stmt, arg, m_listening_stream_socket, m_closed);
1520 sm_ctxt->on_transition (node, stmt, arg, m_connected_stream_socket, m_closed);
9365b2bf
ML
1521
1522 if (is_closed_fd_p (state))
1523 {
6341f14e
DM
1524 sm_ctxt->warn (node, stmt, arg,
1525 make_unique<fd_double_close> (*this, diag_arg));
9365b2bf
ML
1526 sm_ctxt->set_next_state (stmt, arg, m_stop);
1527 }
1528}
1529void
1530fd_state_machine::on_read (sm_context *sm_ctxt, const supernode *node,
1531 const gimple *stmt, const gcall *call,
1532 const tree callee_fndecl) const
1533{
1534 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_READ);
1535}
1536void
1537fd_state_machine::on_write (sm_context *sm_ctxt, const supernode *node,
1538 const gimple *stmt, const gcall *call,
1539 const tree callee_fndecl) const
1540{
1541 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_WRITE);
1542}
1543
1544void
1545fd_state_machine::check_for_open_fd (
1546 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
1547 const gcall *call, const tree callee_fndecl,
1548 enum access_directions callee_fndecl_dir) const
1549{
1550 tree arg = gimple_call_arg (call, 0);
1551 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1552 state_t state = sm_ctxt->get_state (stmt, arg);
1553
1554 if (is_closed_fd_p (state))
1555 {
1556 sm_ctxt->warn (node, stmt, arg,
6341f14e
DM
1557 make_unique<fd_use_after_close> (*this, diag_arg,
1558 callee_fndecl));
9365b2bf
ML
1559 }
1560
1561 else
1562 {
86a90006
DM
1563 if (state == m_new_stream_socket
1564 || state == m_bound_stream_socket
1565 || state == m_listening_stream_socket)
1566 /* Complain about fncall on socket in wrong phase. */
1567 sm_ctxt->warn
1568 (node, stmt, arg,
1569 make_unique<fd_phase_mismatch> (*this, diag_arg,
1570 callee_fndecl,
1571 state,
1572 EXPECTED_PHASE_CAN_TRANSFER));
1573 else if (!(is_valid_fd_p (state)
1574 || state == m_new_datagram_socket
1575 || state == m_bound_unknown_socket
1576 || state == m_connected_stream_socket
1577 || state == m_start
1578 || state == m_stop))
9365b2bf
ML
1579 {
1580 if (!is_constant_fd_p (state))
1581 sm_ctxt->warn (
1582 node, stmt, arg,
6341f14e
DM
1583 make_unique<fd_use_without_check> (*this, diag_arg,
1584 callee_fndecl));
9365b2bf
ML
1585 }
1586 switch (callee_fndecl_dir)
1587 {
6a11f2d9
IM
1588 case DIRS_READ_WRITE:
1589 break;
9365b2bf
ML
1590 case DIRS_READ:
1591 if (is_writeonly_fd_p (state))
1592 {
1593 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1594 sm_ctxt->warn (node, stmt, arg,
6341f14e 1595 make_unique<fd_access_mode_mismatch> (
9365b2bf
ML
1596 *this, diag_arg, DIRS_WRITE, callee_fndecl));
1597 }
1598
1599 break;
1600 case DIRS_WRITE:
1601
1602 if (is_readonly_fd_p (state))
1603 {
1604 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1605 sm_ctxt->warn (node, stmt, arg,
6341f14e 1606 make_unique<fd_access_mode_mismatch> (
9365b2bf
ML
1607 *this, diag_arg, DIRS_READ, callee_fndecl));
1608 }
1609 break;
9365b2bf
ML
1610 }
1611 }
1612}
1613
86a90006
DM
1614static bool
1615add_constraint_ge_zero (region_model *model,
1616 const svalue *fd_sval,
1617 region_model_context *ctxt)
1618{
1619 const svalue *zero
1620 = model->get_manager ()->get_or_create_int_cst (integer_type_node, 0);
1621 return model->add_constraint (fd_sval, GE_EXPR, zero, ctxt);
1622}
1623
1624/* Get the state for a new socket type based on SOCKET_TYPE_SVAL,
1625 a SOCK_* value. */
1626
1627state_machine::state_t
1628fd_state_machine::
1629get_state_for_socket_type (const svalue *socket_type_sval) const
1630{
1631 if (tree socket_type_cst = socket_type_sval->maybe_get_constant ())
1632 {
1633 /* Attempt to use SOCK_* constants stashed from the frontend. */
1634 if (tree_int_cst_equal (socket_type_cst, m_SOCK_STREAM))
1635 return m_new_stream_socket;
1636 if (tree_int_cst_equal (socket_type_cst, m_SOCK_DGRAM))
1637 return m_new_datagram_socket;
1638 }
1639
1640 /* Unrecognized constant, or a symbolic "type" value. */
1641 return m_new_unknown_socket;
1642}
1643
1644/* Update the model and fd state for an outcome of a call to "socket",
1645 where SUCCESSFUL indicate which of the two outcomes.
1646 Return true if the outcome is feasible, or false to reject it. */
1647
1648bool
1649fd_state_machine::on_socket (const call_details &cd,
1650 bool successful,
1651 sm_context *sm_ctxt,
1652 const extrinsic_state &ext_state) const
1653{
1654 const gcall *stmt = cd.get_call_stmt ();
1655 engine *eng = ext_state.get_engine ();
1656 const supergraph *sg = eng->get_supergraph ();
1657 const supernode *node = sg->get_supernode_for_stmt (stmt);
1658 region_model *model = cd.get_model ();
1659
1660 if (successful)
1661 {
1662 if (gimple_call_lhs (stmt))
1663 {
1664 conjured_purge p (model, cd.get_ctxt ());
1665 region_model_manager *mgr = model->get_manager ();
1666 const svalue *new_fd
1667 = mgr->get_or_create_conjured_svalue (integer_type_node,
1668 stmt,
1669 cd.get_lhs_region (),
1670 p);
1671 if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
1672 return false;
1673
1674 const svalue *socket_type_sval = cd.get_arg_svalue (1);
1675 state_machine::state_t new_state
1676 = get_state_for_socket_type (socket_type_sval);
1677 sm_ctxt->on_transition (node, stmt, new_fd, m_start, new_state);
1678 model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
1679 }
1680 else
1681 sm_ctxt->warn (node, stmt, NULL_TREE,
1682 make_unique<fd_leak> (*this, NULL_TREE));
1683 }
1684 else
1685 {
1686 /* Return -1; set errno. */
1687 model->update_for_int_cst_return (cd, -1, true);
1688 model->set_errno (cd);
1689 }
1690
1691 return true;
1692}
1693
1694/* Check that FD_SVAL is usable by socket APIs.
1695 Complain if it has been closed, if it is a non-socket,
1696 or is invalid.
1697 If COMPLAINED is non-NULL and a problem is found,
1698 write *COMPLAINED = true.
1699
1700 If SUCCESSFUL is true, attempt to add the constraint that FD_SVAL >= 0.
1701 Return true if this outcome is feasible. */
1702
1703bool
1704fd_state_machine::check_for_socket_fd (const call_details &cd,
1705 bool successful,
1706 sm_context *sm_ctxt,
1707 const svalue *fd_sval,
1708 const supernode *node,
1709 state_t old_state,
1710 bool *complained) const
1711{
1712 const gcall *stmt = cd.get_call_stmt ();
1713
1714 if (is_closed_fd_p (old_state))
1715 {
1716 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1717 sm_ctxt->warn
1718 (node, stmt, fd_sval,
1719 make_unique<fd_use_after_close> (*this, diag_arg,
1720 cd.get_fndecl_for_call ()));
1721 if (complained)
1722 *complained = true;
1723 if (successful)
1724 return false;
1725 }
1726 else if (is_unchecked_fd_p (old_state) || is_valid_fd_p (old_state))
1727 {
1728 /* Complain about non-socket. */
1729 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1730 sm_ctxt->warn
1731 (node, stmt, fd_sval,
1732 make_unique<fd_type_mismatch> (*this, diag_arg,
1733 cd.get_fndecl_for_call (),
1734 old_state,
1735 EXPECTED_TYPE_SOCKET));
1736 if (complained)
1737 *complained = true;
1738 if (successful)
1739 return false;
1740 }
1741 else if (old_state == m_invalid)
1742 {
1743 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1744 sm_ctxt->warn
1745 (node, stmt, fd_sval,
1746 make_unique<fd_use_without_check> (*this, diag_arg,
1747 cd.get_fndecl_for_call ()));
1748 if (complained)
1749 *complained = true;
1750 if (successful)
1751 return false;
1752 }
1753
1754 if (successful)
1755 if (!add_constraint_ge_zero (cd.get_model (), fd_sval, cd.get_ctxt ()))
1756 return false;
1757
1758 return true;
1759}
1760
1761/* For use by "bind" and "connect".
1762 As per fd_state_machine::check_for_socket_fd above,
1763 but also complain if we don't have a new socket, and check that
1764 we can read up to the size bytes from the address. */
1765
1766bool
1767fd_state_machine::check_for_new_socket_fd (const call_details &cd,
1768 bool successful,
1769 sm_context *sm_ctxt,
1770 const svalue *fd_sval,
1771 const supernode *node,
1772 state_t old_state,
1773 enum expected_phase expected_phase)
1774 const
1775{
1776 bool complained = false;
1777
1778 /* Check address and len. */
1779 const svalue *address_sval = cd.get_arg_svalue (1);
1780 const svalue *len_sval = cd.get_arg_svalue (2);
1781
1782 /* Check that we can read the given number of bytes from the
1783 address. */
1784 region_model *model = cd.get_model ();
1785 const region *address_reg
1786 = model->deref_rvalue (address_sval, cd.get_arg_tree (1),
1787 cd.get_ctxt ());
1788 const region *sized_address_reg
1789 = model->get_manager ()->get_sized_region (address_reg,
1790 NULL_TREE,
1791 len_sval);
1792 model->get_store_value (sized_address_reg, cd.get_ctxt ());
1793
1794 if (!check_for_socket_fd (cd, successful, sm_ctxt,
1795 fd_sval, node, old_state, &complained))
1796 return false;
1797 else if (!complained
1798 && !(old_state == m_new_stream_socket
1799 || old_state == m_new_datagram_socket
1800 || old_state == m_new_unknown_socket
1801 || old_state == m_start
64fb291c
DM
1802 || old_state == m_stop
1803 || old_state == m_constant_fd))
86a90006
DM
1804 {
1805 /* Complain about "bind" or "connect" in wrong phase. */
1806 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1807 sm_ctxt->warn
1808 (node, cd.get_call_stmt (), fd_sval,
1809 make_unique<fd_phase_mismatch> (*this, diag_arg,
1810 cd.get_fndecl_for_call (),
1811 old_state,
1812 expected_phase));
1813 if (successful)
1814 return false;
1815 }
1816 else if (!successful)
1817 {
1818 /* If we were in the start state, assume we had a new socket. */
1819 if (old_state == m_start)
1820 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1821 m_new_unknown_socket);
1822 }
1823
1824 /* Passing NULL as the address will lead to failure. */
1825 if (successful)
1826 if (address_sval->all_zeroes_p ())
1827 return false;
1828
1829 return true;
1830}
1831
1832/* Update the model and fd state for an outcome of a call to "bind",
1833 where SUCCESSFUL indicate which of the two outcomes.
1834 Return true if the outcome is feasible, or false to reject it. */
1835
1836bool
1837fd_state_machine::on_bind (const call_details &cd,
1838 bool successful,
1839 sm_context *sm_ctxt,
1840 const extrinsic_state &ext_state) const
1841{
1842 const gcall *stmt = cd.get_call_stmt ();
1843 engine *eng = ext_state.get_engine ();
1844 const supergraph *sg = eng->get_supergraph ();
1845 const supernode *node = sg->get_supernode_for_stmt (stmt);
1846 const svalue *fd_sval = cd.get_arg_svalue (0);
1847 region_model *model = cd.get_model ();
1848 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1849
1850 if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
1851 fd_sval, node, old_state,
1852 EXPECTED_PHASE_CAN_BIND))
1853 return false;
1854
1855 if (successful)
1856 {
1857 state_t next_state = NULL;
1858 if (old_state == m_new_stream_socket)
1859 next_state = m_bound_stream_socket;
1860 else if (old_state == m_new_datagram_socket)
1861 next_state = m_bound_datagram_socket;
1862 else if (old_state == m_new_unknown_socket)
1863 next_state = m_bound_unknown_socket;
1864 else if (old_state == m_start)
1865 next_state = m_bound_unknown_socket;
1866 else if (old_state == m_stop)
1867 next_state = m_stop;
1868 else
1869 gcc_unreachable ();
1870 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval, next_state);
1871 model->update_for_zero_return (cd, true);
1872 }
1873 else
1874 {
1875 /* Return -1; set errno. */
1876 model->update_for_int_cst_return (cd, -1, true);
1877 model->set_errno (cd);
1878 }
1879
1880 return true;
1881}
1882
1883/* Update the model and fd state for an outcome of a call to "listen",
1884 where SUCCESSFUL indicate which of the two outcomes.
1885 Return true if the outcome is feasible, or false to reject it. */
1886
1887bool
1888fd_state_machine::on_listen (const call_details &cd,
1889 bool successful,
1890 sm_context *sm_ctxt,
1891 const extrinsic_state &ext_state) const
1892{
1893 const gcall *stmt = cd.get_call_stmt ();
1894 engine *eng = ext_state.get_engine ();
1895 const supergraph *sg = eng->get_supergraph ();
1896 const supernode *node = sg->get_supernode_for_stmt (cd.get_call_stmt ());
1897 const svalue *fd_sval = cd.get_arg_svalue (0);
1898 region_model *model = cd.get_model ();
1899 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1900
1901 /* We expect a stream socket that's had "bind" called on it. */
1902 if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
1903 return false;
1904 if (!(old_state == m_start
64fb291c 1905 || old_state == m_constant_fd
86a90006
DM
1906 || old_state == m_stop
1907 || old_state == m_bound_stream_socket
1908 || old_state == m_bound_unknown_socket
1909 /* Assume it's OK to call "listen" more than once. */
1910 || old_state == m_listening_stream_socket))
1911 {
1912 /* Complain about fncall on wrong type or in wrong phase. */
1913 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1914 if (is_stream_socket_fd_p (old_state))
1915 sm_ctxt->warn
1916 (node, stmt, fd_sval,
1917 make_unique<fd_phase_mismatch> (*this, diag_arg,
1918 cd.get_fndecl_for_call (),
1919 old_state,
1920 EXPECTED_PHASE_CAN_LISTEN));
1921 else
1922 sm_ctxt->warn
1923 (node, stmt, fd_sval,
1924 make_unique<fd_type_mismatch> (*this, diag_arg,
1925 cd.get_fndecl_for_call (),
1926 old_state,
1927 EXPECTED_TYPE_STREAM_SOCKET));
1928 if (successful)
1929 return false;
1930 }
1931
1932 if (successful)
1933 {
1934 model->update_for_zero_return (cd, true);
1935 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1936 m_listening_stream_socket);
1937 }
1938 else
1939 {
1940 /* Return -1; set errno. */
1941 model->update_for_int_cst_return (cd, -1, true);
1942 model->set_errno (cd);
1943 if (old_state == m_start)
1944 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1945 m_bound_stream_socket);
1946 }
1947
1948 return true;
1949}
1950
1951/* Update the model and fd state for an outcome of a call to "accept",
1952 where SUCCESSFUL indicate which of the two outcomes.
1953 Return true if the outcome is feasible, or false to reject it. */
1954
1955bool
1956fd_state_machine::on_accept (const call_details &cd,
1957 bool successful,
1958 sm_context *sm_ctxt,
1959 const extrinsic_state &ext_state) const
1960{
1961 const gcall *stmt = cd.get_call_stmt ();
1962 engine *eng = ext_state.get_engine ();
1963 const supergraph *sg = eng->get_supergraph ();
1964 const supernode *node = sg->get_supernode_for_stmt (stmt);
1965 const svalue *fd_sval = cd.get_arg_svalue (0);
1966 const svalue *address_sval = cd.get_arg_svalue (1);
1967 const svalue *len_ptr_sval = cd.get_arg_svalue (2);
1968 region_model *model = cd.get_model ();
1969 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1970
1971 if (!address_sval->all_zeroes_p ())
1972 {
1973 region_model_manager *mgr = model->get_manager ();
1974
1975 /* We might have a union of various pointer types, rather than a
1976 pointer type; cast to (void *) before dereferencing. */
1977 address_sval = mgr->get_or_create_cast (ptr_type_node, address_sval);
1978
1979 const region *address_reg
1980 = model->deref_rvalue (address_sval, cd.get_arg_tree (1),
1981 cd.get_ctxt ());
1982 const region *len_reg
1983 = model->deref_rvalue (len_ptr_sval, cd.get_arg_tree (2),
1984 cd.get_ctxt ());
1985 const svalue *old_len_sval
1986 = model->get_store_value (len_reg, cd.get_ctxt ());
1987 tree len_ptr = cd.get_arg_tree (2);
1988 tree star_len_ptr = build2 (MEM_REF, TREE_TYPE (TREE_TYPE (len_ptr)),
1989 len_ptr,
1990 build_int_cst (TREE_TYPE (len_ptr), 0));
1991 old_len_sval = model->check_for_poison (old_len_sval,
1992 star_len_ptr,
1993 cd.get_ctxt ());
1994 if (successful)
1995 {
1996 conjured_purge p (model, cd.get_ctxt ());
1997 const region *old_sized_address_reg
1998 = mgr->get_sized_region (address_reg,
1999 NULL_TREE,
2000 old_len_sval);
2001 const svalue *new_addr_sval
2002 = mgr->get_or_create_conjured_svalue (NULL_TREE,
2003 stmt,
2004 old_sized_address_reg,
2005 p);
2006 model->set_value (old_sized_address_reg, new_addr_sval,
2007 cd.get_ctxt ());
2008 const svalue *new_addr_len
2009 = mgr->get_or_create_conjured_svalue (NULL_TREE,
2010 stmt,
2011 len_reg,
2012 p);
2013 model->set_value (len_reg, new_addr_len, cd.get_ctxt ());
2014 }
2015 }
2016
2017 /* We expect a stream socket in the "listening" state. */
2018 if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
2019 return false;
2020
64fb291c
DM
2021 if (old_state == m_start || old_state == m_constant_fd)
2022 /* If we were in the start state (or a constant), assume we had the
2023 expected state. */
86a90006
DM
2024 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
2025 m_listening_stream_socket);
2026 else if (old_state == m_stop)
2027 {
2028 /* No further complaints. */
2029 }
2030 else if (old_state != m_listening_stream_socket)
2031 {
2032 /* Complain about fncall on wrong type or in wrong phase. */
2033 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
2034 if (is_stream_socket_fd_p (old_state))
2035 sm_ctxt->warn
2036 (node, stmt, fd_sval,
2037 make_unique<fd_phase_mismatch> (*this, diag_arg,
2038 cd.get_fndecl_for_call (),
2039 old_state,
2040 EXPECTED_PHASE_CAN_ACCEPT));
2041 else
2042 sm_ctxt->warn
2043 (node, stmt, fd_sval,
2044 make_unique<fd_type_mismatch> (*this, diag_arg,
2045 cd.get_fndecl_for_call (),
2046 old_state,
2047 EXPECTED_TYPE_STREAM_SOCKET));
2048 if (successful)
2049 return false;
2050 }
2051
2052 if (successful)
2053 {
2054 /* Return new conjured FD in "connected" state. */
2055 if (gimple_call_lhs (stmt))
2056 {
2057 conjured_purge p (model, cd.get_ctxt ());
2058 region_model_manager *mgr = model->get_manager ();
2059 const svalue *new_fd
2060 = mgr->get_or_create_conjured_svalue (integer_type_node,
2061 stmt,
2062 cd.get_lhs_region (),
2063 p);
2064 if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
2065 return false;
2066 sm_ctxt->on_transition (node, stmt, new_fd,
2067 m_start, m_connected_stream_socket);
2068 model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
2069 }
2070 else
2071 sm_ctxt->warn (node, stmt, NULL_TREE,
2072 make_unique<fd_leak> (*this, NULL_TREE));
2073 }
2074 else
2075 {
2076 /* Return -1; set errno. */
2077 model->update_for_int_cst_return (cd, -1, true);
2078 model->set_errno (cd);
2079 }
2080
2081 return true;
2082}
2083
2084/* Update the model and fd state for an outcome of a call to "connect",
2085 where SUCCESSFUL indicate which of the two outcomes.
2086 Return true if the outcome is feasible, or false to reject it. */
2087
2088bool
2089fd_state_machine::on_connect (const call_details &cd,
2090 bool successful,
2091 sm_context *sm_ctxt,
2092 const extrinsic_state &ext_state) const
2093{
2094 const gcall *stmt = cd.get_call_stmt ();
2095 engine *eng = ext_state.get_engine ();
2096 const supergraph *sg = eng->get_supergraph ();
2097 const supernode *node = sg->get_supernode_for_stmt (stmt);
2098 const svalue *fd_sval = cd.get_arg_svalue (0);
2099 region_model *model = cd.get_model ();
2100 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
2101
2102 if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
2103 fd_sval, node, old_state,
2104 EXPECTED_PHASE_CAN_CONNECT))
2105 return false;
2106
2107 if (successful)
2108 {
2109 model->update_for_zero_return (cd, true);
2110 state_t next_state = NULL;
2111 if (old_state == m_new_stream_socket)
2112 next_state = m_connected_stream_socket;
2113 else if (old_state == m_new_datagram_socket)
2114 /* It's legal to call connect on a datagram socket, potentially
2115 more than once. We don't transition states for this. */
2116 next_state = m_new_datagram_socket;
2117 else if (old_state == m_new_unknown_socket)
2118 next_state = m_stop;
2119 else if (old_state == m_start)
2120 next_state = m_stop;
2121 else if (old_state == m_stop)
2122 next_state = m_stop;
2123 else
2124 gcc_unreachable ();
2125 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval, next_state);
2126 }
2127 else
2128 {
2129 /* Return -1; set errno. */
2130 model->update_for_int_cst_return (cd, -1, true);
2131 model->set_errno (cd);
2132 /* TODO: perhaps transition to a failed state, since the
2133 portable way to handle a failed "connect" is to close
2134 the socket and try again with a new socket. */
2135 }
2136
2137 return true;
2138}
2139
9365b2bf
ML
2140void
2141fd_state_machine::on_condition (sm_context *sm_ctxt, const supernode *node,
2142 const gimple *stmt, const svalue *lhs,
2143 enum tree_code op, const svalue *rhs) const
2144{
2145 if (tree cst = rhs->maybe_get_constant ())
2146 {
2147 if (TREE_CODE (cst) == INTEGER_CST)
2148 {
2149 int val = TREE_INT_CST_LOW (cst);
2150 if (val == -1)
2151 {
2152 if (op == NE_EXPR)
2153 make_valid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2154
2155 else if (op == EQ_EXPR)
2156 make_invalid_transitions_on_condition (sm_ctxt, node, stmt,
2157 lhs);
2158 }
2159 }
2160 }
2161
2162 if (rhs->all_zeroes_p ())
2163 {
2164 if (op == GE_EXPR)
2165 make_valid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2166 else if (op == LT_EXPR)
2167 make_invalid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2168 }
2169}
2170
2171void
2172fd_state_machine::make_valid_transitions_on_condition (sm_context *sm_ctxt,
2173 const supernode *node,
2174 const gimple *stmt,
2175 const svalue *lhs) const
2176{
2177 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_write,
2178 m_valid_read_write);
2179 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_only,
2180 m_valid_read_only);
2181 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_write_only,
2182 m_valid_write_only);
2183}
2184
2185void
2186fd_state_machine::make_invalid_transitions_on_condition (
2187 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
2188 const svalue *lhs) const
2189{
2190 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_write, m_invalid);
2191 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_only, m_invalid);
2192 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_write_only, m_invalid);
2193}
2194
2195bool
2196fd_state_machine::can_purge_p (state_t s) const
2197{
86a90006
DM
2198 if (is_unchecked_fd_p (s)
2199 || is_valid_fd_p (s)
2200 || is_socket_fd_p (s))
9365b2bf
ML
2201 return false;
2202 else
2203 return true;
2204}
2205
6341f14e 2206std::unique_ptr<pending_diagnostic>
9365b2bf
ML
2207fd_state_machine::on_leak (tree var) const
2208{
6341f14e 2209 return make_unique<fd_leak> (*this, var);
9365b2bf
ML
2210}
2211} // namespace
2212
2213state_machine *
2214make_fd_state_machine (logger *logger)
2215{
2216 return new fd_state_machine (logger);
2217}
792f039f 2218
86a90006
DM
2219static bool
2220get_fd_state (region_model_context *ctxt,
2221 sm_state_map **out_smap,
2222 const fd_state_machine **out_sm,
2223 unsigned *out_sm_idx,
2224 std::unique_ptr<sm_context> *out_sm_context)
2225{
2226 if (!ctxt)
2227 return false;
2228
2229 const state_machine *sm;
2230 if (!ctxt->get_fd_map (out_smap, &sm, out_sm_idx, out_sm_context))
2231 return false;
2232
2233 gcc_assert (sm);
2234
2235 *out_sm = (const fd_state_machine *)sm;
2236 return true;
2237}
2238
792f039f 2239/* Specialcase hook for handling pipe, for use by
1c4a7881 2240 kf_pipe::success::update_model. */
792f039f
DM
2241
2242void
2243region_model::mark_as_valid_fd (const svalue *sval, region_model_context *ctxt)
2244{
86a90006
DM
2245 sm_state_map *smap;
2246 const fd_state_machine *fd_sm;
2247 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, NULL))
792f039f
DM
2248 return;
2249 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2250 if (!ext_state)
2251 return;
86a90006
DM
2252 fd_sm->mark_as_valid_fd (this, smap, sval, *ext_state);
2253}
792f039f 2254
50d5b240
DM
2255/* Handle calls to "socket".
2256 See e.g. https://man7.org/linux/man-pages/man3/socket.3p.html */
2257
2258class kf_socket : public known_function
2259{
2260public:
2261 class outcome_of_socket : public succeed_or_fail_call_info
2262 {
2263 public:
2264 outcome_of_socket (const call_details &cd, bool success)
2265 : succeed_or_fail_call_info (cd, success)
2266 {}
2267
2268 bool update_model (region_model *model,
2269 const exploded_edge *,
2270 region_model_context *ctxt) const final override
2271 {
2272 const call_details cd (get_call_details (model, ctxt));
2273 return cd.get_model ()->on_socket (cd, m_success);
2274 }
2275 };
2276
2277 bool matches_call_types_p (const call_details &cd) const final override
2278 {
2279 return cd.num_args () == 3;
2280 }
2281
2282 void impl_call_post (const call_details &cd) const final override
2283 {
2284 if (cd.get_ctxt ())
2285 {
2286 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, false));
2287 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, true));
2288 cd.get_ctxt ()->terminate_path ();
2289 }
2290 }
2291};
2292
86a90006 2293/* Specialcase hook for handling "socket", for use by
1c4a7881 2294 kf_socket::outcome_of_socket::update_model. */
86a90006
DM
2295
2296bool
2297region_model::on_socket (const call_details &cd, bool successful)
2298{
792f039f 2299 sm_state_map *smap;
86a90006
DM
2300 const fd_state_machine *fd_sm;
2301 std::unique_ptr<sm_context> sm_ctxt;
2302 if (!get_fd_state (cd.get_ctxt (), &smap, &fd_sm, NULL, &sm_ctxt))
2303 return true;
2304 const extrinsic_state *ext_state = cd.get_ctxt ()->get_ext_state ();
2305 if (!ext_state)
2306 return true;
792f039f 2307
86a90006
DM
2308 return fd_sm->on_socket (cd, successful, sm_ctxt.get (), *ext_state);
2309}
2310
50d5b240
DM
2311/* Handle calls to "bind".
2312 See e.g. https://man7.org/linux/man-pages/man3/bind.3p.html */
2313
2314class kf_bind : public known_function
2315{
2316public:
2317 class outcome_of_bind : public succeed_or_fail_call_info
2318 {
2319 public:
2320 outcome_of_bind (const call_details &cd, bool success)
2321 : succeed_or_fail_call_info (cd, success)
2322 {}
2323
2324 bool update_model (region_model *model,
2325 const exploded_edge *,
2326 region_model_context *ctxt) const final override
2327 {
2328 const call_details cd (get_call_details (model, ctxt));
2329 return cd.get_model ()->on_bind (cd, m_success);
2330 }
2331 };
2332
2333 bool matches_call_types_p (const call_details &cd) const final override
2334 {
2335 return (cd.num_args () == 3 && cd.arg_is_pointer_p (1));
2336 }
2337
2338 void impl_call_post (const call_details &cd) const final override
2339 {
2340 if (cd.get_ctxt ())
2341 {
2342 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, false));
2343 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, true));
2344 cd.get_ctxt ()->terminate_path ();
2345 }
2346 }
2347};
2348
86a90006 2349/* Specialcase hook for handling "bind", for use by
1c4a7881 2350 kf_bind::outcome_of_bind::update_model. */
86a90006
DM
2351
2352bool
2353region_model::on_bind (const call_details &cd, bool successful)
2354{
2355 sm_state_map *smap;
2356 const fd_state_machine *fd_sm;
2357 std::unique_ptr<sm_context> sm_ctxt;
2358 if (!get_fd_state (cd.get_ctxt (), &smap, &fd_sm, NULL, &sm_ctxt))
2359 return true;
2360 const extrinsic_state *ext_state = cd.get_ctxt ()->get_ext_state ();
2361 if (!ext_state)
2362 return true;
2363
2364 return fd_sm->on_bind (cd, successful, sm_ctxt.get (), *ext_state);
2365}
2366
50d5b240
DM
2367/* Handle calls to "listen".
2368 See e.g. https://man7.org/linux/man-pages/man3/listen.3p.html */
2369
2370class kf_listen : public known_function
2371{
2372 class outcome_of_listen : public succeed_or_fail_call_info
2373 {
2374 public:
2375 outcome_of_listen (const call_details &cd, bool success)
2376 : succeed_or_fail_call_info (cd, success)
2377 {}
2378
2379 bool update_model (region_model *model,
2380 const exploded_edge *,
2381 region_model_context *ctxt) const final override
2382 {
2383 const call_details cd (get_call_details (model, ctxt));
2384 return cd.get_model ()->on_listen (cd, m_success);
2385 }
2386 };
2387
2388 bool matches_call_types_p (const call_details &cd) const final override
2389 {
2390 return cd.num_args () == 2;
2391 }
2392
2393 void impl_call_post (const call_details &cd) const final override
2394 {
2395 if (cd.get_ctxt ())
2396 {
2397 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, false));
2398 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, true));
2399 cd.get_ctxt ()->terminate_path ();
2400 }
2401 }
2402};
2403
86a90006 2404/* Specialcase hook for handling "listen", for use by
1c4a7881 2405 kf_listen::outcome_of_listen::update_model. */
86a90006
DM
2406
2407bool
2408region_model::on_listen (const call_details &cd, bool successful)
2409{
2410 sm_state_map *smap;
2411 const fd_state_machine *fd_sm;
2412 std::unique_ptr<sm_context> sm_ctxt;
2413 if (!get_fd_state (cd.get_ctxt (), &smap, &fd_sm, NULL, &sm_ctxt))
2414 return true;
2415 const extrinsic_state *ext_state = cd.get_ctxt ()->get_ext_state ();
2416 if (!ext_state)
2417 return true;
2418
2419 return fd_sm->on_listen (cd, successful, sm_ctxt.get (), *ext_state);
2420}
2421
50d5b240
DM
2422/* Handle calls to "accept".
2423 See e.g. https://man7.org/linux/man-pages/man3/accept.3p.html */
2424
2425class kf_accept : public known_function
2426{
2427 class outcome_of_accept : public succeed_or_fail_call_info
2428 {
2429 public:
2430 outcome_of_accept (const call_details &cd, bool success)
2431 : succeed_or_fail_call_info (cd, success)
2432 {}
2433
2434 bool update_model (region_model *model,
2435 const exploded_edge *,
2436 region_model_context *ctxt) const final override
2437 {
2438 const call_details cd (get_call_details (model, ctxt));
2439 return cd.get_model ()->on_accept (cd, m_success);
2440 }
2441 };
2442
2443 bool matches_call_types_p (const call_details &cd) const final override
2444 {
2445 return (cd.num_args () == 3
2446 && cd.arg_is_pointer_p (1)
2447 && cd.arg_is_pointer_p (2));
2448 }
2449
2450 void impl_call_post (const call_details &cd) const final override
2451 {
2452 if (cd.get_ctxt ())
2453 {
2454 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, false));
2455 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, true));
2456 cd.get_ctxt ()->terminate_path ();
2457 }
2458 }
2459};
2460
86a90006 2461/* Specialcase hook for handling "accept", for use by
1c4a7881 2462 kf_accept::outcome_of_accept::update_model. */
86a90006
DM
2463
2464bool
2465region_model::on_accept (const call_details &cd, bool successful)
2466{
2467 sm_state_map *smap;
2468 const fd_state_machine *fd_sm;
2469 std::unique_ptr<sm_context> sm_ctxt;
2470 if (!get_fd_state (cd.get_ctxt (), &smap, &fd_sm, NULL, &sm_ctxt))
2471 return true;
2472 const extrinsic_state *ext_state = cd.get_ctxt ()->get_ext_state ();
2473 if (!ext_state)
2474 return true;
2475
2476 return fd_sm->on_accept (cd, successful, sm_ctxt.get (), *ext_state);
2477}
792f039f 2478
50d5b240
DM
2479/* Handle calls to "connect".
2480 See e.g. https://man7.org/linux/man-pages/man3/connect.3p.html */
2481
2482class kf_connect : public known_function
2483{
2484public:
2485 class outcome_of_connect : public succeed_or_fail_call_info
2486 {
2487 public:
2488 outcome_of_connect (const call_details &cd, bool success)
2489 : succeed_or_fail_call_info (cd, success)
2490 {}
2491
2492 bool update_model (region_model *model,
2493 const exploded_edge *,
2494 region_model_context *ctxt) const final override
2495 {
2496 const call_details cd (get_call_details (model, ctxt));
2497 return cd.get_model ()->on_connect (cd, m_success);
2498 }
2499 };
2500
2501 bool matches_call_types_p (const call_details &cd) const final override
2502 {
2503 return (cd.num_args () == 3
2504 && cd.arg_is_pointer_p (1));
2505 }
2506
2507 void impl_call_post (const call_details &cd) const final override
2508 {
2509 if (cd.get_ctxt ())
2510 {
2511 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, false));
2512 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, true));
2513 cd.get_ctxt ()->terminate_path ();
2514 }
2515 }
2516};
2517
86a90006 2518/* Specialcase hook for handling "connect", for use by
1c4a7881 2519 kf_connect::outcome_of_connect::update_model. */
86a90006
DM
2520
2521bool
2522region_model::on_connect (const call_details &cd, bool successful)
2523{
2524 sm_state_map *smap;
2525 const fd_state_machine *fd_sm;
2526 std::unique_ptr<sm_context> sm_ctxt;
2527 if (!get_fd_state (cd.get_ctxt (), &smap, &fd_sm, NULL, &sm_ctxt))
2528 return true;
2529 const extrinsic_state *ext_state = cd.get_ctxt ()->get_ext_state ();
2530 if (!ext_state)
2531 return true;
792f039f 2532
86a90006 2533 return fd_sm->on_connect (cd, successful, sm_ctxt.get (), *ext_state);
792f039f
DM
2534}
2535
50d5b240
DM
2536/* Handler for calls to "pipe" and "pipe2".
2537 See e.g. https://www.man7.org/linux/man-pages/man2/pipe.2.html */
2538
2539class kf_pipe : public known_function
2540{
2541 class failure : public failed_call_info
2542 {
2543 public:
2544 failure (const call_details &cd) : failed_call_info (cd) {}
2545
2546 bool update_model (region_model *model,
2547 const exploded_edge *,
2548 region_model_context *ctxt) const final override
2549 {
2550 /* Return -1; everything else is unchanged. */
2551 const call_details cd (get_call_details (model, ctxt));
2552 model->update_for_int_cst_return (cd, -1, true);
2553 return true;
2554 }
2555 };
2556
2557 class success : public success_call_info
2558 {
2559 public:
2560 success (const call_details &cd) : success_call_info (cd) {}
2561
2562 bool update_model (region_model *model,
2563 const exploded_edge *,
2564 region_model_context *ctxt) const final override
2565 {
2566 const call_details cd (get_call_details (model, ctxt));
2567
2568 /* Return 0. */
2569 model->update_for_zero_return (cd, true);
2570
2571 /* Update fd array. */
2572 region_model_manager *mgr = cd.get_manager ();
2573 tree arr_tree = cd.get_arg_tree (0);
2574 const svalue *arr_sval = cd.get_arg_svalue (0);
2575 for (int idx = 0; idx < 2; idx++)
2576 {
2577 const region *arr_reg
2578 = model->deref_rvalue (arr_sval, arr_tree, cd.get_ctxt ());
2579 const svalue *idx_sval
2580 = mgr->get_or_create_int_cst (integer_type_node, idx);
2581 const region *element_reg
2582 = mgr->get_element_region (arr_reg, integer_type_node, idx_sval);
2583 conjured_purge p (model, cd.get_ctxt ());
2584 const svalue *fd_sval
2585 = mgr->get_or_create_conjured_svalue (integer_type_node,
2586 cd.get_call_stmt (),
2587 element_reg,
2588 p);
2589 model->set_value (element_reg, fd_sval, cd.get_ctxt ());
2590 model->mark_as_valid_fd (fd_sval, cd.get_ctxt ());
2591 }
2592 return true;
2593 }
2594 };
2595
2596public:
2597 kf_pipe (unsigned num_args)
2598 : m_num_args (num_args)
2599 {
2600 gcc_assert (num_args > 0);
2601 }
2602
2603 bool matches_call_types_p (const call_details &cd) const final override
2604 {
2605 return (cd.num_args () == m_num_args && cd.arg_is_pointer_p (0));
2606 }
2607
2608 void impl_call_post (const call_details &cd) const final override
2609 {
2610 if (cd.get_ctxt ())
2611 {
2612 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
2613 cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
2614 cd.get_ctxt ()->terminate_path ();
2615 }
2616 }
2617
2618private:
2619 unsigned m_num_args;
2620};
2621
2622/* Populate KFM with instances of known functions relating to
2623 file descriptors. */
2624
2625void
2626register_known_fd_functions (known_function_manager &kfm)
2627{
2628 kfm.add ("accept", make_unique<kf_accept> ());
2629 kfm.add ("bind", make_unique<kf_bind> ());
2630 kfm.add ("connect", make_unique<kf_connect> ());
2631 kfm.add ("listen", make_unique<kf_listen> ());
2632 kfm.add ("pipe", make_unique<kf_pipe> (1));
2633 kfm.add ("pipe2", make_unique<kf_pipe> (2));
2634 kfm.add ("socket", make_unique<kf_socket> ());
2635}
2636
9365b2bf
ML
2637} // namespace ana
2638
2639#endif // ENABLE_ANALYZER