Print this page
12724 update smatch to 0.6.1-rc1-il-5

@@ -48,10 +48,11 @@
         void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm);
 };
 ALLOCATOR(member_info_callback, "caller_info callbacks");
 DECLARE_PTR_LIST(member_info_cb_list, struct member_info_callback);
 static struct member_info_cb_list *member_callbacks;
+static struct member_info_cb_list *member_callbacks_new;
 
 struct returned_state_callback {
         void (*callback)(int return_id, char *return_ranges, struct expression *return_expr);
 };
 ALLOCATOR(returned_state_callback, "returned state callbacks");

@@ -176,19 +177,40 @@
 void db_ignore_states(int id)
 {
         use_states[id] = 0;
 }
 
+unsigned long long __fn_mtag;
+static void set_fn_mtag(struct symbol *sym)
+{
+        char buf[128];
+
+        if (cur_func_sym->ctype.modifiers & MOD_STATIC)
+                snprintf(buf, sizeof(buf), "%s %s", get_base_file(), get_function());
+        else
+                snprintf(buf, sizeof(buf), "extern %s", get_function());
+
+        __fn_mtag = str_to_mtag(buf);
+}
+
 void sql_insert_return_states(int return_id, const char *return_ranges,
                 int type, int param, const char *key, const char *value)
 {
+        unsigned long long id;
+
+
         if (key && strlen(key) >= 80)
                 return;
+        if (__inline_fn)
+                id = (unsigned long)__inline_fn;
+        else
+                id = __fn_mtag;
+
         return_ranges = replace_return_ranges(return_ranges);
-        sql_insert(return_states, "'%s', '%s', %lu, %d, '%s', %d, %d, %d, '%s', '%s'",
-                   get_base_file(), get_function(), (unsigned long)__inline_fn,
-                   return_id, return_ranges, fn_static(), type, param, key, value);
+        sql_insert(return_states, "'%s', '%s', %llu, %d, '%s', %d, %d, %d, '%s', '%s'",
+                   get_base_file(), get_function(), id, return_id,
+                   return_ranges, fn_static(), type, param, key, value);
 }
 
 static struct string_list *common_funcs;
 static int is_common_function(const char *fn)
 {

@@ -370,19 +392,25 @@
                    type, param, key, value);
 }
 
 void sql_insert_mtag_about(mtag_t tag, const char *left_name, const char *right_name)
 {
-        sql_insert(mtag_about, "%lld, '%s', '%s', %d, '%s', '%s'",
-                   tag, get_filename(), get_function(), get_lineno(), left_name, right_name);
+        sql_insert_cache(mtag_about, "%lld, '%s', '%s', %d, '%s', '%s'",
+                         tag, get_filename(), get_function(), get_lineno(),
+                         left_name, right_name);
 }
 
-void sql_insert_mtag_map(mtag_t tag, int offset, mtag_t container)
+void sql_insert_mtag_info(mtag_t tag, int type, const char *value)
 {
-        sql_insert(mtag_map, "%lld, %d, %lld", tag, offset, container);
+        sql_insert_cache(mtag_info, "'%s', %lld, %d, '%s'", get_filename(), tag, type, value);
 }
 
+void sql_insert_mtag_map(mtag_t container, int container_offset, mtag_t tag, int tag_offset)
+{
+        sql_insert(mtag_map, "%lld, %d, %lld, %d", container, container_offset, tag, tag_offset);
+}
+
 void sql_insert_mtag_alias(mtag_t orig, mtag_t alias)
 {
         sql_insert(mtag_alias, "%lld, %lld", orig, alias);
 }
 

@@ -399,17 +427,17 @@
                 *saved_tag = -1ULL;
 
         return 0;
 }
 
-int mtag_map_select_container(mtag_t tag, int offset, mtag_t *container)
+int mtag_map_select_container(mtag_t tag, int container_offset, mtag_t *container)
 {
         mtag_t tmp = 0;
 
         run_sql(save_mtag, &tmp,
-                "select container from mtag_map where tag = %lld and offset = %d;",
-                tag, offset);
+                "select container from mtag_map where tag = %lld and container_offset = %d and tag_offset = 0;",
+                tag, container_offset);
 
         if (tmp == 0 || tmp == -1ULL)
                 return 0;
         *container = tmp;
         return 1;

