From 88eef8314319ded78d70f491c5c4170ea9232270 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 19 Jun 2014 09:50:03 +0300 Subject: [PATCH] db: make call_implies match caller_info with a key value pair call_implies used to only take the parameter number instead of a "$$->foo" type name stored in the "key" column. I've modified it to be like caller_info and return_states. Signed-off-by: Dan Carpenter --- check_check_deref.c | 40 +++++++++++++++++++++++++++++-- check_deref.c | 48 ++++++++++++++++++++++++++++++++++++-- check_deref_check.c | 16 ++++++++++--- check_dereferences_param.c | 23 +++++------------- check_free.c | 13 +++++++++-- check_frees_param.c | 7 ++++-- smatch.h | 4 ++-- smatch_data/db/call_implies.schema | 2 +- smatch_db.c | 14 +++++------ smatch_extra.c | 26 +++++++++++++++++++-- smatch_extra.h | 1 + 11 files changed, 154 insertions(+), 40 deletions(-) diff --git a/check_check_deref.c b/check_check_deref.c index 676fc67d..289b21e3 100644 --- a/check_check_deref.c +++ b/check_check_deref.c @@ -75,6 +75,33 @@ static void check_dereference(struct expression *expr) } END_FOR_EACH_PTR(tmp); } +static void check_dereference_name_sym(char *name, struct symbol *sym) +{ + struct sm_state *sm; + struct sm_state *tmp; + + sm = get_sm_state(my_id, name, sym); + if (!sm) + return; + if (is_ignored(my_id, sm->name, sm->sym)) + return; + if (implied_not_equal_name_sym(name, sym, 0)) + return; + + FOR_EACH_PTR(sm->possible, tmp) { + if (tmp->state == &merged) + continue; + if (tmp->state == &ok) + continue; + if (tmp->state == &null) { + sm_msg("error: we previously assumed '%s' could be null (see line %d)", + tmp->name, tmp->line); + add_ignore(my_id, sm->name, sm->sym); + return; + } + } END_FOR_EACH_PTR(tmp); +} + static void match_dereferences(struct expression *expr) { if (expr->type != EXPR_PREOP) @@ -89,9 +116,18 @@ static void match_pointer_as_array(struct expression *expr) check_dereference(expr->unop->left); } -static void set_param_dereferenced(struct expression *arg, char *unused) +static void set_param_dereferenced(struct expression *arg, char *key, char *unused) { - check_dereference(arg); + struct symbol *sym; + char *name; + + name = get_variable_from_key(arg, key, &sym); + if (!name || !sym) + goto free; + + check_dereference_name_sym(name, sym); +free: + free_string(name); } static void match_condition(struct expression *expr) diff --git a/check_deref.c b/check_deref.c index 8acbd368..3e4787bc 100644 --- a/check_deref.c +++ b/check_deref.c @@ -97,6 +97,41 @@ static void check_dereference(struct expression *expr) } END_FOR_EACH_PTR(tmp); } +static void check_dereference_name_sym(char *name, struct symbol *sym) +{ + struct sm_state *sm; + struct sm_state *tmp; + + sm = get_sm_state(my_id, name, sym); + if (!sm) + return; + if (is_ignored(my_id, sm->name, sm->sym)) + return; + if (implied_not_equal_name_sym(name, sym, 0)) + return; + + FOR_EACH_PTR(sm->possible, tmp) { + if (tmp->state == &merged) + continue; + if (tmp->state == &ok) + continue; + add_ignore(my_id, sm->name, sm->sym); + if (tmp->state == &null) { + if (option_spammy) + sm_msg("error: potential NULL dereference '%s'.", tmp->name); + return; + } + if (tmp->state == &uninitialized) { + if (option_spammy) + sm_msg("error: potentially dereferencing uninitialized '%s'.", tmp->name); + return; + } + sm_msg("error: potential null dereference '%s'. (%s returns null)", + tmp->name, tmp->state->name); + return; + } END_FOR_EACH_PTR(tmp); +} + static void match_dereferences(struct expression *expr) { if (expr->type != EXPR_PREOP) @@ -111,9 +146,18 @@ static void match_pointer_as_array(struct expression *expr) check_dereference(expr->unop->left); } -static void set_param_dereferenced(struct expression *arg, char *unused) +static void set_param_dereferenced(struct expression *arg, char *key, char *unused) { - check_dereference(arg); + struct symbol *sym; + char *name; + + name = get_variable_from_key(arg, key, &sym); + if (!name || !sym) + goto free; + + check_dereference_name_sym(name, sym); +free: + free_string(name); } static void match_declarations(struct symbol *sym) diff --git a/check_deref_check.c b/check_deref_check.c index d2cd1c04..256047a4 100644 --- a/check_deref_check.c +++ b/check_deref_check.c @@ -40,11 +40,21 @@ static void match_dereference(struct expression *expr) set_state_expr(my_id, expr, &derefed); } -static void set_param_dereferenced(struct expression *arg, char *unused) +static void set_param_dereferenced(struct expression *arg, char *key, char *unused) { - if (implied_not_equal(arg, 0)) + struct symbol *sym; + char *name; + + name = get_variable_from_key(arg, key, &sym); + if (!name || !sym) + goto free; + + if (implied_not_equal_name_sym(name, sym, 0)) return; - set_state_expr(my_id, arg, &derefed); + set_state(my_id, name, sym, &derefed); + +free: + free_string(name); } static void match_condition(struct expression *expr) diff --git a/check_dereferences_param.c b/check_dereferences_param.c index 3317390f..4fb99a41 100644 --- a/check_dereferences_param.c +++ b/check_dereferences_param.c @@ -31,20 +31,6 @@ STATE(derefed); STATE(ignore); STATE(param); -static int is_arg(struct expression *expr) -{ - struct symbol *arg; - - if (expr->type != EXPR_SYMBOL) - return 0; - - FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) { - if (arg == expr->symbol) - return 1; - } END_FOR_EACH_PTR(arg); - return 0; -} - static void set_ignore(struct sm_state *sm, struct expression *mod_expr) { if (sm->state == &derefed) @@ -76,7 +62,7 @@ static void check_deref(struct expression *expr) expr = tmp; expr = strip_expr(expr); - if (!is_arg(expr)) + if (get_param_num(expr) < 0) return; sm = get_sm_state_expr(my_id, expr); @@ -94,8 +80,11 @@ static void match_dereference(struct expression *expr) check_deref(expr->unop); } -static void set_param_dereferenced(struct expression *arg, char *unused) +static void set_param_dereferenced(struct expression *arg, char *key, char *unused) { + /* XXX FIXME: param_implies has more information now */ + if (strcmp(key, "$$") != 0) + return; check_deref(arg); } @@ -110,7 +99,7 @@ static void process_states(struct stree *stree) if (!arg->ident) continue; if (get_state_stree(stree, my_id, arg->ident->name, arg) == &derefed) - sql_insert_call_implies(DEREFERENCE, i, 1); + sql_insert_call_implies(DEREFERENCE, i, "$$", "1"); } END_FOR_EACH_PTR(arg); } diff --git a/check_free.c b/check_free.c index 15de869f..7a54acec 100644 --- a/check_free.c +++ b/check_free.c @@ -88,9 +88,18 @@ static void match_free(const char *fn, struct expression *expr, void *param) set_state_expr(my_id, arg, &freed); } -static void set_param_freed(struct expression *arg, char *unused) +static void set_param_freed(struct expression *arg, char *key, char *unused) { - set_state_expr(my_id, arg, &freed); + struct symbol *sym; + char *name; + + name = get_variable_from_key(arg, key, &sym); + if (!name || !sym) + goto free; + + set_state(my_id, name, sym, &freed); +free: + free_string(name); } void check_free(int id) diff --git a/check_frees_param.c b/check_frees_param.c index 828d7506..d2f8fec8 100644 --- a/check_frees_param.c +++ b/check_frees_param.c @@ -90,8 +90,11 @@ static void match_free(const char *fn, struct expression *expr, void *param) freed_variable(arg); } -static void set_param_freed(struct expression *arg, char *unused) +static void set_param_freed(struct expression *arg, char *key, char *unused) { + /* XXX FIXME: call_implies has been updated with more information */ + if (strcmp(key, "$$") != 0) + return; freed_variable(arg); } @@ -106,7 +109,7 @@ static void process_states(struct stree *stree) if (!arg->ident) continue; if (get_state_stree(stree, my_id, arg->ident->name, arg) == &freed) - sql_insert_call_implies(PARAM_FREED, i, 1); + sql_insert_call_implies(PARAM_FREED, i, "$$", "1"); } END_FOR_EACH_PTR(arg); } diff --git a/smatch.h b/smatch.h index a7a0d083..d4d8009a 100644 --- a/smatch.h +++ b/smatch.h @@ -578,7 +578,7 @@ void select_caller_info_hook(void (*callback)(const char *name, struct symbol *s void add_member_info_callback(int owner, void (*callback)(struct expression *call, int param, char *printed_name, struct smatch_state *state)); void add_split_return_callback(void (*fn)(int return_id, char *return_ranges, struct expression *returned_expr)); void add_returned_member_callback(int owner, void (*callback)(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state)); -void select_call_implies_hook(int type, void (*callback)(struct expression *arg, char *value)); +void select_call_implies_hook(int type, void (*callback)(struct expression *arg, char *key, char *value)); struct range_list *db_return_vals(struct expression *expr); char *return_state_to_var_sym(struct expression *expr, int param, char *key, struct symbol **sym); char *get_variable_from_key(struct expression *arg, char *key, struct symbol **sym); @@ -610,7 +610,7 @@ void sql_insert_caller_info(struct expression *call, int type, int param, const char *key, const char *value); void sql_insert_function_ptr(const char *fn, const char *struct_name); void sql_insert_return_values(const char *return_values); -void sql_insert_call_implies(int type, int param, int value); +void sql_insert_call_implies(int type, int param, const char *key, const char *value); void sql_insert_function_type_size(const char *member, const char *ranges); void sql_insert_local_values(const char *name, const char *value); void sql_insert_function_type_value(const char *type, const char *value); diff --git a/smatch_data/db/call_implies.schema b/smatch_data/db/call_implies.schema index 751363d5..90ca8928 100644 --- a/smatch_data/db/call_implies.schema +++ b/smatch_data/db/call_implies.schema @@ -1 +1 @@ -CREATE TABLE call_implies (file varchar(128), function varchar(64), call_id integer, static integer, type integer, parameter integer, value varchar(256)); +CREATE TABLE call_implies (file varchar(128), function varchar(64), call_id integer, static integer, type integer, parameter integer, key varchar(256), value varchar(256)); diff --git a/smatch_db.c b/smatch_db.c index ec06dafd..22497f58 100644 --- a/smatch_db.c +++ b/smatch_db.c @@ -89,7 +89,7 @@ static struct returned_member_cb_list *returned_member_callbacks; struct call_implies_callback { int type; - void (*callback)(struct expression *arg, char *value); + void (*callback)(struct expression *arg, char *key, char *value); }; ALLOCATOR(call_implies_callback, "call_implies callbacks"); DECLARE_PTR_LIST(call_implies_cb_list, struct call_implies_callback); @@ -215,11 +215,11 @@ void sql_insert_function_ptr(const char *fn, const char *struct_name) struct_name); } -void sql_insert_call_implies(int type, int param, int value) +void sql_insert_call_implies(int type, int param, const char *key, const char *value) { - sql_insert(call_implies, "'%s', '%s', %lu, %d, %d, %d, %d", get_base_file(), + sql_insert(call_implies, "'%s', '%s', %lu, %d, %d, %d, '%s', %s", get_base_file(), get_function(), (unsigned long)__inline_fn, fn_static(), - type, param, value); + type, param, key, value); } void sql_insert_function_type_size(const char *member, const char *ranges) @@ -377,7 +377,7 @@ void add_returned_member_callback(int owner, void (*callback)(int return_id, cha add_ptr_list(&returned_member_callbacks, member_callback); } -void select_call_implies_hook(int type, void (*callback)(struct expression *arg, char *value)) +void select_call_implies_hook(int type, void (*callback)(struct expression *arg, char *key, char *value)) { struct call_implies_callback *cb = __alloc_call_implies_callback(0); @@ -711,7 +711,7 @@ static int call_implies_callbacks(void *unused, int argc, char **argv, char **az if (!arg) continue; } - cb->callback(arg, argv[3]); + cb->callback(arg, argv[3], argv[4]); } END_FOR_EACH_PTR(cb); return 0; @@ -720,7 +720,7 @@ static int call_implies_callbacks(void *unused, int argc, char **argv, char **az static void match_call_implies(struct expression *expr) { static_call_expr = expr; - sql_select_call_implies("function, type, parameter, value", expr, + sql_select_call_implies("function, type, parameter, key, value", expr, call_implies_callbacks); return; } diff --git a/smatch_extra.c b/smatch_extra.c index 08dcb5da..1aa3158d 100644 --- a/smatch_extra.c +++ b/smatch_extra.c @@ -800,9 +800,19 @@ static void match_pointer_as_array(struct expression *expr) check_dereference(expr->unop->left); } -static void set_param_dereferenced(struct expression *arg, char *unused) +static void set_param_dereferenced(struct expression *arg, char *key, char *unused) { - check_dereference(arg); + struct symbol *sym; + char *name; + + name = get_variable_from_key(arg, key, &sym); + if (!name || !sym) + goto free; + + set_extra_nomod(name, sym, alloc_estate_range(valid_ptr_min_sval, valid_ptr_max_sval)); + +free: + free_string(name); } static void match_function_def(struct symbol *sym) @@ -1348,6 +1358,18 @@ int implied_not_equal(struct expression *expr, long long val) return !possibly_false(expr, SPECIAL_NOTEQUAL, value_expr(val)); } +int implied_not_equal_name_sym(char *name, struct symbol *sym, long long val) +{ + struct smatch_state *estate; + + estate = get_state(SMATCH_EXTRA, name, sym); + if (!estate) + return 0; + if (!rl_has_sval(estate_rl(estate), sval_type_val(estate_type(estate), 0))) + return 1; + return 0; +} + static void struct_member_callback(struct expression *call, int param, char *printed_name, struct smatch_state *state) { if (estate_is_whole(state)) diff --git a/smatch_extra.h b/smatch_extra.h index 768daff8..b0be4990 100644 --- a/smatch_extra.h +++ b/smatch_extra.h @@ -143,6 +143,7 @@ struct data_info *get_dinfo(struct smatch_state *state); void add_extra_mod_hook(void (*fn)(const char *name, struct symbol *sym, struct smatch_state *state)); int implied_not_equal(struct expression *expr, long long val); +int implied_not_equal_name_sym(char *name, struct symbol *sym, long long val); struct sm_state *__extra_handle_canonical_loops(struct statement *loop, struct stree **stree); int __iterator_unchanged(struct sm_state *sm); -- 2.11.4.GIT