db: make call_implies match caller_info with a key value pair
authorDan Carpenter <dan.carpenter@oracle.com>
Thu, 19 Jun 2014 06:50:03 +0000 (19 09:50 +0300)
committerDan Carpenter <dan.carpenter@oracle.com>
Thu, 19 Jun 2014 06:50:03 +0000 (19 09:50 +0300)
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 <dan.carpenter@oracle.com>
check_check_deref.c
check_deref.c
check_deref_check.c
check_dereferences_param.c
check_free.c
check_frees_param.c
smatch.h
smatch_data/db/call_implies.schema
smatch_db.c
smatch_extra.c
smatch_extra.h

index 676fc67..289b21e 100644 (file)
@@ -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)
index 8acbd36..3e4787b 100644 (file)
@@ -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)
index d2cd1c0..256047a 100644 (file)
@@ -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)
index 3317390..4fb99a4 100644 (file)
@@ -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);
 }
 
index 15de869..7a54ace 100644 (file)
@@ -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)
index 828d750..d2f8fec 100644 (file)
@@ -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);
 }
 
index a7a0d08..d4d8009 100644 (file)
--- 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);
index 751363d..90ca892 100644 (file)
@@ -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));
index ec06daf..22497f5 100644 (file)
@@ -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;
 }
index 08dcb5d..1aa3158 100644 (file)
@@ -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))
index 768daff..b0be499 100644 (file)
@@ -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);