@@ -418,11 +446,11 @@
 int mtag_map_select_tag(mtag_t container, int offset, mtag_t *tag)
 {
         mtag_t tmp = 0;
 
         run_sql(save_mtag, &tmp,
-                "select tag from mtag_map where container = %lld and offset = %d;",
+                "select tag from mtag_map where container = %lld and container_offset = %d;",
                 container, offset);
 
         if (tmp == 0 || tmp == -1ULL)
                 return 0;
         *tag = tmp;

@@ -620,10 +648,19 @@
         member_callback->owner = owner;
         member_callback->callback = callback;
         add_ptr_list(&member_callbacks, member_callback);
 }
 
+void add_caller_info_callback(int owner, void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm))
+{
+        struct member_info_callback *member_callback = __alloc_member_info_callback(0);
+
+        member_callback->owner = owner;
+        member_callback->callback = callback;
+        add_ptr_list(&member_callbacks_new, member_callback);
+}
+
 void add_split_return_callback(void (*fn)(int return_id, char *return_ranges, struct expression *returned_expr))
 {
         struct returned_state_callback *callback = __alloc_returned_state_callback(0);
 
         callback->callback = fn;

@@ -849,11 +886,12 @@
         free_string(name);
         return ret;
 }
 
 static void print_struct_members(struct expression *call, struct expression *expr, int param, struct stree *stree,
-        void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm))
+        void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm),
+        bool new)
 {
         struct sm_state *sm;
         const char *sm_name;
         char *name;
         struct symbol *sym;

@@ -889,28 +927,37 @@
                         add_star = true;
                         sm_name++;
                 }
                 // FIXME: simplify?
                 if (!add_star && strcmp(name, sm_name) == 0) {
-                        if (is_address)
+                        if (is_address) {
                                 snprintf(printed_name, sizeof(printed_name), "*$");
-                        else /* these are already handled. fixme: handle them here */
+                        } else {
+                                if (new)
+                                        snprintf(printed_name, sizeof(printed_name), "$");
+                                else
                                 continue;
+                        }
                 } else if (add_star && strcmp(name, sm_name) == 0) {
                         snprintf(printed_name, sizeof(printed_name), "%s*$",
                                  is_address ? "*" : "");
                 } else if (strncmp(name, sm_name, len) == 0) {
                         if (sm_name[len] != '.' && sm_name[len] != '-')
                                 continue;
-                        if (is_address)
+                        if (is_address && sm_name[len] == '.') {
                                 snprintf(printed_name, sizeof(printed_name),
                                          "%s$->%s", add_star ? "*" : "",
                                          sm_name + len + 1);
-                        else
+                        } else if (is_address && sm_name[len] == '-') {
                                 snprintf(printed_name, sizeof(printed_name),
+                                         "%s(*$)%s", add_star ? "*" : "",
+                                         sm_name + len);
+                        } else {
+                                snprintf(printed_name, sizeof(printed_name),
                                          "%s$%s", add_star ? "*" : "",
                                          sm_name + len);
+                        }
                 } else {
                         continue;
                 }
                 if (is_recursive_member(printed_name))
                         continue;

@@ -934,19 +981,44 @@
 
         FOR_EACH_PTR(member_callbacks, cb) {
                 stree = get_all_states_stree(cb->owner);
                 i = 0;
                 FOR_EACH_PTR(call->args, arg) {
-                        print_struct_members(call, arg, i, stree, cb->callback);
+                        print_struct_members(call, arg, i, stree, cb->callback, 0);
                         i++;
                 } END_FOR_EACH_PTR(arg);
                 free_stree(&stree);
         } END_FOR_EACH_PTR(cb);
 
         free_string(name);
 }
 
