]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/analyzer/sm-fd.cc
Revert "IRA: Check that reg classes contain a hard reg of given mode in reg move...
[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"
861c917a 50#include "analyzer/call-details.h"
50d5b240 51#include "analyzer/call-info.h"
9365b2bf
ML
52
53#if ENABLE_ANALYZER
54
55namespace ana {
56
57namespace {
58
59/* An enum for distinguishing between three different access modes. */
60
61enum access_mode
62{
63 READ_WRITE,
64 READ_ONLY,
65 WRITE_ONLY
66};
67
68enum access_directions
69{
70 DIRS_READ_WRITE,
71 DIRS_READ,
72 DIRS_WRITE
73};
74
6a11f2d9
IM
75/* An enum for distinguishing between dup, dup2 and dup3. */
76enum dup
77{
78 DUP_1,
79 DUP_2,
80 DUP_3
81};
82
86a90006
DM
83/* Enum for use by -Wanalyzer-fd-phase-mismatch. */
84
85enum expected_phase
86{
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
92};
93
9365b2bf
ML
94class fd_state_machine : public state_machine
95{
96public:
97 fd_state_machine (logger *logger);
98
99 bool
100 inherited_state_p () const final override
101 {
102 return false;
103 }
104
105 state_machine::state_t
106 get_default_state (const svalue *sval) const final override
107 {
108 if (tree cst = sval->maybe_get_constant ())
109 {
110 if (TREE_CODE (cst) == INTEGER_CST)
111 {
112 int val = TREE_INT_CST_LOW (cst);
113 if (val >= 0)
114 return m_constant_fd;
115 else
116 return m_invalid;
117 }
118 }
119 return m_start;
120 }
121
122 bool on_stmt (sm_context *sm_ctxt, const supernode *node,
123 const gimple *stmt) const final override;
124
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;
128
129 bool can_purge_p (state_t s) const final override;
6341f14e 130 std::unique_ptr<pending_diagnostic> on_leak (tree var) const final override;
9365b2bf
ML
131
132 bool is_unchecked_fd_p (state_t s) const;
133 bool is_valid_fd_p (state_t s) const;
86a90006
DM
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;
9365b2bf
ML
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;
6a11f2d9
IM
142 /* Function for one-to-one correspondence between valid
143 and unchecked states. */
144 state_t valid_to_unchecked_state (state_t state) const;
792f039f
DM
145
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;
150
86a90006
DM
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;
171
9365b2bf
ML
172 /* State for a constant file descriptor (>= 0) */
173 state_t m_constant_fd;
174
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;
179
180 state_t m_unchecked_read_only;
181
182 state_t m_unchecked_write_only;
183
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;
187
188 state_t m_valid_read_only;
189
190 state_t m_valid_write_only;
191
192 /* State for a file descriptor that is known to be invalid (< 0). */
193 state_t m_invalid;
194
195 /* State for a file descriptor that has been closed. */
196 state_t m_closed;
197
86a90006
DM
198 /* States for FDs relating to socket APIs. */
199
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;
206
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;
211
212 /* A bound socket after a successful call to "listen" (stream or unknown). */
213 state_t m_listening_stream_socket;
214
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;
220
9365b2bf
ML
221 /* State for a file descriptor that we do not want to track anymore . */
222 state_t m_stop;
223
d8aba860
DM
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;
86a90006
DM
228 tree m_SOCK_STREAM;
229 tree m_SOCK_DGRAM;
d8aba860 230
9365b2bf
ML
231private:
232 void on_open (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
233 const gcall *call) const;
6a11f2d9
IM
234 void on_creat (sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
235 const gcall *call) const;
9365b2bf
ML
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;
246
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;
6a11f2d9
IM
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;
86a90006
DM
262
263 state_t get_state_for_socket_type (const svalue *socket_type_sval) const;
264
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;
9365b2bf
ML
279};
280
281/* Base diagnostic class relative to fd_state_machine. */
282class fd_diagnostic : public pending_diagnostic
283{
284public:
285 fd_diagnostic (const fd_state_machine &sm, tree arg) : m_sm (sm), m_arg (arg)
286 {
287 }
288
289 bool
290 subclass_equal_p (const pending_diagnostic &base_other) const override
291 {
292 return same_tree_p (m_arg, ((const fd_diagnostic &)base_other).m_arg);
293 }
294
295 label_text
296 describe_state_change (const evdesc::state_change &change) override
297 {
86a90006 298 if (change.m_old_state == m_sm.get_start_state ())
9365b2bf 299 {
792f039f
DM
300 if (change.m_new_state == m_sm.m_unchecked_read_write
301 || change.m_new_state == m_sm.m_valid_read_write)
9365b2bf
ML
302 return change.formatted_print ("opened here as read-write");
303
792f039f
DM
304 if (change.m_new_state == m_sm.m_unchecked_read_only
305 || change.m_new_state == m_sm.m_valid_read_only)
9365b2bf
ML
306 return change.formatted_print ("opened here as read-only");
307
792f039f
DM
308 if (change.m_new_state == m_sm.m_unchecked_write_only
309 || change.m_new_state == m_sm.m_valid_write_only)
9365b2bf 310 return change.formatted_print ("opened here as write-only");
86a90006
DM
311
312 if (change.m_new_state == m_sm.m_new_datagram_socket)
313 return change.formatted_print ("datagram socket created here");
314
315 if (change.m_new_state == m_sm.m_new_stream_socket)
316 return change.formatted_print ("stream socket created here");
317
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");
9365b2bf
ML
321 }
322
86a90006
DM
323 if (change.m_new_state == m_sm.m_bound_datagram_socket)
324 return change.formatted_print ("datagram socket bound here");
325
326 if (change.m_new_state == m_sm.m_bound_stream_socket)
327 return change.formatted_print ("stream socket bound here");
328
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");
332
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");
336
9365b2bf
ML
337 if (change.m_new_state == m_sm.m_closed)
338 return change.formatted_print ("closed here");
339
340 if (m_sm.is_unchecked_fd_p (change.m_old_state)
341 && m_sm.is_valid_fd_p (change.m_new_state))
342 {
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");
348 }
349
350 if (m_sm.is_unchecked_fd_p (change.m_old_state)
351 && change.m_new_state == m_sm.m_invalid)
352 {
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");
359 }
360
361 return label_text ();
362 }
363
0f82c0ea
IM
364 diagnostic_event::meaning
365 get_meaning_for_state_change (
366 const evdesc::state_change &change) const final override
367 {
368 if (change.m_old_state == m_sm.get_start_state ()
86a90006
DM
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))
0f82c0ea
IM
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 ();
379 }
380
9365b2bf
ML
381protected:
382 const fd_state_machine &m_sm;
383 tree m_arg;
384};
385
386class fd_param_diagnostic : public fd_diagnostic
387{
388public:
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)
393 {
394 }
395
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)
399 {
400 }
401
402 bool
403 subclass_equal_p (const pending_diagnostic &base_other) const override
404 {
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));
413 }
414
415 void
416 inform_filedescriptor_attribute (access_directions fd_dir)
417 {
418
419 if (m_attr_name)
420 switch (fd_dir)
421 {
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;
440 }
441 }
442
443protected:
444 tree m_callee_fndecl;
445 const char *m_attr_name;
446 /* ARG_IDX is 0-based. */
447 int m_arg_idx;
448};
449
450class fd_leak : public fd_diagnostic
451{
452public:
453 fd_leak (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm, arg) {}
454
455 const char *
456 get_kind () const final override
457 {
458 return "fd_leak";
459 }
460
461 int
462 get_controlling_option () const final override
463 {
464 return OPT_Wanalyzer_fd_leak;
465 }
466
467 bool
468 emit (rich_location *rich_loc) final override
469 {
470 /*CWE-775: Missing Release of File Descriptor or Handle after Effective
471 Lifetime
472 */
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");
481 }
482
483 label_text
484 describe_state_change (const evdesc::state_change &change) final override
485 {
486 if (m_sm.is_unchecked_fd_p (change.m_new_state))
487 {
488 m_open_event = change.m_event_id;
489 return label_text::borrow ("opened here");
490 }
491
492 return fd_diagnostic::describe_state_change (change);
493 }
494
495 label_text
496 describe_final_event (const evdesc::final_event &ev) final override
497 {
498 if (m_open_event.known_p ())
499 {
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);
506 }
507 else
508 {
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");
513 }
514 }
515
516private:
517 diagnostic_event_id_t m_open_event;
518};
519
520class fd_access_mode_mismatch : public fd_param_diagnostic
521{
522public:
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)
529
530 {
531 }
532
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)
537 {
538 }
539
540 const char *
541 get_kind () const final override
542 {
543 return "fd_access_mode_mismatch";
544 }
545
546 int
547 get_controlling_option () const final override
548 {
549 return OPT_Wanalyzer_fd_access_mode_mismatch;
550 }
551
552 bool
553 emit (rich_location *rich_loc) final override
554 {
555 bool warned;
556 switch (m_fd_dir)
557 {
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 ();
570 }
571 if (warned)
572 inform_filedescriptor_attribute (m_fd_dir);
573 return warned;
574 }
575
576 label_text
577 describe_final_event (const evdesc::final_event &ev) final override
578 {
579 switch (m_fd_dir)
580 {
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 ();
589 }
590 }
591
592private:
593 enum access_directions m_fd_dir;
594};
595
596class fd_double_close : public fd_diagnostic
597{
598public:
599 fd_double_close (const fd_state_machine &sm, tree arg) : fd_diagnostic (sm, arg)
600 {
601 }
602
603 const char *
604 get_kind () const final override
605 {
606 return "fd_double_close";
607 }
608
609 int
610 get_controlling_option () const final override
611 {
612 return OPT_Wanalyzer_fd_double_close;
613 }
614 bool
615 emit (rich_location *rich_loc) final override
616 {
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);
622 }
623
624 label_text
625 describe_state_change (const evdesc::state_change &change) override
626 {
627 if (m_sm.is_unchecked_fd_p (change.m_new_state))
628 return label_text::borrow ("opened here");
629
630 if (change.m_new_state == m_sm.m_closed)
631 {
632 m_first_close_event = change.m_event_id;
633 return change.formatted_print ("first %qs here", "close");
634 }
635 return fd_diagnostic::describe_state_change (change);
636 }
637
638 label_text
639 describe_final_event (const evdesc::final_event &ev) final override
640 {
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");
645 }
646
647private:
648 diagnostic_event_id_t m_first_close_event;
649};
650
651class fd_use_after_close : public fd_param_diagnostic
652{
653public:
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)
658 {
659 }
660
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)
664 {
665 }
666
667 const char *
668 get_kind () const final override
669 {
670 return "fd_use_after_close";
671 }
672
673 int
674 get_controlling_option () const final override
675 {
676 return OPT_Wanalyzer_fd_use_after_close;
677 }
678
679 bool
680 emit (rich_location *rich_loc) final override
681 {
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;
689 }
690
691 label_text
692 describe_state_change (const evdesc::state_change &change) override
693 {
694 if (m_sm.is_unchecked_fd_p (change.m_new_state))
695 return label_text::borrow ("opened here");
696
697 if (change.m_new_state == m_sm.m_closed)
698 {
699 m_first_close_event = change.m_event_id;
700 return change.formatted_print ("closed here");
701 }
702
703 return fd_diagnostic::describe_state_change (change);
704 }
705
706 label_text
707 describe_final_event (const evdesc::final_event &ev) final override
708 {
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);
716 }
717
718private:
719 diagnostic_event_id_t m_first_close_event;
720};
721
722class fd_use_without_check : public fd_param_diagnostic
723{
724public:
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)
729 {
730 }
731
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)
735 {
736 }
737
738 const char *
739 get_kind () const final override
740 {
741 return "fd_use_without_check";
742 }
743
744 int
745 get_controlling_option () const final override
746 {
747 return OPT_Wanalyzer_fd_use_without_check;
748 }
749
750 bool
751 emit (rich_location *rich_loc) final override
752 {
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;
760 }
761
762 label_text
763 describe_state_change (const evdesc::state_change &change) override
764 {
765 if (m_sm.is_unchecked_fd_p (change.m_new_state))
766 {
767 m_first_open_event = change.m_event_id;
768 return label_text::borrow ("opened here");
769 }
770
771 return fd_diagnostic::describe_state_change (change);
772 }
773
774 label_text
775 describe_final_event (const evdesc::final_event &ev) final override
776 {
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);
783 }
784
785private:
786 diagnostic_event_id_t m_first_open_event;
787};
788
86a90006
DM
789/* Concrete pending_diagnostic subclass for -Wanalyzer-fd-phase-mismatch. */
790
791class fd_phase_mismatch : public fd_param_diagnostic
792{
793public:
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)
801 {
802 gcc_assert (m_sm.is_socket_fd_p (actual_state));
803 switch (expected_phase)
804 {
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;
836 }
837 }
838
839 const char *
840 get_kind () const final override
841 {
842 return "fd_phase_mismatch";
843 }
844
845 bool
846 subclass_equal_p (const pending_diagnostic &base_other) const final override
847 {
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);
853 }
854
855 int
856 get_controlling_option () const final override
857 {
858 return OPT_Wanalyzer_fd_phase_mismatch;
859 }
860
861 bool
862 emit (rich_location *rich_loc) final override
863 {
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);
870 }
871
872 label_text
873 describe_final_event (const evdesc::final_event &ev) final override
874 {
875 switch (m_expected_phase)
876 {
877 case EXPECTED_PHASE_CAN_TRANSFER:
878 {
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);
895 }
896 break;
897 case EXPECTED_PHASE_CAN_BIND:
898 {
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);
916 }
917 break;
918 case EXPECTED_PHASE_CAN_LISTEN:
919 {
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);
931 }
932 break;
933 case EXPECTED_PHASE_CAN_ACCEPT:
934 {
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);
952 }
953 break;
954 case EXPECTED_PHASE_CAN_CONNECT:
955 {
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);
965 }
966 break;
967 }
968 gcc_unreachable ();
969 }
970
971private:
972 state_machine::state_t m_actual_state;
973 enum expected_phase m_expected_phase;
974};
975
976/* Enum for use by -Wanalyzer-fd-type-mismatch. */
977
978enum expected_type
979{
980 EXPECTED_TYPE_SOCKET,
981 EXPECTED_TYPE_STREAM_SOCKET
982};
983
984/* Concrete pending_diagnostic subclass for -Wanalyzer-fd-type-mismatch. */
985
986class fd_type_mismatch : public fd_param_diagnostic
987{
988public:
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)
996 {
997 }
998
999 const char *
1000 get_kind () const final override
1001 {
1002 return "fd_type_mismatch";
1003 }
1004
1005 bool
1006 subclass_equal_p (const pending_diagnostic &base_other) const final override
1007 {
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);
1013 }
1014
1015 int
1016 get_controlling_option () const final override
1017 {
1018 return OPT_Wanalyzer_fd_type_mismatch;
1019 }
1020
1021 bool
1022 emit (rich_location *rich_loc) final override
1023 {
1024 switch (m_expected_type)
1025 {
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);
1041 }
1042 }
1043
1044 label_text
1045 describe_final_event (const evdesc::final_event &ev) final override
1046 {
1047 switch (m_expected_type)
1048 {
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);
1058 }
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);
1065 }
1066
1067private:
1068 state_machine::state_t m_actual_state;
1069 enum expected_type m_expected_type;
1070};
1071
9365b2bf
ML
1072fd_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")),
86a90006
DM
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")),
d8aba860
DM
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")),
86a90006
DM
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"))
9365b2bf
ML
1097{
1098}
1099
1100bool
1101fd_state_machine::is_unchecked_fd_p (state_t s) const
1102{
1103 return (s == m_unchecked_read_write
1104 || s == m_unchecked_read_only
1105 || s == m_unchecked_write_only);
1106}
1107
1108bool
1109fd_state_machine::is_valid_fd_p (state_t s) const
1110{
1111 return (s == m_valid_read_write
1112 || s == m_valid_read_only
1113 || s == m_valid_write_only);
1114}
1115
86a90006
DM
1116bool
1117fd_state_machine::is_socket_fd_p (state_t s) const
1118{
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);
1127}
1128
1129bool
1130fd_state_machine::is_datagram_socket_fd_p (state_t s) const
1131{
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);
1136}
1137
1138bool
1139fd_state_machine::is_stream_socket_fd_p (state_t s) const
1140{
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);
1147}
1148
9365b2bf
ML
1149enum access_mode
1150fd_state_machine::get_access_mode_from_flag (int flag) const
1151{
d8aba860 1152 if (m_O_ACCMODE && TREE_CODE (m_O_ACCMODE) == INTEGER_CST)
9365b2bf 1153 {
d8aba860
DM
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;
1156
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;
1160
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;
9365b2bf
ML
1164 }
1165 return READ_WRITE;
1166}
1167
1168bool
1169fd_state_machine::is_readonly_fd_p (state_t state) const
1170{
1171 return (state == m_unchecked_read_only || state == m_valid_read_only);
1172}
1173
1174bool
1175fd_state_machine::is_writeonly_fd_p (state_t state) const
1176{
1177 return (state == m_unchecked_write_only || state == m_valid_write_only);
1178}
1179
1180bool
1181fd_state_machine::is_closed_fd_p (state_t state) const
1182{
1183 return (state == m_closed);
1184}
1185
1186bool
1187fd_state_machine::is_constant_fd_p (state_t state) const
1188{
1189 return (state == m_constant_fd);
1190}
1191
6a11f2d9
IM
1192fd_state_machine::state_t
1193fd_state_machine::valid_to_unchecked_state (state_t state) const
1194{
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;
1204}
1205
792f039f
DM
1206void
1207fd_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
1211{
1212 smap->set_state (model, fd_sval, m_valid_read_write, NULL, ext_state);
1213}
1214
9365b2bf
ML
1215bool
1216fd_state_machine::on_stmt (sm_context *sm_ctxt, const supernode *node,
1217 const gimple *stmt) const
1218{
1219 if (const gcall *call = dyn_cast<const gcall *> (stmt))
1220 if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call))
1221 {
1222 if (is_named_call_p (callee_fndecl, "open", call, 2))
1223 {
1224 on_open (sm_ctxt, node, stmt, call);
1225 return true;
1226 } // "open"
1227
6a11f2d9
IM
1228 if (is_named_call_p (callee_fndecl, "creat", call, 2))
1229 {
1230 on_creat (sm_ctxt, node, stmt, call);
792f039f 1231 return true;
6a11f2d9
IM
1232 } // "creat"
1233
9365b2bf
ML
1234 if (is_named_call_p (callee_fndecl, "close", call, 1))
1235 {
1236 on_close (sm_ctxt, node, stmt, call);
1237 return true;
1238 } // "close"
1239
1240 if (is_named_call_p (callee_fndecl, "write", call, 3))
1241 {
1242 on_write (sm_ctxt, node, stmt, call, callee_fndecl);
1243 return true;
1244 } // "write"
1245
1246 if (is_named_call_p (callee_fndecl, "read", call, 3))
1247 {
1248 on_read (sm_ctxt, node, stmt, call, callee_fndecl);
1249 return true;
1250 } // "read"
1251
6a11f2d9
IM
1252 if (is_named_call_p (callee_fndecl, "dup", call, 1))
1253 {
1254 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_1);
1255 return true;
1256 }
1257
1258 if (is_named_call_p (callee_fndecl, "dup2", call, 2))
1259 {
1260 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_2);
1261 return true;
1262 }
1263
1264 if (is_named_call_p (callee_fndecl, "dup3", call, 3))
1265 {
1266 check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_3);
1267 return true;
1268 }
9365b2bf
ML
1269
1270 {
1271 // Handle __attribute__((fd_arg))
1272
1273 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1274 "fd_arg", DIRS_READ_WRITE);
1275
1276 // Handle __attribute__((fd_arg_read))
1277
1278 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1279 "fd_arg_read", DIRS_READ);
1280
1281 // Handle __attribute__((fd_arg_write))
1282
1283 check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
1284 "fd_arg_write", DIRS_WRITE);
1285 }
1286 }
1287
1288 return false;
1289}
1290
1291void
1292fd_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
1296{
1297
1298 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (callee_fndecl));
1299 attrs = lookup_attribute (attr_name, attrs);
1300 if (!attrs)
1301 return;
1302
1303 if (!TREE_VALUE (attrs))
1304 return;
1305
1306 auto_bitmap argmap;
1307
1308 for (tree idx = TREE_VALUE (attrs); idx; idx = TREE_CHAIN (idx))
1309 {
1310 unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (idx)) - 1;
1311 bitmap_set_bit (argmap, val);
1312 }
1313 if (bitmap_empty_p (argmap))
1314 return;
1315
1316 for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
1317 {
1318 tree arg = gimple_call_arg (call, arg_idx);
1319 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1320 state_t state = sm_ctxt->get_state (stmt, arg);
1321 bool bit_set = bitmap_bit_p (argmap, arg_idx);
1322 if (TREE_CODE (TREE_TYPE (arg)) != INTEGER_TYPE)
1323 continue;
1324 if (bit_set) // Check if arg_idx is marked by any of the file descriptor
1325 // attributes
1326 {
1327
1328 if (is_closed_fd_p (state))
1329 {
1330
1331 sm_ctxt->warn (node, stmt, arg,
6341f14e
DM
1332 make_unique<fd_use_after_close>
1333 (*this, diag_arg,
1334 callee_fndecl, attr_name,
1335 arg_idx));
9365b2bf
ML
1336 continue;
1337 }
1338
1339 if (!(is_valid_fd_p (state) || (state == m_stop)))
1340 {
1341 if (!is_constant_fd_p (state))
1342 sm_ctxt->warn (node, stmt, arg,
6341f14e
DM
1343 make_unique<fd_use_without_check>
1344 (*this, diag_arg,
1345 callee_fndecl, attr_name,
1346 arg_idx));
9365b2bf
ML
1347 }
1348
1349 switch (fd_attr_access_dir)
1350 {
1351 case DIRS_READ_WRITE:
1352 break;
1353 case DIRS_READ:
1354
1355 if (is_writeonly_fd_p (state))
1356 {
1357 sm_ctxt->warn (
1358 node, stmt, arg,
6341f14e
DM
1359 make_unique<fd_access_mode_mismatch> (*this, diag_arg,
1360 DIRS_WRITE,
1361 callee_fndecl,
1362 attr_name,
1363 arg_idx));
9365b2bf
ML
1364 }
1365
1366 break;
1367 case DIRS_WRITE:
1368
1369 if (is_readonly_fd_p (state))
1370 {
1371 sm_ctxt->warn (
1372 node, stmt, arg,
6341f14e
DM
1373 make_unique<fd_access_mode_mismatch> (*this, diag_arg,
1374 DIRS_READ,
1375 callee_fndecl,
1376 attr_name,
1377 arg_idx));
9365b2bf
ML
1378 }
1379
1380 break;
1381 }
1382 }
1383 }
1384}
1385
1386
1387void
1388fd_state_machine::on_open (sm_context *sm_ctxt, const supernode *node,
1389 const gimple *stmt, const gcall *call) const
1390{
1391 tree lhs = gimple_call_lhs (call);
1392 if (lhs)
1393 {
1394 tree arg = gimple_call_arg (call, 1);
57bbf3a4 1395 enum access_mode mode = READ_WRITE;
9365b2bf
ML
1396 if (TREE_CODE (arg) == INTEGER_CST)
1397 {
1398 int flag = TREE_INT_CST_LOW (arg);
57bbf3a4
DM
1399 mode = get_access_mode_from_flag (flag);
1400 }
1401 switch (mode)
1402 {
1403 case READ_ONLY:
1404 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1405 m_unchecked_read_only);
1406 break;
1407 case WRITE_ONLY:
1408 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1409 m_unchecked_write_only);
1410 break;
1411 default:
1412 sm_ctxt->on_transition (node, stmt, lhs, m_start,
1413 m_unchecked_read_write);
9365b2bf
ML
1414 }
1415 }
1416 else
1417 {
6341f14e
DM
1418 sm_ctxt->warn (node, stmt, NULL_TREE,
1419 make_unique<fd_leak> (*this, NULL_TREE));
9365b2bf
ML
1420 }
1421}
1422
6a11f2d9
IM
1423void
1424fd_state_machine::on_creat (sm_context *sm_ctxt, const supernode *node,
1425 const gimple *stmt, const gcall *call) const
1426{
1427 tree lhs = gimple_call_lhs (call);
1428 if (lhs)
1429 sm_ctxt->on_transition (node, stmt, lhs, m_start, m_unchecked_write_only);
1430 else
6341f14e
DM
1431 sm_ctxt->warn (node, stmt, NULL_TREE,
1432 make_unique<fd_leak> (*this, NULL_TREE));
6a11f2d9
IM
1433}
1434
1435void
1436fd_state_machine::check_for_dup (sm_context *sm_ctxt, const supernode *node,
1437 const gimple *stmt, const gcall *call,
1438 const tree callee_fndecl, enum dup kind) const
1439{
1440 tree lhs = gimple_call_lhs (call);
1441 tree arg_1 = gimple_call_arg (call, 0);
1442 state_t state_arg_1 = sm_ctxt->get_state (stmt, arg_1);
1443 if (state_arg_1 == m_stop)
1444 return;
83714225
IM
1445 if (!(is_constant_fd_p (state_arg_1) || is_valid_fd_p (state_arg_1)
1446 || state_arg_1 == m_start))
6a11f2d9
IM
1447 {
1448 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl,
1449 DIRS_READ_WRITE);
ed7e7620 1450 return;
6a11f2d9
IM
1451 }
1452 switch (kind)
1453 {
1454 case DUP_1:
1455 if (lhs)
1456 {
83714225 1457 if (is_constant_fd_p (state_arg_1) || state_arg_1 == m_start)
6a11f2d9
IM
1458 sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write);
1459 else
1460 sm_ctxt->set_next_state (stmt, lhs,
1461 valid_to_unchecked_state (state_arg_1));
1462 }
1463 break;
1464
1465 case DUP_2:
1466 case DUP_3:
1467 tree arg_2 = gimple_call_arg (call, 1);
1468 state_t state_arg_2 = sm_ctxt->get_state (stmt, arg_2);
1469 tree diag_arg_2 = sm_ctxt->get_diagnostic_tree (arg_2);
1470 if (state_arg_2 == m_stop)
1471 return;
1472 /* Check if -1 was passed as second argument to dup2. */
83714225
IM
1473 if (!(is_constant_fd_p (state_arg_2) || is_valid_fd_p (state_arg_2)
1474 || state_arg_2 == m_start))
6a11f2d9
IM
1475 {
1476 sm_ctxt->warn (
1477 node, stmt, arg_2,
6341f14e
DM
1478 make_unique<fd_use_without_check> (*this, diag_arg_2,
1479 callee_fndecl));
6a11f2d9
IM
1480 return;
1481 }
1482 /* dup2 returns value of its second argument on success.But, the
1483 access mode of the returned file descriptor depends on the duplicated
1484 file descriptor i.e the first argument. */
1485 if (lhs)
1486 {
83714225 1487 if (is_constant_fd_p (state_arg_1) || state_arg_1 == m_start)
6a11f2d9
IM
1488 sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write);
1489 else
1490 sm_ctxt->set_next_state (stmt, lhs,
1491 valid_to_unchecked_state (state_arg_1));
1492 }
1493
1494 break;
1495 }
1496}
1497
9365b2bf
ML
1498void
1499fd_state_machine::on_close (sm_context *sm_ctxt, const supernode *node,
1500 const gimple *stmt, const gcall *call) const
1501{
1502 tree arg = gimple_call_arg (call, 0);
1503 state_t state = sm_ctxt->get_state (stmt, arg);
1504 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1505
1506 sm_ctxt->on_transition (node, stmt, arg, m_start, m_closed);
1507 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_read_write, m_closed);
1508 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_read_only, m_closed);
1509 sm_ctxt->on_transition (node, stmt, arg, m_unchecked_write_only, m_closed);
1510 sm_ctxt->on_transition (node, stmt, arg, m_valid_read_write, m_closed);
1511 sm_ctxt->on_transition (node, stmt, arg, m_valid_read_only, m_closed);
1512 sm_ctxt->on_transition (node, stmt, arg, m_valid_write_only, m_closed);
1513 sm_ctxt->on_transition (node, stmt, arg, m_constant_fd, m_closed);
86a90006
DM
1514 sm_ctxt->on_transition (node, stmt, arg, m_new_datagram_socket, m_closed);
1515 sm_ctxt->on_transition (node, stmt, arg, m_new_stream_socket, m_closed);
1516 sm_ctxt->on_transition (node, stmt, arg, m_new_unknown_socket, m_closed);
1517 sm_ctxt->on_transition (node, stmt, arg, m_bound_datagram_socket, m_closed);
1518 sm_ctxt->on_transition (node, stmt, arg, m_bound_stream_socket, m_closed);
1519 sm_ctxt->on_transition (node, stmt, arg, m_bound_unknown_socket, m_closed);
1520 sm_ctxt->on_transition (node, stmt, arg, m_listening_stream_socket, m_closed);
1521 sm_ctxt->on_transition (node, stmt, arg, m_connected_stream_socket, m_closed);
9365b2bf
ML
1522
1523 if (is_closed_fd_p (state))
1524 {
6341f14e
DM
1525 sm_ctxt->warn (node, stmt, arg,
1526 make_unique<fd_double_close> (*this, diag_arg));
9365b2bf
ML
1527 sm_ctxt->set_next_state (stmt, arg, m_stop);
1528 }
1529}
1530void
1531fd_state_machine::on_read (sm_context *sm_ctxt, const supernode *node,
1532 const gimple *stmt, const gcall *call,
1533 const tree callee_fndecl) const
1534{
1535 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_READ);
1536}
1537void
1538fd_state_machine::on_write (sm_context *sm_ctxt, const supernode *node,
1539 const gimple *stmt, const gcall *call,
1540 const tree callee_fndecl) const
1541{
1542 check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_WRITE);
1543}
1544
1545void
1546fd_state_machine::check_for_open_fd (
1547 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
1548 const gcall *call, const tree callee_fndecl,
1549 enum access_directions callee_fndecl_dir) const
1550{
1551 tree arg = gimple_call_arg (call, 0);
1552 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1553 state_t state = sm_ctxt->get_state (stmt, arg);
1554
1555 if (is_closed_fd_p (state))
1556 {
1557 sm_ctxt->warn (node, stmt, arg,
6341f14e
DM
1558 make_unique<fd_use_after_close> (*this, diag_arg,
1559 callee_fndecl));
9365b2bf
ML
1560 }
1561
1562 else
1563 {
86a90006
DM
1564 if (state == m_new_stream_socket
1565 || state == m_bound_stream_socket
1566 || state == m_listening_stream_socket)
1567 /* Complain about fncall on socket in wrong phase. */
1568 sm_ctxt->warn
1569 (node, stmt, arg,
1570 make_unique<fd_phase_mismatch> (*this, diag_arg,
1571 callee_fndecl,
1572 state,
1573 EXPECTED_PHASE_CAN_TRANSFER));
1574 else if (!(is_valid_fd_p (state)
1575 || state == m_new_datagram_socket
1576 || state == m_bound_unknown_socket
1577 || state == m_connected_stream_socket
1578 || state == m_start
1579 || state == m_stop))
9365b2bf
ML
1580 {
1581 if (!is_constant_fd_p (state))
1582 sm_ctxt->warn (
1583 node, stmt, arg,
6341f14e
DM
1584 make_unique<fd_use_without_check> (*this, diag_arg,
1585 callee_fndecl));
9365b2bf
ML
1586 }
1587 switch (callee_fndecl_dir)
1588 {
6a11f2d9
IM
1589 case DIRS_READ_WRITE:
1590 break;
9365b2bf
ML
1591 case DIRS_READ:
1592 if (is_writeonly_fd_p (state))
1593 {
1594 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1595 sm_ctxt->warn (node, stmt, arg,
6341f14e 1596 make_unique<fd_access_mode_mismatch> (
9365b2bf
ML
1597 *this, diag_arg, DIRS_WRITE, callee_fndecl));
1598 }
1599
1600 break;
1601 case DIRS_WRITE:
1602
1603 if (is_readonly_fd_p (state))
1604 {
1605 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1606 sm_ctxt->warn (node, stmt, arg,
6341f14e 1607 make_unique<fd_access_mode_mismatch> (
9365b2bf
ML
1608 *this, diag_arg, DIRS_READ, callee_fndecl));
1609 }
1610 break;
9365b2bf
ML
1611 }
1612 }
1613}
1614
86a90006
DM
1615static bool
1616add_constraint_ge_zero (region_model *model,
1617 const svalue *fd_sval,
1618 region_model_context *ctxt)
1619{
1620 const svalue *zero
1621 = model->get_manager ()->get_or_create_int_cst (integer_type_node, 0);
1622 return model->add_constraint (fd_sval, GE_EXPR, zero, ctxt);
1623}
1624
1625/* Get the state for a new socket type based on SOCKET_TYPE_SVAL,
1626 a SOCK_* value. */
1627
1628state_machine::state_t
1629fd_state_machine::
1630get_state_for_socket_type (const svalue *socket_type_sval) const
1631{
1632 if (tree socket_type_cst = socket_type_sval->maybe_get_constant ())
1633 {
1634 /* Attempt to use SOCK_* constants stashed from the frontend. */
1635 if (tree_int_cst_equal (socket_type_cst, m_SOCK_STREAM))
1636 return m_new_stream_socket;
1637 if (tree_int_cst_equal (socket_type_cst, m_SOCK_DGRAM))
1638 return m_new_datagram_socket;
1639 }
1640
1641 /* Unrecognized constant, or a symbolic "type" value. */
1642 return m_new_unknown_socket;
1643}
1644
1645/* Update the model and fd state for an outcome of a call to "socket",
1646 where SUCCESSFUL indicate which of the two outcomes.
1647 Return true if the outcome is feasible, or false to reject it. */
1648
1649bool
1650fd_state_machine::on_socket (const call_details &cd,
1651 bool successful,
1652 sm_context *sm_ctxt,
1653 const extrinsic_state &ext_state) const
1654{
1655 const gcall *stmt = cd.get_call_stmt ();
1656 engine *eng = ext_state.get_engine ();
1657 const supergraph *sg = eng->get_supergraph ();
1658 const supernode *node = sg->get_supernode_for_stmt (stmt);
1659 region_model *model = cd.get_model ();
1660
1661 if (successful)
1662 {
1663 if (gimple_call_lhs (stmt))
1664 {
1665 conjured_purge p (model, cd.get_ctxt ());
1666 region_model_manager *mgr = model->get_manager ();
1667 const svalue *new_fd
1668 = mgr->get_or_create_conjured_svalue (integer_type_node,
1669 stmt,
1670 cd.get_lhs_region (),
1671 p);
1672 if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
1673 return false;
1674
1675 const svalue *socket_type_sval = cd.get_arg_svalue (1);
1676 state_machine::state_t new_state
1677 = get_state_for_socket_type (socket_type_sval);
1678 sm_ctxt->on_transition (node, stmt, new_fd, m_start, new_state);
1679 model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
1680 }
1681 else
1682 sm_ctxt->warn (node, stmt, NULL_TREE,
1683 make_unique<fd_leak> (*this, NULL_TREE));
1684 }
1685 else
1686 {
1687 /* Return -1; set errno. */
1688 model->update_for_int_cst_return (cd, -1, true);
1689 model->set_errno (cd);
1690 }
1691
1692 return true;
1693}
1694
1695/* Check that FD_SVAL is usable by socket APIs.
1696 Complain if it has been closed, if it is a non-socket,
1697 or is invalid.
1698 If COMPLAINED is non-NULL and a problem is found,
1699 write *COMPLAINED = true.
1700
1701 If SUCCESSFUL is true, attempt to add the constraint that FD_SVAL >= 0.
1702 Return true if this outcome is feasible. */
1703
1704bool
1705fd_state_machine::check_for_socket_fd (const call_details &cd,
1706 bool successful,
1707 sm_context *sm_ctxt,
1708 const svalue *fd_sval,
1709 const supernode *node,
1710 state_t old_state,
1711 bool *complained) const
1712{
1713 const gcall *stmt = cd.get_call_stmt ();
1714
1715 if (is_closed_fd_p (old_state))
1716 {
1717 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1718 sm_ctxt->warn
1719 (node, stmt, fd_sval,
1720 make_unique<fd_use_after_close> (*this, diag_arg,
1721 cd.get_fndecl_for_call ()));
1722 if (complained)
1723 *complained = true;
1724 if (successful)
1725 return false;
1726 }
1727 else if (is_unchecked_fd_p (old_state) || is_valid_fd_p (old_state))
1728 {
1729 /* Complain about non-socket. */
1730 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1731 sm_ctxt->warn
1732 (node, stmt, fd_sval,
1733 make_unique<fd_type_mismatch> (*this, diag_arg,
1734 cd.get_fndecl_for_call (),
1735 old_state,
1736 EXPECTED_TYPE_SOCKET));
1737 if (complained)
1738 *complained = true;
1739 if (successful)
1740 return false;
1741 }
1742 else if (old_state == m_invalid)
1743 {
1744 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1745 sm_ctxt->warn
1746 (node, stmt, fd_sval,
1747 make_unique<fd_use_without_check> (*this, diag_arg,
1748 cd.get_fndecl_for_call ()));
1749 if (complained)
1750 *complained = true;
1751 if (successful)
1752 return false;
1753 }
1754
1755 if (successful)
1756 if (!add_constraint_ge_zero (cd.get_model (), fd_sval, cd.get_ctxt ()))
1757 return false;
1758
1759 return true;
1760}
1761
1762/* For use by "bind" and "connect".
1763 As per fd_state_machine::check_for_socket_fd above,
1764 but also complain if we don't have a new socket, and check that
1765 we can read up to the size bytes from the address. */
1766
1767bool
1768fd_state_machine::check_for_new_socket_fd (const call_details &cd,
1769 bool successful,
1770 sm_context *sm_ctxt,
1771 const svalue *fd_sval,
1772 const supernode *node,
1773 state_t old_state,
1774 enum expected_phase expected_phase)
1775 const
1776{
1777 bool complained = false;
1778
1779 /* Check address and len. */
1780 const svalue *address_sval = cd.get_arg_svalue (1);
1781 const svalue *len_sval = cd.get_arg_svalue (2);
1782
1783 /* Check that we can read the given number of bytes from the
1784 address. */
1785 region_model *model = cd.get_model ();
1786 const region *address_reg
1787 = model->deref_rvalue (address_sval, cd.get_arg_tree (1),
1788 cd.get_ctxt ());
1789 const region *sized_address_reg
1790 = model->get_manager ()->get_sized_region (address_reg,
1791 NULL_TREE,
1792 len_sval);
1793 model->get_store_value (sized_address_reg, cd.get_ctxt ());
1794
1795 if (!check_for_socket_fd (cd, successful, sm_ctxt,
1796 fd_sval, node, old_state, &complained))
1797 return false;
1798 else if (!complained
1799 && !(old_state == m_new_stream_socket
1800 || old_state == m_new_datagram_socket
1801 || old_state == m_new_unknown_socket
1802 || old_state == m_start
64fb291c
DM
1803 || old_state == m_stop
1804 || old_state == m_constant_fd))
86a90006
DM
1805 {
1806 /* Complain about "bind" or "connect" in wrong phase. */
1807 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1808 sm_ctxt->warn
1809 (node, cd.get_call_stmt (), fd_sval,
1810 make_unique<fd_phase_mismatch> (*this, diag_arg,
1811 cd.get_fndecl_for_call (),
1812 old_state,
1813 expected_phase));
1814 if (successful)
1815 return false;
1816 }
1817 else if (!successful)
1818 {
1819 /* If we were in the start state, assume we had a new socket. */
1820 if (old_state == m_start)
1821 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1822 m_new_unknown_socket);
1823 }
1824
1825 /* Passing NULL as the address will lead to failure. */
1826 if (successful)
1827 if (address_sval->all_zeroes_p ())
1828 return false;
1829
1830 return true;
1831}
1832
1833/* Update the model and fd state for an outcome of a call to "bind",
1834 where SUCCESSFUL indicate which of the two outcomes.
1835 Return true if the outcome is feasible, or false to reject it. */
1836
1837bool
1838fd_state_machine::on_bind (const call_details &cd,
1839 bool successful,
1840 sm_context *sm_ctxt,
1841 const extrinsic_state &ext_state) const
1842{
1843 const gcall *stmt = cd.get_call_stmt ();
1844 engine *eng = ext_state.get_engine ();
1845 const supergraph *sg = eng->get_supergraph ();
1846 const supernode *node = sg->get_supernode_for_stmt (stmt);
1847 const svalue *fd_sval = cd.get_arg_svalue (0);
1848 region_model *model = cd.get_model ();
1849 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1850
1851 if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
1852 fd_sval, node, old_state,
1853 EXPECTED_PHASE_CAN_BIND))
1854 return false;
1855
1856 if (successful)
1857 {
1858 state_t next_state = NULL;
1859 if (old_state == m_new_stream_socket)
1860 next_state = m_bound_stream_socket;
1861 else if (old_state == m_new_datagram_socket)
1862 next_state = m_bound_datagram_socket;
1863 else if (old_state == m_new_unknown_socket)
1864 next_state = m_bound_unknown_socket;
45a75fd3
DM
1865 else if (old_state == m_start
1866 || old_state == m_constant_fd)
86a90006
DM
1867 next_state = m_bound_unknown_socket;
1868 else if (old_state == m_stop)
1869 next_state = m_stop;
1870 else
1871 gcc_unreachable ();
1872 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval, next_state);
1873 model->update_for_zero_return (cd, true);
1874 }
1875 else
1876 {
1877 /* Return -1; set errno. */
1878 model->update_for_int_cst_return (cd, -1, true);
1879 model->set_errno (cd);
1880 }
1881
1882 return true;
1883}
1884
1885/* Update the model and fd state for an outcome of a call to "listen",
1886 where SUCCESSFUL indicate which of the two outcomes.
1887 Return true if the outcome is feasible, or false to reject it. */
1888
1889bool
1890fd_state_machine::on_listen (const call_details &cd,
1891 bool successful,
1892 sm_context *sm_ctxt,
1893 const extrinsic_state &ext_state) const
1894{
1895 const gcall *stmt = cd.get_call_stmt ();
1896 engine *eng = ext_state.get_engine ();
1897 const supergraph *sg = eng->get_supergraph ();
1898 const supernode *node = sg->get_supernode_for_stmt (cd.get_call_stmt ());
1899 const svalue *fd_sval = cd.get_arg_svalue (0);
1900 region_model *model = cd.get_model ();
1901 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1902
1903 /* We expect a stream socket that's had "bind" called on it. */
1904 if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
1905 return false;
1906 if (!(old_state == m_start
64fb291c 1907 || old_state == m_constant_fd
86a90006
DM
1908 || old_state == m_stop
1909 || old_state == m_bound_stream_socket
1910 || old_state == m_bound_unknown_socket
1911 /* Assume it's OK to call "listen" more than once. */
1912 || old_state == m_listening_stream_socket))
1913 {
1914 /* Complain about fncall on wrong type or in wrong phase. */
1915 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
1916 if (is_stream_socket_fd_p (old_state))
1917 sm_ctxt->warn
1918 (node, stmt, fd_sval,
1919 make_unique<fd_phase_mismatch> (*this, diag_arg,
1920 cd.get_fndecl_for_call (),
1921 old_state,
1922 EXPECTED_PHASE_CAN_LISTEN));
1923 else
1924 sm_ctxt->warn
1925 (node, stmt, fd_sval,
1926 make_unique<fd_type_mismatch> (*this, diag_arg,
1927 cd.get_fndecl_for_call (),
1928 old_state,
1929 EXPECTED_TYPE_STREAM_SOCKET));
1930 if (successful)
1931 return false;
1932 }
1933
1934 if (successful)
1935 {
1936 model->update_for_zero_return (cd, true);
1937 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1938 m_listening_stream_socket);
1939 }
1940 else
1941 {
1942 /* Return -1; set errno. */
1943 model->update_for_int_cst_return (cd, -1, true);
1944 model->set_errno (cd);
1945 if (old_state == m_start)
1946 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
1947 m_bound_stream_socket);
1948 }
1949
1950 return true;
1951}
1952
1953/* Update the model and fd state for an outcome of a call to "accept",
1954 where SUCCESSFUL indicate which of the two outcomes.
1955 Return true if the outcome is feasible, or false to reject it. */
1956
1957bool
1958fd_state_machine::on_accept (const call_details &cd,
1959 bool successful,
1960 sm_context *sm_ctxt,
1961 const extrinsic_state &ext_state) const
1962{
1963 const gcall *stmt = cd.get_call_stmt ();
1964 engine *eng = ext_state.get_engine ();
1965 const supergraph *sg = eng->get_supergraph ();
1966 const supernode *node = sg->get_supernode_for_stmt (stmt);
1967 const svalue *fd_sval = cd.get_arg_svalue (0);
1968 const svalue *address_sval = cd.get_arg_svalue (1);
1969 const svalue *len_ptr_sval = cd.get_arg_svalue (2);
1970 region_model *model = cd.get_model ();
1971 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
1972
1973 if (!address_sval->all_zeroes_p ())
1974 {
1975 region_model_manager *mgr = model->get_manager ();
1976
1977 /* We might have a union of various pointer types, rather than a
1978 pointer type; cast to (void *) before dereferencing. */
1979 address_sval = mgr->get_or_create_cast (ptr_type_node, address_sval);
1980
1981 const region *address_reg
1982 = model->deref_rvalue (address_sval, cd.get_arg_tree (1),
1983 cd.get_ctxt ());
1984 const region *len_reg
1985 = model->deref_rvalue (len_ptr_sval, cd.get_arg_tree (2),
1986 cd.get_ctxt ());
1987 const svalue *old_len_sval
1988 = model->get_store_value (len_reg, cd.get_ctxt ());
1989 tree len_ptr = cd.get_arg_tree (2);
1990 tree star_len_ptr = build2 (MEM_REF, TREE_TYPE (TREE_TYPE (len_ptr)),
1991 len_ptr,
1992 build_int_cst (TREE_TYPE (len_ptr), 0));
1993 old_len_sval = model->check_for_poison (old_len_sval,
1994 star_len_ptr,
1995 cd.get_ctxt ());
1996 if (successful)
1997 {
1998 conjured_purge p (model, cd.get_ctxt ());
1999 const region *old_sized_address_reg
2000 = mgr->get_sized_region (address_reg,
2001 NULL_TREE,
2002 old_len_sval);
2003 const svalue *new_addr_sval
2004 = mgr->get_or_create_conjured_svalue (NULL_TREE,
2005 stmt,
2006 old_sized_address_reg,
2007 p);
2008 model->set_value (old_sized_address_reg, new_addr_sval,
2009 cd.get_ctxt ());
2010 const svalue *new_addr_len
2011 = mgr->get_or_create_conjured_svalue (NULL_TREE,
2012 stmt,
2013 len_reg,
2014 p);
2015 model->set_value (len_reg, new_addr_len, cd.get_ctxt ());
2016 }
2017 }
2018
2019 /* We expect a stream socket in the "listening" state. */
2020 if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
2021 return false;
2022
64fb291c
DM
2023 if (old_state == m_start || old_state == m_constant_fd)
2024 /* If we were in the start state (or a constant), assume we had the
2025 expected state. */
86a90006
DM
2026 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval,
2027 m_listening_stream_socket);
2028 else if (old_state == m_stop)
2029 {
2030 /* No further complaints. */
2031 }
2032 else if (old_state != m_listening_stream_socket)
2033 {
2034 /* Complain about fncall on wrong type or in wrong phase. */
2035 tree diag_arg = sm_ctxt->get_diagnostic_tree (fd_sval);
2036 if (is_stream_socket_fd_p (old_state))
2037 sm_ctxt->warn
2038 (node, stmt, fd_sval,
2039 make_unique<fd_phase_mismatch> (*this, diag_arg,
2040 cd.get_fndecl_for_call (),
2041 old_state,
2042 EXPECTED_PHASE_CAN_ACCEPT));
2043 else
2044 sm_ctxt->warn
2045 (node, stmt, fd_sval,
2046 make_unique<fd_type_mismatch> (*this, diag_arg,
2047 cd.get_fndecl_for_call (),
2048 old_state,
2049 EXPECTED_TYPE_STREAM_SOCKET));
2050 if (successful)
2051 return false;
2052 }
2053
2054 if (successful)
2055 {
2056 /* Return new conjured FD in "connected" state. */
2057 if (gimple_call_lhs (stmt))
2058 {
2059 conjured_purge p (model, cd.get_ctxt ());
2060 region_model_manager *mgr = model->get_manager ();
2061 const svalue *new_fd
2062 = mgr->get_or_create_conjured_svalue (integer_type_node,
2063 stmt,
2064 cd.get_lhs_region (),
2065 p);
2066 if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
2067 return false;
2068 sm_ctxt->on_transition (node, stmt, new_fd,
2069 m_start, m_connected_stream_socket);
2070 model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
2071 }
2072 else
2073 sm_ctxt->warn (node, stmt, NULL_TREE,
2074 make_unique<fd_leak> (*this, NULL_TREE));
2075 }
2076 else
2077 {
2078 /* Return -1; set errno. */
2079 model->update_for_int_cst_return (cd, -1, true);
2080 model->set_errno (cd);
2081 }
2082
2083 return true;
2084}
2085
2086/* Update the model and fd state for an outcome of a call to "connect",
2087 where SUCCESSFUL indicate which of the two outcomes.
2088 Return true if the outcome is feasible, or false to reject it. */
2089
2090bool
2091fd_state_machine::on_connect (const call_details &cd,
2092 bool successful,
2093 sm_context *sm_ctxt,
2094 const extrinsic_state &ext_state) const
2095{
2096 const gcall *stmt = cd.get_call_stmt ();
2097 engine *eng = ext_state.get_engine ();
2098 const supergraph *sg = eng->get_supergraph ();
2099 const supernode *node = sg->get_supernode_for_stmt (stmt);
2100 const svalue *fd_sval = cd.get_arg_svalue (0);
2101 region_model *model = cd.get_model ();
2102 state_t old_state = sm_ctxt->get_state (stmt, fd_sval);
2103
2104 if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
2105 fd_sval, node, old_state,
2106 EXPECTED_PHASE_CAN_CONNECT))
2107 return false;
2108
2109 if (successful)
2110 {
2111 model->update_for_zero_return (cd, true);
2112 state_t next_state = NULL;
2113 if (old_state == m_new_stream_socket)
2114 next_state = m_connected_stream_socket;
2115 else if (old_state == m_new_datagram_socket)
2116 /* It's legal to call connect on a datagram socket, potentially
2117 more than once. We don't transition states for this. */
2118 next_state = m_new_datagram_socket;
2119 else if (old_state == m_new_unknown_socket)
2120 next_state = m_stop;
45a75fd3
DM
2121 else if (old_state == m_start
2122 || old_state == m_constant_fd)
86a90006
DM
2123 next_state = m_stop;
2124 else if (old_state == m_stop)
2125 next_state = m_stop;
2126 else
2127 gcc_unreachable ();
2128 sm_ctxt->set_next_state (cd.get_call_stmt (), fd_sval, next_state);
2129 }
2130 else
2131 {
2132 /* Return -1; set errno. */
2133 model->update_for_int_cst_return (cd, -1, true);
2134 model->set_errno (cd);
2135 /* TODO: perhaps transition to a failed state, since the
2136 portable way to handle a failed "connect" is to close
2137 the socket and try again with a new socket. */
2138 }
2139
2140 return true;
2141}
2142
9365b2bf
ML
2143void
2144fd_state_machine::on_condition (sm_context *sm_ctxt, const supernode *node,
2145 const gimple *stmt, const svalue *lhs,
2146 enum tree_code op, const svalue *rhs) const
2147{
2148 if (tree cst = rhs->maybe_get_constant ())
2149 {
2150 if (TREE_CODE (cst) == INTEGER_CST)
2151 {
2152 int val = TREE_INT_CST_LOW (cst);
2153 if (val == -1)
2154 {
2155 if (op == NE_EXPR)
2156 make_valid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2157
2158 else if (op == EQ_EXPR)
2159 make_invalid_transitions_on_condition (sm_ctxt, node, stmt,
2160 lhs);
2161 }
2162 }
2163 }
2164
2165 if (rhs->all_zeroes_p ())
2166 {
2167 if (op == GE_EXPR)
2168 make_valid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2169 else if (op == LT_EXPR)
2170 make_invalid_transitions_on_condition (sm_ctxt, node, stmt, lhs);
2171 }
2172}
2173
2174void
2175fd_state_machine::make_valid_transitions_on_condition (sm_context *sm_ctxt,
2176 const supernode *node,
2177 const gimple *stmt,
2178 const svalue *lhs) const
2179{
2180 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_write,
2181 m_valid_read_write);
2182 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_only,
2183 m_valid_read_only);
2184 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_write_only,
2185 m_valid_write_only);
2186}
2187
2188void
2189fd_state_machine::make_invalid_transitions_on_condition (
2190 sm_context *sm_ctxt, const supernode *node, const gimple *stmt,
2191 const svalue *lhs) const
2192{
2193 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_write, m_invalid);
2194 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_read_only, m_invalid);
2195 sm_ctxt->on_transition (node, stmt, lhs, m_unchecked_write_only, m_invalid);
2196}
2197
2198bool
2199fd_state_machine::can_purge_p (state_t s) const
2200{
86a90006
DM
2201 if (is_unchecked_fd_p (s)
2202 || is_valid_fd_p (s)
2203 || is_socket_fd_p (s))
9365b2bf
ML
2204 return false;
2205 else
2206 return true;
2207}
2208
6341f14e 2209std::unique_ptr<pending_diagnostic>
9365b2bf
ML
2210fd_state_machine::on_leak (tree var) const
2211{
6341f14e 2212 return make_unique<fd_leak> (*this, var);
9365b2bf
ML
2213}
2214} // namespace
2215
2216state_machine *
2217make_fd_state_machine (logger *logger)
2218{
2219 return new fd_state_machine (logger);
2220}
792f039f 2221
86a90006
DM
2222static bool
2223get_fd_state (region_model_context *ctxt,
2224 sm_state_map **out_smap,
2225 const fd_state_machine **out_sm,
2226 unsigned *out_sm_idx,
2227 std::unique_ptr<sm_context> *out_sm_context)
2228{
2229 if (!ctxt)
2230 return false;
2231
2232 const state_machine *sm;
2233 if (!ctxt->get_fd_map (out_smap, &sm, out_sm_idx, out_sm_context))
2234 return false;
2235
2236 gcc_assert (sm);
2237
2238 *out_sm = (const fd_state_machine *)sm;
2239 return true;
2240}
2241
792f039f 2242/* Specialcase hook for handling pipe, for use by
1c4a7881 2243 kf_pipe::success::update_model. */
792f039f
DM
2244
2245void
2246region_model::mark_as_valid_fd (const svalue *sval, region_model_context *ctxt)
2247{
86a90006
DM
2248 sm_state_map *smap;
2249 const fd_state_machine *fd_sm;
2250 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, NULL))
792f039f
DM
2251 return;
2252 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2253 if (!ext_state)
2254 return;
86a90006
DM
2255 fd_sm->mark_as_valid_fd (this, smap, sval, *ext_state);
2256}
792f039f 2257
50d5b240
DM
2258/* Handle calls to "socket".
2259 See e.g. https://man7.org/linux/man-pages/man3/socket.3p.html */
2260
2261class kf_socket : public known_function
2262{
2263public:
2264 class outcome_of_socket : public succeed_or_fail_call_info
2265 {
2266 public:
2267 outcome_of_socket (const call_details &cd, bool success)
2268 : succeed_or_fail_call_info (cd, success)
2269 {}
2270
2271 bool update_model (region_model *model,
2272 const exploded_edge *,
2273 region_model_context *ctxt) const final override
2274 {
2275 const call_details cd (get_call_details (model, ctxt));
5d2908b7
DM
2276 sm_state_map *smap;
2277 const fd_state_machine *fd_sm;
2278 std::unique_ptr<sm_context> sm_ctxt;
2279 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2280 return true;
2281 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2282 if (!ext_state)
2283 return true;
2284
2285 return fd_sm->on_socket (cd, m_success, sm_ctxt.get (), *ext_state);
50d5b240
DM
2286 }
2287 };
2288
2289 bool matches_call_types_p (const call_details &cd) const final override
2290 {
2291 return cd.num_args () == 3;
2292 }
2293
2294 void impl_call_post (const call_details &cd) const final override
2295 {
2296 if (cd.get_ctxt ())
2297 {
2298 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, false));
2299 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, true));
2300 cd.get_ctxt ()->terminate_path ();
2301 }
2302 }
2303};
2304
50d5b240
DM
2305/* Handle calls to "bind".
2306 See e.g. https://man7.org/linux/man-pages/man3/bind.3p.html */
2307
2308class kf_bind : public known_function
2309{
2310public:
2311 class outcome_of_bind : public succeed_or_fail_call_info
2312 {
2313 public:
2314 outcome_of_bind (const call_details &cd, bool success)
2315 : succeed_or_fail_call_info (cd, success)
2316 {}
2317
2318 bool update_model (region_model *model,
2319 const exploded_edge *,
2320 region_model_context *ctxt) const final override
2321 {
2322 const call_details cd (get_call_details (model, ctxt));
5d2908b7
DM
2323 sm_state_map *smap;
2324 const fd_state_machine *fd_sm;
2325 std::unique_ptr<sm_context> sm_ctxt;
2326 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2327 return true;
2328 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2329 if (!ext_state)
2330 return true;
2331 return fd_sm->on_bind (cd, m_success, sm_ctxt.get (), *ext_state);
50d5b240
DM
2332 }
2333 };
2334
2335 bool matches_call_types_p (const call_details &cd) const final override
2336 {
2337 return (cd.num_args () == 3 && cd.arg_is_pointer_p (1));
2338 }
2339
2340 void impl_call_post (const call_details &cd) const final override
2341 {
2342 if (cd.get_ctxt ())
2343 {
2344 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, false));
2345 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, true));
2346 cd.get_ctxt ()->terminate_path ();
2347 }
2348 }
2349};
2350
50d5b240
DM
2351/* Handle calls to "listen".
2352 See e.g. https://man7.org/linux/man-pages/man3/listen.3p.html */
2353
2354class kf_listen : public known_function
2355{
2356 class outcome_of_listen : public succeed_or_fail_call_info
2357 {
2358 public:
2359 outcome_of_listen (const call_details &cd, bool success)
2360 : succeed_or_fail_call_info (cd, success)
2361 {}
2362
2363 bool update_model (region_model *model,
2364 const exploded_edge *,
2365 region_model_context *ctxt) const final override
2366 {
2367 const call_details cd (get_call_details (model, ctxt));
5d2908b7
DM
2368 sm_state_map *smap;
2369 const fd_state_machine *fd_sm;
2370 std::unique_ptr<sm_context> sm_ctxt;
2371 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2372 return true;
2373 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2374 if (!ext_state)
2375 return true;
2376
2377 return fd_sm->on_listen (cd, m_success, sm_ctxt.get (), *ext_state);
50d5b240
DM
2378 }
2379 };
2380
2381 bool matches_call_types_p (const call_details &cd) const final override
2382 {
2383 return cd.num_args () == 2;
2384 }
2385
2386 void impl_call_post (const call_details &cd) const final override
2387 {
2388 if (cd.get_ctxt ())
2389 {
2390 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, false));
2391 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, true));
2392 cd.get_ctxt ()->terminate_path ();
2393 }
2394 }
2395};
2396
50d5b240
DM
2397/* Handle calls to "accept".
2398 See e.g. https://man7.org/linux/man-pages/man3/accept.3p.html */
2399
2400class kf_accept : public known_function
2401{
2402 class outcome_of_accept : public succeed_or_fail_call_info
2403 {
2404 public:
2405 outcome_of_accept (const call_details &cd, bool success)
2406 : succeed_or_fail_call_info (cd, success)
2407 {}
2408
2409 bool update_model (region_model *model,
2410 const exploded_edge *,
2411 region_model_context *ctxt) const final override
2412 {
2413 const call_details cd (get_call_details (model, ctxt));
5d2908b7
DM
2414 sm_state_map *smap;
2415 const fd_state_machine *fd_sm;
2416 std::unique_ptr<sm_context> sm_ctxt;
2417 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2418 return true;
2419 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2420 if (!ext_state)
2421 return true;
2422
2423 return fd_sm->on_accept (cd, m_success, sm_ctxt.get (), *ext_state);
50d5b240
DM
2424 }
2425 };
2426
2427 bool matches_call_types_p (const call_details &cd) const final override
2428 {
2429 return (cd.num_args () == 3
2430 && cd.arg_is_pointer_p (1)
2431 && cd.arg_is_pointer_p (2));
2432 }
2433
2434 void impl_call_post (const call_details &cd) const final override
2435 {
2436 if (cd.get_ctxt ())
2437 {
2438 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, false));
2439 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, true));
2440 cd.get_ctxt ()->terminate_path ();
2441 }
2442 }
2443};
2444
50d5b240
DM
2445/* Handle calls to "connect".
2446 See e.g. https://man7.org/linux/man-pages/man3/connect.3p.html */
2447
2448class kf_connect : public known_function
2449{
2450public:
2451 class outcome_of_connect : public succeed_or_fail_call_info
2452 {
2453 public:
2454 outcome_of_connect (const call_details &cd, bool success)
2455 : succeed_or_fail_call_info (cd, success)
2456 {}
2457
2458 bool update_model (region_model *model,
2459 const exploded_edge *,
2460 region_model_context *ctxt) const final override
2461 {
2462 const call_details cd (get_call_details (model, ctxt));
5d2908b7
DM
2463 sm_state_map *smap;
2464 const fd_state_machine *fd_sm;
2465 std::unique_ptr<sm_context> sm_ctxt;
2466 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2467 return true;
2468 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2469 if (!ext_state)
2470 return true;
2471
2472 return fd_sm->on_connect (cd, m_success, sm_ctxt.get (), *ext_state);
50d5b240
DM
2473 }
2474 };
2475
2476 bool matches_call_types_p (const call_details &cd) const final override
2477 {
2478 return (cd.num_args () == 3
2479 && cd.arg_is_pointer_p (1));
2480 }
2481
2482 void impl_call_post (const call_details &cd) const final override
2483 {
2484 if (cd.get_ctxt ())
2485 {
2486 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, false));
2487 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, true));
2488 cd.get_ctxt ()->terminate_path ();
2489 }
2490 }
2491};
2492
78a17f44
DM
2493/* Handler for "isatty"".
2494 See e.g. https://man7.org/linux/man-pages/man3/isatty.3.html */
2495
2496class kf_isatty : public known_function
2497{
2498 class outcome_of_isatty : public succeed_or_fail_call_info
2499 {
2500 public:
2501 outcome_of_isatty (const call_details &cd, bool success)
2502 : succeed_or_fail_call_info (cd, success)
2503 {}
2504
2505 bool update_model (region_model *model,
2506 const exploded_edge *,
2507 region_model_context *ctxt) const final override
2508 {
2509 const call_details cd (get_call_details (model, ctxt));
2510
2511 if (m_success)
2512 {
2513 /* Return 1. */
2514 model->update_for_int_cst_return (cd, 1, true);
2515 }
2516 else
2517 {
2518 /* Return 0; set errno. */
2519 model->update_for_int_cst_return (cd, 0, true);
2520 model->set_errno (cd);
2521 }
2522
2523 return feasible_p (cd, ctxt);
2524 }
2525
2526 private:
2527 bool feasible_p (const call_details &cd,
2528 region_model_context *ctxt) const
2529 {
2530 if (m_success)
2531 {
2532 /* Can't be "success" on a closed/invalid fd. */
2533 sm_state_map *smap;
2534 const fd_state_machine *fd_sm;
2535 std::unique_ptr<sm_context> sm_ctxt;
2536 if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
2537 return true;
2538 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2539 if (!ext_state)
2540 return true;
2541
2542 const svalue *fd_sval = cd.get_arg_svalue (0);
2543 state_machine::state_t old_state
2544 = sm_ctxt->get_state (cd.get_call_stmt (), fd_sval);
2545
2546 if (fd_sm->is_closed_fd_p (old_state)
2547 || old_state == fd_sm->m_invalid)
2548 return false;
2549 }
2550 return true;
2551 }
2552 }; // class outcome_of_isatty
2553
2554public:
2555 bool matches_call_types_p (const call_details &cd) const final override
2556 {
2557 return cd.num_args () == 1;
2558 }
2559
2560 void impl_call_post (const call_details &cd) const final override
2561 {
2562 if (cd.get_ctxt ())
2563 {
2564 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, false));
2565 cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, true));
2566 cd.get_ctxt ()->terminate_path ();
2567 }
2568 }
2569};
2570
50d5b240
DM
2571/* Handler for calls to "pipe" and "pipe2".
2572 See e.g. https://www.man7.org/linux/man-pages/man2/pipe.2.html */
2573
2574class kf_pipe : public known_function
2575{
2576 class failure : public failed_call_info
2577 {
2578 public:
2579 failure (const call_details &cd) : failed_call_info (cd) {}
2580
2581 bool update_model (region_model *model,
2582 const exploded_edge *,
2583 region_model_context *ctxt) const final override
2584 {
2585 /* Return -1; everything else is unchanged. */
2586 const call_details cd (get_call_details (model, ctxt));
2587 model->update_for_int_cst_return (cd, -1, true);
2588 return true;
2589 }
2590 };
2591
2592 class success : public success_call_info
2593 {
2594 public:
2595 success (const call_details &cd) : success_call_info (cd) {}
2596
2597 bool update_model (region_model *model,
2598 const exploded_edge *,
2599 region_model_context *ctxt) const final override
2600 {
2601 const call_details cd (get_call_details (model, ctxt));
2602
2603 /* Return 0. */
2604 model->update_for_zero_return (cd, true);
2605
2606 /* Update fd array. */
2607 region_model_manager *mgr = cd.get_manager ();
2608 tree arr_tree = cd.get_arg_tree (0);
2609 const svalue *arr_sval = cd.get_arg_svalue (0);
2610 for (int idx = 0; idx < 2; idx++)
2611 {
2612 const region *arr_reg
2613 = model->deref_rvalue (arr_sval, arr_tree, cd.get_ctxt ());
2614 const svalue *idx_sval
2615 = mgr->get_or_create_int_cst (integer_type_node, idx);
2616 const region *element_reg
2617 = mgr->get_element_region (arr_reg, integer_type_node, idx_sval);
2618 conjured_purge p (model, cd.get_ctxt ());
2619 const svalue *fd_sval
2620 = mgr->get_or_create_conjured_svalue (integer_type_node,
2621 cd.get_call_stmt (),
2622 element_reg,
2623 p);
2624 model->set_value (element_reg, fd_sval, cd.get_ctxt ());
2625 model->mark_as_valid_fd (fd_sval, cd.get_ctxt ());
2626 }
2627 return true;
2628 }
2629 };
2630
2631public:
2632 kf_pipe (unsigned num_args)
2633 : m_num_args (num_args)
2634 {
2635 gcc_assert (num_args > 0);
2636 }
2637
2638 bool matches_call_types_p (const call_details &cd) const final override
2639 {
2640 return (cd.num_args () == m_num_args && cd.arg_is_pointer_p (0));
2641 }
2642
2643 void impl_call_post (const call_details &cd) const final override
2644 {
2645 if (cd.get_ctxt ())
2646 {
2647 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
2648 cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
2649 cd.get_ctxt ()->terminate_path ();
2650 }
2651 }
2652
2653private:
2654 unsigned m_num_args;
2655};
2656
2657/* Populate KFM with instances of known functions relating to
2658 file descriptors. */
2659
2660void
2661register_known_fd_functions (known_function_manager &kfm)
2662{
2663 kfm.add ("accept", make_unique<kf_accept> ());
2664 kfm.add ("bind", make_unique<kf_bind> ());
2665 kfm.add ("connect", make_unique<kf_connect> ());
78a17f44 2666 kfm.add ("isatty", make_unique<kf_isatty> ());
50d5b240
DM
2667 kfm.add ("listen", make_unique<kf_listen> ());
2668 kfm.add ("pipe", make_unique<kf_pipe> (1));
2669 kfm.add ("pipe2", make_unique<kf_pipe> (2));
2670 kfm.add ("socket", make_unique<kf_socket> ());
2671}
2672
9365b2bf
ML
2673} // namespace ana
2674
2675#endif // ENABLE_ANALYZER