1 /* Pointer Bounds Checker insrumentation pass.
2 Copyright (C) 2014-2015 Free Software Foundation, Inc.
3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
28 #include "fold-const.h"
29 #include "stor-layout.h"
32 #include "tree-iterator.h"
34 #include "langhooks.h"
35 #include "tree-pass.h"
36 #include "diagnostic.h"
38 #include "stringpool.h"
39 #include "tree-ssa-alias.h"
40 #include "tree-ssanames.h"
41 #include "tree-ssa-operands.h"
42 #include "tree-ssa-address.h"
45 #include "dominance.h"
47 #include "basic-block.h"
48 #include "tree-ssa-loop-niter.h"
49 #include "gimple-expr.h"
51 #include "tree-phinodes.h"
52 #include "gimple-ssa.h"
53 #include "ssa-iterators.h"
54 #include "gimple-pretty-print.h"
55 #include "gimple-iterator.h"
57 #include "gimplify-me.h"
58 #include "print-tree.h"
60 #include "hard-reg-set.h"
64 #include "insn-config.h"
72 #include "tree-ssa-propagate.h"
73 #include "gimple-fold.h"
74 #include "tree-chkp.h"
75 #include "gimple-walk.h"
76 #include "rtl.h" /* For MEM_P, assign_temp. */
79 #include "lto-streamer.h"
84 /* Pointer Bounds Checker instruments code with memory checks to find
85 out-of-bounds memory accesses. Checks are performed by computing
86 bounds for each pointer and then comparing address of accessed
87 memory before pointer dereferencing.
95 There are few things to instrument:
97 a) Memory accesses - add checker calls to check address of accessed memory
98 against bounds of dereferenced pointer. Obviously safe memory
99 accesses like static variable access does not have to be instrumented
106 with 4 bytes access is transformed into:
108 __builtin___chkp_bndcl (__bound_tmp.1_3, p_1);
110 __builtin___chkp_bndcu (__bound_tmp.1_3, D.1_4);
113 where __bound_tmp.1_3 are bounds computed for pointer p_1,
114 __builtin___chkp_bndcl is a lower bound check and
115 __builtin___chkp_bndcu is an upper bound check.
119 When pointer is stored in memory we need to store its bounds. To
120 achieve compatibility of instrumented code with regular codes
121 we have to keep data layout and store bounds in special bound tables
122 via special checker call. Implementation of bounds table may vary for
123 different platforms. It has to associate pointer value and its
124 location (it is required because we may have two equal pointers
125 with different bounds stored in different places) with bounds.
126 Another checker builtin allows to get bounds for specified pointer
127 loaded from specified location.
137 __builtin___chkp_bndstx (D.1_2, &buf2, __bound_tmp.1_2);
139 where __bound_tmp.1_2 are bounds of &buf2.
141 c) Static initialization.
143 The special case of pointer store is static pointer initialization.
144 Bounds initialization is performed in a few steps:
145 - register all static initializations in front-end using
146 chkp_register_var_initializer
147 - when file compilation finishes we create functions with special
148 attribute 'chkp ctor' and put explicit initialization code
149 (assignments) for all statically initialized pointers.
150 - when checker constructor is compiled checker pass adds required
151 bounds initialization for all statically initialized pointers
152 - since we do not actually need excess pointers initialization
153 in checker constructor we remove such assignments from them
157 For each call in the code we add additional arguments to pass
158 bounds for pointer arguments. We determine type of call arguments
159 using arguments list from function declaration; if function
160 declaration is not available we use function type; otherwise
161 (e.g. for unnamed arguments) we use type of passed value. Function
162 declaration/type is replaced with the instrumented one.
166 val_1 = foo (&buf1, &buf2, &buf1, 0);
170 val_1 = foo.chkp (&buf1, __bound_tmp.1_2, &buf2, __bound_tmp.1_3,
171 &buf1, __bound_tmp.1_2, 0);
175 If function returns a pointer value we have to return bounds also.
176 A new operand was added for return statement to hold returned bounds.
184 return &_buf1, __bound_tmp.1_1;
186 3. Bounds computation.
188 Compiler is fully responsible for computing bounds to be used for each
189 memory access. The first step for bounds computation is to find the
190 origin of pointer dereferenced for memory access. Basing on pointer
191 origin we define a way to compute its bounds. There are just few
194 a) Pointer is returned by call.
196 In this case we use corresponding checker builtin method to obtain returned
201 buf_1 = malloc (size_2);
206 buf_1 = malloc (size_2);
207 __bound_tmp.1_3 = __builtin___chkp_bndret (buf_1);
208 foo (buf_1, __bound_tmp.1_3);
210 b) Pointer is an address of an object.
212 In this case compiler tries to compute objects size and create corresponding
213 bounds. If object has incomplete type then special checker builtin is used to
214 obtain its size at runtime.
220 <unnamed type> __bound_tmp.3;
224 __bound_tmp.3_2 = __builtin___chkp_bndmk (&buf, 400);
227 return &buf, __bound_tmp.3_2;
232 Address of an object 'extern int buf[]' with incomplete type is
237 <unnamed type> __bound_tmp.4;
238 long unsigned int __size_tmp.3;
241 __size_tmp.3_4 = __builtin_ia32_sizeof (buf);
242 __bound_tmp.4_3 = __builtin_ia32_bndmk (&buf, __size_tmp.3_4);
245 return &buf, __bound_tmp.4_3;
248 c) Pointer is the result of object narrowing.
250 It happens when we use pointer to an object to compute pointer to a part
251 of an object. E.g. we take pointer to a field of a structure. In this
252 case we perform bounds intersection using bounds of original object and
253 bounds of object's part (which are computed basing on its type).
255 There may be some debatable questions about when narrowing should occur
256 and when it should not. To avoid false bound violations in correct
257 programs we do not perform narrowing when address of an array element is
258 obtained (it has address of the whole array) and when address of the first
259 structure field is obtained (because it is guaranteed to be equal to
260 address of the whole structure and it is legal to cast it back to structure).
262 Default narrowing behavior may be changed using compiler flags.
266 In this example address of the second structure field is returned.
268 foo (struct A * p, __bounds_type __bounds_of_p)
270 <unnamed type> __bound_tmp.3;
275 _5 = &p_1(D)->second_field;
276 __bound_tmp.3_6 = __builtin___chkp_bndmk (_5, 4);
277 __bound_tmp.3_8 = __builtin___chkp_intersect (__bound_tmp.3_6,
279 _2 = &p_1(D)->second_field;
280 return _2, __bound_tmp.3_8;
285 In this example address of the first field of array element is returned.
287 foo (struct A * p, __bounds_type __bounds_of_p, int i)
289 long unsigned int _3;
290 long unsigned int _4;
295 _3 = (long unsigned int) i_1(D);
298 _7 = &_6->first_field;
299 return _7, __bounds_of_p_2(D);
303 d) Pointer is the result of pointer arithmetic or type cast.
305 In this case bounds of the base pointer are used. In case of binary
306 operation producing a pointer we are analyzing data flow further
307 looking for operand's bounds. One operand is considered as a base
308 if it has some valid bounds. If we fall into a case when none of
309 operands (or both of them) has valid bounds, a default bounds value
312 Trying to find out bounds for binary operations we may fall into
313 cyclic dependencies for pointers. To avoid infinite recursion all
314 walked phi nodes instantly obtain corresponding bounds but created
315 bounds are marked as incomplete. It helps us to stop DF walk during
318 When we reach pointer source, some args of incomplete bounds phi obtain
319 valid bounds and those values are propagated further through phi nodes.
320 If no valid bounds were found for phi node then we mark its result as
321 invalid bounds. Process stops when all incomplete bounds become either
322 valid or invalid and we are able to choose a pointer base.
324 e) Pointer is loaded from the memory.
326 In this case we just need to load bounds from the bounds table.
332 <unnamed type> __bound_tmp.3;
338 __bound_tmp.3_4 = __builtin___chkp_bndldx (&buf, _2);
339 return _2, __bound_tmp.3_4;
344 typedef void (*assign_handler
)(tree
, tree
, void *);
346 static tree
chkp_get_zero_bounds ();
347 static tree
chkp_find_bounds (tree ptr
, gimple_stmt_iterator
*iter
);
348 static tree
chkp_find_bounds_loaded (tree ptr
, tree ptr_src
,
349 gimple_stmt_iterator
*iter
);
350 static void chkp_parse_array_and_component_ref (tree node
, tree
*ptr
,
351 tree
*elt
, bool *safe
,
354 gimple_stmt_iterator
*iter
,
355 bool innermost_bounds
);
357 #define chkp_bndldx_fndecl \
358 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDLDX))
359 #define chkp_bndstx_fndecl \
360 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDSTX))
361 #define chkp_checkl_fndecl \
362 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL))
363 #define chkp_checku_fndecl \
364 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU))
365 #define chkp_bndmk_fndecl \
366 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK))
367 #define chkp_ret_bnd_fndecl \
368 (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDRET))
369 #define chkp_intersect_fndecl \
370 (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT))
371 #define chkp_narrow_bounds_fndecl \
372 (targetm.builtin_chkp_function (BUILT_IN_CHKP_NARROW))
373 #define chkp_sizeof_fndecl \
374 (targetm.builtin_chkp_function (BUILT_IN_CHKP_SIZEOF))
375 #define chkp_extract_lower_fndecl \
376 (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_LOWER))
377 #define chkp_extract_upper_fndecl \
378 (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_UPPER))
380 static GTY (()) tree chkp_uintptr_type
;
382 static GTY (()) tree chkp_zero_bounds_var
;
383 static GTY (()) tree chkp_none_bounds_var
;
385 static GTY (()) basic_block entry_block
;
386 static GTY (()) tree zero_bounds
;
387 static GTY (()) tree none_bounds
;
388 static GTY (()) tree incomplete_bounds
;
389 static GTY (()) tree tmp_var
;
390 static GTY (()) tree size_tmp_var
;
391 static GTY (()) bitmap chkp_abnormal_copies
;
393 struct hash_set
<tree
> *chkp_invalid_bounds
;
394 struct hash_set
<tree
> *chkp_completed_bounds_set
;
395 struct hash_map
<tree
, tree
> *chkp_reg_bounds
;
396 struct hash_map
<tree
, tree
> *chkp_bound_vars
;
397 struct hash_map
<tree
, tree
> *chkp_reg_addr_bounds
;
398 struct hash_map
<tree
, tree
> *chkp_incomplete_bounds_map
;
399 struct hash_map
<tree
, tree
> *chkp_bounds_map
;
400 struct hash_map
<tree
, tree
> *chkp_static_var_bounds
;
402 static bool in_chkp_pass
;
404 #define CHKP_BOUND_TMP_NAME "__bound_tmp"
405 #define CHKP_SIZE_TMP_NAME "__size_tmp"
406 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
407 #define CHKP_STRING_BOUNDS_PREFIX "__chkp_string_bounds_"
408 #define CHKP_VAR_BOUNDS_PREFIX "__chkp_var_bounds_"
409 #define CHKP_ZERO_BOUNDS_VAR_NAME "__chkp_zero_bounds"
410 #define CHKP_NONE_BOUNDS_VAR_NAME "__chkp_none_bounds"
412 /* Static checker constructors may become very large and their
413 compilation with optimization may take too much time.
414 Therefore we put a limit to number of statements in one
415 constructor. Tests with 100 000 statically initialized
416 pointers showed following compilation times on Sandy Bridge
418 limit 100 => ~18 sec.
419 limit 300 => ~22 sec.
420 limit 1000 => ~30 sec.
421 limit 3000 => ~49 sec.
422 limit 5000 => ~55 sec.
423 limit 10000 => ~76 sec.
424 limit 100000 => ~532 sec. */
425 #define MAX_STMTS_IN_STATIC_CHKP_CTOR (PARAM_VALUE (PARAM_CHKP_MAX_CTOR_SIZE))
427 struct chkp_ctor_stmt_list
433 /* Return 1 if function FNDECL is instrumented by Pointer
436 chkp_function_instrumented_p (tree fndecl
)
439 && lookup_attribute ("chkp instrumented", DECL_ATTRIBUTES (fndecl
));
442 /* Mark function FNDECL as instrumented. */
444 chkp_function_mark_instrumented (tree fndecl
)
446 if (chkp_function_instrumented_p (fndecl
))
449 DECL_ATTRIBUTES (fndecl
)
450 = tree_cons (get_identifier ("chkp instrumented"), NULL
,
451 DECL_ATTRIBUTES (fndecl
));
454 /* Return true when STMT is builtin call to instrumentation function
455 corresponding to CODE. */
458 chkp_gimple_call_builtin_p (gimple call
,
459 enum built_in_function code
)
462 if (is_gimple_call (call
)
463 && (fndecl
= targetm
.builtin_chkp_function (code
))
464 && gimple_call_fndecl (call
) == fndecl
)
469 /* Emit code to build zero bounds and return RTL holding
472 chkp_expand_zero_bounds ()
476 if (flag_chkp_use_static_const_bounds
)
477 zero_bnd
= chkp_get_zero_bounds_var ();
479 zero_bnd
= chkp_build_make_bounds_call (integer_zero_node
,
481 return expand_normal (zero_bnd
);
484 /* Emit code to store zero bounds for PTR located at MEM. */
486 chkp_expand_bounds_reset_for_mem (tree mem
, tree ptr
)
488 tree zero_bnd
, bnd
, addr
, bndstx
;
490 if (flag_chkp_use_static_const_bounds
)
491 zero_bnd
= chkp_get_zero_bounds_var ();
493 zero_bnd
= chkp_build_make_bounds_call (integer_zero_node
,
495 bnd
= make_tree (pointer_bounds_type_node
,
496 assign_temp (pointer_bounds_type_node
, 0, 1));
497 addr
= build1 (ADDR_EXPR
,
498 build_pointer_type (TREE_TYPE (mem
)), mem
);
499 bndstx
= chkp_build_bndstx_call (addr
, ptr
, bnd
);
501 expand_assignment (bnd
, zero_bnd
, false);
502 expand_normal (bndstx
);
505 /* Build retbnd call for returned value RETVAL.
507 If BNDVAL is not NULL then result is stored
508 in it. Otherwise a temporary is created to
511 GSI points to a position for a retbnd call
512 and is set to created stmt.
514 Cgraph edge is created for a new call if
517 Obtained bounds are returned. */
519 chkp_insert_retbnd_call (tree bndval
, tree retval
,
520 gimple_stmt_iterator
*gsi
)
525 bndval
= create_tmp_reg (pointer_bounds_type_node
, "retbnd");
527 call
= gimple_build_call (chkp_ret_bnd_fndecl
, 1, retval
);
528 gimple_call_set_lhs (call
, bndval
);
529 gsi_insert_after (gsi
, call
, GSI_CONTINUE_LINKING
);
534 /* Build a GIMPLE_CALL identical to CALL but skipping bounds
538 chkp_copy_call_skip_bounds (gcall
*call
)
543 bitmap_obstack_initialize (NULL
);
544 bounds
= BITMAP_ALLOC (NULL
);
546 for (i
= 0; i
< gimple_call_num_args (call
); i
++)
547 if (POINTER_BOUNDS_P (gimple_call_arg (call
, i
)))
548 bitmap_set_bit (bounds
, i
);
550 if (!bitmap_empty_p (bounds
))
551 call
= gimple_call_copy_skip_args (call
, bounds
);
552 gimple_call_set_with_bounds (call
, false);
554 BITMAP_FREE (bounds
);
555 bitmap_obstack_release (NULL
);
560 /* Redirect edge E to the correct node according to call_stmt.
561 Return 1 if bounds removal from call_stmt should be done
562 instead of redirection. */
565 chkp_redirect_edge (cgraph_edge
*e
)
567 bool instrumented
= false;
568 tree decl
= e
->callee
->decl
;
570 if (e
->callee
->instrumentation_clone
571 || chkp_function_instrumented_p (decl
))
575 && !gimple_call_with_bounds_p (e
->call_stmt
))
576 e
->redirect_callee (cgraph_node::get_create (e
->callee
->orig_decl
));
577 else if (!instrumented
578 && gimple_call_with_bounds_p (e
->call_stmt
)
579 && !chkp_gimple_call_builtin_p (e
->call_stmt
, BUILT_IN_CHKP_BNDCL
)
580 && !chkp_gimple_call_builtin_p (e
->call_stmt
, BUILT_IN_CHKP_BNDCU
)
581 && !chkp_gimple_call_builtin_p (e
->call_stmt
, BUILT_IN_CHKP_BNDSTX
))
583 if (e
->callee
->instrumented_version
)
584 e
->redirect_callee (e
->callee
->instrumented_version
);
587 tree args
= TYPE_ARG_TYPES (TREE_TYPE (decl
));
588 /* Avoid bounds removal if all args will be removed. */
589 if (!args
|| TREE_VALUE (args
) != void_type_node
)
592 gimple_call_set_with_bounds (e
->call_stmt
, false);
599 /* Mark statement S to not be instrumented. */
601 chkp_mark_stmt (gimple s
)
603 gimple_set_plf (s
, GF_PLF_1
, true);
606 /* Mark statement S to be instrumented. */
608 chkp_unmark_stmt (gimple s
)
610 gimple_set_plf (s
, GF_PLF_1
, false);
613 /* Return 1 if statement S should not be instrumented. */
615 chkp_marked_stmt_p (gimple s
)
617 return gimple_plf (s
, GF_PLF_1
);
620 /* Get var to be used for bound temps. */
622 chkp_get_tmp_var (void)
625 tmp_var
= create_tmp_reg (pointer_bounds_type_node
, CHKP_BOUND_TMP_NAME
);
630 /* Get SSA_NAME to be used as temp. */
632 chkp_get_tmp_reg (gimple stmt
)
635 return make_ssa_name (chkp_get_tmp_var (), stmt
);
637 return make_temp_ssa_name (pointer_bounds_type_node
, stmt
,
638 CHKP_BOUND_TMP_NAME
);
641 /* Get var to be used for size temps. */
643 chkp_get_size_tmp_var (void)
646 size_tmp_var
= create_tmp_reg (chkp_uintptr_type
, CHKP_SIZE_TMP_NAME
);
651 /* Register bounds BND for address of OBJ. */
653 chkp_register_addr_bounds (tree obj
, tree bnd
)
655 if (bnd
== incomplete_bounds
)
658 chkp_reg_addr_bounds
->put (obj
, bnd
);
660 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
662 fprintf (dump_file
, "Regsitered bound ");
663 print_generic_expr (dump_file
, bnd
, 0);
664 fprintf (dump_file
, " for address of ");
665 print_generic_expr (dump_file
, obj
, 0);
666 fprintf (dump_file
, "\n");
670 /* Return bounds registered for address of OBJ. */
672 chkp_get_registered_addr_bounds (tree obj
)
674 tree
*slot
= chkp_reg_addr_bounds
->get (obj
);
675 return slot
? *slot
: NULL_TREE
;
678 /* Mark BOUNDS as completed. */
680 chkp_mark_completed_bounds (tree bounds
)
682 chkp_completed_bounds_set
->add (bounds
);
684 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
686 fprintf (dump_file
, "Marked bounds ");
687 print_generic_expr (dump_file
, bounds
, 0);
688 fprintf (dump_file
, " as completed\n");
692 /* Return 1 if BOUNDS were marked as completed and 0 otherwise. */
694 chkp_completed_bounds (tree bounds
)
696 return chkp_completed_bounds_set
->contains (bounds
);
699 /* Clear comleted bound marks. */
701 chkp_erase_completed_bounds (void)
703 delete chkp_completed_bounds_set
;
704 chkp_completed_bounds_set
= new hash_set
<tree
>;
707 /* Mark BOUNDS associated with PTR as incomplete. */
709 chkp_register_incomplete_bounds (tree bounds
, tree ptr
)
711 chkp_incomplete_bounds_map
->put (bounds
, ptr
);
713 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
715 fprintf (dump_file
, "Regsitered incomplete bounds ");
716 print_generic_expr (dump_file
, bounds
, 0);
717 fprintf (dump_file
, " for ");
718 print_generic_expr (dump_file
, ptr
, 0);
719 fprintf (dump_file
, "\n");
723 /* Return 1 if BOUNDS are incomplete and 0 otherwise. */
725 chkp_incomplete_bounds (tree bounds
)
727 if (bounds
== incomplete_bounds
)
730 if (chkp_completed_bounds (bounds
))
733 return chkp_incomplete_bounds_map
->get (bounds
) != NULL
;
736 /* Clear incomleted bound marks. */
738 chkp_erase_incomplete_bounds (void)
740 delete chkp_incomplete_bounds_map
;
741 chkp_incomplete_bounds_map
= new hash_map
<tree
, tree
>;
744 /* Build and return bndmk call which creates bounds for structure
745 pointed by PTR. Structure should have complete type. */
747 chkp_make_bounds_for_struct_addr (tree ptr
)
749 tree type
= TREE_TYPE (ptr
);
752 gcc_assert (POINTER_TYPE_P (type
));
754 size
= TYPE_SIZE (TREE_TYPE (type
));
758 return build_call_nary (pointer_bounds_type_node
,
759 build_fold_addr_expr (chkp_bndmk_fndecl
),
763 /* Traversal function for chkp_may_finish_incomplete_bounds.
764 Set RES to 0 if at least one argument of phi statement
765 defining bounds (passed in KEY arg) is unknown.
766 Traversal stops when first unknown phi argument is found. */
768 chkp_may_complete_phi_bounds (tree
const &bounds
, tree
*slot ATTRIBUTE_UNUSED
,
774 gcc_assert (TREE_CODE (bounds
) == SSA_NAME
);
776 phi
= SSA_NAME_DEF_STMT (bounds
);
778 gcc_assert (phi
&& gimple_code (phi
) == GIMPLE_PHI
);
780 for (i
= 0; i
< gimple_phi_num_args (phi
); i
++)
782 tree phi_arg
= gimple_phi_arg_def (phi
, i
);
786 /* Do not need to traverse further. */
794 /* Return 1 if all phi nodes created for bounds have their
795 arguments computed. */
797 chkp_may_finish_incomplete_bounds (void)
801 chkp_incomplete_bounds_map
802 ->traverse
<bool *, chkp_may_complete_phi_bounds
> (&res
);
807 /* Helper function for chkp_finish_incomplete_bounds.
808 Recompute args for bounds phi node. */
810 chkp_recompute_phi_bounds (tree
const &bounds
, tree
*slot
,
811 void *res ATTRIBUTE_UNUSED
)
818 gcc_assert (TREE_CODE (bounds
) == SSA_NAME
);
819 gcc_assert (TREE_CODE (ptr
) == SSA_NAME
);
821 bounds_phi
= as_a
<gphi
*> (SSA_NAME_DEF_STMT (bounds
));
822 ptr_phi
= as_a
<gphi
*> (SSA_NAME_DEF_STMT (ptr
));
824 for (i
= 0; i
< gimple_phi_num_args (bounds_phi
); i
++)
826 tree ptr_arg
= gimple_phi_arg_def (ptr_phi
, i
);
827 tree bound_arg
= chkp_find_bounds (ptr_arg
, NULL
);
829 add_phi_arg (bounds_phi
, bound_arg
,
830 gimple_phi_arg_edge (ptr_phi
, i
),
837 /* Mark BOUNDS as invalid. */
839 chkp_mark_invalid_bounds (tree bounds
)
841 chkp_invalid_bounds
->add (bounds
);
843 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
845 fprintf (dump_file
, "Marked bounds ");
846 print_generic_expr (dump_file
, bounds
, 0);
847 fprintf (dump_file
, " as invalid\n");
851 /* Return 1 if BOUNDS were marked as invalid and 0 otherwise. */
853 chkp_valid_bounds (tree bounds
)
855 if (bounds
== zero_bounds
|| bounds
== none_bounds
)
858 return !chkp_invalid_bounds
->contains (bounds
);
861 /* Helper function for chkp_finish_incomplete_bounds.
862 Check all arguments of phi nodes trying to find
863 valid completed bounds. If there is at least one
864 such arg then bounds produced by phi node are marked
865 as valid completed bounds and all phi args are
868 chkp_find_valid_phi_bounds (tree
const &bounds
, tree
*slot
, bool *res
)
873 gcc_assert (TREE_CODE (bounds
) == SSA_NAME
);
875 if (chkp_completed_bounds (bounds
))
878 phi
= SSA_NAME_DEF_STMT (bounds
);
880 gcc_assert (phi
&& gimple_code (phi
) == GIMPLE_PHI
);
882 for (i
= 0; i
< gimple_phi_num_args (phi
); i
++)
884 tree phi_arg
= gimple_phi_arg_def (phi
, i
);
886 gcc_assert (phi_arg
);
888 if (chkp_valid_bounds (phi_arg
) && !chkp_incomplete_bounds (phi_arg
))
891 chkp_mark_completed_bounds (bounds
);
892 chkp_recompute_phi_bounds (bounds
, slot
, NULL
);
900 /* Helper function for chkp_finish_incomplete_bounds.
901 Marks all incompleted bounds as invalid. */
903 chkp_mark_invalid_bounds_walker (tree
const &bounds
,
904 tree
*slot ATTRIBUTE_UNUSED
,
905 void *res ATTRIBUTE_UNUSED
)
907 if (!chkp_completed_bounds (bounds
))
909 chkp_mark_invalid_bounds (bounds
);
910 chkp_mark_completed_bounds (bounds
);
915 /* When all bound phi nodes have all their args computed
916 we have enough info to find valid bounds. We iterate
917 through all incompleted bounds searching for valid
918 bounds. Found valid bounds are marked as completed
919 and all remaining incompleted bounds are recomputed.
920 Process continues until no new valid bounds may be
921 found. All remained incompleted bounds are marked as
922 invalid (i.e. have no valid source of bounds). */
924 chkp_finish_incomplete_bounds (void)
932 chkp_incomplete_bounds_map
->
933 traverse
<bool *, chkp_find_valid_phi_bounds
> (&found_valid
);
936 chkp_incomplete_bounds_map
->
937 traverse
<void *, chkp_recompute_phi_bounds
> (NULL
);
940 chkp_incomplete_bounds_map
->
941 traverse
<void *, chkp_mark_invalid_bounds_walker
> (NULL
);
942 chkp_incomplete_bounds_map
->
943 traverse
<void *, chkp_recompute_phi_bounds
> (NULL
);
945 chkp_erase_completed_bounds ();
946 chkp_erase_incomplete_bounds ();
949 /* Return 1 if type TYPE is a pointer type or a
950 structure having a pointer type as one of its fields.
951 Otherwise return 0. */
953 chkp_type_has_pointer (const_tree type
)
957 if (BOUNDED_TYPE_P (type
))
959 else if (RECORD_OR_UNION_TYPE_P (type
))
963 for (field
= TYPE_FIELDS (type
); field
; field
= DECL_CHAIN (field
))
964 if (TREE_CODE (field
) == FIELD_DECL
)
965 res
= res
|| chkp_type_has_pointer (TREE_TYPE (field
));
967 else if (TREE_CODE (type
) == ARRAY_TYPE
)
968 res
= chkp_type_has_pointer (TREE_TYPE (type
));
974 chkp_type_bounds_count (const_tree type
)
980 else if (BOUNDED_TYPE_P (type
))
982 else if (RECORD_OR_UNION_TYPE_P (type
))
986 bitmap_obstack_initialize (NULL
);
987 have_bound
= BITMAP_ALLOC (NULL
);
988 chkp_find_bound_slots (type
, have_bound
);
989 res
= bitmap_count_bits (have_bound
);
990 BITMAP_FREE (have_bound
);
991 bitmap_obstack_release (NULL
);
997 /* Get bounds associated with NODE via
998 chkp_set_bounds call. */
1000 chkp_get_bounds (tree node
)
1004 if (!chkp_bounds_map
)
1007 slot
= chkp_bounds_map
->get (node
);
1008 return slot
? *slot
: NULL_TREE
;
1011 /* Associate bounds VAL with NODE. */
1013 chkp_set_bounds (tree node
, tree val
)
1015 if (!chkp_bounds_map
)
1016 chkp_bounds_map
= new hash_map
<tree
, tree
>;
1018 chkp_bounds_map
->put (node
, val
);
1021 /* Check if statically initialized variable VAR require
1022 static bounds initialization. If VAR is added into
1023 bounds initlization list then 1 is returned. Otherwise
1026 chkp_register_var_initializer (tree var
)
1028 if (!flag_check_pointer_bounds
1029 || DECL_INITIAL (var
) == error_mark_node
)
1032 gcc_assert (TREE_CODE (var
) == VAR_DECL
);
1033 gcc_assert (DECL_INITIAL (var
));
1035 if (TREE_STATIC (var
)
1036 && chkp_type_has_pointer (TREE_TYPE (var
)))
1038 varpool_node::get_create (var
)->need_bounds_init
= 1;
1045 /* Helper function for chkp_finish_file.
1047 Add new modification statement (RHS is assigned to LHS)
1048 into list of static initializer statementes (passed in ARG).
1049 If statements list becomes too big, emit checker constructor
1050 and start the new one. */
1052 chkp_add_modification_to_stmt_list (tree lhs
,
1056 struct chkp_ctor_stmt_list
*stmts
= (struct chkp_ctor_stmt_list
*)arg
;
1059 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1060 rhs
= build1 (CONVERT_EXPR
, TREE_TYPE (lhs
), rhs
);
1062 modify
= build2 (MODIFY_EXPR
, TREE_TYPE (lhs
), lhs
, rhs
);
1063 append_to_statement_list (modify
, &stmts
->stmts
);
1068 /* Build and return ADDR_EXPR for specified object OBJ. */
1070 chkp_build_addr_expr (tree obj
)
1072 return TREE_CODE (obj
) == TARGET_MEM_REF
1073 ? tree_mem_ref_addr (ptr_type_node
, obj
)
1074 : build_fold_addr_expr (obj
);
1077 /* Helper function for chkp_finish_file.
1078 Initialize bound variable BND_VAR with bounds of variable
1079 VAR to statements list STMTS. If statements list becomes
1080 too big, emit checker constructor and start the new one. */
1082 chkp_output_static_bounds (tree bnd_var
, tree var
,
1083 struct chkp_ctor_stmt_list
*stmts
)
1087 if (TREE_CODE (var
) == STRING_CST
)
1089 lb
= build1 (CONVERT_EXPR
, size_type_node
, chkp_build_addr_expr (var
));
1090 size
= build_int_cst (size_type_node
, TREE_STRING_LENGTH (var
) - 1);
1092 else if (DECL_SIZE (var
)
1093 && !chkp_variable_size_type (TREE_TYPE (var
)))
1095 /* Compute bounds using statically known size. */
1096 lb
= build1 (CONVERT_EXPR
, size_type_node
, chkp_build_addr_expr (var
));
1097 size
= size_binop (MINUS_EXPR
, DECL_SIZE_UNIT (var
), size_one_node
);
1101 /* Compute bounds using dynamic size. */
1104 lb
= build1 (CONVERT_EXPR
, size_type_node
, chkp_build_addr_expr (var
));
1105 call
= build1 (ADDR_EXPR
,
1106 build_pointer_type (TREE_TYPE (chkp_sizeof_fndecl
)),
1107 chkp_sizeof_fndecl
);
1108 size
= build_call_nary (TREE_TYPE (TREE_TYPE (chkp_sizeof_fndecl
)),
1111 if (flag_chkp_zero_dynamic_size_as_infinite
)
1113 tree max_size
, cond
;
1115 max_size
= build2 (MINUS_EXPR
, size_type_node
, size_zero_node
, lb
);
1116 cond
= build2 (NE_EXPR
, boolean_type_node
, size
, size_zero_node
);
1117 size
= build3 (COND_EXPR
, size_type_node
, cond
, size
, max_size
);
1120 size
= size_binop (MINUS_EXPR
, size
, size_one_node
);
1123 ub
= size_binop (PLUS_EXPR
, lb
, size
);
1124 stmts
->avail
-= targetm
.chkp_initialize_bounds (bnd_var
, lb
, ub
,
1126 if (stmts
->avail
<= 0)
1128 cgraph_build_static_cdtor ('B', stmts
->stmts
,
1129 MAX_RESERVED_INIT_PRIORITY
+ 2);
1130 stmts
->avail
= MAX_STMTS_IN_STATIC_CHKP_CTOR
;
1131 stmts
->stmts
= NULL
;
1135 /* Return entry block to be used for checker initilization code.
1136 Create new block if required. */
1138 chkp_get_entry_block (void)
1142 = split_block_after_labels (ENTRY_BLOCK_PTR_FOR_FN (cfun
))->dest
;
1147 /* Return a bounds var to be used for pointer var PTR_VAR. */
1149 chkp_get_bounds_var (tree ptr_var
)
1154 slot
= chkp_bound_vars
->get (ptr_var
);
1159 bnd_var
= create_tmp_reg (pointer_bounds_type_node
,
1160 CHKP_BOUND_TMP_NAME
);
1161 chkp_bound_vars
->put (ptr_var
, bnd_var
);
1167 /* If BND is an abnormal bounds copy, return a copied value.
1168 Otherwise return BND. */
1170 chkp_get_orginal_bounds_for_abnormal_copy (tree bnd
)
1172 if (bitmap_bit_p (chkp_abnormal_copies
, SSA_NAME_VERSION (bnd
)))
1174 gimple bnd_def
= SSA_NAME_DEF_STMT (bnd
);
1175 gcc_checking_assert (gimple_code (bnd_def
) == GIMPLE_ASSIGN
);
1176 bnd
= gimple_assign_rhs1 (bnd_def
);
1182 /* Register bounds BND for object PTR in global bounds table.
1183 A copy of bounds may be created for abnormal ssa names.
1184 Returns bounds to use for PTR. */
1186 chkp_maybe_copy_and_register_bounds (tree ptr
, tree bnd
)
1190 if (!chkp_reg_bounds
)
1193 /* Do nothing if bounds are incomplete_bounds
1194 because it means bounds will be recomputed. */
1195 if (bnd
== incomplete_bounds
)
1198 abnormal_ptr
= (TREE_CODE (ptr
) == SSA_NAME
1199 && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
)
1200 && gimple_code (SSA_NAME_DEF_STMT (ptr
)) != GIMPLE_PHI
);
1202 /* A single bounds value may be reused multiple times for
1203 different pointer values. It may cause coalescing issues
1204 for abnormal SSA names. To avoid it we create a bounds
1205 copy in case it is computed for abnormal SSA name.
1207 We also cannot reuse such created copies for other pointers */
1209 || bitmap_bit_p (chkp_abnormal_copies
, SSA_NAME_VERSION (bnd
)))
1211 tree bnd_var
= NULL_TREE
;
1215 if (SSA_NAME_VAR (ptr
))
1216 bnd_var
= chkp_get_bounds_var (SSA_NAME_VAR (ptr
));
1219 bnd_var
= chkp_get_tmp_var ();
1221 /* For abnormal copies we may just find original
1222 bounds and use them. */
1223 if (!abnormal_ptr
&& !SSA_NAME_IS_DEFAULT_DEF (bnd
))
1224 bnd
= chkp_get_orginal_bounds_for_abnormal_copy (bnd
);
1225 /* For undefined values we usually use none bounds
1226 value but in case of abnormal edge it may cause
1227 coalescing failures. Use default definition of
1228 bounds variable instead to avoid it. */
1229 else if (SSA_NAME_IS_DEFAULT_DEF (ptr
)
1230 && TREE_CODE (SSA_NAME_VAR (ptr
)) != PARM_DECL
)
1232 bnd
= get_or_create_ssa_default_def (cfun
, bnd_var
);
1234 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1236 fprintf (dump_file
, "Using default def bounds ");
1237 print_generic_expr (dump_file
, bnd
, 0);
1238 fprintf (dump_file
, " for abnormal default def SSA name ");
1239 print_generic_expr (dump_file
, ptr
, 0);
1240 fprintf (dump_file
, "\n");
1246 gimple def
= SSA_NAME_DEF_STMT (ptr
);
1248 gimple_stmt_iterator gsi
;
1251 copy
= make_ssa_name (bnd_var
);
1253 copy
= make_temp_ssa_name (pointer_bounds_type_node
,
1255 CHKP_BOUND_TMP_NAME
);
1256 bnd
= chkp_get_orginal_bounds_for_abnormal_copy (bnd
);
1257 assign
= gimple_build_assign (copy
, bnd
);
1259 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1261 fprintf (dump_file
, "Creating a copy of bounds ");
1262 print_generic_expr (dump_file
, bnd
, 0);
1263 fprintf (dump_file
, " for abnormal SSA name ");
1264 print_generic_expr (dump_file
, ptr
, 0);
1265 fprintf (dump_file
, "\n");
1268 if (gimple_code (def
) == GIMPLE_NOP
)
1270 gsi
= gsi_last_bb (chkp_get_entry_block ());
1271 if (!gsi_end_p (gsi
) && is_ctrl_stmt (gsi_stmt (gsi
)))
1272 gsi_insert_before (&gsi
, assign
, GSI_CONTINUE_LINKING
);
1274 gsi_insert_after (&gsi
, assign
, GSI_CONTINUE_LINKING
);
1278 gimple bnd_def
= SSA_NAME_DEF_STMT (bnd
);
1279 /* Sometimes (e.g. when we load a pointer from a
1280 memory) bounds are produced later than a pointer.
1281 We need to insert bounds copy appropriately. */
1282 if (gimple_code (bnd_def
) != GIMPLE_NOP
1283 && stmt_dominates_stmt_p (def
, bnd_def
))
1284 gsi
= gsi_for_stmt (bnd_def
);
1286 gsi
= gsi_for_stmt (def
);
1287 gsi_insert_after (&gsi
, assign
, GSI_CONTINUE_LINKING
);
1294 bitmap_set_bit (chkp_abnormal_copies
, SSA_NAME_VERSION (bnd
));
1297 chkp_reg_bounds
->put (ptr
, bnd
);
1299 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1301 fprintf (dump_file
, "Regsitered bound ");
1302 print_generic_expr (dump_file
, bnd
, 0);
1303 fprintf (dump_file
, " for pointer ");
1304 print_generic_expr (dump_file
, ptr
, 0);
1305 fprintf (dump_file
, "\n");
1311 /* Get bounds registered for object PTR in global bounds table. */
1313 chkp_get_registered_bounds (tree ptr
)
1317 if (!chkp_reg_bounds
)
1320 slot
= chkp_reg_bounds
->get (ptr
);
1321 return slot
? *slot
: NULL_TREE
;
1324 /* Add bound retvals to return statement pointed by GSI. */
1327 chkp_add_bounds_to_ret_stmt (gimple_stmt_iterator
*gsi
)
1329 greturn
*ret
= as_a
<greturn
*> (gsi_stmt (*gsi
));
1330 tree retval
= gimple_return_retval (ret
);
1331 tree ret_decl
= DECL_RESULT (cfun
->decl
);
1337 if (BOUNDED_P (ret_decl
))
1339 bounds
= chkp_find_bounds (retval
, gsi
);
1340 bounds
= chkp_maybe_copy_and_register_bounds (ret_decl
, bounds
);
1341 gimple_return_set_retbnd (ret
, bounds
);
1347 /* Force OP to be suitable for using as an argument for call.
1348 New statements (if any) go to SEQ. */
1350 chkp_force_gimple_call_op (tree op
, gimple_seq
*seq
)
1353 gimple_stmt_iterator si
;
1355 op
= force_gimple_operand (unshare_expr (op
), &stmts
, true, NULL_TREE
);
1357 for (si
= gsi_start (stmts
); !gsi_end_p (si
); gsi_next (&si
))
1358 chkp_mark_stmt (gsi_stmt (si
));
1360 gimple_seq_add_seq (seq
, stmts
);
1365 /* Generate lower bound check for memory access by ADDR.
1366 Check is inserted before the position pointed by ITER.
1367 DIRFLAG indicates whether memory access is load or store. */
1369 chkp_check_lower (tree addr
, tree bounds
,
1370 gimple_stmt_iterator iter
,
1371 location_t location
,
1378 if (!chkp_function_instrumented_p (current_function_decl
)
1379 && bounds
== chkp_get_zero_bounds ())
1382 if (dirflag
== integer_zero_node
1383 && !flag_chkp_check_read
)
1386 if (dirflag
== integer_one_node
1387 && !flag_chkp_check_write
)
1392 node
= chkp_force_gimple_call_op (addr
, &seq
);
1394 check
= gimple_build_call (chkp_checkl_fndecl
, 2, node
, bounds
);
1395 chkp_mark_stmt (check
);
1396 gimple_call_set_with_bounds (check
, true);
1397 gimple_set_location (check
, location
);
1398 gimple_seq_add_stmt (&seq
, check
);
1400 gsi_insert_seq_before (&iter
, seq
, GSI_SAME_STMT
);
1402 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1404 gimple before
= gsi_stmt (iter
);
1405 fprintf (dump_file
, "Generated lower bound check for statement ");
1406 print_gimple_stmt (dump_file
, before
, 0, TDF_VOPS
|TDF_MEMSYMS
);
1407 fprintf (dump_file
, " ");
1408 print_gimple_stmt (dump_file
, check
, 0, TDF_VOPS
|TDF_MEMSYMS
);
1412 /* Generate upper bound check for memory access by ADDR.
1413 Check is inserted before the position pointed by ITER.
1414 DIRFLAG indicates whether memory access is load or store. */
1416 chkp_check_upper (tree addr
, tree bounds
,
1417 gimple_stmt_iterator iter
,
1418 location_t location
,
1425 if (!chkp_function_instrumented_p (current_function_decl
)
1426 && bounds
== chkp_get_zero_bounds ())
1429 if (dirflag
== integer_zero_node
1430 && !flag_chkp_check_read
)
1433 if (dirflag
== integer_one_node
1434 && !flag_chkp_check_write
)
1439 node
= chkp_force_gimple_call_op (addr
, &seq
);
1441 check
= gimple_build_call (chkp_checku_fndecl
, 2, node
, bounds
);
1442 chkp_mark_stmt (check
);
1443 gimple_call_set_with_bounds (check
, true);
1444 gimple_set_location (check
, location
);
1445 gimple_seq_add_stmt (&seq
, check
);
1447 gsi_insert_seq_before (&iter
, seq
, GSI_SAME_STMT
);
1449 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1451 gimple before
= gsi_stmt (iter
);
1452 fprintf (dump_file
, "Generated upper bound check for statement ");
1453 print_gimple_stmt (dump_file
, before
, 0, TDF_VOPS
|TDF_MEMSYMS
);
1454 fprintf (dump_file
, " ");
1455 print_gimple_stmt (dump_file
, check
, 0, TDF_VOPS
|TDF_MEMSYMS
);
1459 /* Generate lower and upper bound checks for memory access
1460 to memory slot [FIRST, LAST] againsr BOUNDS. Checks
1461 are inserted before the position pointed by ITER.
1462 DIRFLAG indicates whether memory access is load or store. */
1464 chkp_check_mem_access (tree first
, tree last
, tree bounds
,
1465 gimple_stmt_iterator iter
,
1466 location_t location
,
1469 chkp_check_lower (first
, bounds
, iter
, location
, dirflag
);
1470 chkp_check_upper (last
, bounds
, iter
, location
, dirflag
);
1473 /* Replace call to _bnd_chk_* pointed by GSI with
1474 bndcu and bndcl calls. DIRFLAG determines whether
1475 check is for read or write. */
1478 chkp_replace_address_check_builtin (gimple_stmt_iterator
*gsi
,
1481 gimple_stmt_iterator call_iter
= *gsi
;
1482 gimple call
= gsi_stmt (*gsi
);
1483 tree fndecl
= gimple_call_fndecl (call
);
1484 tree addr
= gimple_call_arg (call
, 0);
1485 tree bounds
= chkp_find_bounds (addr
, gsi
);
1487 if (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_CHECK_PTR_LBOUNDS
1488 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_CHECK_PTR_BOUNDS
)
1489 chkp_check_lower (addr
, bounds
, *gsi
, gimple_location (call
), dirflag
);
1491 if (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_CHECK_PTR_UBOUNDS
)
1492 chkp_check_upper (addr
, bounds
, *gsi
, gimple_location (call
), dirflag
);
1494 if (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_CHECK_PTR_BOUNDS
)
1496 tree size
= gimple_call_arg (call
, 1);
1497 addr
= fold_build_pointer_plus (addr
, size
);
1498 addr
= fold_build_pointer_plus_hwi (addr
, -1);
1499 chkp_check_upper (addr
, bounds
, *gsi
, gimple_location (call
), dirflag
);
1502 gsi_remove (&call_iter
, true);
1505 /* Replace call to _bnd_get_ptr_* pointed by GSI with
1506 corresponding bounds extract call. */
1509 chkp_replace_extract_builtin (gimple_stmt_iterator
*gsi
)
1511 gimple call
= gsi_stmt (*gsi
);
1512 tree fndecl
= gimple_call_fndecl (call
);
1513 tree addr
= gimple_call_arg (call
, 0);
1514 tree bounds
= chkp_find_bounds (addr
, gsi
);
1517 if (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_GET_PTR_LBOUND
)
1518 fndecl
= chkp_extract_lower_fndecl
;
1519 else if (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_GET_PTR_UBOUND
)
1520 fndecl
= chkp_extract_upper_fndecl
;
1524 extract
= gimple_build_call (fndecl
, 1, bounds
);
1525 gimple_call_set_lhs (extract
, gimple_call_lhs (call
));
1526 chkp_mark_stmt (extract
);
1528 gsi_replace (gsi
, extract
, false);
1531 /* Return COMPONENT_REF accessing FIELD in OBJ. */
1533 chkp_build_component_ref (tree obj
, tree field
)
1537 /* If object is TMR then we do not use component_ref but
1538 add offset instead. We need it to be able to get addr
1539 of the reasult later. */
1540 if (TREE_CODE (obj
) == TARGET_MEM_REF
)
1542 tree offs
= TMR_OFFSET (obj
);
1543 offs
= fold_binary_to_constant (PLUS_EXPR
, TREE_TYPE (offs
),
1544 offs
, DECL_FIELD_OFFSET (field
));
1548 res
= copy_node (obj
);
1549 TREE_TYPE (res
) = TREE_TYPE (field
);
1550 TMR_OFFSET (res
) = offs
;
1553 res
= build3 (COMPONENT_REF
, TREE_TYPE (field
), obj
, field
, NULL_TREE
);
1558 /* Return ARRAY_REF for array ARR and index IDX with
1559 specified element type ETYPE and element size ESIZE. */
1561 chkp_build_array_ref (tree arr
, tree etype
, tree esize
,
1562 unsigned HOST_WIDE_INT idx
)
1564 tree index
= build_int_cst (size_type_node
, idx
);
1567 /* If object is TMR then we do not use array_ref but
1568 add offset instead. We need it to be able to get addr
1569 of the reasult later. */
1570 if (TREE_CODE (arr
) == TARGET_MEM_REF
)
1572 tree offs
= TMR_OFFSET (arr
);
1574 esize
= fold_binary_to_constant (MULT_EXPR
, TREE_TYPE (esize
),
1578 offs
= fold_binary_to_constant (PLUS_EXPR
, TREE_TYPE (offs
),
1582 res
= copy_node (arr
);
1583 TREE_TYPE (res
) = etype
;
1584 TMR_OFFSET (res
) = offs
;
1587 res
= build4 (ARRAY_REF
, etype
, arr
, index
, NULL_TREE
, NULL_TREE
);
1592 /* Helper function for chkp_add_bounds_to_call_stmt.
1593 Fill ALL_BOUNDS output array with created bounds.
1595 OFFS is used for recursive calls and holds basic
1596 offset of TYPE in outer structure in bits.
1598 ITER points a position where bounds are searched.
1600 ALL_BOUNDS[i] is filled with elem bounds if there
1601 is a field in TYPE which has pointer type and offset
1602 equal to i * POINTER_SIZE in bits. */
1604 chkp_find_bounds_for_elem (tree elem
, tree
*all_bounds
,
1606 gimple_stmt_iterator
*iter
)
1608 tree type
= TREE_TYPE (elem
);
1610 if (BOUNDED_TYPE_P (type
))
1612 if (!all_bounds
[offs
/ POINTER_SIZE
])
1614 tree temp
= make_temp_ssa_name (type
, NULL
, "");
1615 gimple assign
= gimple_build_assign (temp
, elem
);
1616 gimple_stmt_iterator gsi
;
1618 gsi_insert_before (iter
, assign
, GSI_SAME_STMT
);
1619 gsi
= gsi_for_stmt (assign
);
1621 all_bounds
[offs
/ POINTER_SIZE
] = chkp_find_bounds (temp
, &gsi
);
1624 else if (RECORD_OR_UNION_TYPE_P (type
))
1628 for (field
= TYPE_FIELDS (type
); field
; field
= DECL_CHAIN (field
))
1629 if (TREE_CODE (field
) == FIELD_DECL
)
1631 tree base
= unshare_expr (elem
);
1632 tree field_ref
= chkp_build_component_ref (base
, field
);
1633 HOST_WIDE_INT field_offs
1634 = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field
));
1635 if (DECL_FIELD_OFFSET (field
))
1636 field_offs
+= TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field
)) * 8;
1638 chkp_find_bounds_for_elem (field_ref
, all_bounds
,
1639 offs
+ field_offs
, iter
);
1642 else if (TREE_CODE (type
) == ARRAY_TYPE
)
1644 tree maxval
= TYPE_MAX_VALUE (TYPE_DOMAIN (type
));
1645 tree etype
= TREE_TYPE (type
);
1646 HOST_WIDE_INT esize
= TREE_INT_CST_LOW (TYPE_SIZE (etype
));
1647 unsigned HOST_WIDE_INT cur
;
1649 if (!maxval
|| integer_minus_onep (maxval
))
1652 for (cur
= 0; cur
<= TREE_INT_CST_LOW (maxval
); cur
++)
1654 tree base
= unshare_expr (elem
);
1655 tree arr_elem
= chkp_build_array_ref (base
, etype
,
1658 chkp_find_bounds_for_elem (arr_elem
, all_bounds
, offs
+ cur
* esize
,
1664 /* Fill HAVE_BOUND output bitmap with information about
1665 bounds requred for object of type TYPE.
1667 OFFS is used for recursive calls and holds basic
1668 offset of TYPE in outer structure in bits.
1670 HAVE_BOUND[i] is set to 1 if there is a field
1671 in TYPE which has pointer type and offset
1672 equal to i * POINTER_SIZE - OFFS in bits. */
1674 chkp_find_bound_slots_1 (const_tree type
, bitmap have_bound
,
1677 if (BOUNDED_TYPE_P (type
))
1678 bitmap_set_bit (have_bound
, offs
/ POINTER_SIZE
);
1679 else if (RECORD_OR_UNION_TYPE_P (type
))
1683 for (field
= TYPE_FIELDS (type
); field
; field
= DECL_CHAIN (field
))
1684 if (TREE_CODE (field
) == FIELD_DECL
)
1686 HOST_WIDE_INT field_offs
1687 = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field
));
1688 if (DECL_FIELD_OFFSET (field
))
1689 field_offs
+= TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field
)) * 8;
1690 chkp_find_bound_slots_1 (TREE_TYPE (field
), have_bound
,
1694 else if (TREE_CODE (type
) == ARRAY_TYPE
)
1696 tree maxval
= TYPE_MAX_VALUE (TYPE_DOMAIN (type
));
1697 tree etype
= TREE_TYPE (type
);
1698 HOST_WIDE_INT esize
= TREE_INT_CST_LOW (TYPE_SIZE (etype
));
1699 unsigned HOST_WIDE_INT cur
;
1702 || TREE_CODE (maxval
) != INTEGER_CST
1703 || integer_minus_onep (maxval
))
1706 for (cur
= 0; cur
<= TREE_INT_CST_LOW (maxval
); cur
++)
1707 chkp_find_bound_slots_1 (etype
, have_bound
, offs
+ cur
* esize
);
1711 /* Fill bitmap RES with information about bounds for
1712 type TYPE. See chkp_find_bound_slots_1 for more
1715 chkp_find_bound_slots (const_tree type
, bitmap res
)
1718 chkp_find_bound_slots_1 (type
, res
, 0);
1721 /* Return 1 if call to FNDECL should be instrumented
1725 chkp_instrument_normal_builtin (tree fndecl
)
1727 switch (DECL_FUNCTION_CODE (fndecl
))
1729 case BUILT_IN_STRLEN
:
1730 case BUILT_IN_STRCPY
:
1731 case BUILT_IN_STRNCPY
:
1732 case BUILT_IN_STPCPY
:
1733 case BUILT_IN_STPNCPY
:
1734 case BUILT_IN_STRCAT
:
1735 case BUILT_IN_STRNCAT
:
1736 case BUILT_IN_MEMCPY
:
1737 case BUILT_IN_MEMPCPY
:
1738 case BUILT_IN_MEMSET
:
1739 case BUILT_IN_MEMMOVE
:
1740 case BUILT_IN_BZERO
:
1741 case BUILT_IN_STRCMP
:
1742 case BUILT_IN_STRNCMP
:
1744 case BUILT_IN_MEMCMP
:
1745 case BUILT_IN_MEMCPY_CHK
:
1746 case BUILT_IN_MEMPCPY_CHK
:
1747 case BUILT_IN_MEMMOVE_CHK
:
1748 case BUILT_IN_MEMSET_CHK
:
1749 case BUILT_IN_STRCPY_CHK
:
1750 case BUILT_IN_STRNCPY_CHK
:
1751 case BUILT_IN_STPCPY_CHK
:
1752 case BUILT_IN_STPNCPY_CHK
:
1753 case BUILT_IN_STRCAT_CHK
:
1754 case BUILT_IN_STRNCAT_CHK
:
1755 case BUILT_IN_MALLOC
:
1756 case BUILT_IN_CALLOC
:
1757 case BUILT_IN_REALLOC
:
1765 /* Add bound arguments to call statement pointed by GSI.
1766 Also performs a replacement of user checker builtins calls
1767 with internal ones. */
1770 chkp_add_bounds_to_call_stmt (gimple_stmt_iterator
*gsi
)
1772 gcall
*call
= as_a
<gcall
*> (gsi_stmt (*gsi
));
1773 unsigned arg_no
= 0;
1774 tree fndecl
= gimple_call_fndecl (call
);
1776 tree first_formal_arg
;
1778 bool use_fntype
= false;
1783 /* Do nothing for internal functions. */
1784 if (gimple_call_internal_p (call
))
1787 fntype
= TREE_TYPE (TREE_TYPE (gimple_call_fn (call
)));
1789 /* Do nothing if back-end builtin is called. */
1790 if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_MD
)
1793 /* Do nothing for some middle-end builtins. */
1794 if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
1795 && DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_OBJECT_SIZE
)
1798 /* Do nothing for calls to not instrumentable functions. */
1799 if (fndecl
&& !chkp_instrumentable_p (fndecl
))
1802 /* Ignore CHKP_INIT_PTR_BOUNDS, CHKP_NULL_PTR_BOUNDS
1803 and CHKP_COPY_PTR_BOUNDS. */
1804 if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
1805 && (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_INIT_PTR_BOUNDS
1806 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_NULL_PTR_BOUNDS
1807 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_COPY_PTR_BOUNDS
1808 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_SET_PTR_BOUNDS
))
1811 /* Check user builtins are replaced with checks. */
1812 if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
1813 && (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_CHECK_PTR_LBOUNDS
1814 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_CHECK_PTR_UBOUNDS
1815 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_CHECK_PTR_BOUNDS
))
1817 chkp_replace_address_check_builtin (gsi
, integer_minus_one_node
);
1821 /* Check user builtins are replaced with bound extract. */
1822 if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
1823 && (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_GET_PTR_LBOUND
1824 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_GET_PTR_UBOUND
))
1826 chkp_replace_extract_builtin (gsi
);
1830 /* BUILT_IN_CHKP_NARROW_PTR_BOUNDS call is replaced with
1831 target narrow bounds call. */
1832 if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
1833 && DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_NARROW_PTR_BOUNDS
)
1835 tree arg
= gimple_call_arg (call
, 1);
1836 tree bounds
= chkp_find_bounds (arg
, gsi
);
1838 gimple_call_set_fndecl (call
, chkp_narrow_bounds_fndecl
);
1839 gimple_call_set_arg (call
, 1, bounds
);
1845 /* BUILT_IN_CHKP_STORE_PTR_BOUNDS call is replaced with
1847 if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
1848 && DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_STORE_PTR_BOUNDS
)
1850 tree addr
= gimple_call_arg (call
, 0);
1851 tree ptr
= gimple_call_arg (call
, 1);
1852 tree bounds
= chkp_find_bounds (ptr
, gsi
);
1853 gimple_stmt_iterator iter
= gsi_for_stmt (call
);
1855 chkp_build_bndstx (addr
, ptr
, bounds
, gsi
);
1856 gsi_remove (&iter
, true);
1861 if (!flag_chkp_instrument_calls
)
1864 /* We instrument only some subset of builtins. We also instrument
1865 builtin calls to be inlined. */
1867 && DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
1868 && !chkp_instrument_normal_builtin (fndecl
))
1870 if (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl
)))
1873 struct cgraph_node
*clone
= chkp_maybe_create_clone (fndecl
);
1875 || !gimple_has_body_p (clone
->decl
))
1879 /* If function decl is available then use it for
1880 formal arguments list. Otherwise use function type. */
1881 if (fndecl
&& DECL_ARGUMENTS (fndecl
))
1882 first_formal_arg
= DECL_ARGUMENTS (fndecl
);
1885 first_formal_arg
= TYPE_ARG_TYPES (fntype
);
1889 /* Fill vector of new call args. */
1890 vec
<tree
> new_args
= vNULL
;
1891 new_args
.create (gimple_call_num_args (call
));
1892 arg
= first_formal_arg
;
1893 for (arg_no
= 0; arg_no
< gimple_call_num_args (call
); arg_no
++)
1895 tree call_arg
= gimple_call_arg (call
, arg_no
);
1898 /* Get arg type using formal argument description
1899 or actual argument type. */
1902 if (TREE_VALUE (arg
) != void_type_node
)
1904 type
= TREE_VALUE (arg
);
1905 arg
= TREE_CHAIN (arg
);
1908 type
= TREE_TYPE (call_arg
);
1911 type
= TREE_TYPE (arg
);
1912 arg
= TREE_CHAIN (arg
);
1915 type
= TREE_TYPE (call_arg
);
1917 new_args
.safe_push (call_arg
);
1919 if (BOUNDED_TYPE_P (type
)
1920 || pass_by_reference (NULL
, TYPE_MODE (type
), type
, true))
1921 new_args
.safe_push (chkp_find_bounds (call_arg
, gsi
));
1922 else if (chkp_type_has_pointer (type
))
1924 HOST_WIDE_INT max_bounds
1925 = TREE_INT_CST_LOW (TYPE_SIZE (type
)) / POINTER_SIZE
;
1926 tree
*all_bounds
= (tree
*)xmalloc (sizeof (tree
) * max_bounds
);
1927 HOST_WIDE_INT bnd_no
;
1929 memset (all_bounds
, 0, sizeof (tree
) * max_bounds
);
1931 chkp_find_bounds_for_elem (call_arg
, all_bounds
, 0, gsi
);
1933 for (bnd_no
= 0; bnd_no
< max_bounds
; bnd_no
++)
1934 if (all_bounds
[bnd_no
])
1935 new_args
.safe_push (all_bounds
[bnd_no
]);
1941 if (new_args
.length () == gimple_call_num_args (call
))
1945 new_call
= gimple_build_call_vec (gimple_op (call
, 1), new_args
);
1946 gimple_call_set_lhs (new_call
, gimple_call_lhs (call
));
1947 gimple_call_copy_flags (new_call
, call
);
1948 gimple_call_set_chain (new_call
, gimple_call_chain (call
));
1950 new_args
.release ();
1952 /* For direct calls fndecl is replaced with instrumented version. */
1955 tree new_decl
= chkp_maybe_create_clone (fndecl
)->decl
;
1956 gimple_call_set_fndecl (new_call
, new_decl
);
1957 gimple_call_set_fntype (new_call
, TREE_TYPE (new_decl
));
1959 /* For indirect call we should fix function pointer type if
1960 pass some bounds. */
1961 else if (new_call
!= call
)
1963 tree type
= gimple_call_fntype (call
);
1964 type
= chkp_copy_function_type_adding_bounds (type
);
1965 gimple_call_set_fntype (new_call
, type
);
1968 /* replace old call statement with the new one. */
1969 if (call
!= new_call
)
1971 FOR_EACH_SSA_TREE_OPERAND (op
, call
, iter
, SSA_OP_ALL_DEFS
)
1973 SSA_NAME_DEF_STMT (op
) = new_call
;
1975 gsi_replace (gsi
, new_call
, true);
1978 update_stmt (new_call
);
1980 gimple_call_set_with_bounds (new_call
, true);
1983 /* Return constant static bounds var with specified bounds LB and UB.
1984 If such var does not exists then new var is created with specified NAME. */
1986 chkp_make_static_const_bounds (HOST_WIDE_INT lb
,
1990 tree id
= get_identifier (name
);
1995 var
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
, id
,
1996 pointer_bounds_type_node
);
1997 TREE_STATIC (var
) = 1;
1998 TREE_PUBLIC (var
) = 1;
2000 /* With LTO we may have constant bounds already in varpool.
2002 if ((snode
= symtab_node::get_for_asmname (DECL_ASSEMBLER_NAME (var
))))
2004 /* We don't allow this symbol usage for non bounds. */
2005 if (snode
->type
!= SYMTAB_VARIABLE
2006 || !POINTER_BOUNDS_P (snode
->decl
))
2007 sorry ("-fcheck-pointer-bounds requires '%s' "
2008 "name for internal usage",
2009 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (var
)));
2014 TREE_USED (var
) = 1;
2015 TREE_READONLY (var
) = 1;
2016 TREE_ADDRESSABLE (var
) = 0;
2017 DECL_ARTIFICIAL (var
) = 1;
2018 DECL_READ_P (var
) = 1;
2019 DECL_INITIAL (var
) = targetm
.chkp_make_bounds_constant (lb
, ub
);
2020 make_decl_one_only (var
, DECL_ASSEMBLER_NAME (var
));
2021 /* We may use this symbol during ctors generation in chkp_finish_file
2022 when all symbols are emitted. Force output to avoid undefined
2023 symbols in ctors. */
2024 node
= varpool_node::get_create (var
);
2025 node
->force_output
= 1;
2027 varpool_node::finalize_decl (var
);
2032 /* Generate code to make bounds with specified lower bound LB and SIZE.
2033 if AFTER is 1 then code is inserted after position pointed by ITER
2034 otherwise code is inserted before position pointed by ITER.
2035 If ITER is NULL then code is added to entry block. */
2037 chkp_make_bounds (tree lb
, tree size
, gimple_stmt_iterator
*iter
, bool after
)
2040 gimple_stmt_iterator gsi
;
2047 gsi
= gsi_start_bb (chkp_get_entry_block ());
2051 lb
= chkp_force_gimple_call_op (lb
, &seq
);
2052 size
= chkp_force_gimple_call_op (size
, &seq
);
2054 stmt
= gimple_build_call (chkp_bndmk_fndecl
, 2, lb
, size
);
2055 chkp_mark_stmt (stmt
);
2057 bounds
= chkp_get_tmp_reg (stmt
);
2058 gimple_call_set_lhs (stmt
, bounds
);
2060 gimple_seq_add_stmt (&seq
, stmt
);
2063 gsi_insert_seq_after (&gsi
, seq
, GSI_SAME_STMT
);
2065 gsi_insert_seq_before (&gsi
, seq
, GSI_SAME_STMT
);
2067 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2069 fprintf (dump_file
, "Made bounds: ");
2070 print_gimple_stmt (dump_file
, stmt
, 0, TDF_VOPS
|TDF_MEMSYMS
);
2073 fprintf (dump_file
, " inserted before statement: ");
2074 print_gimple_stmt (dump_file
, gsi_stmt (*iter
), 0, TDF_VOPS
|TDF_MEMSYMS
);
2077 fprintf (dump_file
, " at function entry\n");
2080 /* update_stmt (stmt); */
2085 /* Return var holding zero bounds. */
2087 chkp_get_zero_bounds_var (void)
2089 if (!chkp_zero_bounds_var
)
2090 chkp_zero_bounds_var
2091 = chkp_make_static_const_bounds (0, -1,
2092 CHKP_ZERO_BOUNDS_VAR_NAME
);
2093 return chkp_zero_bounds_var
;
2096 /* Return var holding none bounds. */
2098 chkp_get_none_bounds_var (void)
2100 if (!chkp_none_bounds_var
)
2101 chkp_none_bounds_var
2102 = chkp_make_static_const_bounds (-1, 0,
2103 CHKP_NONE_BOUNDS_VAR_NAME
);
2104 return chkp_none_bounds_var
;
2107 /* Return SSA_NAME used to represent zero bounds. */
2109 chkp_get_zero_bounds (void)
2114 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2115 fprintf (dump_file
, "Creating zero bounds...");
2117 if ((flag_chkp_use_static_bounds
&& flag_chkp_use_static_const_bounds
)
2118 || flag_chkp_use_static_const_bounds
> 0)
2120 gimple_stmt_iterator gsi
= gsi_start_bb (chkp_get_entry_block ());
2123 zero_bounds
= chkp_get_tmp_reg (NULL
);
2124 stmt
= gimple_build_assign (zero_bounds
, chkp_get_zero_bounds_var ());
2125 gsi_insert_before (&gsi
, stmt
, GSI_SAME_STMT
);
2128 zero_bounds
= chkp_make_bounds (integer_zero_node
,
2136 /* Return SSA_NAME used to represent none bounds. */
2138 chkp_get_none_bounds (void)
2143 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2144 fprintf (dump_file
, "Creating none bounds...");
2147 if ((flag_chkp_use_static_bounds
&& flag_chkp_use_static_const_bounds
)
2148 || flag_chkp_use_static_const_bounds
> 0)
2150 gimple_stmt_iterator gsi
= gsi_start_bb (chkp_get_entry_block ());
2153 none_bounds
= chkp_get_tmp_reg (NULL
);
2154 stmt
= gimple_build_assign (none_bounds
, chkp_get_none_bounds_var ());
2155 gsi_insert_before (&gsi
, stmt
, GSI_SAME_STMT
);
2158 none_bounds
= chkp_make_bounds (integer_minus_one_node
,
2159 build_int_cst (size_type_node
, 2),
2166 /* Return bounds to be used as a result of operation which
2167 should not create poiunter (e.g. MULT_EXPR). */
2169 chkp_get_invalid_op_bounds (void)
2171 return chkp_get_zero_bounds ();
2174 /* Return bounds to be used for loads of non-pointer values. */
2176 chkp_get_nonpointer_load_bounds (void)
2178 return chkp_get_zero_bounds ();
2181 /* Return 1 if may use bndret call to get bounds for pointer
2182 returned by CALL. */
2184 chkp_call_returns_bounds_p (gcall
*call
)
2186 if (gimple_call_internal_p (call
))
2189 if (gimple_call_builtin_p (call
, BUILT_IN_CHKP_NARROW_PTR_BOUNDS
)
2190 || chkp_gimple_call_builtin_p (call
, BUILT_IN_CHKP_NARROW
))
2193 if (gimple_call_with_bounds_p (call
))
2196 tree fndecl
= gimple_call_fndecl (call
);
2198 if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_MD
)
2201 if (fndecl
&& !chkp_instrumentable_p (fndecl
))
2204 if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
)
2206 if (chkp_instrument_normal_builtin (fndecl
))
2209 if (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl
)))
2212 struct cgraph_node
*clone
= chkp_maybe_create_clone (fndecl
);
2213 return (clone
&& gimple_has_body_p (clone
->decl
));
2219 /* Build bounds returned by CALL. */
2221 chkp_build_returned_bound (gcall
*call
)
2223 gimple_stmt_iterator gsi
;
2226 tree fndecl
= gimple_call_fndecl (call
);
2227 unsigned int retflags
;
2229 /* To avoid fixing alloca expands in targets we handle
2232 && DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
2233 && (DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_ALLOCA
2234 || DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_ALLOCA_WITH_ALIGN
))
2236 tree size
= gimple_call_arg (call
, 0);
2237 tree lb
= gimple_call_lhs (call
);
2238 gimple_stmt_iterator iter
= gsi_for_stmt (call
);
2239 bounds
= chkp_make_bounds (lb
, size
, &iter
, true);
2241 /* We know bounds returned by set_bounds builtin call. */
2243 && DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
2244 && DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_SET_PTR_BOUNDS
)
2246 tree lb
= gimple_call_arg (call
, 0);
2247 tree size
= gimple_call_arg (call
, 1);
2248 gimple_stmt_iterator iter
= gsi_for_stmt (call
);
2249 bounds
= chkp_make_bounds (lb
, size
, &iter
, true);
2251 /* Detect bounds initialization calls. */
2253 && DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
2254 && DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_INIT_PTR_BOUNDS
)
2255 bounds
= chkp_get_zero_bounds ();
2256 /* Detect bounds nullification calls. */
2258 && DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
2259 && DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_NULL_PTR_BOUNDS
)
2260 bounds
= chkp_get_none_bounds ();
2261 /* Detect bounds copy calls. */
2263 && DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
2264 && DECL_FUNCTION_CODE (fndecl
) == BUILT_IN_CHKP_COPY_PTR_BOUNDS
)
2266 gimple_stmt_iterator iter
= gsi_for_stmt (call
);
2267 bounds
= chkp_find_bounds (gimple_call_arg (call
, 1), &iter
);
2269 /* Do not use retbnd when returned bounds are equal to some
2270 of passed bounds. */
2271 else if (((retflags
= gimple_call_return_flags (call
)) & ERF_RETURNS_ARG
)
2272 && (retflags
& ERF_RETURN_ARG_MASK
) < gimple_call_num_args (call
))
2274 gimple_stmt_iterator iter
= gsi_for_stmt (call
);
2275 unsigned int retarg
= retflags
& ERF_RETURN_ARG_MASK
, argno
;
2276 if (gimple_call_with_bounds_p (call
))
2278 for (argno
= 0; argno
< gimple_call_num_args (call
); argno
++)
2279 if (!POINTER_BOUNDS_P (gimple_call_arg (call
, argno
)))
2290 bounds
= chkp_find_bounds (gimple_call_arg (call
, argno
), &iter
);
2292 else if (chkp_call_returns_bounds_p (call
))
2294 gcc_assert (TREE_CODE (gimple_call_lhs (call
)) == SSA_NAME
);
2296 /* In general case build checker builtin call to
2297 obtain returned bounds. */
2298 stmt
= gimple_build_call (chkp_ret_bnd_fndecl
, 1,
2299 gimple_call_lhs (call
));
2300 chkp_mark_stmt (stmt
);
2302 gsi
= gsi_for_stmt (call
);
2303 gsi_insert_after (&gsi
, stmt
, GSI_SAME_STMT
);
2305 bounds
= chkp_get_tmp_reg (stmt
);
2306 gimple_call_set_lhs (stmt
, bounds
);
2311 bounds
= chkp_get_zero_bounds ();
2313 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2315 fprintf (dump_file
, "Built returned bounds (");
2316 print_generic_expr (dump_file
, bounds
, 0);
2317 fprintf (dump_file
, ") for call: ");
2318 print_gimple_stmt (dump_file
, call
, 0, TDF_VOPS
|TDF_MEMSYMS
);
2321 bounds
= chkp_maybe_copy_and_register_bounds (gimple_call_lhs (call
), bounds
);
2326 /* Return bounds used as returned by call
2327 which produced SSA name VAL. */
2329 chkp_retbnd_call_by_val (tree val
)
2331 if (TREE_CODE (val
) != SSA_NAME
)
2334 gcc_assert (gimple_code (SSA_NAME_DEF_STMT (val
)) == GIMPLE_CALL
);
2336 imm_use_iterator use_iter
;
2337 use_operand_p use_p
;
2338 FOR_EACH_IMM_USE_FAST (use_p
, use_iter
, val
)
2339 if (gimple_code (USE_STMT (use_p
)) == GIMPLE_CALL
2340 && gimple_call_fndecl (USE_STMT (use_p
)) == chkp_ret_bnd_fndecl
)
2341 return as_a
<gcall
*> (USE_STMT (use_p
));
2346 /* Check the next parameter for the given PARM is bounds
2347 and return it's default SSA_NAME (create if required). */
2349 chkp_get_next_bounds_parm (tree parm
)
2351 tree bounds
= TREE_CHAIN (parm
);
2352 gcc_assert (POINTER_BOUNDS_P (bounds
));
2353 bounds
= ssa_default_def (cfun
, bounds
);
2356 bounds
= make_ssa_name (TREE_CHAIN (parm
), gimple_build_nop ());
2357 set_ssa_default_def (cfun
, TREE_CHAIN (parm
), bounds
);
2362 /* Return bounds to be used for input argument PARM. */
2364 chkp_get_bound_for_parm (tree parm
)
2366 tree decl
= SSA_NAME_VAR (parm
);
2369 gcc_assert (TREE_CODE (decl
) == PARM_DECL
);
2371 bounds
= chkp_get_registered_bounds (parm
);
2374 bounds
= chkp_get_registered_bounds (decl
);
2378 tree orig_decl
= cgraph_node::get (cfun
->decl
)->orig_decl
;
2380 /* For static chain param we return zero bounds
2381 because currently we do not check dereferences
2383 if (cfun
->static_chain_decl
== decl
)
2384 bounds
= chkp_get_zero_bounds ();
2385 /* If non instrumented runtime is used then it may be useful
2386 to use zero bounds for input arguments of main
2388 else if (flag_chkp_zero_input_bounds_for_main
2389 && strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (orig_decl
)),
2391 bounds
= chkp_get_zero_bounds ();
2392 else if (BOUNDED_P (parm
))
2394 bounds
= chkp_get_next_bounds_parm (decl
);
2395 bounds
= chkp_maybe_copy_and_register_bounds (decl
, bounds
);
2397 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2399 fprintf (dump_file
, "Built arg bounds (");
2400 print_generic_expr (dump_file
, bounds
, 0);
2401 fprintf (dump_file
, ") for arg: ");
2402 print_node (dump_file
, "", decl
, 0);
2406 bounds
= chkp_get_zero_bounds ();
2409 if (!chkp_get_registered_bounds (parm
))
2410 bounds
= chkp_maybe_copy_and_register_bounds (parm
, bounds
);
2412 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2414 fprintf (dump_file
, "Using bounds ");
2415 print_generic_expr (dump_file
, bounds
, 0);
2416 fprintf (dump_file
, " for parm ");
2417 print_generic_expr (dump_file
, parm
, 0);
2418 fprintf (dump_file
, " of type ");
2419 print_generic_expr (dump_file
, TREE_TYPE (parm
), 0);
2420 fprintf (dump_file
, ".\n");
2426 /* Build and return CALL_EXPR for bndstx builtin with specified
2429 chkp_build_bndldx_call (tree addr
, tree ptr
)
2431 tree fn
= build1 (ADDR_EXPR
,
2432 build_pointer_type (TREE_TYPE (chkp_bndldx_fndecl
)),
2433 chkp_bndldx_fndecl
);
2434 tree call
= build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndldx_fndecl
)),
2436 CALL_WITH_BOUNDS_P (call
) = true;
2440 /* Insert code to load bounds for PTR located by ADDR.
2441 Code is inserted after position pointed by GSI.
2442 Loaded bounds are returned. */
2444 chkp_build_bndldx (tree addr
, tree ptr
, gimple_stmt_iterator
*gsi
)
2452 addr
= chkp_force_gimple_call_op (addr
, &seq
);
2453 ptr
= chkp_force_gimple_call_op (ptr
, &seq
);
2455 stmt
= gimple_build_call (chkp_bndldx_fndecl
, 2, addr
, ptr
);
2456 chkp_mark_stmt (stmt
);
2457 bounds
= chkp_get_tmp_reg (stmt
);
2458 gimple_call_set_lhs (stmt
, bounds
);
2460 gimple_seq_add_stmt (&seq
, stmt
);
2462 gsi_insert_seq_after (gsi
, seq
, GSI_CONTINUE_LINKING
);
2464 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2466 fprintf (dump_file
, "Generated bndldx for pointer ");
2467 print_generic_expr (dump_file
, ptr
, 0);
2468 fprintf (dump_file
, ": ");
2469 print_gimple_stmt (dump_file
, stmt
, 0, TDF_VOPS
|TDF_MEMSYMS
);
2475 /* Build and return CALL_EXPR for bndstx builtin with specified
2478 chkp_build_bndstx_call (tree addr
, tree ptr
, tree bounds
)
2480 tree fn
= build1 (ADDR_EXPR
,
2481 build_pointer_type (TREE_TYPE (chkp_bndstx_fndecl
)),
2482 chkp_bndstx_fndecl
);
2483 tree call
= build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndstx_fndecl
)),
2484 fn
, 3, ptr
, bounds
, addr
);
2485 CALL_WITH_BOUNDS_P (call
) = true;
2489 /* Insert code to store BOUNDS for PTR stored by ADDR.
2490 New statements are inserted after position pointed
2493 chkp_build_bndstx (tree addr
, tree ptr
, tree bounds
,
2494 gimple_stmt_iterator
*gsi
)
2501 addr
= chkp_force_gimple_call_op (addr
, &seq
);
2502 ptr
= chkp_force_gimple_call_op (ptr
, &seq
);
2504 stmt
= gimple_build_call (chkp_bndstx_fndecl
, 3, ptr
, bounds
, addr
);
2505 chkp_mark_stmt (stmt
);
2506 gimple_call_set_with_bounds (stmt
, true);
2508 gimple_seq_add_stmt (&seq
, stmt
);
2510 gsi_insert_seq_after (gsi
, seq
, GSI_CONTINUE_LINKING
);
2512 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2514 fprintf (dump_file
, "Generated bndstx for pointer store ");
2515 print_gimple_stmt (dump_file
, gsi_stmt (*gsi
), 0, TDF_VOPS
|TDF_MEMSYMS
);
2516 print_gimple_stmt (dump_file
, stmt
, 2, TDF_VOPS
|TDF_MEMSYMS
);
2520 /* Compute bounds for pointer NODE which was assigned in
2521 assignment statement ASSIGN. Return computed bounds. */
2523 chkp_compute_bounds_for_assignment (tree node
, gimple assign
)
2525 enum tree_code rhs_code
= gimple_assign_rhs_code (assign
);
2526 tree rhs1
= gimple_assign_rhs1 (assign
);
2527 tree bounds
= NULL_TREE
;
2528 gimple_stmt_iterator iter
= gsi_for_stmt (assign
);
2530 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2532 fprintf (dump_file
, "Computing bounds for assignment: ");
2533 print_gimple_stmt (dump_file
, assign
, 0, TDF_VOPS
|TDF_MEMSYMS
);
2539 case TARGET_MEM_REF
:
2542 /* We need to load bounds from the bounds table. */
2543 bounds
= chkp_find_bounds_loaded (node
, rhs1
, &iter
);
2549 case POINTER_PLUS_EXPR
:
2553 /* Bounds are just propagated from RHS. */
2554 bounds
= chkp_find_bounds (rhs1
, &iter
);
2557 case VIEW_CONVERT_EXPR
:
2558 /* Bounds are just propagated from RHS. */
2559 bounds
= chkp_find_bounds (TREE_OPERAND (rhs1
, 0), &iter
);
2563 if (BOUNDED_P (rhs1
))
2565 /* We need to load bounds from the bounds table. */
2566 bounds
= chkp_build_bndldx (chkp_build_addr_expr (rhs1
),
2568 TREE_ADDRESSABLE (rhs1
) = 1;
2571 bounds
= chkp_get_nonpointer_load_bounds ();
2580 tree rhs2
= gimple_assign_rhs2 (assign
);
2581 tree bnd1
= chkp_find_bounds (rhs1
, &iter
);
2582 tree bnd2
= chkp_find_bounds (rhs2
, &iter
);
2584 /* First we try to check types of operands. If it
2585 does not help then look at bound values.
2587 If some bounds are incomplete and other are
2588 not proven to be valid (i.e. also incomplete
2589 or invalid because value is not pointer) then
2590 resulting value is incomplete and will be
2591 recomputed later in chkp_finish_incomplete_bounds. */
2592 if (BOUNDED_P (rhs1
)
2593 && !BOUNDED_P (rhs2
))
2595 else if (BOUNDED_P (rhs2
)
2596 && !BOUNDED_P (rhs1
)
2597 && rhs_code
!= MINUS_EXPR
)
2599 else if (chkp_incomplete_bounds (bnd1
))
2600 if (chkp_valid_bounds (bnd2
) && rhs_code
!= MINUS_EXPR
2601 && !chkp_incomplete_bounds (bnd2
))
2604 bounds
= incomplete_bounds
;
2605 else if (chkp_incomplete_bounds (bnd2
))
2606 if (chkp_valid_bounds (bnd1
)
2607 && !chkp_incomplete_bounds (bnd1
))
2610 bounds
= incomplete_bounds
;
2611 else if (!chkp_valid_bounds (bnd1
))
2612 if (chkp_valid_bounds (bnd2
) && rhs_code
!= MINUS_EXPR
)
2614 else if (bnd2
== chkp_get_zero_bounds ())
2618 else if (!chkp_valid_bounds (bnd2
))
2621 /* Seems both operands may have valid bounds
2622 (e.g. pointer minus pointer). In such case
2623 use default invalid op bounds. */
2624 bounds
= chkp_get_invalid_op_bounds ();
2642 case TRUNC_DIV_EXPR
:
2643 case FLOOR_DIV_EXPR
:
2645 case ROUND_DIV_EXPR
:
2646 case TRUNC_MOD_EXPR
:
2647 case FLOOR_MOD_EXPR
:
2649 case ROUND_MOD_EXPR
:
2650 case EXACT_DIV_EXPR
:
2651 case FIX_TRUNC_EXPR
:
2655 /* No valid bounds may be produced by these exprs. */
2656 bounds
= chkp_get_invalid_op_bounds ();
2661 tree val1
= gimple_assign_rhs2 (assign
);
2662 tree val2
= gimple_assign_rhs3 (assign
);
2663 tree bnd1
= chkp_find_bounds (val1
, &iter
);
2664 tree bnd2
= chkp_find_bounds (val2
, &iter
);
2667 if (chkp_incomplete_bounds (bnd1
) || chkp_incomplete_bounds (bnd2
))
2668 bounds
= incomplete_bounds
;
2669 else if (bnd1
== bnd2
)
2673 rhs1
= unshare_expr (rhs1
);
2675 bounds
= chkp_get_tmp_reg (assign
);
2676 stmt
= gimple_build_assign (bounds
, COND_EXPR
, rhs1
, bnd1
, bnd2
);
2677 gsi_insert_after (&iter
, stmt
, GSI_SAME_STMT
);
2679 if (!chkp_valid_bounds (bnd1
) && !chkp_valid_bounds (bnd2
))
2680 chkp_mark_invalid_bounds (bounds
);
2688 tree rhs2
= gimple_assign_rhs2 (assign
);
2689 tree bnd1
= chkp_find_bounds (rhs1
, &iter
);
2690 tree bnd2
= chkp_find_bounds (rhs2
, &iter
);
2692 if (chkp_incomplete_bounds (bnd1
) || chkp_incomplete_bounds (bnd2
))
2693 bounds
= incomplete_bounds
;
2694 else if (bnd1
== bnd2
)
2699 tree cond
= build2 (rhs_code
== MAX_EXPR
? GT_EXPR
: LT_EXPR
,
2700 boolean_type_node
, rhs1
, rhs2
);
2701 bounds
= chkp_get_tmp_reg (assign
);
2702 stmt
= gimple_build_assign (bounds
, COND_EXPR
, cond
, bnd1
, bnd2
);
2704 gsi_insert_after (&iter
, stmt
, GSI_SAME_STMT
);
2706 if (!chkp_valid_bounds (bnd1
) && !chkp_valid_bounds (bnd2
))
2707 chkp_mark_invalid_bounds (bounds
);
2713 bounds
= chkp_get_zero_bounds ();
2714 warning (0, "pointer bounds were lost due to unexpected expression %s",
2715 get_tree_code_name (rhs_code
));
2718 gcc_assert (bounds
);
2721 bounds
= chkp_maybe_copy_and_register_bounds (node
, bounds
);
2726 /* Compute bounds for ssa name NODE defined by DEF_STMT pointed by ITER.
2728 There are just few statement codes allowed: NOP (for default ssa names),
2729 ASSIGN, CALL, PHI, ASM.
2731 Return computed bounds. */
2733 chkp_get_bounds_by_definition (tree node
, gimple def_stmt
,
2734 gphi_iterator
*iter
)
2737 enum gimple_code code
= gimple_code (def_stmt
);
2740 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2742 fprintf (dump_file
, "Searching for bounds for node: ");
2743 print_generic_expr (dump_file
, node
, 0);
2745 fprintf (dump_file
, " using its definition: ");
2746 print_gimple_stmt (dump_file
, def_stmt
, 0, TDF_VOPS
|TDF_MEMSYMS
);
2752 var
= SSA_NAME_VAR (node
);
2753 switch (TREE_CODE (var
))
2756 bounds
= chkp_get_bound_for_parm (node
);
2760 /* For uninitialized pointers use none bounds. */
2761 bounds
= chkp_get_none_bounds ();
2762 bounds
= chkp_maybe_copy_and_register_bounds (node
, bounds
);
2769 gcc_assert (TREE_CODE (TREE_TYPE (node
)) == REFERENCE_TYPE
);
2771 base_type
= TREE_TYPE (TREE_TYPE (node
));
2773 gcc_assert (TYPE_SIZE (base_type
)
2774 && TREE_CODE (TYPE_SIZE (base_type
)) == INTEGER_CST
2775 && tree_to_uhwi (TYPE_SIZE (base_type
)) != 0);
2777 bounds
= chkp_make_bounds (node
, TYPE_SIZE_UNIT (base_type
),
2779 bounds
= chkp_maybe_copy_and_register_bounds (node
, bounds
);
2784 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2786 fprintf (dump_file
, "Unexpected var with no definition\n");
2787 print_generic_expr (dump_file
, var
, 0);
2789 internal_error ("chkp_get_bounds_by_definition: Unexpected var of type %s",
2790 get_tree_code_name (TREE_CODE (var
)));
2795 bounds
= chkp_compute_bounds_for_assignment (node
, def_stmt
);
2799 bounds
= chkp_build_returned_bound (as_a
<gcall
*> (def_stmt
));
2803 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (node
))
2804 if (SSA_NAME_VAR (node
))
2805 var
= chkp_get_bounds_var (SSA_NAME_VAR (node
));
2807 var
= make_temp_ssa_name (pointer_bounds_type_node
,
2809 CHKP_BOUND_TMP_NAME
);
2811 var
= chkp_get_tmp_var ();
2812 stmt
= create_phi_node (var
, gimple_bb (def_stmt
));
2813 bounds
= gimple_phi_result (stmt
);
2814 *iter
= gsi_for_phi (stmt
);
2816 bounds
= chkp_maybe_copy_and_register_bounds (node
, bounds
);
2818 /* Created bounds do not have all phi args computed and
2819 therefore we do not know if there is a valid source
2820 of bounds for that node. Therefore we mark bounds
2821 as incomplete and then recompute them when all phi
2822 args are computed. */
2823 chkp_register_incomplete_bounds (bounds
, node
);
2827 bounds
= chkp_get_zero_bounds ();
2828 bounds
= chkp_maybe_copy_and_register_bounds (node
, bounds
);
2832 internal_error ("chkp_get_bounds_by_definition: Unexpected GIMPLE code %s",
2833 gimple_code_name
[code
]);
2839 /* Return CALL_EXPR for bndmk with specified LOWER_BOUND and SIZE. */
2841 chkp_build_make_bounds_call (tree lower_bound
, tree size
)
2843 tree call
= build1 (ADDR_EXPR
,
2844 build_pointer_type (TREE_TYPE (chkp_bndmk_fndecl
)),
2846 return build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndmk_fndecl
)),
2847 call
, 2, lower_bound
, size
);
2850 /* Create static bounds var of specfified OBJ which is
2851 is either VAR_DECL or string constant. */
2853 chkp_make_static_bounds (tree obj
)
2855 static int string_id
= 1;
2856 static int var_id
= 1;
2858 const char *var_name
;
2862 /* First check if we already have required var. */
2863 if (chkp_static_var_bounds
)
2865 /* For vars we use assembler name as a key in
2866 chkp_static_var_bounds map. It allows to
2867 avoid duplicating bound vars for decls
2868 sharing assembler name. */
2869 if (TREE_CODE (obj
) == VAR_DECL
)
2871 tree name
= DECL_ASSEMBLER_NAME (obj
);
2872 slot
= chkp_static_var_bounds
->get (name
);
2878 slot
= chkp_static_var_bounds
->get (obj
);
2884 /* Build decl for bounds var. */
2885 if (TREE_CODE (obj
) == VAR_DECL
)
2887 if (DECL_IGNORED_P (obj
))
2889 bnd_var_name
= (char *) xmalloc (strlen (CHKP_VAR_BOUNDS_PREFIX
) + 10);
2890 sprintf (bnd_var_name
, "%s%d", CHKP_VAR_BOUNDS_PREFIX
, var_id
++);
2894 var_name
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (obj
));
2896 /* For hidden symbols we want to skip first '*' char. */
2897 if (*var_name
== '*')
2900 bnd_var_name
= (char *) xmalloc (strlen (var_name
)
2901 + strlen (CHKP_BOUNDS_OF_SYMBOL_PREFIX
) + 1);
2902 strcpy (bnd_var_name
, CHKP_BOUNDS_OF_SYMBOL_PREFIX
);
2903 strcat (bnd_var_name
, var_name
);
2906 bnd_var
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
2907 get_identifier (bnd_var_name
),
2908 pointer_bounds_type_node
);
2910 /* Address of the obj will be used as lower bound. */
2911 TREE_ADDRESSABLE (obj
) = 1;
2915 bnd_var_name
= (char *) xmalloc (strlen (CHKP_STRING_BOUNDS_PREFIX
) + 10);
2916 sprintf (bnd_var_name
, "%s%d", CHKP_STRING_BOUNDS_PREFIX
, string_id
++);
2918 bnd_var
= build_decl (UNKNOWN_LOCATION
, VAR_DECL
,
2919 get_identifier (bnd_var_name
),
2920 pointer_bounds_type_node
);
2923 TREE_PUBLIC (bnd_var
) = 0;
2924 TREE_USED (bnd_var
) = 1;
2925 TREE_READONLY (bnd_var
) = 0;
2926 TREE_STATIC (bnd_var
) = 1;
2927 TREE_ADDRESSABLE (bnd_var
) = 0;
2928 DECL_ARTIFICIAL (bnd_var
) = 1;
2929 DECL_COMMON (bnd_var
) = 1;
2930 DECL_COMDAT (bnd_var
) = 1;
2931 DECL_READ_P (bnd_var
) = 1;
2932 DECL_INITIAL (bnd_var
) = chkp_build_addr_expr (obj
);
2933 /* Force output similar to constant bounds.
2934 See chkp_make_static_const_bounds. */
2935 varpool_node::get_create (bnd_var
)->force_output
= 1;
2936 /* Mark symbol as requiring bounds initialization. */
2937 varpool_node::get_create (bnd_var
)->need_bounds_init
= 1;
2938 varpool_node::finalize_decl (bnd_var
);
2940 /* Add created var to the map to use it for other references
2942 if (!chkp_static_var_bounds
)
2943 chkp_static_var_bounds
= new hash_map
<tree
, tree
>;
2945 if (TREE_CODE (obj
) == VAR_DECL
)
2947 tree name
= DECL_ASSEMBLER_NAME (obj
);
2948 chkp_static_var_bounds
->put (name
, bnd_var
);
2951 chkp_static_var_bounds
->put (obj
, bnd_var
);
2956 /* When var has incomplete type we cannot get size to
2957 compute its bounds. In such cases we use checker
2958 builtin call which determines object size at runtime. */
2960 chkp_generate_extern_var_bounds (tree var
)
2962 tree bounds
, size_reloc
, lb
, size
, max_size
, cond
;
2963 gimple_stmt_iterator gsi
;
2964 gimple_seq seq
= NULL
;
2967 /* If instrumentation is not enabled for vars having
2968 incomplete type then just return zero bounds to avoid
2969 checks for this var. */
2970 if (!flag_chkp_incomplete_type
)
2971 return chkp_get_zero_bounds ();
2973 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
2975 fprintf (dump_file
, "Generating bounds for extern symbol '");
2976 print_generic_expr (dump_file
, var
, 0);
2977 fprintf (dump_file
, "'\n");
2980 stmt
= gimple_build_call (chkp_sizeof_fndecl
, 1, var
);
2982 size_reloc
= create_tmp_reg (chkp_uintptr_type
, CHKP_SIZE_TMP_NAME
);
2983 gimple_call_set_lhs (stmt
, size_reloc
);
2985 gimple_seq_add_stmt (&seq
, stmt
);
2987 lb
= chkp_build_addr_expr (var
);
2988 size
= make_ssa_name (chkp_get_size_tmp_var ());
2990 if (flag_chkp_zero_dynamic_size_as_infinite
)
2992 /* We should check that size relocation was resolved.
2993 If it was not then use maximum possible size for the var. */
2994 max_size
= build2 (MINUS_EXPR
, chkp_uintptr_type
, integer_zero_node
,
2995 fold_convert (chkp_uintptr_type
, lb
));
2996 max_size
= chkp_force_gimple_call_op (max_size
, &seq
);
2998 cond
= build2 (NE_EXPR
, boolean_type_node
,
2999 size_reloc
, integer_zero_node
);
3000 stmt
= gimple_build_assign (size
, COND_EXPR
, cond
, size_reloc
, max_size
);
3001 gimple_seq_add_stmt (&seq
, stmt
);
3005 stmt
= gimple_build_assign (size
, size_reloc
);
3006 gimple_seq_add_stmt (&seq
, stmt
);
3009 gsi
= gsi_start_bb (chkp_get_entry_block ());
3010 gsi_insert_seq_after (&gsi
, seq
, GSI_CONTINUE_LINKING
);
3012 bounds
= chkp_make_bounds (lb
, size
, &gsi
, true);
3017 /* Return 1 if TYPE has fields with zero size or fields
3018 marked with chkp_variable_size attribute. */
3020 chkp_variable_size_type (tree type
)
3025 if (RECORD_OR_UNION_TYPE_P (type
))
3026 for (field
= TYPE_FIELDS (type
); field
; field
= DECL_CHAIN (field
))
3028 if (TREE_CODE (field
) == FIELD_DECL
)
3030 || lookup_attribute ("bnd_variable_size", DECL_ATTRIBUTES (field
))
3031 || chkp_variable_size_type (TREE_TYPE (field
));
3034 res
= !TYPE_SIZE (type
)
3035 || TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
3036 || tree_to_uhwi (TYPE_SIZE (type
)) == 0;
3041 /* Compute and return bounds for address of DECL which is
3042 one of VAR_DECL, PARM_DECL, RESULT_DECL. */
3044 chkp_get_bounds_for_decl_addr (tree decl
)
3048 gcc_assert (TREE_CODE (decl
) == VAR_DECL
3049 || TREE_CODE (decl
) == PARM_DECL
3050 || TREE_CODE (decl
) == RESULT_DECL
);
3052 bounds
= chkp_get_registered_addr_bounds (decl
);
3057 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
3059 fprintf (dump_file
, "Building bounds for address of decl ");
3060 print_generic_expr (dump_file
, decl
, 0);
3061 fprintf (dump_file
, "\n");
3064 /* Use zero bounds if size is unknown and checks for
3065 unknown sizes are restricted. */
3066 if ((!DECL_SIZE (decl
)
3067 || (chkp_variable_size_type (TREE_TYPE (decl
))
3068 && (TREE_STATIC (decl
)
3069 || DECL_EXTERNAL (decl
)
3070 || TREE_PUBLIC (decl
))))
3071 && !flag_chkp_incomplete_type
)
3072 return chkp_get_zero_bounds ();
3074 if (flag_chkp_use_static_bounds
3075 && TREE_CODE (decl
) == VAR_DECL
3076 && (TREE_STATIC (decl
)
3077 || DECL_EXTERNAL (decl
)
3078 || TREE_PUBLIC (decl
))
3079 && !DECL_THREAD_LOCAL_P (decl
))
3081 tree bnd_var
= chkp_make_static_bounds (decl
);
3082 gimple_stmt_iterator gsi
= gsi_start_bb (chkp_get_entry_block ());
3085 bounds
= chkp_get_tmp_reg (NULL
);
3086 stmt
= gimple_build_assign (bounds
, bnd_var
);
3087 gsi_insert_before (&gsi
, stmt
, GSI_SAME_STMT
);
3089 else if (!DECL_SIZE (decl
)
3090 || (chkp_variable_size_type (TREE_TYPE (decl
))
3091 && (TREE_STATIC (decl
)
3092 || DECL_EXTERNAL (decl
)
3093 || TREE_PUBLIC (decl
))))
3095 gcc_assert (TREE_CODE (decl
) == VAR_DECL
);
3096 bounds
= chkp_generate_extern_var_bounds (decl
);
3100 tree lb
= chkp_build_addr_expr (decl
);
3101 bounds
= chkp_make_bounds (lb
, DECL_SIZE_UNIT (decl
), NULL
, false);
3107 /* Compute and return bounds for constant string. */
3109 chkp_get_bounds_for_string_cst (tree cst
)
3115 gcc_assert (TREE_CODE (cst
) == STRING_CST
);
3117 bounds
= chkp_get_registered_bounds (cst
);
3122 if ((flag_chkp_use_static_bounds
&& flag_chkp_use_static_const_bounds
)
3123 || flag_chkp_use_static_const_bounds
> 0)
3125 tree bnd_var
= chkp_make_static_bounds (cst
);
3126 gimple_stmt_iterator gsi
= gsi_start_bb (chkp_get_entry_block ());
3129 bounds
= chkp_get_tmp_reg (NULL
);
3130 stmt
= gimple_build_assign (bounds
, bnd_var
);
3131 gsi_insert_before (&gsi
, stmt
, GSI_SAME_STMT
);
3135 lb
= chkp_build_addr_expr (cst
);
3136 size
= build_int_cst (chkp_uintptr_type
, TREE_STRING_LENGTH (cst
));
3137 bounds
= chkp_make_bounds (lb
, size
, NULL
, false);
3140 bounds
= chkp_maybe_copy_and_register_bounds (cst
, bounds
);
3145 /* Generate code to instersect bounds BOUNDS1 and BOUNDS2 and
3146 return the result. if ITER is not NULL then Code is inserted
3147 before position pointed by ITER. Otherwise code is added to
3150 chkp_intersect_bounds (tree bounds1
, tree bounds2
, gimple_stmt_iterator
*iter
)
3152 if (!bounds1
|| bounds1
== chkp_get_zero_bounds ())
3153 return bounds2
? bounds2
: bounds1
;
3154 else if (!bounds2
|| bounds2
== chkp_get_zero_bounds ())
3164 stmt
= gimple_build_call (chkp_intersect_fndecl
, 2, bounds1
, bounds2
);
3165 chkp_mark_stmt (stmt
);
3167 bounds
= chkp_get_tmp_reg (stmt
);
3168 gimple_call_set_lhs (stmt
, bounds
);
3170 gimple_seq_add_stmt (&seq
, stmt
);
3172 /* We are probably doing narrowing for constant expression.
3173 In such case iter may be undefined. */
3176 gimple_stmt_iterator gsi
= gsi_last_bb (chkp_get_entry_block ());
3178 gsi_insert_seq_after (iter
, seq
, GSI_SAME_STMT
);
3181 gsi_insert_seq_before (iter
, seq
, GSI_SAME_STMT
);
3183 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
3185 fprintf (dump_file
, "Bounds intersection: ");
3186 print_gimple_stmt (dump_file
, stmt
, 0, TDF_VOPS
|TDF_MEMSYMS
);
3187 fprintf (dump_file
, " inserted before statement: ");
3188 print_gimple_stmt (dump_file
, gsi_stmt (*iter
), 0,
3189 TDF_VOPS
|TDF_MEMSYMS
);
3196 /* Return 1 if we are allowed to narrow bounds for addressed FIELD
3199 chkp_may_narrow_to_field (tree field
)
3201 return DECL_SIZE (field
) && TREE_CODE (DECL_SIZE (field
)) == INTEGER_CST
3202 && tree_to_uhwi (DECL_SIZE (field
)) != 0
3203 && (!DECL_FIELD_OFFSET (field
)
3204 || TREE_CODE (DECL_FIELD_OFFSET (field
)) == INTEGER_CST
)
3205 && (!DECL_FIELD_BIT_OFFSET (field
)
3206 || TREE_CODE (DECL_FIELD_BIT_OFFSET (field
)) == INTEGER_CST
)
3207 && !lookup_attribute ("bnd_variable_size", DECL_ATTRIBUTES (field
))
3208 && !chkp_variable_size_type (TREE_TYPE (field
));
3211 /* Return 1 if bounds for FIELD should be narrowed to
3212 field's own size. */
3214 chkp_narrow_bounds_for_field (tree field
)
3217 HOST_WIDE_INT bit_offs
;
3219 if (!chkp_may_narrow_to_field (field
))
3222 /* Accesse to compiler generated fields should not cause
3223 bounds narrowing. */
3224 if (DECL_ARTIFICIAL (field
))
3227 offs
= tree_to_uhwi (DECL_FIELD_OFFSET (field
));
3228 bit_offs
= tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field
));
3230 return (flag_chkp_narrow_bounds
3231 && (flag_chkp_first_field_has_own_bounds
3236 /* Perform narrowing for BOUNDS using bounds computed for field
3237 access COMPONENT. ITER meaning is the same as for
3238 chkp_intersect_bounds. */
3240 chkp_narrow_bounds_to_field (tree bounds
, tree component
,
3241 gimple_stmt_iterator
*iter
)
3243 tree field
= TREE_OPERAND (component
, 1);
3244 tree size
= DECL_SIZE_UNIT (field
);
3245 tree field_ptr
= chkp_build_addr_expr (component
);
3248 field_bounds
= chkp_make_bounds (field_ptr
, size
, iter
, false);
3250 return chkp_intersect_bounds (field_bounds
, bounds
, iter
);
3253 /* Parse field or array access NODE.
3255 PTR ouput parameter holds a pointer to the outermost
3258 BITFIELD output parameter is set to 1 if bitfield is
3259 accessed and to 0 otherwise. If it is 1 then ELT holds
3260 outer component for accessed bit field.
3262 SAFE outer parameter is set to 1 if access is safe and
3263 checks are not required.
3265 BOUNDS outer parameter holds bounds to be used to check
3266 access (may be NULL).
3268 If INNERMOST_BOUNDS is 1 then try to narrow bounds to the
3269 innermost accessed component. */
3271 chkp_parse_array_and_component_ref (tree node
, tree
*ptr
,
3272 tree
*elt
, bool *safe
,
3275 gimple_stmt_iterator
*iter
,
3276 bool innermost_bounds
)
3278 tree comp_to_narrow
= NULL_TREE
;
3279 tree last_comp
= NULL_TREE
;
3280 bool array_ref_found
= false;
3286 /* Compute tree height for expression. */
3289 while (TREE_CODE (var
) == COMPONENT_REF
3290 || TREE_CODE (var
) == ARRAY_REF
3291 || TREE_CODE (var
) == VIEW_CONVERT_EXPR
)
3293 var
= TREE_OPERAND (var
, 0);
3297 gcc_assert (len
> 1);
3299 /* It is more convenient for us to scan left-to-right,
3300 so walk tree again and put all node to nodes vector
3301 in reversed order. */
3302 nodes
= XALLOCAVEC (tree
, len
);
3303 nodes
[len
- 1] = node
;
3304 for (i
= len
- 2; i
>= 0; i
--)
3305 nodes
[i
] = TREE_OPERAND (nodes
[i
+ 1], 0);
3310 *bitfield
= (TREE_CODE (node
) == COMPONENT_REF
3311 && DECL_BIT_FIELD_TYPE (TREE_OPERAND (node
, 1)));
3312 /* To get bitfield address we will need outer elemnt. */
3314 *elt
= nodes
[len
- 2];
3318 /* If we have indirection in expression then compute
3319 outermost structure bounds. Computed bounds may be
3321 if (TREE_CODE (nodes
[0]) == MEM_REF
|| INDIRECT_REF_P (nodes
[0]))
3324 *ptr
= TREE_OPERAND (nodes
[0], 0);
3326 *bounds
= chkp_find_bounds (*ptr
, iter
);
3330 gcc_assert (TREE_CODE (var
) == VAR_DECL
3331 || TREE_CODE (var
) == PARM_DECL
3332 || TREE_CODE (var
) == RESULT_DECL
3333 || TREE_CODE (var
) == STRING_CST
3334 || TREE_CODE (var
) == SSA_NAME
);
3336 *ptr
= chkp_build_addr_expr (var
);
3339 /* In this loop we are trying to find a field access
3340 requiring narrowing. There are two simple rules
3342 1. Leftmost array_ref is chosen if any.
3343 2. Rightmost suitable component_ref is chosen if innermost
3344 bounds are required and no array_ref exists. */
3345 for (i
= 1; i
< len
; i
++)
3349 if (TREE_CODE (var
) == ARRAY_REF
)
3352 array_ref_found
= true;
3353 if (flag_chkp_narrow_bounds
3354 && !flag_chkp_narrow_to_innermost_arrray
3356 || chkp_may_narrow_to_field (TREE_OPERAND (last_comp
, 1))))
3358 comp_to_narrow
= last_comp
;
3362 else if (TREE_CODE (var
) == COMPONENT_REF
)
3364 tree field
= TREE_OPERAND (var
, 1);
3366 if (innermost_bounds
3368 && chkp_narrow_bounds_for_field (field
))
3369 comp_to_narrow
= var
;
3372 if (flag_chkp_narrow_bounds
3373 && flag_chkp_narrow_to_innermost_arrray
3374 && TREE_CODE (TREE_TYPE (field
)) == ARRAY_TYPE
)
3377 *bounds
= chkp_narrow_bounds_to_field (*bounds
, var
, iter
);
3378 comp_to_narrow
= NULL
;
3381 else if (TREE_CODE (var
) == VIEW_CONVERT_EXPR
)
3382 /* Nothing to do for it. */
3388 if (comp_to_narrow
&& DECL_SIZE (TREE_OPERAND (comp_to_narrow
, 1)) && bounds
)
3389 *bounds
= chkp_narrow_bounds_to_field (*bounds
, comp_to_narrow
, iter
);
3391 if (innermost_bounds
&& bounds
&& !*bounds
)
3392 *bounds
= chkp_find_bounds (*ptr
, iter
);
3395 /* Compute and return bounds for address of OBJ. */
3397 chkp_make_addressed_object_bounds (tree obj
, gimple_stmt_iterator
*iter
)
3399 tree bounds
= chkp_get_registered_addr_bounds (obj
);
3404 switch (TREE_CODE (obj
))
3409 bounds
= chkp_get_bounds_for_decl_addr (obj
);
3413 bounds
= chkp_get_bounds_for_string_cst (obj
);
3424 chkp_parse_array_and_component_ref (obj
, &ptr
, &elt
, &safe
,
3425 &bitfield
, &bounds
, iter
, true);
3427 gcc_assert (bounds
);
3433 bounds
= chkp_get_zero_bounds ();
3437 bounds
= chkp_find_bounds (TREE_OPERAND (obj
, 0), iter
);
3442 bounds
= chkp_make_addressed_object_bounds (TREE_OPERAND (obj
, 0), iter
);
3446 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
3448 fprintf (dump_file
, "chkp_make_addressed_object_bounds: "
3449 "unexpected object of type %s\n",
3450 get_tree_code_name (TREE_CODE (obj
)));
3451 print_node (dump_file
, "", obj
, 0);
3453 internal_error ("chkp_make_addressed_object_bounds: "
3454 "Unexpected tree code %s",
3455 get_tree_code_name (TREE_CODE (obj
)));
3458 chkp_register_addr_bounds (obj
, bounds
);
3463 /* Compute bounds for pointer PTR loaded from PTR_SRC. Generate statements
3464 to compute bounds if required. Computed bounds should be available at
3465 position pointed by ITER.
3467 If PTR_SRC is NULL_TREE then pointer definition is identified.
3469 If PTR_SRC is not NULL_TREE then ITER points to statements which loads
3470 PTR. If PTR is a any memory reference then ITER points to a statement
3471 after which bndldx will be inserterd. In both cases ITER will be updated
3472 to point to the inserted bndldx statement. */
3475 chkp_find_bounds_1 (tree ptr
, tree ptr_src
, gimple_stmt_iterator
*iter
)
3477 tree addr
= NULL_TREE
;
3478 tree bounds
= NULL_TREE
;
3483 bounds
= chkp_get_registered_bounds (ptr_src
);
3488 switch (TREE_CODE (ptr_src
))
3492 if (BOUNDED_P (ptr_src
))
3493 if (TREE_CODE (ptr
) == VAR_DECL
&& DECL_REGISTER (ptr
))
3494 bounds
= chkp_get_zero_bounds ();
3497 addr
= chkp_build_addr_expr (ptr_src
);
3498 bounds
= chkp_build_bndldx (addr
, ptr
, iter
);
3501 bounds
= chkp_get_nonpointer_load_bounds ();
3506 addr
= get_base_address (ptr_src
);
3508 || TREE_CODE (addr
) == MEM_REF
3509 || TREE_CODE (addr
) == TARGET_MEM_REF
)
3511 if (BOUNDED_P (ptr_src
))
3512 if (TREE_CODE (ptr
) == VAR_DECL
&& DECL_REGISTER (ptr
))
3513 bounds
= chkp_get_zero_bounds ();
3516 addr
= chkp_build_addr_expr (ptr_src
);
3517 bounds
= chkp_build_bndldx (addr
, ptr
, iter
);
3520 bounds
= chkp_get_nonpointer_load_bounds ();
3524 gcc_assert (TREE_CODE (addr
) == SSA_NAME
);
3525 bounds
= chkp_find_bounds (addr
, iter
);
3531 bounds
= chkp_get_bound_for_parm (ptr_src
);
3534 case TARGET_MEM_REF
:
3535 addr
= chkp_build_addr_expr (ptr_src
);
3536 bounds
= chkp_build_bndldx (addr
, ptr
, iter
);
3540 bounds
= chkp_get_registered_bounds (ptr_src
);
3543 gimple def_stmt
= SSA_NAME_DEF_STMT (ptr_src
);
3544 gphi_iterator phi_iter
;
3546 bounds
= chkp_get_bounds_by_definition (ptr_src
, def_stmt
, &phi_iter
);
3548 gcc_assert (bounds
);
3550 if (gphi
*def_phi
= dyn_cast
<gphi
*> (def_stmt
))
3554 for (i
= 0; i
< gimple_phi_num_args (def_phi
); i
++)
3556 tree arg
= gimple_phi_arg_def (def_phi
, i
);
3560 arg_bnd
= chkp_find_bounds (arg
, NULL
);
3562 /* chkp_get_bounds_by_definition created new phi
3563 statement and phi_iter points to it.
3565 Previous call to chkp_find_bounds could create
3566 new basic block and therefore change phi statement
3567 phi_iter points to. */
3568 phi_bnd
= phi_iter
.phi ();
3570 add_phi_arg (phi_bnd
, arg_bnd
,
3571 gimple_phi_arg_edge (def_phi
, i
),
3575 /* If all bound phi nodes have their arg computed
3576 then we may finish its computation. See
3577 chkp_finish_incomplete_bounds for more details. */
3578 if (chkp_may_finish_incomplete_bounds ())
3579 chkp_finish_incomplete_bounds ();
3582 gcc_assert (bounds
== chkp_get_registered_bounds (ptr_src
)
3583 || chkp_incomplete_bounds (bounds
));
3588 bounds
= chkp_make_addressed_object_bounds (TREE_OPERAND (ptr_src
, 0), iter
);
3592 if (integer_zerop (ptr_src
))
3593 bounds
= chkp_get_none_bounds ();
3595 bounds
= chkp_get_invalid_op_bounds ();
3599 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
3601 fprintf (dump_file
, "chkp_find_bounds: unexpected ptr of type %s\n",
3602 get_tree_code_name (TREE_CODE (ptr_src
)));
3603 print_node (dump_file
, "", ptr_src
, 0);
3605 internal_error ("chkp_find_bounds: Unexpected tree code %s",
3606 get_tree_code_name (TREE_CODE (ptr_src
)));
3611 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
3613 fprintf (stderr
, "chkp_find_bounds: cannot find bounds for pointer\n");
3614 print_node (dump_file
, "", ptr_src
, 0);
3616 internal_error ("chkp_find_bounds: Cannot find bounds for pointer");
3622 /* Normal case for bounds search without forced narrowing. */
3624 chkp_find_bounds (tree ptr
, gimple_stmt_iterator
*iter
)
3626 return chkp_find_bounds_1 (ptr
, NULL_TREE
, iter
);
3629 /* Search bounds for pointer PTR loaded from PTR_SRC
3630 by statement *ITER points to. */
3632 chkp_find_bounds_loaded (tree ptr
, tree ptr_src
, gimple_stmt_iterator
*iter
)
3634 return chkp_find_bounds_1 (ptr
, ptr_src
, iter
);
3637 /* Helper function which checks type of RHS and finds all pointers in
3638 it. For each found pointer we build it's accesses in LHS and RHS
3639 objects and then call HANDLER for them. Function is used to copy
3640 or initilize bounds for copied object. */
3642 chkp_walk_pointer_assignments (tree lhs
, tree rhs
, void *arg
,
3643 assign_handler handler
)
3645 tree type
= TREE_TYPE (lhs
);
3647 /* We have nothing to do with clobbers. */
3648 if (TREE_CLOBBER_P (rhs
))
3651 if (BOUNDED_TYPE_P (type
))
3652 handler (lhs
, rhs
, arg
);
3653 else if (RECORD_OR_UNION_TYPE_P (type
))
3657 if (TREE_CODE (rhs
) == CONSTRUCTOR
)
3659 unsigned HOST_WIDE_INT cnt
;
3662 FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (rhs
), cnt
, field
, val
)
3664 if (chkp_type_has_pointer (TREE_TYPE (field
)))
3666 tree lhs_field
= chkp_build_component_ref (lhs
, field
);
3667 chkp_walk_pointer_assignments (lhs_field
, val
, arg
, handler
);
3672 for (field
= TYPE_FIELDS (type
); field
; field
= DECL_CHAIN (field
))
3673 if (TREE_CODE (field
) == FIELD_DECL
3674 && chkp_type_has_pointer (TREE_TYPE (field
)))
3676 tree rhs_field
= chkp_build_component_ref (rhs
, field
);
3677 tree lhs_field
= chkp_build_component_ref (lhs
, field
);
3678 chkp_walk_pointer_assignments (lhs_field
, rhs_field
, arg
, handler
);
3681 else if (TREE_CODE (type
) == ARRAY_TYPE
)
3683 unsigned HOST_WIDE_INT cur
= 0;
3684 tree maxval
= TYPE_MAX_VALUE (TYPE_DOMAIN (type
));
3685 tree etype
= TREE_TYPE (type
);
3686 tree esize
= TYPE_SIZE (etype
);
3688 if (TREE_CODE (rhs
) == CONSTRUCTOR
)
3690 unsigned HOST_WIDE_INT cnt
;
3691 tree purp
, val
, lhs_elem
;
3693 FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (rhs
), cnt
, purp
, val
)
3695 if (purp
&& TREE_CODE (purp
) == RANGE_EXPR
)
3697 tree lo_index
= TREE_OPERAND (purp
, 0);
3698 tree hi_index
= TREE_OPERAND (purp
, 1);
3700 for (cur
= (unsigned)tree_to_uhwi (lo_index
);
3701 cur
<= (unsigned)tree_to_uhwi (hi_index
);
3704 lhs_elem
= chkp_build_array_ref (lhs
, etype
, esize
, cur
);
3705 chkp_walk_pointer_assignments (lhs_elem
, val
, arg
, handler
);
3712 gcc_assert (TREE_CODE (purp
) == INTEGER_CST
);
3713 cur
= tree_to_uhwi (purp
);
3716 lhs_elem
= chkp_build_array_ref (lhs
, etype
, esize
, cur
++);
3718 chkp_walk_pointer_assignments (lhs_elem
, val
, arg
, handler
);
3722 /* Copy array only when size is known. */
3723 else if (maxval
&& !integer_minus_onep (maxval
))
3724 for (cur
= 0; cur
<= TREE_INT_CST_LOW (maxval
); cur
++)
3726 tree lhs_elem
= chkp_build_array_ref (lhs
, etype
, esize
, cur
);
3727 tree rhs_elem
= chkp_build_array_ref (rhs
, etype
, esize
, cur
);
3728 chkp_walk_pointer_assignments (lhs_elem
, rhs_elem
, arg
, handler
);
3732 internal_error("chkp_walk_pointer_assignments: unexpected RHS type: %s",
3733 get_tree_code_name (TREE_CODE (type
)));
3736 /* Add code to copy bounds for assignment of RHS to LHS.
3737 ARG is an iterator pointing ne code position. */
3739 chkp_copy_bounds_for_elem (tree lhs
, tree rhs
, void *arg
)
3741 gimple_stmt_iterator
*iter
= (gimple_stmt_iterator
*)arg
;
3742 tree bounds
= chkp_find_bounds (rhs
, iter
);
3743 tree addr
= chkp_build_addr_expr(lhs
);
3745 chkp_build_bndstx (addr
, rhs
, bounds
, iter
);
3748 /* Emit static bound initilizers and size vars. */
3750 chkp_finish_file (void)
3752 struct varpool_node
*node
;
3753 struct chkp_ctor_stmt_list stmts
;
3758 /* Iterate through varpool and generate bounds initialization
3759 constructors for all statically initialized pointers. */
3760 stmts
.avail
= MAX_STMTS_IN_STATIC_CHKP_CTOR
;
3762 FOR_EACH_VARIABLE (node
)
3763 /* Check that var is actually emitted and we need and may initialize
3765 if (node
->need_bounds_init
3766 && !POINTER_BOUNDS_P (node
->decl
)
3767 && DECL_RTL (node
->decl
)
3768 && MEM_P (DECL_RTL (node
->decl
))
3769 && TREE_ASM_WRITTEN (node
->decl
))
3771 chkp_walk_pointer_assignments (node
->decl
,
3772 DECL_INITIAL (node
->decl
),
3774 chkp_add_modification_to_stmt_list
);
3776 if (stmts
.avail
<= 0)
3778 cgraph_build_static_cdtor ('P', stmts
.stmts
,
3779 MAX_RESERVED_INIT_PRIORITY
+ 3);
3780 stmts
.avail
= MAX_STMTS_IN_STATIC_CHKP_CTOR
;
3786 cgraph_build_static_cdtor ('P', stmts
.stmts
,
3787 MAX_RESERVED_INIT_PRIORITY
+ 3);
3789 /* Iterate through varpool and generate bounds initialization
3790 constructors for all static bounds vars. */
3791 stmts
.avail
= MAX_STMTS_IN_STATIC_CHKP_CTOR
;
3793 FOR_EACH_VARIABLE (node
)
3794 if (node
->need_bounds_init
3795 && POINTER_BOUNDS_P (node
->decl
)
3796 && TREE_ASM_WRITTEN (node
->decl
))
3798 tree bnd
= node
->decl
;
3801 gcc_assert (DECL_INITIAL (bnd
)
3802 && TREE_CODE (DECL_INITIAL (bnd
)) == ADDR_EXPR
);
3804 var
= TREE_OPERAND (DECL_INITIAL (bnd
), 0);
3805 chkp_output_static_bounds (bnd
, var
, &stmts
);
3809 cgraph_build_static_cdtor ('B', stmts
.stmts
,
3810 MAX_RESERVED_INIT_PRIORITY
+ 2);
3812 delete chkp_static_var_bounds
;
3813 delete chkp_bounds_map
;
3816 /* An instrumentation function which is called for each statement
3817 having memory access we want to instrument. It inserts check
3818 code and bounds copy code.
3820 ITER points to statement to instrument.
3822 NODE holds memory access in statement to check.
3824 LOC holds the location information for statement.
3826 DIRFLAGS determines whether access is read or write.
3828 ACCESS_OFFS should be added to address used in NODE
3831 ACCESS_SIZE holds size of checked access.
3833 SAFE indicates if NODE access is safe and should not be
3836 chkp_process_stmt (gimple_stmt_iterator
*iter
, tree node
,
3837 location_t loc
, tree dirflag
,
3838 tree access_offs
, tree access_size
,
3841 tree node_type
= TREE_TYPE (node
);
3842 tree size
= access_size
? access_size
: TYPE_SIZE_UNIT (node_type
);
3843 tree addr_first
= NULL_TREE
; /* address of the first accessed byte */
3844 tree addr_last
= NULL_TREE
; /* address of the last accessed byte */
3845 tree ptr
= NULL_TREE
; /* a pointer used for dereference */
3846 tree bounds
= NULL_TREE
;
3848 /* We do not need instrumentation for clobbers. */
3849 if (dirflag
== integer_one_node
3850 && gimple_code (gsi_stmt (*iter
)) == GIMPLE_ASSIGN
3851 && TREE_CLOBBER_P (gimple_assign_rhs1 (gsi_stmt (*iter
))))
3854 switch (TREE_CODE (node
))
3864 /* We are not going to generate any checks, so do not
3865 generate bounds as well. */
3866 addr_first
= chkp_build_addr_expr (node
);
3870 chkp_parse_array_and_component_ref (node
, &ptr
, &elt
, &safe
,
3871 &bitfield
, &bounds
, iter
, false);
3873 /* Break if there is no dereference and operation is safe. */
3877 tree field
= TREE_OPERAND (node
, 1);
3879 if (TREE_CODE (DECL_SIZE_UNIT (field
)) == INTEGER_CST
)
3880 size
= DECL_SIZE_UNIT (field
);
3883 elt
= chkp_build_addr_expr (elt
);
3884 addr_first
= fold_convert_loc (loc
, ptr_type_node
, elt
? elt
: ptr
);
3885 addr_first
= fold_build_pointer_plus_loc (loc
,
3887 byte_position (field
));
3890 addr_first
= chkp_build_addr_expr (node
);
3895 ptr
= TREE_OPERAND (node
, 0);
3900 ptr
= TREE_OPERAND (node
, 0);
3901 addr_first
= chkp_build_addr_expr (node
);
3904 case TARGET_MEM_REF
:
3905 ptr
= TMR_BASE (node
);
3906 addr_first
= chkp_build_addr_expr (node
);
3909 case ARRAY_RANGE_REF
:
3910 printf("ARRAY_RANGE_REF\n");
3911 debug_gimple_stmt(gsi_stmt(*iter
));
3918 tree offs
, rem
, bpu
;
3920 gcc_assert (!access_offs
);
3921 gcc_assert (!access_size
);
3923 bpu
= fold_convert (size_type_node
, bitsize_int (BITS_PER_UNIT
));
3924 offs
= fold_convert (size_type_node
, TREE_OPERAND (node
, 2));
3925 rem
= size_binop_loc (loc
, TRUNC_MOD_EXPR
, offs
, bpu
);
3926 offs
= size_binop_loc (loc
, TRUNC_DIV_EXPR
, offs
, bpu
);
3928 size
= fold_convert (size_type_node
, TREE_OPERAND (node
, 1));
3929 size
= size_binop_loc (loc
, PLUS_EXPR
, size
, rem
);
3930 size
= size_binop_loc (loc
, CEIL_DIV_EXPR
, size
, bpu
);
3931 size
= fold_convert (size_type_node
, size
);
3933 chkp_process_stmt (iter
, TREE_OPERAND (node
, 0), loc
,
3934 dirflag
, offs
, size
, safe
);
3942 if (dirflag
!= integer_one_node
3943 || DECL_REGISTER (node
))
3947 addr_first
= chkp_build_addr_expr (node
);
3954 /* If addr_last was not computed then use (addr_first + size - 1)
3955 expression to compute it. */
3958 addr_last
= fold_build_pointer_plus_loc (loc
, addr_first
, size
);
3959 addr_last
= fold_build_pointer_plus_hwi_loc (loc
, addr_last
, -1);
3962 /* Shift both first_addr and last_addr by access_offs if specified. */
3965 addr_first
= fold_build_pointer_plus_loc (loc
, addr_first
, access_offs
);
3966 addr_last
= fold_build_pointer_plus_loc (loc
, addr_last
, access_offs
);
3969 /* Generate bndcl/bndcu checks if memory access is not safe. */
3972 gimple_stmt_iterator stmt_iter
= *iter
;
3975 bounds
= chkp_find_bounds (ptr
, iter
);
3977 chkp_check_mem_access (addr_first
, addr_last
, bounds
,
3978 stmt_iter
, loc
, dirflag
);
3981 /* We need to store bounds in case pointer is stored. */
3982 if (dirflag
== integer_one_node
3983 && chkp_type_has_pointer (node_type
)
3984 && flag_chkp_store_bounds
)
3986 gimple stmt
= gsi_stmt (*iter
);
3987 tree rhs1
= gimple_assign_rhs1 (stmt
);
3988 enum tree_code rhs_code
= gimple_assign_rhs_code (stmt
);
3990 if (get_gimple_rhs_class (rhs_code
) == GIMPLE_SINGLE_RHS
)
3991 chkp_walk_pointer_assignments (node
, rhs1
, iter
,
3992 chkp_copy_bounds_for_elem
);
3995 bounds
= chkp_compute_bounds_for_assignment (NULL_TREE
, stmt
);
3996 chkp_build_bndstx (addr_first
, rhs1
, bounds
, iter
);
4001 /* Add code to copy bounds for all pointers copied
4002 in ASSIGN created during inline of EDGE. */
4004 chkp_copy_bounds_for_assign (gimple assign
, struct cgraph_edge
*edge
)
4006 tree lhs
= gimple_assign_lhs (assign
);
4007 tree rhs
= gimple_assign_rhs1 (assign
);
4008 gimple_stmt_iterator iter
= gsi_for_stmt (assign
);
4010 if (!flag_chkp_store_bounds
)
4013 chkp_walk_pointer_assignments (lhs
, rhs
, &iter
, chkp_copy_bounds_for_elem
);
4015 /* We should create edges for all created calls to bndldx and bndstx. */
4016 while (gsi_stmt (iter
) != assign
)
4018 gimple stmt
= gsi_stmt (iter
);
4019 if (gimple_code (stmt
) == GIMPLE_CALL
)
4021 tree fndecl
= gimple_call_fndecl (stmt
);
4022 struct cgraph_node
*callee
= cgraph_node::get_create (fndecl
);
4023 struct cgraph_edge
*new_edge
;
4025 gcc_assert (fndecl
== chkp_bndstx_fndecl
4026 || fndecl
== chkp_bndldx_fndecl
4027 || fndecl
== chkp_ret_bnd_fndecl
);
4029 new_edge
= edge
->caller
->create_edge (callee
,
4030 as_a
<gcall
*> (stmt
),
4033 new_edge
->frequency
= compute_call_stmt_bb_frequency
4034 (edge
->caller
->decl
, gimple_bb (stmt
));
4040 /* Some code transformation made during instrumentation pass
4041 may put code into inconsistent state. Here we find and fix
4047 gimple_stmt_iterator i
;
4049 /* We could insert some code right after stmt which ends bb.
4050 We wanted to put this code on fallthru edge but did not
4051 add new edges from the beginning because it may cause new
4052 phi node creation which may be incorrect due to incomplete
4054 FOR_ALL_BB_FN (bb
, cfun
)
4055 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); gsi_next (&i
))
4057 gimple stmt
= gsi_stmt (i
);
4058 gimple_stmt_iterator next
= i
;
4062 if (stmt_ends_bb_p (stmt
)
4063 && !gsi_end_p (next
))
4065 edge fall
= find_fallthru_edge (bb
->succs
);
4066 basic_block dest
= NULL
;
4071 /* We cannot split abnormal edge. Therefore we
4072 store its params, make it regular and then
4073 rebuild abnormal edge after split. */
4074 if (fall
->flags
& EDGE_ABNORMAL
)
4076 flags
= fall
->flags
& ~EDGE_FALLTHRU
;
4079 fall
->flags
&= ~EDGE_COMPLEX
;
4082 while (!gsi_end_p (next
))
4084 gimple next_stmt
= gsi_stmt (next
);
4085 gsi_remove (&next
, false);
4086 gsi_insert_on_edge (fall
, next_stmt
);
4089 gsi_commit_edge_inserts ();
4091 /* Re-create abnormal edge. */
4093 make_edge (bb
, dest
, flags
);
4098 /* Walker callback for chkp_replace_function_pointers. Replaces
4099 function pointer in the specified operand with pointer to the
4100 instrumented function version. */
4102 chkp_replace_function_pointer (tree
*op
, int *walk_subtrees
,
4103 void *data ATTRIBUTE_UNUSED
)
4105 if (TREE_CODE (*op
) == FUNCTION_DECL
4106 && chkp_instrumentable_p (*op
)
4107 && (DECL_BUILT_IN_CLASS (*op
) == NOT_BUILT_IN
4108 /* For builtins we replace pointers only for selected
4109 function and functions having definitions. */
4110 || (DECL_BUILT_IN_CLASS (*op
) == BUILT_IN_NORMAL
4111 && (chkp_instrument_normal_builtin (*op
)
4112 || gimple_has_body_p (*op
)))))
4114 struct cgraph_node
*node
= cgraph_node::get_create (*op
);
4115 struct cgraph_node
*clone
= NULL
;
4117 if (!node
->instrumentation_clone
)
4118 clone
= chkp_maybe_create_clone (*op
);
4128 /* This function searches for function pointers in statement
4129 pointed by GSI and replaces them with pointers to instrumented
4130 function versions. */
4132 chkp_replace_function_pointers (gimple_stmt_iterator
*gsi
)
4134 gimple stmt
= gsi_stmt (*gsi
);
4135 /* For calls we want to walk call args only. */
4136 if (gimple_code (stmt
) == GIMPLE_CALL
)
4139 for (i
= 0; i
< gimple_call_num_args (stmt
); i
++)
4140 walk_tree (gimple_call_arg_ptr (stmt
, i
),
4141 chkp_replace_function_pointer
, NULL
, NULL
);
4144 walk_gimple_stmt (gsi
, NULL
, chkp_replace_function_pointer
, NULL
);
4147 /* This function instruments all statements working with memory,
4150 It also removes excess statements from static initializers. */
4152 chkp_instrument_function (void)
4154 basic_block bb
, next
;
4155 gimple_stmt_iterator i
;
4156 enum gimple_rhs_class grhs_class
;
4157 bool safe
= lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun
->decl
));
4159 bb
= ENTRY_BLOCK_PTR_FOR_FN (cfun
)->next_bb
;
4163 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); )
4165 gimple s
= gsi_stmt (i
);
4167 /* Skip statement marked to not be instrumented. */
4168 if (chkp_marked_stmt_p (s
))
4174 chkp_replace_function_pointers (&i
);
4176 switch (gimple_code (s
))
4179 chkp_process_stmt (&i
, gimple_assign_lhs (s
),
4180 gimple_location (s
), integer_one_node
,
4181 NULL_TREE
, NULL_TREE
, safe
);
4182 chkp_process_stmt (&i
, gimple_assign_rhs1 (s
),
4183 gimple_location (s
), integer_zero_node
,
4184 NULL_TREE
, NULL_TREE
, safe
);
4185 grhs_class
= get_gimple_rhs_class (gimple_assign_rhs_code (s
));
4186 if (grhs_class
== GIMPLE_BINARY_RHS
)
4187 chkp_process_stmt (&i
, gimple_assign_rhs2 (s
),
4188 gimple_location (s
), integer_zero_node
,
4189 NULL_TREE
, NULL_TREE
, safe
);
4194 greturn
*r
= as_a
<greturn
*> (s
);
4195 if (gimple_return_retval (r
) != NULL_TREE
)
4197 chkp_process_stmt (&i
, gimple_return_retval (r
),
4198 gimple_location (r
),
4200 NULL_TREE
, NULL_TREE
, safe
);
4202 /* Additionally we need to add bounds
4203 to return statement. */
4204 chkp_add_bounds_to_ret_stmt (&i
);
4210 chkp_add_bounds_to_call_stmt (&i
);
4219 /* We do not need any actual pointer stores in checker
4220 static initializer. */
4221 if (lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun
->decl
))
4222 && gimple_code (s
) == GIMPLE_ASSIGN
4223 && gimple_store_p (s
))
4225 gimple_stmt_iterator del_iter
= gsi_for_stmt (s
);
4226 gsi_remove (&del_iter
, true);
4227 unlink_stmt_vdef (s
);
4235 /* Some input params may have bounds and be address taken. In this case
4236 we should store incoming bounds into bounds table. */
4238 if (flag_chkp_store_bounds
)
4239 for (arg
= DECL_ARGUMENTS (cfun
->decl
); arg
; arg
= DECL_CHAIN (arg
))
4240 if (TREE_ADDRESSABLE (arg
))
4242 if (BOUNDED_P (arg
))
4244 tree bounds
= chkp_get_next_bounds_parm (arg
);
4245 tree def_ptr
= ssa_default_def (cfun
, arg
);
4246 gimple_stmt_iterator iter
4247 = gsi_start_bb (chkp_get_entry_block ());
4248 chkp_build_bndstx (chkp_build_addr_expr (arg
),
4249 def_ptr
? def_ptr
: arg
,
4252 /* Skip bounds arg. */
4253 arg
= TREE_CHAIN (arg
);
4255 else if (chkp_type_has_pointer (TREE_TYPE (arg
)))
4257 tree orig_arg
= arg
;
4258 bitmap slots
= BITMAP_ALLOC (NULL
);
4259 gimple_stmt_iterator iter
4260 = gsi_start_bb (chkp_get_entry_block ());
4264 chkp_find_bound_slots (TREE_TYPE (arg
), slots
);
4266 EXECUTE_IF_SET_IN_BITMAP (slots
, 0, bnd_no
, bi
)
4268 tree bounds
= chkp_get_next_bounds_parm (arg
);
4269 HOST_WIDE_INT offs
= bnd_no
* POINTER_SIZE
/ BITS_PER_UNIT
;
4270 tree addr
= chkp_build_addr_expr (orig_arg
);
4271 tree ptr
= build2 (MEM_REF
, ptr_type_node
, addr
,
4272 build_int_cst (ptr_type_node
, offs
));
4273 chkp_build_bndstx (chkp_build_addr_expr (ptr
), ptr
,
4276 arg
= DECL_CHAIN (arg
);
4278 BITMAP_FREE (slots
);
4283 /* Find init/null/copy_ptr_bounds calls and replace them
4284 with assignments. It should allow better code
4288 chkp_remove_useless_builtins ()
4291 gimple_stmt_iterator gsi
;
4293 FOR_EACH_BB_FN (bb
, cfun
)
4295 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
4297 gimple stmt
= gsi_stmt (gsi
);
4299 enum built_in_function fcode
;
4301 /* Find builtins returning first arg and replace
4302 them with assignments. */
4303 if (gimple_code (stmt
) == GIMPLE_CALL
4304 && (fndecl
= gimple_call_fndecl (stmt
))
4305 && DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
4306 && (fcode
= DECL_FUNCTION_CODE (fndecl
))
4307 && (fcode
== BUILT_IN_CHKP_INIT_PTR_BOUNDS
4308 || fcode
== BUILT_IN_CHKP_NULL_PTR_BOUNDS
4309 || fcode
== BUILT_IN_CHKP_COPY_PTR_BOUNDS
4310 || fcode
== BUILT_IN_CHKP_SET_PTR_BOUNDS
))
4312 tree res
= gimple_call_arg (stmt
, 0);
4313 update_call_from_tree (&gsi
, res
);
4314 stmt
= gsi_stmt (gsi
);
4321 /* Initialize pass. */
4326 gimple_stmt_iterator i
;
4328 in_chkp_pass
= true;
4330 for (bb
= ENTRY_BLOCK_PTR_FOR_FN (cfun
)->next_bb
; bb
; bb
= bb
->next_bb
)
4331 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); gsi_next (&i
))
4332 chkp_unmark_stmt (gsi_stmt (i
));
4334 chkp_invalid_bounds
= new hash_set
<tree
>;
4335 chkp_completed_bounds_set
= new hash_set
<tree
>;
4336 delete chkp_reg_bounds
;
4337 chkp_reg_bounds
= new hash_map
<tree
, tree
>;
4338 delete chkp_bound_vars
;
4339 chkp_bound_vars
= new hash_map
<tree
, tree
>;
4340 chkp_reg_addr_bounds
= new hash_map
<tree
, tree
>;
4341 chkp_incomplete_bounds_map
= new hash_map
<tree
, tree
>;
4342 delete chkp_bounds_map
;
4343 chkp_bounds_map
= new hash_map
<tree
, tree
>;
4344 chkp_abnormal_copies
= BITMAP_GGC_ALLOC ();
4347 zero_bounds
= NULL_TREE
;
4348 none_bounds
= NULL_TREE
;
4349 incomplete_bounds
= integer_zero_node
;
4350 tmp_var
= NULL_TREE
;
4351 size_tmp_var
= NULL_TREE
;
4353 chkp_uintptr_type
= lang_hooks
.types
.type_for_mode (ptr_mode
, true);
4355 /* We create these constant bounds once for each object file.
4356 These symbols go to comdat section and result in single copy
4357 of each one in the final binary. */
4358 chkp_get_zero_bounds_var ();
4359 chkp_get_none_bounds_var ();
4361 calculate_dominance_info (CDI_DOMINATORS
);
4362 calculate_dominance_info (CDI_POST_DOMINATORS
);
4364 bitmap_obstack_initialize (NULL
);
4367 /* Finalize instrumentation pass. */
4371 in_chkp_pass
= false;
4373 delete chkp_invalid_bounds
;
4374 delete chkp_completed_bounds_set
;
4375 delete chkp_reg_addr_bounds
;
4376 delete chkp_incomplete_bounds_map
;
4378 free_dominance_info (CDI_DOMINATORS
);
4379 free_dominance_info (CDI_POST_DOMINATORS
);
4381 bitmap_obstack_release (NULL
);
4384 zero_bounds
= NULL_TREE
;
4385 none_bounds
= NULL_TREE
;
4388 /* Main instrumentation pass function. */
4394 chkp_instrument_function ();
4396 chkp_remove_useless_builtins ();
4398 chkp_function_mark_instrumented (cfun
->decl
);
4407 /* Instrumentation pass gate. */
4411 cgraph_node
*node
= cgraph_node::get (cfun
->decl
);
4412 return ((node
!= NULL
4413 && node
->instrumentation_clone
)
4414 || lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun
->decl
)));
4419 const pass_data pass_data_chkp
=
4421 GIMPLE_PASS
, /* type */
4423 OPTGROUP_NONE
, /* optinfo_flags */
4424 TV_NONE
, /* tv_id */
4425 PROP_ssa
| PROP_cfg
, /* properties_required */
4426 0, /* properties_provided */
4427 0, /* properties_destroyed */
4428 0, /* todo_flags_start */
4430 | TODO_update_ssa
/* todo_flags_finish */
4433 class pass_chkp
: public gimple_opt_pass
4436 pass_chkp (gcc::context
*ctxt
)
4437 : gimple_opt_pass (pass_data_chkp
, ctxt
)
4440 /* opt_pass methods: */
4441 virtual opt_pass
* clone ()
4443 return new pass_chkp (m_ctxt
);
4446 virtual bool gate (function
*)
4448 return chkp_gate ();
4451 virtual unsigned int execute (function
*)
4453 return chkp_execute ();
4456 }; // class pass_chkp
4461 make_pass_chkp (gcc::context
*ctxt
)
4463 return new pass_chkp (ctxt
);
4466 #include "gt-tree-chkp.h"