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 #if BUILDING_GCC_MAJOR < 4 || (BUILDING_GCC_MAJOR == 4 && BUILDING_GCC_MINOR < 7)
23 #error "The RANDSTRUCT plugin requires GCC 4.7 or newer."
26 #define ORIG_TYPE_NAME(node) \
27 (TYPE_NAME(TYPE_MAIN_VARIANT(node)) != NULL_TREE ? ((const unsigned char *)IDENTIFIER_POINTER(TYPE_NAME(TYPE_MAIN_VARIANT(node)))) : (const unsigned char *)"anonymous")
29 #define INFORM(loc, msg, ...) inform(loc, "randstruct: " msg, ##__VA_ARGS__)
30 #define MISMATCH(loc, how, ...) INFORM(loc, "casting between randomized structure pointer types (" how "): %qT and %qT\n", __VA_ARGS__)
32 __visible
int plugin_is_GPL_compatible
;
34 static int performance_mode
;
36 static struct plugin_info randomize_layout_plugin_info
= {
37 .version
= "201402201816vanilla",
38 .help
= "disable\t\t\tdo not activate plugin\n"
39 "performance-mode\tenable cacheline-aware layout randomization\n"
42 struct whitelist_entry
{
48 static const struct whitelist_entry whitelist
[] = {
49 /* NIU overloads mapping with page struct */
50 { "drivers/net/ethernet/sun/niu.c", "page", "address_space" },
51 /* unix_skb_parms via UNIXCB() buffer */
52 { "net/unix/af_unix.c", "unix_skb_parms", "char" },
53 /* big_key payload.data struct splashing */
54 { "security/keys/big_key.c", "path", "void *" },
55 /* walk struct security_hook_heads as an array of struct hlist_head */
56 { "security/security.c", "hlist_head", "security_hook_heads" },
60 /* from old Linux dcache.h */
61 static inline unsigned long
62 partial_name_hash(unsigned long c
, unsigned long prevhash
)
64 return (prevhash
+ (c
<< 4) + (c
>> 4)) * 11;
66 static inline unsigned int
67 name_hash(const unsigned char *name
)
69 unsigned long hash
= 0;
70 unsigned int len
= strlen((const char *)name
);
72 hash
= partial_name_hash(*name
++, hash
);
73 return (unsigned int)hash
;
76 static tree
handle_randomize_layout_attr(tree
*node
, tree name
, tree args
, int flags
, bool *no_add_attrs
)
81 if (TREE_CODE(*node
) == FUNCTION_DECL
) {
82 error("%qE attribute does not apply to functions (%qF)", name
, *node
);
86 if (TREE_CODE(*node
) == PARM_DECL
) {
87 error("%qE attribute does not apply to function parameters (%qD)", name
, *node
);
91 if (TREE_CODE(*node
) == VAR_DECL
) {
92 error("%qE attribute does not apply to variables (%qD)", name
, *node
);
99 gcc_assert(TREE_CODE(*node
) == TYPE_DECL
);
100 type
= TREE_TYPE(*node
);
103 if (TREE_CODE(type
) != RECORD_TYPE
) {
104 error("%qE attribute used on %qT applies to struct types only", name
, type
);
108 if (lookup_attribute(IDENTIFIER_POINTER(name
), TYPE_ATTRIBUTES(type
))) {
109 error("%qE attribute is already applied to the type %qT", name
, type
);
113 *no_add_attrs
= false;
118 /* set on complete types that we don't need to inspect further at all */
119 static tree
handle_randomize_considered_attr(tree
*node
, tree name
, tree args
, int flags
, bool *no_add_attrs
)
121 *no_add_attrs
= false;
126 * set on types that we've performed a shuffle on, to prevent re-shuffling
127 * this does not preclude us from inspecting its fields for potential shuffles
129 static tree
handle_randomize_performed_attr(tree
*node
, tree name
, tree args
, int flags
, bool *no_add_attrs
)
131 *no_add_attrs
= false;
136 * 64bit variant of Bob Jenkins' public domain PRNG
137 * 256 bits of internal state
140 typedef unsigned long long u64
;
142 typedef struct ranctx
{ u64 a
; u64 b
; u64 c
; u64 d
; } ranctx
;
144 #define rot(x,k) (((x)<<(k))|((x)>>(64-(k))))
145 static u64
ranval(ranctx
*x
) {
146 u64 e
= x
->a
- rot(x
->b
, 7);
147 x
->a
= x
->b
^ rot(x
->c
, 13);
148 x
->b
= x
->c
+ rot(x
->d
, 37);
154 static void raninit(ranctx
*x
, u64
*seed
) {
162 for (i
=0; i
< 30; ++i
)
166 static u64 shuffle_seed
[4];
168 struct partition_group
{
171 unsigned long length
;
174 static void partition_struct(tree
*fields
, unsigned long length
, struct partition_group
*size_groups
, unsigned long *num_groups
)
177 unsigned long accum_size
= 0;
178 unsigned long accum_length
= 0;
179 unsigned long group_idx
= 0;
181 gcc_assert(length
< INT_MAX
);
183 memset(size_groups
, 0, sizeof(struct partition_group
) * length
);
185 for (i
= 0; i
< length
; i
++) {
186 if (size_groups
[group_idx
].tree_start
== NULL_TREE
) {
187 size_groups
[group_idx
].tree_start
= fields
[i
];
188 size_groups
[group_idx
].start
= i
;
192 accum_size
+= (unsigned long)int_size_in_bytes(TREE_TYPE(fields
[i
]));
194 if (accum_size
>= 64) {
195 size_groups
[group_idx
].length
= accum_length
;
201 if (size_groups
[group_idx
].tree_start
!= NULL_TREE
&&
202 !size_groups
[group_idx
].length
) {
203 size_groups
[group_idx
].length
= accum_length
;
207 *num_groups
= group_idx
;
210 static void performance_shuffle(tree
*newtree
, unsigned long length
, ranctx
*prng_state
)
213 struct partition_group size_group
[length
];
214 unsigned long num_groups
= 0;
215 unsigned long randnum
;
217 partition_struct(newtree
, length
, (struct partition_group
*)&size_group
, &num_groups
);
218 for (i
= num_groups
- 1; i
> 0; i
--) {
219 struct partition_group tmp
;
220 randnum
= ranval(prng_state
) % (i
+ 1);
222 size_group
[i
] = size_group
[randnum
];
223 size_group
[randnum
] = tmp
;
226 for (x
= 0; x
< num_groups
; x
++) {
227 for (i
= size_group
[x
].start
+ size_group
[x
].length
- 1; i
> size_group
[x
].start
; i
--) {
229 if (DECL_BIT_FIELD_TYPE(newtree
[i
]))
231 randnum
= ranval(prng_state
) % (i
+ 1);
232 // we could handle this case differently if desired
233 if (DECL_BIT_FIELD_TYPE(newtree
[randnum
]))
236 newtree
[i
] = newtree
[randnum
];
237 newtree
[randnum
] = tmp
;
242 static void full_shuffle(tree
*newtree
, unsigned long length
, ranctx
*prng_state
)
244 unsigned long i
, randnum
;
246 for (i
= length
- 1; i
> 0; i
--) {
248 randnum
= ranval(prng_state
) % (i
+ 1);
250 newtree
[i
] = newtree
[randnum
];
251 newtree
[randnum
] = tmp
;
255 /* modern in-place Fisher-Yates shuffle */
256 static void shuffle(const_tree type
, tree
*newtree
, unsigned long length
)
261 const unsigned char *structname
;
266 gcc_assert(TREE_CODE(type
) == RECORD_TYPE
);
268 structname
= ORIG_TYPE_NAME(type
);
270 #ifdef __DEBUG_PLUGIN
271 fprintf(stderr
, "Shuffling struct %s %p\n", (const char *)structname
, type
);
272 #ifdef __DEBUG_VERBOSE
273 debug_tree((tree
)type
);
277 for (i
= 0; i
< 4; i
++) {
278 seed
[i
] = shuffle_seed
[i
];
279 seed
[i
] ^= name_hash(structname
);
282 raninit(&prng_state
, (u64
*)&seed
);
284 if (performance_mode
)
285 performance_shuffle(newtree
, length
, &prng_state
);
287 full_shuffle(newtree
, length
, &prng_state
);
290 static bool is_flexible_array(const_tree field
)
292 const_tree fieldtype
;
297 fieldtype
= TREE_TYPE(field
);
298 typesize
= TYPE_SIZE(fieldtype
);
300 if (TREE_CODE(fieldtype
) != ARRAY_TYPE
)
303 elemtype
= TREE_TYPE(fieldtype
);
304 elemsize
= TYPE_SIZE(elemtype
);
306 /* size of type is represented in bits */
308 if (typesize
== NULL_TREE
&& TYPE_DOMAIN(fieldtype
) != NULL_TREE
&&
309 TYPE_MAX_VALUE(TYPE_DOMAIN(fieldtype
)) == NULL_TREE
)
312 if (typesize
!= NULL_TREE
&&
313 (TREE_CONSTANT(typesize
) && (!tree_to_uhwi(typesize
) ||
314 tree_to_uhwi(typesize
) == tree_to_uhwi(elemsize
))))
320 static int relayout_struct(tree type
)
322 unsigned long num_fields
= (unsigned long)list_length(TYPE_FIELDS(type
));
323 unsigned long shuffle_length
= num_fields
;
325 tree newtree
[num_fields
];
330 expanded_location xloc
;
331 bool has_flexarray
= false;
333 if (TYPE_FIELDS(type
) == NULL_TREE
)
339 gcc_assert(TREE_CODE(type
) == RECORD_TYPE
);
341 gcc_assert(num_fields
< INT_MAX
);
343 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type
)) ||
344 lookup_attribute("no_randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type
))))
347 /* Workaround for 3rd-party VirtualBox source that we can't modify ourselves */
348 if (!strcmp((const char *)ORIG_TYPE_NAME(type
), "INTNETTRUNKFACTORY") ||
349 !strcmp((const char *)ORIG_TYPE_NAME(type
), "RAWPCIFACTORY"))
352 /* throw out any structs in uapi */
353 xloc
= expand_location(DECL_SOURCE_LOCATION(TYPE_FIELDS(type
)));
355 if (strstr(xloc
.file
, "/uapi/"))
356 error(G_("attempted to randomize userland API struct %s"), ORIG_TYPE_NAME(type
));
358 for (field
= TYPE_FIELDS(type
), i
= 0; field
; field
= TREE_CHAIN(field
), i
++) {
359 gcc_assert(TREE_CODE(field
) == FIELD_DECL
);
364 * enforce that we don't randomize the layout of the last
365 * element of a struct if it's a 0 or 1-length array
366 * or a proper flexible array
368 if (is_flexible_array(newtree
[num_fields
- 1])) {
369 has_flexarray
= true;
373 shuffle(type
, (tree
*)newtree
, shuffle_length
);
376 * set up a bogus anonymous struct field designed to error out on unnamed struct initializers
377 * as gcc provides no other way to detect such code
379 list
= make_node(FIELD_DECL
);
380 TREE_CHAIN(list
) = newtree
[0];
381 TREE_TYPE(list
) = void_type_node
;
382 DECL_SIZE(list
) = bitsize_zero_node
;
383 DECL_NONADDRESSABLE_P(list
) = 1;
384 DECL_FIELD_BIT_OFFSET(list
) = bitsize_zero_node
;
385 DECL_SIZE_UNIT(list
) = size_zero_node
;
386 DECL_FIELD_OFFSET(list
) = size_zero_node
;
387 DECL_CONTEXT(list
) = type
;
388 // to satisfy the constify plugin
389 TREE_READONLY(list
) = 1;
391 for (i
= 0; i
< num_fields
- 1; i
++)
392 TREE_CHAIN(newtree
[i
]) = newtree
[i
+1];
393 TREE_CHAIN(newtree
[num_fields
- 1]) = NULL_TREE
;
395 main_variant
= TYPE_MAIN_VARIANT(type
);
396 for (variant
= main_variant
; variant
; variant
= TYPE_NEXT_VARIANT(variant
)) {
397 TYPE_FIELDS(variant
) = list
;
398 TYPE_ATTRIBUTES(variant
) = copy_list(TYPE_ATTRIBUTES(variant
));
399 TYPE_ATTRIBUTES(variant
) = tree_cons(get_identifier("randomize_performed"), NULL_TREE
, TYPE_ATTRIBUTES(variant
));
400 TYPE_ATTRIBUTES(variant
) = tree_cons(get_identifier("designated_init"), NULL_TREE
, TYPE_ATTRIBUTES(variant
));
402 TYPE_ATTRIBUTES(type
) = tree_cons(get_identifier("has_flexarray"), NULL_TREE
, TYPE_ATTRIBUTES(type
));
406 * force a re-layout of the main variant
407 * the TYPE_SIZE for all variants will be recomputed
408 * by finalize_type_size()
410 TYPE_SIZE(main_variant
) = NULL_TREE
;
411 layout_type(main_variant
);
412 gcc_assert(TYPE_SIZE(main_variant
) != NULL_TREE
);
417 /* from constify plugin */
418 static const_tree
get_field_type(const_tree field
)
420 return strip_array_types(TREE_TYPE(field
));
423 /* from constify plugin */
424 static bool is_fptr(const_tree fieldtype
)
426 if (TREE_CODE(fieldtype
) != POINTER_TYPE
)
429 return TREE_CODE(TREE_TYPE(fieldtype
)) == FUNCTION_TYPE
;
432 /* derived from constify plugin */
433 static int is_pure_ops_struct(const_tree node
)
437 gcc_assert(TREE_CODE(node
) == RECORD_TYPE
|| TREE_CODE(node
) == UNION_TYPE
);
439 for (field
= TYPE_FIELDS(node
); field
; field
= TREE_CHAIN(field
)) {
440 const_tree fieldtype
= get_field_type(field
);
441 enum tree_code code
= TREE_CODE(fieldtype
);
443 if (node
== fieldtype
)
446 if (code
== RECORD_TYPE
|| code
== UNION_TYPE
) {
447 if (!is_pure_ops_struct(fieldtype
))
452 if (!is_fptr(fieldtype
))
459 static void randomize_type(tree type
)
463 gcc_assert(TREE_CODE(type
) == RECORD_TYPE
);
465 if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type
)))
468 if (lookup_attribute("randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type
))) || is_pure_ops_struct(type
))
469 relayout_struct(type
);
471 for (variant
= TYPE_MAIN_VARIANT(type
); variant
; variant
= TYPE_NEXT_VARIANT(variant
)) {
472 TYPE_ATTRIBUTES(type
) = copy_list(TYPE_ATTRIBUTES(type
));
473 TYPE_ATTRIBUTES(type
) = tree_cons(get_identifier("randomize_considered"), NULL_TREE
, TYPE_ATTRIBUTES(type
));
475 #ifdef __DEBUG_PLUGIN
476 fprintf(stderr
, "Marking randomize_considered on struct %s\n", ORIG_TYPE_NAME(type
));
477 #ifdef __DEBUG_VERBOSE
483 static void update_decl_size(tree decl
)
485 tree lastval
, lastidx
, field
, init
, type
, flexsize
;
486 unsigned HOST_WIDE_INT len
;
488 type
= TREE_TYPE(decl
);
490 if (!lookup_attribute("has_flexarray", TYPE_ATTRIBUTES(type
)))
493 init
= DECL_INITIAL(decl
);
494 if (init
== NULL_TREE
|| init
== error_mark_node
)
497 if (TREE_CODE(init
) != CONSTRUCTOR
)
500 len
= CONSTRUCTOR_NELTS(init
);
504 lastval
= CONSTRUCTOR_ELT(init
, CONSTRUCTOR_NELTS(init
) - 1)->value
;
505 lastidx
= CONSTRUCTOR_ELT(init
, CONSTRUCTOR_NELTS(init
) - 1)->index
;
507 for (field
= TYPE_FIELDS(TREE_TYPE(decl
)); TREE_CHAIN(field
); field
= TREE_CHAIN(field
))
510 if (lastidx
!= field
)
513 if (TREE_CODE(lastval
) != STRING_CST
) {
514 error("Only string constants are supported as initializers "
515 "for randomized structures with flexible arrays");
519 flexsize
= bitsize_int(TREE_STRING_LENGTH(lastval
) *
520 tree_to_uhwi(TYPE_SIZE(TREE_TYPE(TREE_TYPE(lastval
)))));
522 DECL_SIZE(decl
) = size_binop(PLUS_EXPR
, TYPE_SIZE(type
), flexsize
);
528 static void randomize_layout_finish_decl(void *event_data
, void *data
)
530 tree decl
= (tree
)event_data
;
533 if (decl
== NULL_TREE
|| decl
== error_mark_node
)
536 type
= TREE_TYPE(decl
);
538 if (TREE_CODE(decl
) != VAR_DECL
)
541 if (TREE_CODE(type
) != RECORD_TYPE
&& TREE_CODE(type
) != UNION_TYPE
)
544 if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type
)))
548 DECL_SIZE_UNIT(decl
) = 0;
549 SET_DECL_ALIGN(decl
, 0);
550 SET_DECL_MODE (decl
, VOIDmode
);
551 SET_DECL_RTL(decl
, 0);
552 update_decl_size(decl
);
553 layout_decl(decl
, 0);
556 static void finish_type(void *event_data
, void *data
)
558 tree type
= (tree
)event_data
;
560 if (type
== NULL_TREE
|| type
== error_mark_node
)
563 if (TREE_CODE(type
) != RECORD_TYPE
)
566 if (TYPE_FIELDS(type
) == NULL_TREE
)
569 if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type
)))
572 #ifdef __DEBUG_PLUGIN
573 fprintf(stderr
, "Calling randomize_type on %s\n", ORIG_TYPE_NAME(type
));
575 #ifdef __DEBUG_VERBOSE
578 randomize_type(type
);
583 static struct attribute_spec randomize_layout_attr
= { };
584 static struct attribute_spec no_randomize_layout_attr
= { };
585 static struct attribute_spec randomize_considered_attr
= { };
586 static struct attribute_spec randomize_performed_attr
= { };
588 static void register_attributes(void *event_data
, void *data
)
590 randomize_layout_attr
.name
= "randomize_layout";
591 randomize_layout_attr
.type_required
= true;
592 randomize_layout_attr
.handler
= handle_randomize_layout_attr
;
593 randomize_layout_attr
.affects_type_identity
= true;
595 no_randomize_layout_attr
.name
= "no_randomize_layout";
596 no_randomize_layout_attr
.type_required
= true;
597 no_randomize_layout_attr
.handler
= handle_randomize_layout_attr
;
598 no_randomize_layout_attr
.affects_type_identity
= true;
600 randomize_considered_attr
.name
= "randomize_considered";
601 randomize_considered_attr
.type_required
= true;
602 randomize_considered_attr
.handler
= handle_randomize_considered_attr
;
604 randomize_performed_attr
.name
= "randomize_performed";
605 randomize_performed_attr
.type_required
= true;
606 randomize_performed_attr
.handler
= handle_randomize_performed_attr
;
608 register_attribute(&randomize_layout_attr
);
609 register_attribute(&no_randomize_layout_attr
);
610 register_attribute(&randomize_considered_attr
);
611 register_attribute(&randomize_performed_attr
);
614 static void check_bad_casts_in_constructor(tree var
, tree init
)
616 unsigned HOST_WIDE_INT idx
;
618 tree field_type
, val_type
;
620 FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(init
), idx
, field
, val
) {
621 if (TREE_CODE(val
) == CONSTRUCTOR
) {
622 check_bad_casts_in_constructor(var
, val
);
626 /* pipacs' plugin creates franken-arrays that differ from those produced by
627 normal code which all have valid 'field' trees. work around this */
628 if (field
== NULL_TREE
)
630 field_type
= TREE_TYPE(field
);
631 val_type
= TREE_TYPE(val
);
633 if (TREE_CODE(field_type
) != POINTER_TYPE
|| TREE_CODE(val_type
) != POINTER_TYPE
)
636 if (field_type
== val_type
)
639 field_type
= TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(field_type
))));
640 val_type
= TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(val_type
))));
642 if (field_type
== void_type_node
)
644 if (field_type
== val_type
)
646 if (TREE_CODE(val_type
) != RECORD_TYPE
)
649 if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(val_type
)))
651 MISMATCH(DECL_SOURCE_LOCATION(var
), "constructor\n", TYPE_MAIN_VARIANT(field_type
), TYPE_MAIN_VARIANT(val_type
));
655 /* derived from the constify plugin */
656 static void check_global_variables(void *event_data
, void *data
)
658 struct varpool_node
*node
;
661 FOR_EACH_VARIABLE(node
) {
662 tree var
= NODE_DECL(node
);
663 init
= DECL_INITIAL(var
);
664 if (init
== NULL_TREE
)
667 if (TREE_CODE(init
) != CONSTRUCTOR
)
670 check_bad_casts_in_constructor(var
, init
);
674 static bool dominated_by_is_err(const_tree rhs
, basic_block bb
)
680 const_tree poss_is_err_cond
;
681 const_tree poss_is_err_func
;
682 const_tree is_err_arg
;
684 dom
= get_immediate_dominator(CDI_DOMINATORS
, bb
);
688 dom_stmt
= last_stmt(dom
);
692 if (gimple_code(dom_stmt
) != GIMPLE_COND
)
695 if (gimple_cond_code(dom_stmt
) != NE_EXPR
)
698 if (!integer_zerop(gimple_cond_rhs(dom_stmt
)))
701 poss_is_err_cond
= gimple_cond_lhs(dom_stmt
);
703 if (TREE_CODE(poss_is_err_cond
) != SSA_NAME
)
706 call_stmt
= SSA_NAME_DEF_STMT(poss_is_err_cond
);
708 if (gimple_code(call_stmt
) != GIMPLE_CALL
)
711 dom_lhs
= gimple_get_lhs(call_stmt
);
712 poss_is_err_func
= gimple_call_fndecl(call_stmt
);
713 if (!poss_is_err_func
)
715 if (dom_lhs
!= poss_is_err_cond
)
717 if (strcmp(DECL_NAME_POINTER(poss_is_err_func
), "IS_ERR"))
720 is_err_arg
= gimple_call_arg(call_stmt
, 0);
724 if (is_err_arg
!= rhs
)
730 static void handle_local_var_initializers(void)
735 FOR_EACH_LOCAL_DECL(cfun
, i
, var
) {
736 tree init
= DECL_INITIAL(var
);
739 if (TREE_CODE(init
) != CONSTRUCTOR
)
741 check_bad_casts_in_constructor(var
, init
);
745 static bool type_name_eq(gimple stmt
, const_tree type_tree
, const char *wanted_name
)
747 const char *type_name
;
749 if (type_tree
== NULL_TREE
)
752 switch (TREE_CODE(type_tree
)) {
754 type_name
= TYPE_NAME_POINTER(type_tree
);
757 if (TYPE_PRECISION(type_tree
) == CHAR_TYPE_SIZE
)
760 INFORM(gimple_location(stmt
), "found non-char INTEGER_TYPE cast comparison: %qT\n", type_tree
);
761 debug_tree(type_tree
);
766 if (TREE_CODE(TREE_TYPE(type_tree
)) == VOID_TYPE
) {
767 type_name
= "void *";
770 INFORM(gimple_location(stmt
), "found non-void POINTER_TYPE cast comparison %qT\n", type_tree
);
771 debug_tree(type_tree
);
775 INFORM(gimple_location(stmt
), "unhandled cast comparison: %qT\n", type_tree
);
776 debug_tree(type_tree
);
780 return strcmp(type_name
, wanted_name
) == 0;
783 static bool whitelisted_cast(gimple stmt
, const_tree lhs_tree
, const_tree rhs_tree
)
785 const struct whitelist_entry
*entry
;
786 expanded_location xloc
= expand_location(gimple_location(stmt
));
788 for (entry
= whitelist
; entry
->pathname
; entry
++) {
789 if (!strstr(xloc
.file
, entry
->pathname
))
792 if (type_name_eq(stmt
, lhs_tree
, entry
->lhs
) && type_name_eq(stmt
, rhs_tree
, entry
->rhs
))
800 * iterate over all statements to find "bad" casts:
801 * those where the address of the start of a structure is cast
802 * to a pointer of a structure of a different type, or a
803 * structure pointer type is cast to a different structure pointer type
805 static unsigned int find_bad_casts_execute(void)
809 handle_local_var_initializers();
811 FOR_EACH_BB_FN(bb
, cfun
) {
812 gimple_stmt_iterator gsi
;
814 for (gsi
= gsi_start_bb(bb
); !gsi_end_p(gsi
); gsi_next(&gsi
)) {
820 const_tree ptr_lhs_type
;
821 const_tree ptr_rhs_type
;
824 enum tree_code rhs_code
;
826 stmt
= gsi_stmt(gsi
);
828 #ifdef __DEBUG_PLUGIN
829 #ifdef __DEBUG_VERBOSE
830 debug_gimple_stmt(stmt
);
831 debug_tree(gimple_get_lhs(stmt
));
835 if (gimple_code(stmt
) != GIMPLE_ASSIGN
)
838 #ifdef __DEBUG_PLUGIN
839 #ifdef __DEBUG_VERBOSE
840 debug_tree(gimple_assign_rhs1(stmt
));
845 rhs_code
= gimple_assign_rhs_code(stmt
);
847 if (rhs_code
!= ADDR_EXPR
&& rhs_code
!= SSA_NAME
)
850 lhs
= gimple_get_lhs(stmt
);
851 lhs_type
= TREE_TYPE(lhs
);
852 rhs1
= gimple_assign_rhs1(stmt
);
853 rhs_type
= TREE_TYPE(rhs1
);
855 if (TREE_CODE(rhs_type
) != POINTER_TYPE
||
856 TREE_CODE(lhs_type
) != POINTER_TYPE
)
859 ptr_lhs_type
= TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(lhs_type
))));
860 ptr_rhs_type
= TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(rhs_type
))));
862 if (ptr_rhs_type
== void_type_node
)
865 if (ptr_lhs_type
== void_type_node
)
868 if (dominated_by_is_err(rhs1
, bb
))
871 if (TREE_CODE(ptr_rhs_type
) != RECORD_TYPE
) {
872 #ifndef __DEBUG_PLUGIN
873 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type
)))
876 if (!whitelisted_cast(stmt
, ptr_lhs_type
, ptr_rhs_type
))
877 MISMATCH(gimple_location(stmt
), "rhs", ptr_lhs_type
, ptr_rhs_type
);
882 if (rhs_code
== SSA_NAME
&& ptr_lhs_type
== ptr_rhs_type
)
885 if (rhs_code
== ADDR_EXPR
) {
886 op0
= TREE_OPERAND(rhs1
, 0);
888 if (op0
== NULL_TREE
)
891 if (TREE_CODE(op0
) != VAR_DECL
)
894 op0_type
= TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(op0
))));
895 if (op0_type
== ptr_lhs_type
)
898 #ifndef __DEBUG_PLUGIN
899 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type
)))
902 if (!whitelisted_cast(stmt
, ptr_lhs_type
, op0_type
))
903 MISMATCH(gimple_location(stmt
), "op0", ptr_lhs_type
, op0_type
);
906 const_tree ssa_name_var
= SSA_NAME_VAR(rhs1
);
907 /* skip bogus type casts introduced by container_of */
908 if (ssa_name_var
!= NULL_TREE
&& DECL_NAME(ssa_name_var
) &&
909 !strcmp((const char *)DECL_NAME_POINTER(ssa_name_var
), "__mptr"))
911 #ifndef __DEBUG_PLUGIN
912 if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type
)))
915 if (!whitelisted_cast(stmt
, ptr_lhs_type
, ptr_rhs_type
))
916 MISMATCH(gimple_location(stmt
), "ssa", ptr_lhs_type
, ptr_rhs_type
);
925 #define PASS_NAME find_bad_casts
927 #define TODO_FLAGS_FINISH TODO_dump_func
928 #include "gcc-generate-gimple-pass.h"
930 __visible
int plugin_init(struct plugin_name_args
*plugin_info
, struct plugin_gcc_version
*version
)
933 const char * const plugin_name
= plugin_info
->base_name
;
934 const int argc
= plugin_info
->argc
;
935 const struct plugin_argument
* const argv
= plugin_info
->argv
;
937 int obtained_seed
= 0;
938 struct register_pass_info find_bad_casts_pass_info
;
940 find_bad_casts_pass_info
.pass
= make_find_bad_casts_pass();
941 find_bad_casts_pass_info
.reference_pass_name
= "ssa";
942 find_bad_casts_pass_info
.ref_pass_instance_number
= 1;
943 find_bad_casts_pass_info
.pos_op
= PASS_POS_INSERT_AFTER
;
945 if (!plugin_default_version_check(version
, &gcc_version
)) {
946 error(G_("incompatible gcc/plugin versions"));
950 if (strncmp(lang_hooks
.name
, "GNU C", 5) && !strncmp(lang_hooks
.name
, "GNU C+", 6)) {
951 inform(UNKNOWN_LOCATION
, G_("%s supports C only, not %s"), plugin_name
, lang_hooks
.name
);
955 for (i
= 0; i
< argc
; ++i
) {
956 if (!strcmp(argv
[i
].key
, "disable")) {
960 if (!strcmp(argv
[i
].key
, "performance-mode")) {
961 performance_mode
= 1;
964 error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name
, argv
[i
].key
);
967 if (strlen(randstruct_seed
) != 64) {
968 error(G_("invalid seed value supplied for %s plugin"), plugin_name
);
971 obtained_seed
= sscanf(randstruct_seed
, "%016llx%016llx%016llx%016llx",
972 &shuffle_seed
[0], &shuffle_seed
[1], &shuffle_seed
[2], &shuffle_seed
[3]);
973 if (obtained_seed
!= 4) {
974 error(G_("Invalid seed supplied for %s plugin"), plugin_name
);
978 register_callback(plugin_name
, PLUGIN_INFO
, NULL
, &randomize_layout_plugin_info
);
980 register_callback(plugin_name
, PLUGIN_ALL_IPA_PASSES_START
, check_global_variables
, NULL
);
981 register_callback(plugin_name
, PLUGIN_PASS_MANAGER_SETUP
, NULL
, &find_bad_casts_pass_info
);
982 register_callback(plugin_name
, PLUGIN_FINISH_TYPE
, finish_type
, NULL
);
983 register_callback(plugin_name
, PLUGIN_FINISH_DECL
, randomize_layout_finish_decl
, NULL
);
985 register_callback(plugin_name
, PLUGIN_ATTRIBUTES
, register_attributes
, NULL
);