return; DECL_SIZE(decl) = 0; DECL_SIZE_UNIT(decl) = 0; SET_DECL_ALIGN(decl, 0); SET_DECL_MODE (decl, VOIDmode); SET_DECL_RTL(decl, 0); update_decl_size(decl); layout_decl(decl, 0);} static void finish_type(void *event_data, void *data){ tree type = (tree)event_data; if (type == NULL_TREE || type == error_mark_node) return; if (TREE_CODE(type) != RECORD_TYPE) return; if (TYPE_FIELDS(type) == NULL_TREE) return; if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type))) return; #ifdef __DEBUG_PLUGIN fprintf(stderr, "Calling randomize_type on %s\n", ORIG_TYPE_NAME(type));#endif#ifdef __DEBUG_VERBOSE debug_tree(type);#endif randomize_type(type); return;} static struct attribute_spec randomize_layout_attr = { };static struct attribute_spec no_randomize_layout_attr = { };static struct attribute_spec randomize_considered_attr = { };static struct attribute_spec randomize_performed_attr = { }; static void register_attributes(void *event_data, void *data){ randomize_layout_attr.name = "randomize_layout"; randomize_layout_attr.type_required = true; randomize_layout_attr.handler = handle_randomize_layout_attr; randomize_layout_attr.affects_type_identity = true; no_randomize_layout_attr.name = "no_randomize_layout"; no_randomize_layout_attr.type_required = true; no_randomize_layout_attr.handler = handle_randomize_layout_attr; no_randomize_layout_attr.affects_type_identity = true; randomize_considered_attr.name = "randomize_considered"; randomize_considered_attr.type_required = true; randomize_considered_attr.handler = handle_randomize_considered_attr; randomize_performed_attr.name = "randomize_performed"; randomize_performed_attr.type_required = true; randomize_performed_attr.handler = handle_randomize_performed_attr; register_attribute(&randomize_layout_attr); register_attribute(&no_randomize_layout_attr); register_attribute(&randomize_considered_attr); register_attribute(&randomize_performed_attr);} static void check_bad_casts_in_constructor(tree var, tree init){ unsigned HOST_WIDE_INT idx; tree field, val; tree field_type, val_type; FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(init), idx, field, val) { if (TREE_CODE(val) == CONSTRUCTOR) { check_bad_casts_in_constructor(var, val); continue; } /* pipacs' plugin creates franken-arrays that differ from those produced by normal code which all have valid 'field' trees. work around this */ if (field == NULL_TREE) continue; field_type = TREE_TYPE(field); val_type = TREE_TYPE(val); if (TREE_CODE(field_type) != POINTER_TYPE || TREE_CODE(val_type) != POINTER_TYPE) continue; if (field_type == val_type) continue; field_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(field_type)))); val_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(val_type)))); if (field_type == void_type_node) continue; if (field_type == val_type) continue; if (TREE_CODE(val_type) != RECORD_TYPE) continue; if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(val_type))) continue; MISMATCH(DECL_SOURCE_LOCATION(var), "constructor\n", TYPE_MAIN_VARIANT(field_type), TYPE_MAIN_VARIANT(val_type)); }} /* derived from the constify plugin */static void check_global_variables(void *event_data, void *data){ struct varpool_node *node; tree init; FOR_EACH_VARIABLE(node) { tree var = NODE_DECL(node); init = DECL_INITIAL(var); if (init == NULL_TREE) continue; if (TREE_CODE(init) != CONSTRUCTOR) continue; check_bad_casts_in_constructor(var, init); }} static bool dominated_by_is_err(const_tree rhs, basic_block bb){ basic_block dom; gimple dom_stmt; gimple call_stmt; const_tree dom_lhs; const_tree poss_is_err_cond; const_tree poss_is_err_func; const_tree is_err_arg; dom = get_immediate_dominator(CDI_DOMINATORS, bb); if (!dom) return false; dom_stmt = last_stmt(dom); if (!dom_stmt) return false; if (gimple_code(dom_stmt) != GIMPLE_COND) return false; if (gimple_cond_code(dom_stmt) != NE_EXPR) return false; if (!integer_zerop(gimple_cond_rhs(dom_stmt))) return false; poss_is_err_cond = gimple_cond_lhs(dom_stmt); if (TREE_CODE(poss_is_err_cond) != SSA_NAME) return false; call_stmt = SSA_NAME_DEF_STMT(poss_is_err_cond); if (gimple_code(call_stmt) != GIMPLE_CALL) return false; dom_lhs = gimple_get_lhs(call_stmt); poss_is_err_func = gimple_call_fndecl(call_stmt); if (!poss_is_err_func) return false; if (dom_lhs != poss_is_err_cond) return false; if (strcmp(DECL_NAME_POINTER(poss_is_err_func), "IS_ERR")) return false; is_err_arg = gimple_call_arg(call_stmt, 0); if (!is_err_arg) return false; if (is_err_arg != rhs) return false; return true;} static void handle_local_var_initializers(void){ tree var; unsigned int i; FOR_EACH_LOCAL_DECL(cfun, i, var) { tree init = DECL_INITIAL(var); if (!init) continue; if (TREE_CODE(init) != CONSTRUCTOR) continue; check_bad_casts_in_constructor(var, init); }} /* * iterate over all statements to find "bad" casts: * those where the address of the start of a structure is cast * to a pointer of a structure of a different type, or a * structure pointer type is cast to a different structure pointer type */static unsigned int find_bad_casts_execute(void){ basic_block bb; handle_local_var_initializers(); FOR_EACH_BB_FN(bb, cfun) { gimple_stmt_iterator gsi; for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { gimple stmt; const_tree lhs; const_tree lhs_type; const_tree rhs1; const_tree rhs_type; const_tree ptr_lhs_type; const_tree ptr_rhs_type; const_tree op0; const_tree op0_type; enum tree_code rhs_code; stmt = gsi_stmt(gsi); #ifdef __DEBUG_PLUGIN#ifdef __DEBUG_VERBOSE debug_gimple_stmt(stmt); debug_tree(gimple_get_lhs(stmt));#endif#endif if (gimple_code(stmt) != GIMPLE_ASSIGN) continue; #ifdef __DEBUG_PLUGIN#ifdef __DEBUG_VERBOSE debug_tree(gimple_assign_rhs1(stmt));#endif#endif rhs_code = gimple_assign_rhs_code(stmt); if (rhs_code != ADDR_EXPR && rhs_code != SSA_NAME) continue; lhs = gimple_get_lhs(stmt); lhs_type = TREE_TYPE(lhs); rhs1 = gimple_assign_rhs1(stmt); rhs_type = TREE_TYPE(rhs1); if (TREE_CODE(rhs_type) != POINTER_TYPE || TREE_CODE(lhs_type) != POINTER_TYPE) continue; ptr_lhs_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(lhs_type)))); ptr_rhs_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(rhs_type)))); if (ptr_rhs_type == void_type_node) continue; if (ptr_lhs_type == void_type_node) continue; if (dominated_by_is_err(rhs1, bb)) continue; if (TREE_CODE(ptr_rhs_type) != RECORD_TYPE) {#ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type)))#endif MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type); continue; } if (rhs_code == SSA_NAME && ptr_lhs_type == ptr_rhs_type) continue; if (rhs_code == ADDR_EXPR) { op0 = TREE_OPERAND(rhs1, 0); if (op0 == NULL_TREE) continue; if (TREE_CODE(op0) != VAR_DECL) continue; op0_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(op0)))); if (op0_type == ptr_lhs_type) continue; #ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type)))#endif MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type); } else { const_tree ssa_name_var = SSA_NAME_VAR(rhs1); /* skip bogus type casts introduced by container_of */ if (ssa_name_var != NULL_TREE && DECL_NAME(ssa_name_var) && !strcmp((const char *)DECL_NAME_POINTER(ssa_name_var), "__mptr")) continue;#ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type)))#endif MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type); } } } return 0;} #define PASS_NAME find_bad_casts#define NO_GATE#define TODO_FLAGS_FINISH TODO_dump_func#include "gcc-generate-gimple-pass.h" __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version){ int i; const char * const plugin_name = plugin_info->base_name; const int argc = plugin_info->argc; const struct plugin_argument * const argv = plugin_info->argv; bool enable = true; int obtained_seed = 0; struct register_pass_info find_bad_casts_pass_info; find_bad_casts_pass_info.pass = make_find_bad_casts_pass(); find_bad_casts_pass_info.reference_pass_name = "ssa"; find_bad_casts_pass_info.ref_pass_instance_number = 1; find_bad_casts_pass_info.pos_op = PASS_POS_INSERT_AFTER; if (!plugin_default_version_check(version, &gcc_version)) { error(G_("incompatible gcc/plugin versions")); return 1; } if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) { inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name); enable = false; } for (i = 0; i < argc; ++i) { if (!strcmp(argv[i].key, "disable")) { enable = false; continue; } if (!strcmp(argv[i].key, "performance-mode")) { performance_mode = 1; continue; } error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); } if (strlen(randstruct_seed) != 64) { error(G_("invalid seed value supplied for %s plugin"), plugin_name); return 1; } obtained_seed = sscanf(randstruct_seed, "%016llx%016llx%016llx%016llx", &shuffle_seed[0], &shuffle_seed[1], &shuffle_seed[2], &shuffle_seed[3]); if (obtained_seed != 4) { error(G_("Invalid seed supplied for %s plugin"), plugin_name); return 1; } register_callback(plugin_name, PLUGIN_INFO, NULL, &randomize_layout_plugin_info); if (enable) { register_callback(plugin_name, PLUGIN_ALL_IPA_PASSES_START, check_global_variables, NULL); register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &find_bad_casts_pass_info); register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL); register_callback(plugin_name, PLUGIN_FINISH_DECL, randomize_layout_finish_decl, NULL); } register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); return 0;}Lines 501–881 of 881. Previous lines
return; DECL_SIZE(decl) = 0; DECL_SIZE_UNIT(decl) = 0; SET_DECL_ALIGN(decl, 0); SET_DECL_MODE (decl, VOIDmode); SET_DECL_RTL(decl, 0); update_decl_size(decl); layout_decl(decl, 0); } static void finish_type(void *event_data, void *data) { tree type = (tree)event_data; if (type == NULL_TREE || type == error_mark_node) return; if (TREE_CODE(type) != RECORD_TYPE) return; if (TYPE_FIELDS(type) == NULL_TREE) return; if (lookup_attribute("randomize_considered", TYPE_ATTRIBUTES(type))) return; #ifdef __DEBUG_PLUGIN fprintf(stderr, "Calling randomize_type on %s\n", ORIG_TYPE_NAME(type)); #endif #ifdef __DEBUG_VERBOSE debug_tree(type); #endif randomize_type(type); return; } static struct attribute_spec randomize_layout_attr = { }; static struct attribute_spec no_randomize_layout_attr = { }; static struct attribute_spec randomize_considered_attr = { }; static struct attribute_spec randomize_performed_attr = { }; static void register_attributes(void *event_data, void *data) { randomize_layout_attr.name = "randomize_layout"; randomize_layout_attr.type_required = true; randomize_layout_attr.handler = handle_randomize_layout_attr; randomize_layout_attr.affects_type_identity = true; no_randomize_layout_attr.name = "no_randomize_layout"; no_randomize_layout_attr.type_required = true; no_randomize_layout_attr.handler = handle_randomize_layout_attr; no_randomize_layout_attr.affects_type_identity = true; randomize_considered_attr.name = "randomize_considered"; randomize_considered_attr.type_required = true; randomize_considered_attr.handler = handle_randomize_considered_attr; randomize_performed_attr.name = "randomize_performed"; randomize_performed_attr.type_required = true; randomize_performed_attr.handler = handle_randomize_performed_attr; register_attribute(&randomize_layout_attr); register_attribute(&no_randomize_layout_attr); register_attribute(&randomize_considered_attr); register_attribute(&randomize_performed_attr); } static void check_bad_casts_in_constructor(tree var, tree init) { unsigned HOST_WIDE_INT idx; tree field, val; tree field_type, val_type; FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(init), idx, field, val) { if (TREE_CODE(val) == CONSTRUCTOR) { check_bad_casts_in_constructor(var, val); continue; } /* pipacs' plugin creates franken-arrays that differ from those produced by normal code which all have valid 'field' trees. work around this */ if (field == NULL_TREE) continue; field_type = TREE_TYPE(field); val_type = TREE_TYPE(val); if (TREE_CODE(field_type) != POINTER_TYPE || TREE_CODE(val_type) != POINTER_TYPE) continue; if (field_type == val_type) continue; field_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(field_type)))); val_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(val_type)))); if (field_type == void_type_node) continue; if (field_type == val_type) continue; if (TREE_CODE(val_type) != RECORD_TYPE) continue; if (!lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(val_type))) continue; MISMATCH(DECL_SOURCE_LOCATION(var), "constructor\n", TYPE_MAIN_VARIANT(field_type), TYPE_MAIN_VARIANT(val_type)); } } /* derived from the constify plugin */ static void check_global_variables(void *event_data, void *data) { struct varpool_node *node; tree init; FOR_EACH_VARIABLE(node) { tree var = NODE_DECL(node); init = DECL_INITIAL(var); if (init == NULL_TREE) continue; if (TREE_CODE(init) != CONSTRUCTOR) continue; check_bad_casts_in_constructor(var, init); } } static bool dominated_by_is_err(const_tree rhs, basic_block bb) { basic_block dom; gimple dom_stmt; gimple call_stmt; const_tree dom_lhs; const_tree poss_is_err_cond; const_tree poss_is_err_func; const_tree is_err_arg; dom = get_immediate_dominator(CDI_DOMINATORS, bb); if (!dom) return false; dom_stmt = last_stmt(dom); if (!dom_stmt) return false; if (gimple_code(dom_stmt) != GIMPLE_COND) return false; if (gimple_cond_code(dom_stmt) != NE_EXPR) return false; if (!integer_zerop(gimple_cond_rhs(dom_stmt))) return false; poss_is_err_cond = gimple_cond_lhs(dom_stmt); if (TREE_CODE(poss_is_err_cond) != SSA_NAME) return false; call_stmt = SSA_NAME_DEF_STMT(poss_is_err_cond); if (gimple_code(call_stmt) != GIMPLE_CALL) return false; dom_lhs = gimple_get_lhs(call_stmt); poss_is_err_func = gimple_call_fndecl(call_stmt); if (!poss_is_err_func) return false; if (dom_lhs != poss_is_err_cond) return false; if (strcmp(DECL_NAME_POINTER(poss_is_err_func), "IS_ERR")) return false; is_err_arg = gimple_call_arg(call_stmt, 0); if (!is_err_arg) return false; if (is_err_arg != rhs) return false; return true; } static void handle_local_var_initializers(void) { tree var; unsigned int i; FOR_EACH_LOCAL_DECL(cfun, i, var) { tree init = DECL_INITIAL(var); if (!init) continue; if (TREE_CODE(init) != CONSTRUCTOR) continue; check_bad_casts_in_constructor(var, init); } } /* * iterate over all statements to find "bad" casts: * those where the address of the start of a structure is cast * to a pointer of a structure of a different type, or a * structure pointer type is cast to a different structure pointer type */ static unsigned int find_bad_casts_execute(void) { basic_block bb; handle_local_var_initializers(); FOR_EACH_BB_FN(bb, cfun) { gimple_stmt_iterator gsi; for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { gimple stmt; const_tree lhs; const_tree lhs_type; const_tree rhs1; const_tree rhs_type; const_tree ptr_lhs_type; const_tree ptr_rhs_type; const_tree op0; const_tree op0_type; enum tree_code rhs_code; stmt = gsi_stmt(gsi); #ifdef __DEBUG_PLUGIN #ifdef __DEBUG_VERBOSE debug_gimple_stmt(stmt); debug_tree(gimple_get_lhs(stmt)); #endif #endif if (gimple_code(stmt) != GIMPLE_ASSIGN) continue; #ifdef __DEBUG_PLUGIN #ifdef __DEBUG_VERBOSE debug_tree(gimple_assign_rhs1(stmt)); #endif #endif rhs_code = gimple_assign_rhs_code(stmt); if (rhs_code != ADDR_EXPR && rhs_code != SSA_NAME) continue; lhs = gimple_get_lhs(stmt); lhs_type = TREE_TYPE(lhs); rhs1 = gimple_assign_rhs1(stmt); rhs_type = TREE_TYPE(rhs1); if (TREE_CODE(rhs_type) != POINTER_TYPE || TREE_CODE(lhs_type) != POINTER_TYPE) continue; ptr_lhs_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(lhs_type)))); ptr_rhs_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(rhs_type)))); if (ptr_rhs_type == void_type_node) continue; if (ptr_lhs_type == void_type_node) continue; if (dominated_by_is_err(rhs1, bb)) continue; if (TREE_CODE(ptr_rhs_type) != RECORD_TYPE) { #ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_lhs_type))) #endif MISMATCH(gimple_location(stmt), "rhs", ptr_lhs_type, ptr_rhs_type); continue; } if (rhs_code == SSA_NAME && ptr_lhs_type == ptr_rhs_type) continue; if (rhs_code == ADDR_EXPR) { op0 = TREE_OPERAND(rhs1, 0); if (op0 == NULL_TREE) continue; if (TREE_CODE(op0) != VAR_DECL) continue; op0_type = TYPE_MAIN_VARIANT(strip_array_types(TYPE_MAIN_VARIANT(TREE_TYPE(op0)))); if (op0_type == ptr_lhs_type) continue; #ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(op0_type))) #endif MISMATCH(gimple_location(stmt), "op0", ptr_lhs_type, op0_type); } else { const_tree ssa_name_var = SSA_NAME_VAR(rhs1); /* skip bogus type casts introduced by container_of */ if (ssa_name_var != NULL_TREE && DECL_NAME(ssa_name_var) && !strcmp((const char *)DECL_NAME_POINTER(ssa_name_var), "__mptr")) continue; #ifndef __DEBUG_PLUGIN if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(ptr_rhs_type))) #endif MISMATCH(gimple_location(stmt), "ssa", ptr_lhs_type, ptr_rhs_type); } } } return 0; } #define PASS_NAME find_bad_casts #define NO_GATE #define TODO_FLAGS_FINISH TODO_dump_func #include "gcc-generate-gimple-pass.h" __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) { int i; const char * const plugin_name = plugin_info->base_name; const int argc = plugin_info->argc; const struct plugin_argument * const argv = plugin_info->argv; bool enable = true; int obtained_seed = 0; struct register_pass_info find_bad_casts_pass_info; find_bad_casts_pass_info.pass = make_find_bad_casts_pass(); find_bad_casts_pass_info.reference_pass_name = "ssa"; find_bad_casts_pass_info.ref_pass_instance_number = 1; find_bad_casts_pass_info.pos_op = PASS_POS_INSERT_AFTER; if (!plugin_default_version_check(version, &gcc_version)) { error(G_("incompatible gcc/plugin versions")); return 1; } if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) { inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name); enable = false; } for (i = 0; i < argc; ++i) { if (!strcmp(argv[i].key, "disable")) { enable = false; continue; } if (!strcmp(argv[i].key, "performance-mode")) { performance_mode = 1; continue; } error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); } if (strlen(randstruct_seed) != 64) { error(G_("invalid seed value supplied for %s plugin"), plugin_name); return 1; } obtained_seed = sscanf(randstruct_seed, "%016llx%016llx%016llx%016llx", &shuffle_seed[0], &shuffle_seed[1], &shuffle_seed[2], &shuffle_seed[3]); if (obtained_seed != 4) { error(G_("Invalid seed supplied for %s plugin"), plugin_name); return 1; } register_callback(plugin_name, PLUGIN_INFO, NULL, &randomize_layout_plugin_info); if (enable) { register_callback(plugin_name, PLUGIN_ALL_IPA_PASSES_START, check_global_variables, NULL); register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &find_bad_casts_pass_info); register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL); register_callback(plugin_name, PLUGIN_FINISH_DECL, randomize_layout_finish_decl, NULL); } register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); return 0; }