+static void match_call_info_new(struct expression *call)
+{
+        struct member_info_callback *cb;
+        struct expression *arg;
+        struct stree *stree;
+        char *name;
+        int i;
+
+        name = get_fnptr_name(call->fn);
+        if (!name)
+                return;
+
+        FOR_EACH_PTR(member_callbacks_new, cb) {
+                stree = get_all_states_stree(cb->owner);
+                i = 0;
+                FOR_EACH_PTR(call->args, arg) {
+                        print_struct_members(call, arg, i, stree, cb->callback, 1);
+                        i++;
+                } END_FOR_EACH_PTR(arg);
+                free_stree(&stree);
+        } END_FOR_EACH_PTR(cb);
+
+        free_string(name);
+}
+
 static int get_param(int param, char **name, struct symbol **sym)
 {
         struct symbol *arg;
         int i;
 

@@ -1104,10 +1176,11 @@
         struct timeval end_time;
 
         if (!sym || !sym->ident)
                 return;
 
+        set_fn_mtag(sym);
         gettimeofday(&data.start_time, NULL);
 
         __push_fake_cur_stree();
         __unnullify_path();
 

@@ -1567,11 +1640,11 @@
 
 static int call_return_state_hooks_split_possible(struct expression *expr)
 {
         struct sm_state *sm;
 
-        if (!expr || expr_equal_to_param(expr, -1))
+        if (!expr)
                 return 0;
 
         sm = get_sm_state_expr(SMATCH_EXTRA, expr);
         return split_possible_helper(sm, expr);
 }

@@ -1705,10 +1778,12 @@
         state = sm->state;
         if (!estate_rl(state))
                 return 0;
         if (estate_min(state).value == 0 && estate_max(state).value == 0)
                 return 0;
+        if (has_possible_negative(sm))
+                return 0;
         if (!has_separate_zero_null(sm))
                 return 0;
 
         nr_states = get_db_state_count();
         if (option_info && nr_states >= 1500)

@@ -2018,10 +2093,28 @@
         if (!last_stmt || last_stmt->type != STMT_EXPRESSION)
                 return orig;
         return strip_expr(last_stmt->expression);
 }
 
+static bool is_kernel_error_path(struct expression *expr)
+{
+        struct range_list *rl;
+
+        /*
+         * Splitting up returns requires resources.  It also requires resources
+         * for the caller.  It doesn't seem worth it to split anything up.
+         */
+        if (!get_implied_rl(expr, &rl))
+                return false;
+        if (rl_type(rl) != &int_ctype)
+                return false;
+        if (rl_min(rl).value >= -4095 &&
+            rl_max(rl).value < 0)
+                return true;
+        return false;
+}
+
 static void call_return_state_hooks(struct expression *expr)
 {
         struct returned_state_callback *cb;
         struct range_list *ret_rl;
         const char *return_ranges;

@@ -2042,10 +2135,12 @@
             (is_condition(expr) || is_boolean(expr))) {
                 call_return_state_hooks_compare(expr);
                 return;
         } else if (call_return_state_hooks_conditional(expr)) {
                 return;
+        } else if (is_kernel_error_path(expr)) {
+                goto vanilla;
         } else if (call_return_state_hooks_split_possible(expr)) {
                 return;
         } else if (split_positive_from_negative(expr)) {
                 return;
         } else if (call_return_state_hooks_split_null_non_null_zero(expr)) {

@@ -2163,10 +2258,11 @@
                 "db/constraints.schema",
                 "db/constraints_required.schema",
                 "db/fn_ptr_data_link.schema",
                 "db/fn_data_link.schema",
                 "db/mtag_about.schema",
+                "db/mtag_info.schema",
                 "db/mtag_map.schema",
                 "db/mtag_data.schema",
                 "db/mtag_alias.schema",
         };
         static char buf[4096];

@@ -2210,11 +2306,13 @@
         int rc;
         const char *schema_files[] = {
                 "db/call_implies.schema",
                 "db/return_implies.schema",
                 "db/type_info.schema",
+                "db/mtag_about.schema",
                 "db/mtag_data.schema",
+                "db/mtag_info.schema",
                 "db/sink_info.schema",
         };
         static char buf[4096];
         int fd;
         int ret;

