0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 #include "gcc-common.h"
0033
0034
0035 #define TYPE_USERSPACE(TYPE) TYPE_LANG_FLAG_5(TYPE)
0036
0037 __visible int plugin_is_GPL_compatible;
0038
0039 static struct plugin_info structleak_plugin_info = {
0040 .version = PLUGIN_VERSION,
0041 .help = "disable\tdo not activate plugin\n"
0042 "byref\tinit structs passed by reference\n"
0043 "byref-all\tinit anything passed by reference\n"
0044 "verbose\tprint all initialized variables\n",
0045 };
0046
0047 #define BYREF_STRUCT 1
0048 #define BYREF_ALL 2
0049
0050 static bool verbose;
0051 static int byref;
0052
0053 static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
0054 {
0055 *no_add_attrs = true;
0056
0057
0058 if (TREE_CODE(*node) != FIELD_DECL)
0059 return NULL_TREE;
0060
0061 *no_add_attrs = false;
0062 return NULL_TREE;
0063 }
0064
0065 static struct attribute_spec user_attr = { };
0066
0067 static void register_attributes(void *event_data, void *data)
0068 {
0069 user_attr.name = "user";
0070 user_attr.handler = handle_user_attribute;
0071 user_attr.affects_type_identity = true;
0072
0073 register_attribute(&user_attr);
0074 }
0075
0076 static tree get_field_type(tree field)
0077 {
0078 return strip_array_types(TREE_TYPE(field));
0079 }
0080
0081 static bool is_userspace_type(tree type)
0082 {
0083 tree field;
0084
0085 for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) {
0086 tree fieldtype = get_field_type(field);
0087 enum tree_code code = TREE_CODE(fieldtype);
0088
0089 if (code == RECORD_TYPE || code == UNION_TYPE)
0090 if (is_userspace_type(fieldtype))
0091 return true;
0092
0093 if (lookup_attribute("user", DECL_ATTRIBUTES(field)))
0094 return true;
0095 }
0096 return false;
0097 }
0098
0099 static void finish_type(void *event_data, void *data)
0100 {
0101 tree type = (tree)event_data;
0102
0103 if (type == NULL_TREE || type == error_mark_node)
0104 return;
0105
0106 if (TREE_CODE(type) == ENUMERAL_TYPE)
0107 return;
0108
0109 if (TYPE_USERSPACE(type))
0110 return;
0111
0112 if (is_userspace_type(type))
0113 TYPE_USERSPACE(type) = 1;
0114 }
0115
0116 static void initialize(tree var)
0117 {
0118 basic_block bb;
0119 gimple_stmt_iterator gsi;
0120 tree initializer;
0121 gimple init_stmt;
0122 tree type;
0123
0124
0125 bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
0126
0127
0128 for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
0129 gimple stmt = gsi_stmt(gsi);
0130 tree rhs1;
0131
0132
0133 if (!gimple_assign_single_p(stmt))
0134 continue;
0135 rhs1 = gimple_assign_rhs1(stmt);
0136
0137 if (TREE_CLOBBER_P(rhs1))
0138 continue;
0139
0140 if (gimple_get_lhs(stmt) != var)
0141 continue;
0142
0143 if (TREE_CODE(rhs1) == CONSTRUCTOR)
0144 return;
0145 }
0146
0147
0148 if (verbose)
0149 inform(DECL_SOURCE_LOCATION(var),
0150 "%s variable will be forcibly initialized",
0151 (byref && TREE_ADDRESSABLE(var)) ? "byref"
0152 : "userspace");
0153
0154
0155 type = TREE_TYPE(var);
0156 if (AGGREGATE_TYPE_P(type))
0157 initializer = build_constructor(type, NULL);
0158 else
0159 initializer = fold_convert(type, integer_zero_node);
0160
0161
0162 init_stmt = gimple_build_assign(var, initializer);
0163 gsi = gsi_after_labels(single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
0164 gsi_insert_before(&gsi, init_stmt, GSI_NEW_STMT);
0165 update_stmt(init_stmt);
0166 }
0167
0168 static unsigned int structleak_execute(void)
0169 {
0170 basic_block bb;
0171 tree var;
0172 unsigned int i;
0173
0174
0175 gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
0176 bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
0177 if (!single_pred_p(bb)) {
0178 split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
0179 gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
0180 }
0181
0182
0183 FOR_EACH_LOCAL_DECL(cfun, i, var) {
0184 tree type = TREE_TYPE(var);
0185
0186 gcc_assert(DECL_P(var));
0187 if (!auto_var_in_fn_p(var, current_function_decl))
0188 continue;
0189
0190
0191 if (byref != BYREF_ALL && TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE)
0192 continue;
0193
0194
0195 if (TYPE_USERSPACE(type) ||
0196 (byref && TREE_ADDRESSABLE(var)))
0197 initialize(var);
0198 }
0199
0200 return 0;
0201 }
0202
0203 #define PASS_NAME structleak
0204 #define NO_GATE
0205 #define PROPERTIES_REQUIRED PROP_cfg
0206 #define TODO_FLAGS_FINISH TODO_verify_il | TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_remove_unused_locals | TODO_update_ssa | TODO_ggc_collect | TODO_verify_flow
0207 #include "gcc-generate-gimple-pass.h"
0208
0209 __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
0210 {
0211 int i;
0212 const char * const plugin_name = plugin_info->base_name;
0213 const int argc = plugin_info->argc;
0214 const struct plugin_argument * const argv = plugin_info->argv;
0215 bool enable = true;
0216
0217 PASS_INFO(structleak, "early_optimizations", 1, PASS_POS_INSERT_BEFORE);
0218
0219 if (!plugin_default_version_check(version, &gcc_version)) {
0220 error(G_("incompatible gcc/plugin versions"));
0221 return 1;
0222 }
0223
0224 if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) {
0225 inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name);
0226 enable = false;
0227 }
0228
0229 for (i = 0; i < argc; ++i) {
0230 if (!strcmp(argv[i].key, "disable")) {
0231 enable = false;
0232 continue;
0233 }
0234 if (!strcmp(argv[i].key, "verbose")) {
0235 verbose = true;
0236 continue;
0237 }
0238 if (!strcmp(argv[i].key, "byref")) {
0239 byref = BYREF_STRUCT;
0240 continue;
0241 }
0242 if (!strcmp(argv[i].key, "byref-all")) {
0243 byref = BYREF_ALL;
0244 continue;
0245 }
0246 error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
0247 }
0248
0249 register_callback(plugin_name, PLUGIN_INFO, NULL, &structleak_plugin_info);
0250 if (enable) {
0251 register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &structleak_pass_info);
0252 register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL);
0253 }
0254 register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL);
0255
0256 return 0;
0257 }