2 * Copyright 2014-2016 by Open Source Security, Inc., Brad Spengler <spender@grsecurity.net>
3 * and PaX Team <pageexec@freemail.hu>
4 * Licensed under the GPL v2
6 * Note: the choice of the license means that the compilation process is
7 * NOT 'eligible' as defined by gcc's library exception to the GPL v3,
8 * but for the kernel it doesn't matter since it doesn't link against
9 * any of the gcc libraries
12 * $ # for 4.5/4.6/C based 4.7
13 * $ gcc -I`gcc -print-file-name=plugin`/include -I`gcc -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o randomize_layout_plugin.so randomize_layout_plugin.c
14 * $ # for C++ based 4.7/4.8+
15 * $ g++ -I`g++ -print-file-name=plugin`/include -I`g++ -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o randomize_layout_plugin.so randomize_layout_plugin.c
16 * $ gcc -fplugin=./randomize_layout_plugin.so test.c -O2
19 #include "gcc-common.h"
20 #include "randomize_layout_seed.h"
22 #define ORIG_TYPE_NAME(node) \
23 (TYPE_NAME(TYPE_MAIN_VARIANT(node)) != NULL_TREE ? ((const unsigned char *)IDENTIFIER_POINTER(TYPE_NAME(TYPE_MAIN_VARIANT(node)))) : (const unsigned char *)"anonymous")
25 #define INFORM(loc, msg, ...) inform(loc, "randstruct: " msg, ##__VA_ARGS__)
26 #define MISMATCH(loc, how, ...) INFORM(loc, "casting between randomized structure pointer types (" how "): %qT and %qT\n", __VA_ARGS__)
28 __visible
int plugin_is_GPL_compatible
;
30 static int performance_mode
;
32 static struct plugin_info randomize_layout_plugin_info
= {
33 .version
= PLUGIN_VERSION
,
34 .help
= "disable\t\t\tdo not activate plugin\n"
35 "performance-mode\tenable cacheline-aware layout randomization\n"
38 /* from old Linux dcache.h */
39 static inline unsigned long
40 partial_name_hash(unsigned long c
, unsigned long prevhash
)
42 return (prevhash
+ (c
<< 4) + (c
>> 4)) * 11;
44 static inline unsigned int
45 name_hash(const unsigned char *name
)
47 unsigned long hash
= 0;
48 unsigned int len
= strlen((const char *)name
);
50 hash
= partial_name_hash(*name
++, hash
);
51 return (unsigned int)hash
;
54 static tree
handle_randomize_layout_attr(tree
*node
, tree name
, tree args
, int flags
, bool *no_add_attrs
)
59 if (TREE_CODE(*node
) == FUNCTION_DECL
) {
60 error("%qE attribute does not apply to functions (%qF)", name
, *node
);
64 if (TREE_CODE(*node
) == PARM_DECL
) {
65 error("%qE attribute does not apply to function parameters (%qD)", name
, *node
);
69 if (TREE_CODE(*node
) == VAR_DECL
) {
70 error("%qE attribute does not apply to variables (%qD)", name
, *node
);
77 gcc_assert(TREE_CODE(*node
) == TYPE_DECL
);
78 type
= TREE_TYPE(*node
);
81 if (TREE_CODE(type
) != RECORD_TYPE
) {
82 error("%qE attribute used on %qT applies to struct types only", name
, type
);
86 if (lookup_attribute(IDENTIFIER_POINTER(name
), TYPE_ATTRIBUTES(type
))) {
87 error("%qE attribute is already applied to the type %qT", name
, type
);
91 *no_add_attrs
= false;
96 /* set on complete types that we don't need to inspect further at all */
97 static tree
handle_randomize_considered_attr(tree
*node
, tree name
, tree args
, int flags
, bool *no_add_attrs
)
99 *no_add_attrs
= false;
104 * set on types that we've performed a shuffle on, to prevent re-shuffling
105 * this does not preclude us from inspecting its fields for potential shuffles
107 static tree
handle_randomize_performed_attr(tree
*node
, tree name
, tree args
, int flags
, bool *no_add_attrs
)
109 *no_add_attrs
= false;
114 * 64bit variant of Bob Jenkins' public domain PRNG
115 * 256 bits of internal state
118 typedef unsigned long long u64
;
120 typedef struct ranctx
{ u64 a
; u64 b
; u64 c
; u64 d
; } ranctx
;
122 #define rot(x,k) (((x)<<(k))|((x)>>(64-(k))))
123 static u64
ranval(ranctx
*x
) {
124 u64 e
= x
->a
- rot(x
->b
, 7);
125 x
->a
= x
->b
^ rot(x
->c
, 13);
126 x
->b
= x
->c
+ rot(x
->d
, 37);
132 static void raninit(ranctx
*x
, u64
*seed
) {
140 for (i
=0; i
< 30; ++i
)
144 static u64 shuffle_seed
[4];
146 struct partition_group
{
149 unsigned long length
;
152 static void partition_struct(tree
*fields
, unsigned long length
, struct partition_group
*size_groups
, unsigned long *num_groups
)
155 unsigned long accum_size
= 0;
156 unsigned long accum_length
= 0;
157 unsigned long group_idx
= 0;
159 gcc_assert(length
< INT_MAX
);
161 memset(size_groups
, 0, sizeof(struct partition_group
) * length
);
163 for (i
= 0; i
< length
; i
++) {
164 if (size_groups
[group_idx
].tree_start
== NULL_TREE
) {
165 size_groups
[group_idx
].tree_start
= fields
[i
];
166 size_groups
[group_idx
].start
= i
;
170 accum_size
+= (unsigned long)int_size_in_bytes(TREE_TYPE(fields
[i
]));
172 if (accum_size
>= 64) {
173 size_groups
[group_idx
].length
= accum_length
;
179 if (size_groups
[group_idx
].tree_start
!= NULL_TREE
&&
180 !size_groups
[group_idx
].length
) {
181 size_groups
[group_idx
].length
= accum_length
;
185 *num_groups
= group_idx
;
188 static void performance_shuffle(tree
*newtree
, unsigned long length
, ranctx
*prng_state
)
190 unsigned long i
, x
, index
;
191 struct partition_group size_group
[length
];
192 unsigned long num_groups
= 0;
193 unsigned long randnum
;
195 partition_struct(newtree
, length
, (struct partition_group
*)&size_group
, &num_groups
);
197 /* FIXME: this group shuffle is currently a no-op. */
198 for (i
= num_groups
- 1; i
> 0; i
--) {
199 struct partition_group tmp
;
200 randnum
= ranval(prng_state
) % (i
+ 1);
202 size_group
[i
] = size_group
[randnum
];
203 size_group
[randnum
] = tmp
;
206 for (x
= 0; x
< num_groups
; x
++) {
207 for (index
= size_group
[x
].length
- 1; index
> 0; index
--) {
210 i
= size_group
[x
].start
+ index
;
211 if (DECL_BIT_FIELD_TYPE(newtree
[i
]))
213 randnum
= ranval(prng_state
) % (index
+ 1);
214 randnum
+= size_group
[x
].start
;
215 // we could handle this case differently if desired
216 if (DECL_BIT_FIELD_TYPE(newtree
[randnum
]))
219 newtree
[i
] = newtree
[randnum
];
220 newtree
[randnum
] = tmp
;
225 static void full_shuffle(tree
*newtree
, unsigned long length
, ranctx
*prng_state
)
227 unsigned long i
, randnum
;
229 for (i
= length
- 1; i
> 0; i
--) {
231 randnum
= ranval(prng_state
) % (i
+ 1);
233 newtree
[i
] = newtree
[randnum
];
234 newtree
[randnum
] = tmp
;
238 /* modern in-place Fisher-Yates shuffle */
239 static void shuffle(const_tree type
, tree
*newtree
, unsigned long length
)
244 const unsigned char *structname
;
249 gcc_assert(TREE_CODE(type
) == RECORD_TYPE
);
251 structname
= ORIG_TYPE_NAME(type
);
253 #ifdef __DEBUG_PLUGIN
254 fprintf(stderr
, "Shuffling struct %s %p\n", (const char *)structname
, type
);
255 #ifdef __DEBUG_VERBOSE
256 debug_tree((tree
)type
);
260 for (i
= 0; i
< 4; i
++) {
261 seed
[i
] = shuffle_seed
[i
];
262 seed
[i
] ^= name_hash(structname
);
265 raninit(&prng_state
, (u64
*)&seed
);
267 if (performance_mode
)
268 performance_shuffle(newtree
, length
, &prng_state
);
270 full_shuffle(newtree
, length
, &prng_state
);
273 static bool is_flexible_array(const_tree field
)
275 const_tree fieldtype
;
278 fieldtype
= TREE_TYPE(field
);
279 typesize
= TYPE_SIZE(fieldtype
);
281 if (TREE_CODE(fieldtype
) != ARRAY_TYPE
)
284 /* size of type is represented in bits */
286 if (typesize
== NULL_TREE
&& TYPE_DOMAIN(fieldtype
) != NULL_TREE
&&
287 TYPE_MAX_VALUE(TYPE_DOMAIN(fieldtype
)) == NULL_TREE
)
293 static int relayout_struct(tree type
)
295 unsigned long num_fields
= (unsigned long)list_length(TYPE_FIELDS(type
));
296 unsigned long shuffle_length
= num_fields
;
298 tree newtree
[num_fields
];
303 expanded_location xloc
;
304 bool has_flexarray
= false;
306 if (TYPE_FIELDS(type
) == NULL_TREE
)
312 gcc_assert(TREE_CODE(type
) == RECORD_TYPE
);
314 gcc_assert(num_fields
< INT_MAX
);
316 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type
)) ||
317 lookup_attribute("no_randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type
))))
320 /* Workaround for 3rd-party VirtualBox source that we can't modify ourselves */
321 if (!strcmp((const char *)ORIG_TYPE_NAME(type
), "INTNETTRUNKFACTORY") ||
322 !strcmp((const char *)ORIG_TYPE_NAME(type
), "RAWPCIFACTORY"))
325 /* throw out any structs in uapi */
326 xloc
= expand_location(DECL_SOURCE_LOCATION(TYPE_FIELDS(type
)));
328 if (strstr(xloc
.file
, "/uapi/"))
329 error(G_("attempted to randomize userland API struct %s"), ORIG_TYPE_NAME(type
));
331 for (field
= TYPE_FIELDS(type
), i
= 0; field
; field
= TREE_CHAIN(field
), i
++) {
332 gcc_assert(TREE_CODE(field
) == FIELD_DECL
);
337 * enforce that we don't randomize the layout of the last
338 * element of a struct if it's a proper flexible array
340 if (is_flexible_array(newtree
[num_fields
- 1])) {
341 has_flexarray
= true;
345 shuffle(type
, (tree
*)newtree
, shuffle_length
);
348 * set up a bogus anonymous struct field designed to error out on unnamed struct initializers
349 * as gcc provides no other way to detect such code
351 list
= make_node(FIELD_DECL
);
352 TREE_CHAIN(list
) = newtree
[0];
353 TREE_TYPE(list
) = void_type_node
;
354 DECL_SIZE(list
) = bitsize_zero_node
;
355 DECL_NONADDRESSABLE_P(list
) = 1;
356 DECL_FIELD_BIT_OFFSET(list
) = bitsize_zero_node
;
357 DECL_SIZE_UNIT(list
) = size_zero_node
;
358 DECL_FIELD_OFFSET(list
) = size_zero_node
;
359 DECL_CONTEXT(list
) = type
;
360 // to satisfy the constify plugin
361 TREE_READONLY(list
) = 1;
363 for (i
= 0; i
< num_fields
- 1; i
++)
364 TREE_CHAIN(newtree
[i
]) = newtree
[i
+1];
365 TREE_CHAIN(newtree
[num_fields
- 1]) = NULL_TREE
;
367 main_variant
= TYPE_MAIN_VARIANT(type
);
368 for (variant
= main_variant
; variant
; variant
= TYPE_NEXT_VARIANT(variant
)) {
369 TYPE_FIELDS(variant
) = list
;
370 TYPE_ATTRIBUTES(variant
) = copy_list(TYPE_ATTRIBUTES(variant
));
371 TYPE_ATTRIBUTES(variant
) = tree_cons(get_identifier("randomize_performed"), NULL_TREE
, TYPE_ATTRIBUTES(variant
));
372 TYPE_ATTRIBUTES(variant
) = tree_cons(get_identifier("designated_init"), NULL_TREE
, TYPE_ATTRIBUTES(variant
));
374 TYPE_ATTRIBUTES(type
) = tree_cons(get_identifier("has_flexarray"), NULL_TREE
, TYPE_ATTRIBUTES(type
));
378 * force a re-layout of the main variant
379 * the TYPE_SIZE for all variants will be recomputed
380 * by finalize_type_size()
382 TYPE_SIZE(main_variant
) = NULL_TREE
;
383 layout_type(main_variant
);
384 gcc_assert(TYPE_SIZE(main_variant
) != NULL_TREE
);
389 /* from constify plugin */
390 static const_tree
get_field_type(const_tree field
)
392 return strip_array_types(TREE_TYPE(field
));
395 /* from constify plugin */
396 static bool is_fptr(const_tree fieldtype
)
398 if (TREE_CODE(fieldtype
) != POINTER_TYPE
)
401 return TREE_CODE(TREE_TYPE(fieldtype
)) == FUNCTION_TYPE
;
404 /* derived from constify plugin */
405 static int is_pure_ops_struct(const_tree node
)
409 gcc_assert(TREE_CODE(node
) == RECORD_TYPE
|| TREE_CODE(node
) == UNION_TYPE
);
411 for (field
= TYPE_FIELDS(node
); field
; field
= TREE_CHAIN(field
)) {
412 const_tree fieldtype
= get_field_type(field
);
413 enum tree_code code
= TREE_CODE(fieldtype
);
415 if (node
== fieldtype
)
418 if (code
== RECORD_TYPE
|| code
== UNION_TYPE
) {
419 if (!is_pure_ops_struct(fieldtype
))
424 if (!is_fptr(fieldtype
))
431 static void randomize_type(tree type
)
435 gcc_assert(TREE_CODE(type
) == RECORD_TYPE
);
437 if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type
)))
440 if (lookup_attribute("randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type
))) || is_pure_ops_struct(type
))
441 relayout_struct(type
);
443 for (variant
= TYPE_MAIN_VARIANT(type
); variant
; variant
= TYPE_NEXT_VARIANT(variant
)) {
444 TYPE_ATTRIBUTES(type
) = copy_list(TYPE_ATTRIBUTES(type
));
445 TYPE_ATTRIBUTES(type
) = tree_cons(get_identifier("randomize_considered"), NULL_TREE
, TYPE_ATTRIBUTES(type
));
447 #ifdef __DEBUG_PLUGIN
448 fprintf(stderr
, "Marking randomize_considered on struct %s\n", ORIG_TYPE_NAME(type
));
449 #ifdef __DEBUG_VERBOSE
455 static void update_decl_size(tree decl
)
457 tree lastval
, lastidx
, field
, init
, type
, flexsize
;
458 unsigned HOST_WIDE_INT len
;
460 type
= TREE_TYPE(decl
);
462 if (!lookup_attribute("has_flexarray", TYPE_ATTRIBUTES(type
)))
465 init
= DECL_INITIAL(decl
);
466 if (init
== NULL_TREE
|| init
== error_mark_node
)
469 if (TREE_CODE(init
) != CONSTRUCTOR
)
472 len
= CONSTRUCTOR_NELTS(init
);
476 lastval
= CONSTRUCTOR_ELT(init
, CONSTRUCTOR_NELTS(init
) - 1)->value
;
477 lastidx
= CONSTRUCTOR_ELT(init
, CONSTRUCTOR_NELTS(init
) - 1)->index
;
479 for (field
= TYPE_FIELDS(TREE_TYPE(decl
)); TREE_CHAIN(field
); field
= TREE_CHAIN(field
))
482 if (lastidx
!= field
)
485 if (TREE_CODE(lastval
) != STRING_CST
) {
486 error("Only string constants are supported as initializers "
487 "for randomized structures with flexible arrays");
491 flexsize
= bitsize_int(TREE_STRING_LENGTH(lastval
) *
492 tree_to_uhwi(TYPE_SIZE(TREE_TYPE(TREE_TYPE(lastval
)))));
494 DECL_SIZE(decl
) = size_binop(PLUS_EXPR
, TYPE_SIZE(type
), flexsize
);
500 static void randomize_layout_finish_decl(void *event_data
, void *data
)
502 tree decl
= (tree
)event_data
;
505 if (decl
== NULL_TREE
|| decl
== error_mark_node
)
508 type
= TREE_TYPE(decl
);
510 if (TREE_CODE(decl
) != VAR_DECL
)
513 if (TREE_CODE(type
) != RECORD_TYPE
&& TREE_CODE(type
) != UNION_TYPE
)
516 if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type
)))
520 DECL_SIZE_UNIT(decl
) = 0;
521 SET_DECL_ALIGN(decl
, 0);
522 SET_DECL_MODE (decl
, VOIDmode
);
523 SET_DECL_RTL(decl
, 0);
524 update_decl_size(decl
);
525 layout_decl(decl
, 0);
528 static void finish_type(void *event_data
, void *data
)
530 tree type
= (tree
)event_data
;
532 if (type
== NULL_TREE
|| type
== error_mark_node
)
535 if (TREE_CODE(type
) != RECORD_TYPE
)
538 if (TYPE_FIELDS(type
) == NULL_TREE
)
541 if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type
)))
544 #ifdef __DEBUG_PLUGIN
545 fprintf(stderr
, "Calling randomize_type on %s\n", ORIG_TYPE_NAME(type
));
547 #ifdef __DEBUG_VERBOSE
550 randomize_type(type
);
555 static struct attribute_spec randomize_layout_attr
= { };
556 static struct attribute_spec no_randomize_layout_attr
= { };
557 static struct attribute_spec randomize_considered_attr
= { };
558 static struct attribute_spec randomize_performed_attr
= { };
560 static void register_attributes(void *event_data
, void *data
)
562 randomize_layout_attr
.name
= "randomize_layout";
563 randomize_layout_attr
.type_required
= true;
564 randomize_layout_attr
.handler
= handle_randomize_layout_attr
;
565 randomize_layout_attr
.affects_type_identity
= true;
567 no_randomize_layout_attr
.name
= "no_randomize_layout";
568 no_randomize_layout_attr
.type_required
= true;
569 no_randomize_layout_attr
.handler
= handle_randomize_layout_attr
;
570 no_randomize_layout_attr
.affects_type_identity
= true;
572 randomize_considered_attr
.name
= "randomize_considered";
573 randomize_considered_attr
.type_required
= true;
574 randomize_considered_attr
.handler
= handle_randomize_considered_attr
;
576 randomize_performed_attr
.name
= "randomize_performed";
577 randomize_performed_attr
.type_required
= true;
578 randomize_performed_attr
.handler
= handle_randomize_performed_attr
;
580 register_attribute(&randomize_layout_attr
);
581 register_attribute(&no_randomize_layout_attr
);
582 register_attribute(&randomize_considered_attr
);
583 register_attribute(&randomize_performed_attr
);
586 static void check_bad_casts_in_constructor(tree var
, tree init
)
588 unsigned HOST_WIDE_INT idx
;
590 tree field_type
, val_type
;
592 FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(init
), idx
, field
, val
) {
593 if (TREE_CODE(val
) == CONSTRUCTOR
) {
594 check_bad_casts_in_constructor(var
, val
);
598 /* pipacs' plugin creates franken-arrays that differ from those produced by
599 normal code which all have valid 'field' trees. work around this */
600 if (field
== NULL_TREE
)
602 field_type
= TREE_TYPE(field
);
603 val_type
= TREE_TYPE(val
);
605 if (TREE_CODE(field_type
) != POINTER_TYPE
|| TREE_CODE(val_type
) != POINTER_TYPE
)
608 if (field_type
== val_type
)
611 field_type
= TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(field_type
))));
612 val_type
= TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(val_type
))));
614 if (field_type
== void_type_node
)
616 if (field_type
== val_type
)
618 if (TREE_CODE(val_type
) != RECORD_TYPE
)
621 if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(val_type
)))
623 MISMATCH(DECL_SOURCE_LOCATION(var
), "constructor\n", TYPE_MAIN_VARIANT(field_type
), TYPE_MAIN_VARIANT(val_type
));
627 /* derived from the constify plugin */
628 static void check_global_variables(void *event_data
, void *data
)
630 struct varpool_node
*node
;
633 FOR_EACH_VARIABLE(node
) {
634 tree var
= NODE_DECL(node
);
635 init
= DECL_INITIAL(var
);
636 if (init
== NULL_TREE
)
639 if (TREE_CODE(init
) != CONSTRUCTOR
)
642 check_bad_casts_in_constructor(var
, init
);
646 static bool dominated_by_is_err(const_tree rhs
, basic_block bb
)
652 const_tree poss_is_err_cond
;
653 const_tree poss_is_err_func
;
654 const_tree is_err_arg
;
656 dom
= get_immediate_dominator(CDI_DOMINATORS
, bb
);
660 dom_stmt
= last_stmt(dom
);
664 if (gimple_code(dom_stmt
) != GIMPLE_COND
)
667 if (gimple_cond_code(dom_stmt
) != NE_EXPR
)
670 if (!integer_zerop(gimple_cond_rhs(dom_stmt
)))
673 poss_is_err_cond
= gimple_cond_lhs(dom_stmt
);
675 if (TREE_CODE(poss_is_err_cond
) != SSA_NAME
)
678 call_stmt
= SSA_NAME_DEF_STMT(poss_is_err_cond
);
680 if (gimple_code(call_stmt
) != GIMPLE_CALL
)
683 dom_lhs
= gimple_get_lhs(call_stmt
);
684 poss_is_err_func
= gimple_call_fndecl(call_stmt
);
685 if (!poss_is_err_func
)
687 if (dom_lhs
!= poss_is_err_cond
)
689 if (strcmp(DECL_NAME_POINTER(poss_is_err_func
), "IS_ERR"))
692 is_err_arg
= gimple_call_arg(call_stmt
, 0);
696 if (is_err_arg
!= rhs
)
702 static void handle_local_var_initializers(void)
707 FOR_EACH_LOCAL_DECL(cfun
, i
, var
) {
708 tree init
= DECL_INITIAL(var
);
711 if (TREE_CODE(init
) != CONSTRUCTOR
)
713 check_bad_casts_in_constructor(var
, init
);
718 * iterate over all statements to find "bad" casts:
719 * those where the address of the start of a structure is cast
720 * to a pointer of a structure of a different type, or a
721 * structure pointer type is cast to a different structure pointer type
723 static unsigned int find_bad_casts_execute(void)
727 handle_local_var_initializers();
729 FOR_EACH_BB_FN(bb
, cfun
) {
730 gimple_stmt_iterator gsi
;
732 for (gsi
= gsi_start_bb(bb
); !gsi_end_p(gsi
); gsi_next(&gsi
)) {
738 const_tree ptr_lhs_type
;
739 const_tree ptr_rhs_type
;
742 enum tree_code rhs_code
;
744 stmt
= gsi_stmt(gsi
);
746 #ifdef __DEBUG_PLUGIN
747 #ifdef __DEBUG_VERBOSE
748 debug_gimple_stmt(stmt
);
749 debug_tree(gimple_get_lhs(stmt
));
753 if (gimple_code(stmt
) != GIMPLE_ASSIGN
)
756 #ifdef __DEBUG_PLUGIN
757 #ifdef __DEBUG_VERBOSE
758 debug_tree(gimple_assign_rhs1(stmt
));
763 rhs_code
= gimple_assign_rhs_code(stmt
);
765 if (rhs_code
!= ADDR_EXPR
&& rhs_code
!= SSA_NAME
)
768 lhs
= gimple_get_lhs(stmt
);
769 lhs_type
= TREE_TYPE(lhs
);
770 rhs1
= gimple_assign_rhs1(stmt
);
771 rhs_type
= TREE_TYPE(rhs1
);
773 if (TREE_CODE(rhs_type
) != POINTER_TYPE
||
774 TREE_CODE(lhs_type
) != POINTER_TYPE
)
777 ptr_lhs_type
= TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(lhs_type
))));
778 ptr_rhs_type
= TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(rhs_type
))));
780 if (ptr_rhs_type
== void_type_node
)
783 if (ptr_lhs_type
== void_type_node
)
786 if (dominated_by_is_err(rhs1
, bb
))
789 if (TREE_CODE(ptr_rhs_type
) != RECORD_TYPE
) {
790 #ifndef __DEBUG_PLUGIN
791 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type
)))
793 MISMATCH(gimple_location(stmt
), "rhs", ptr_lhs_type
, ptr_rhs_type
);
797 if (rhs_code
== SSA_NAME
&& ptr_lhs_type
== ptr_rhs_type
)
800 if (rhs_code
== ADDR_EXPR
) {
801 op0
= TREE_OPERAND(rhs1
, 0);
803 if (op0
== NULL_TREE
)
806 if (TREE_CODE(op0
) != VAR_DECL
)
809 op0_type
= TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(op0
))));
810 if (op0_type
== ptr_lhs_type
)
813 #ifndef __DEBUG_PLUGIN
814 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type
)))
816 MISMATCH(gimple_location(stmt
), "op0", ptr_lhs_type
, op0_type
);
818 const_tree ssa_name_var
= SSA_NAME_VAR(rhs1
);
819 /* skip bogus type casts introduced by container_of */
820 if (ssa_name_var
!= NULL_TREE
&& DECL_NAME(ssa_name_var
) &&
821 !strcmp((const char *)DECL_NAME_POINTER(ssa_name_var
), "__mptr"))
823 #ifndef __DEBUG_PLUGIN
824 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type
)))
826 MISMATCH(gimple_location(stmt
), "ssa", ptr_lhs_type
, ptr_rhs_type
);
834 #define PASS_NAME find_bad_casts
836 #define TODO_FLAGS_FINISH TODO_dump_func
837 #include "gcc-generate-gimple-pass.h"
839 __visible
int plugin_init(struct plugin_name_args
*plugin_info
, struct plugin_gcc_version
*version
)
842 const char * const plugin_name
= plugin_info
->base_name
;
843 const int argc
= plugin_info
->argc
;
844 const struct plugin_argument
* const argv
= plugin_info
->argv
;
846 int obtained_seed
= 0;
847 struct register_pass_info find_bad_casts_pass_info
;
849 find_bad_casts_pass_info
.pass
= make_find_bad_casts_pass();
850 find_bad_casts_pass_info
.reference_pass_name
= "ssa";
851 find_bad_casts_pass_info
.ref_pass_instance_number
= 1;
852 find_bad_casts_pass_info
.pos_op
= PASS_POS_INSERT_AFTER
;
854 if (!plugin_default_version_check(version
, &gcc_version
)) {
855 error(G_("incompatible gcc/plugin versions"));
859 if (strncmp(lang_hooks
.name
, "GNU C", 5) && !strncmp(lang_hooks
.name
, "GNU C+", 6)) {
860 inform(UNKNOWN_LOCATION
, G_("%s supports C only, not %s"), plugin_name
, lang_hooks
.name
);
864 for (i
= 0; i
< argc
; ++i
) {
865 if (!strcmp(argv
[i
].key
, "disable")) {
869 if (!strcmp(argv
[i
].key
, "performance-mode")) {
870 performance_mode
= 1;
873 error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name
, argv
[i
].key
);
876 if (strlen(randstruct_seed
) != 64) {
877 error(G_("invalid seed value supplied for %s plugin"), plugin_name
);
880 obtained_seed
= sscanf(randstruct_seed
, "%016llx%016llx%016llx%016llx",
881 &shuffle_seed
[0], &shuffle_seed
[1], &shuffle_seed
[2], &shuffle_seed
[3]);
882 if (obtained_seed
!= 4) {
883 error(G_("Invalid seed supplied for %s plugin"), plugin_name
);
887 register_callback(plugin_name
, PLUGIN_INFO
, NULL
, &randomize_layout_plugin_info
);
889 register_callback(plugin_name
, PLUGIN_ALL_IPA_PASSES_START
, check_global_variables
, NULL
);
890 register_callback(plugin_name
, PLUGIN_PASS_MANAGER_SETUP
, NULL
, &find_bad_casts_pass_info
);
891 register_callback(plugin_name
, PLUGIN_FINISH_TYPE
, finish_type
, NULL
);
892 register_callback(plugin_name
, PLUGIN_FINISH_DECL
, randomize_layout_finish_decl
, NULL
);
894 register_callback(plugin_name
, PLUGIN_ATTRIBUTES
, register_attributes
, NULL
);