@@ -2275,17 +2373,24 @@
         return 0;
 }
 
 static void dump_cache(struct symbol_list *sym_list)
 {
+        const char *cache_tables[] = {
+                "type_info", "return_implies", "call_implies", "mtag_data",
+                "mtag_info", "mtag_about", "sink_info",
+        };
+        char buf[64];
+        int i;
+
         if (!option_info)
                 return;
-        cache_sql(&save_cache_data, (char *)"type_info", "select * from type_info;");
-        cache_sql(&save_cache_data, (char *)"return_implies", "select * from return_implies;");
-        cache_sql(&save_cache_data, (char *)"call_implies", "select * from call_implies;");
-        cache_sql(&save_cache_data, (char *)"mtag_data", "select * from mtag_data;");
-        cache_sql(&save_cache_data, (char *)"sink_info", "select * from sink_info;");
+
+        for (i = 0; i < ARRAY_SIZE(cache_tables); i++) {
+                snprintf(buf, sizeof(buf), "select * from %s;", cache_tables[i]);
+                cache_sql(&save_cache_data, (char *)cache_tables[i], buf);
+        }
 }
 
 void open_smatch_db(char *db_file)
 {
         int rc;

@@ -2427,10 +2532,11 @@
 }
 
 void register_definition_db_callbacks(int id)
 {
         add_hook(&match_call_info, FUNCTION_CALL_HOOK);
+        add_hook(&match_call_info_new, FUNCTION_CALL_HOOK);
         add_split_return_callback(match_return_info);
         add_split_return_callback(print_returned_struct_members);
         add_hook(&call_return_state_hooks, RETURN_HOOK);
         add_hook(&match_end_func_info, END_FUNC_HOOK);
         add_hook(&match_after_func, AFTER_FUNC_HOOK);

@@ -2491,13 +2597,15 @@
         return get_variable_from_key(arg, key, sym);
 }
 
 char *get_variable_from_key(struct expression *arg, const char *key, struct symbol **sym)
 {
+        struct symbol *type;
         char buf[256];
         char *tmp;
         int star_cnt = 0;
+        bool add_dot = false;
 
         if (!arg)
                 return NULL;
 
         arg = strip_expr(arg);

@@ -2517,16 +2625,41 @@
                         free_string(tmp);
                         return alloc_string(buf);
                 }
         }
 
+        if (strncmp(key, "(*$)", 4) == 0) {
+                char buf[64];
+
+                if (arg->type == EXPR_PREOP && arg->op == '&') {
+                        arg = strip_expr(arg->unop);
+                        snprintf(buf, sizeof(buf), "$%s", key + 4);
+                        return get_variable_from_key(arg, buf, sym);
+                } else {
+                        tmp = expr_to_var_sym(arg, sym);
+                        if (!tmp)
+                                return NULL;
+                        snprintf(buf, sizeof(buf), "(*%s)%s", tmp, key + 4);
+                        free_string(tmp);
+                        return alloc_string(buf);
+                }
+        }
+
         while (key[0] == '*') {
                 star_cnt++;
                 key++;
         }
 
-        if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt) {
+        /*
+         * FIXME:  This is a hack.
+         * We should be able to parse expressions like (*$)->foo and *$->foo.
+         */
+        type = get_type(arg);
+        if (is_struct_ptr(type))
+                add_dot = true;
+
+        if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt && !add_dot) {
                 arg = strip_expr(arg->unop);
                 star_cnt--;
         }
 
         if (arg->type == EXPR_PREOP && arg->op == '&') {

@@ -2571,10 +2704,18 @@
 
         /* ten out of ten stars! */
         if (star_cnt > 10)
                 return NULL;
 
+        if (strncmp(state_name, "(*", 2) == 0 &&
+            strncmp(state_name + 2, param_name, name_len) == 0 &&
+            state_name[name_len + 2] == ')') {
+                snprintf(buf, sizeof(buf), "%.*s(*$)%s", star_cnt, "**********",
+                         state_name + name_len + 3);
+                return alloc_sname(buf);
+        }
+
         if (strcmp(state_name, param_name) == 0) {
                 snprintf(buf, sizeof(buf), "%.*s$", star_cnt, "**********");
                 return alloc_sname(buf);
         }