Print this page
12166 resync smatch to 0.6.1-rc1-il-3

@@ -25,12 +25,16 @@
 
 struct sqlite3 *smatch_db;
 struct sqlite3 *mem_db;
 struct sqlite3 *cache_db;
 
+int debug_db;
+
 static int return_id;
 
+static void call_return_state_hooks(struct expression *expr);
+
 #define SQLITE_CACHE_PAGES 1000
 
 struct def_callback {
         int hook_type;
         void (*callback)(const char *name, struct symbol *sym, char *key, char *value);

@@ -103,11 +107,11 @@
 {
         int i;
 
         for (i = 0; i < argc; i++) {
                 if (i != 0)
-                        printf(", ");
+                        sm_printf(", ");
                 sm_printf("%s", argv[i]);
         }
         sm_printf("\n");
         return 0;
 }

@@ -118,11 +122,11 @@
         int rc;
 
         if (!db)
                 return;
 
-        if (option_debug) {
+        if (option_debug || debug_db) {
                 sm_msg("%s", sql);
                 if (strncasecmp(sql, "select", strlen("select")) == 0)
                         sqlite3_exec(db, sql, print_sql_output, NULL, NULL);
         }
 

@@ -799,10 +803,65 @@
                         return 1;
                 p = next;
         }
 }
 
+char *sm_to_arg_name(struct expression *expr, struct sm_state *sm)
+{
+        struct symbol *sym;
+        const char *sm_name;
+        char *name;
+        bool is_address = false;
+        bool add_star = false;
+        char buf[256];
+        char *ret = NULL;
+        int len;
+
+        expr = strip_expr(expr);
+        if (!expr)
+                return NULL;
+
+        if (expr->type == EXPR_PREOP && expr->op == '&') {
+                expr = strip_expr(expr->unop);
+                is_address = true;
+        }
+
+        name = expr_to_var_sym(expr, &sym);
+        if (!name || !sym)
+                goto free;
+        if (sym != sm->sym)
+                goto free;
+
+        sm_name = sm->name;
+        add_star = false;
+        if (sm_name[0] == '*') {
+                add_star = true;
+                sm_name++;
+        }
+
+        len = strlen(name);
+        if (strncmp(name, sm_name, len) != 0)
+                goto free;
+        if (sm_name[len] == '\0') {
+                snprintf(buf, sizeof(buf), "%s%s$",
+                         add_star ? "*" : "", is_address ? "*" : "");
+        } else {
+                if (sm_name[len] != '.' && sm_name[len] != '-')
+                        goto free;
+                if (sm_name[len] == '-')
+                        len++;
+                // FIXME does is_address really imply that sm_name[len] == '-'
+                snprintf(buf, sizeof(buf), "%s$->%s", add_star ? "*" : "",
+                         sm_name + len);
+        }
+
+        ret = alloc_sname(buf);
+free:
+        free_string(name);
+        return ret;
+}
+
 static void print_struct_members(struct expression *call, struct expression *expr, int param, int offset, struct stree *stree,
         void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm))
 {
         struct sm_state *sm;
         const char *sm_name;

@@ -1415,45 +1474,41 @@
 static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
 {
         sql_insert_return_states(return_id, return_ranges, INTERNAL, -1, "", function_signature());
 }
 
-static void call_return_state_hooks_conditional(struct expression *expr)
+static bool call_return_state_hooks_conditional(struct expression *expr)
 {
-        struct returned_state_callback *cb;
-        struct range_list *rl;
-        const char *return_ranges;
         int final_pass_orig = final_pass;
+        static int recurse;
 
+        if (recurse >= 2)
+                return false;
+        if (!expr ||
+            (expr->type != EXPR_CONDITIONAL && expr->type != EXPR_SELECT))
+                return false;
+
+        recurse++;
+
         __push_fake_cur_stree();
 
         final_pass = 0;
         __split_whole_condition(expr->conditional);
         final_pass = final_pass_orig;
 
-        return_ranges = get_return_ranges_str(expr->cond_true ?: expr->conditional, &rl);
+        call_return_state_hooks(expr->cond_true ?: expr->conditional);
 
-        set_state(RETURN_ID, "return_ranges", NULL, alloc_estate_rl(rl));
-
-        return_id++;
-        FOR_EACH_PTR(returned_state_callbacks, cb) {
-                cb->callback(return_id, (char *)return_ranges, expr->cond_true);
-        } END_FOR_EACH_PTR(cb);
-
         __push_true_states();
         __use_false_states();
 
-        return_ranges = get_return_ranges_str(expr->cond_false, &rl);
-        set_state(RETURN_ID, "return_ranges", NULL, alloc_estate_rl(rl));
+        call_return_state_hooks(expr->cond_false);
 
-        return_id++;
-        FOR_EACH_PTR(returned_state_callbacks, cb) {
-                cb->callback(return_id, (char *)return_ranges, expr->cond_false);
-        } END_FOR_EACH_PTR(cb);
-
         __merge_true_states();
         __free_fake_cur_stree();
+
+        recurse--;
+        return true;
 }
 
 static void call_return_state_hooks_compare(struct expression *expr)
 {
         struct returned_state_callback *cb;

@@ -1534,12 +1589,16 @@
         /* bail if it gets too complicated */
         nr_possible = 0;
         FOR_EACH_PTR(sm->possible, tmp) {
                 if (tmp->merged)
                         continue;
+                if (ptr_in_list(tmp, already_handled))
+                        continue;
+                add_ptr_list(&already_handled, tmp);
                 nr_possible++;
         } END_FOR_EACH_PTR(tmp);
+        free_slist(&already_handled);
         nr_states = get_db_state_count();
         if (nr_states * nr_possible >= 2000)
                 return 0;
 
         FOR_EACH_PTR(sm->possible, tmp) {

@@ -1591,10 +1650,13 @@
 
 static bool has_possible_negative(struct sm_state *sm)
 {
         struct sm_state *tmp;
 
+        if (!type_signed(estate_type(sm->state)))
+                return false;
+
         FOR_EACH_PTR(sm->possible, tmp) {
                 if (!estate_rl(tmp->state))
                         continue;
                 if (sval_is_negative(estate_min(tmp->state)) &&
                     sval_is_negative(estate_max(tmp->state)))

@@ -1602,11 +1664,11 @@
         } END_FOR_EACH_PTR(tmp);
 
         return false;
 }
 
-static bool has_possible_zero_null(struct sm_state *sm)
+static bool has_separate_zero_null(struct sm_state *sm)
 {
         struct sm_state *tmp;
         sval_t sval;
 
         FOR_EACH_PTR(sm->possible, tmp) {

@@ -1624,21 +1686,19 @@
         struct sm_state *sm;
         struct returned_state_callback *cb;
         struct range_list *rl;
         const char *return_ranges;
         struct range_list *ret_rl;
+        bool separate_zero;
         int undo;
-        bool has_zero;
 
         /* We're going to print the states 3 times */
         if (get_db_state_count() > 10000 / 3)
                 return 0;
 
         if (!get_implied_rl(expr, &rl) || !rl)
                 return 0;
-        if (is_whole_rl(rl) || is_whole_rl_non_zero(rl))
-                return 0;
         /* Forget about INT_MAX and larger */
         if (rl_max(rl).value <= 0)
                 return 0;
         if (!sval_is_negative(rl_min(rl)))
                 return 0;

@@ -1646,13 +1706,13 @@
         sm = get_sm_state_expr(SMATCH_EXTRA, expr);
         if (!sm)
                 return 0;
         if (!has_possible_negative(sm))
                 return 0;
-        has_zero = has_possible_zero_null(sm);
+        separate_zero = has_separate_zero_null(sm);
 
-        if (!assume(compare_expression(expr, has_zero ? '>' : SPECIAL_GTE, zero_expr())))
+        if (!assume(compare_expression(expr, separate_zero ? '>' : SPECIAL_GTE, zero_expr())))
                 return 0;
 
         return_id++;
         return_ranges = get_return_ranges_str(expr, &ret_rl);
         set_state(RETURN_ID, "return_ranges", NULL, alloc_estate_rl(ret_rl));

@@ -1660,11 +1720,11 @@
                 cb->callback(return_id, (char *)return_ranges, expr);
         } END_FOR_EACH_PTR(cb);
 
         end_assume();
 
-        if (has_zero) {
+        if (separate_zero) {
                 undo = assume(compare_expression(expr, SPECIAL_EQUAL, zero_expr()));
 
                 return_id++;
                 return_ranges = get_return_ranges_str(expr, &ret_rl);
                 set_state(RETURN_ID, "return_ranges", NULL, alloc_estate_rl(ret_rl));

@@ -1717,11 +1777,11 @@
         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_zero_null(sm))
+        if (!has_separate_zero_null(sm))
                 return 0;
 
         nr_states = get_db_state_count();
         if (option_info && nr_states >= 1500)
                 return 0;

@@ -1759,10 +1819,41 @@
         __free_fake_cur_stree();
 
         return 1;
 }
 
+static bool is_kernel_success_fail(struct sm_state *sm)
+{
+        struct sm_state *tmp;
+        struct range_list *rl;
+        bool has_zero = false;
+        bool has_neg = false;
+
+        if (!type_signed(estate_type(sm->state)))
+                return false;
+
+        FOR_EACH_PTR(sm->possible, tmp) {
+                rl = estate_rl(tmp->state);
+                if (!rl)
+                        return false;
+                if (rl_min(rl).value == 0 && rl_max(rl).value == 0) {
+                        has_zero = true;
+                        continue;
+                }
+                has_neg = true;
+                if (rl_min(rl).value >= -4095 && rl_max(rl).value < 0)
+                        continue;
+                if (strcmp(tmp->state->name, "s32min-(-1)") == 0)
+                        continue;
+                if (strcmp(tmp->state->name, "s32min-(-1),1-s32max") == 0)
+                        continue;
+                return false;
+        } END_FOR_EACH_PTR(tmp);
+
+        return has_zero && has_neg;
+}
+
 static int call_return_state_hooks_split_success_fail(struct expression *expr)
 {
         struct sm_state *sm;
         struct range_list *rl;
         struct range_list *nonzero_rl;

@@ -1775,30 +1866,25 @@
 
         if (option_project != PROJ_KERNEL)
                 return 0;
 
         nr_states = get_db_state_count();
-        if (nr_states > 1500)
+        if (nr_states > 2000)
                 return 0;
 
         sm = get_sm_state_expr(SMATCH_EXTRA, expr);
         if (!sm)
                 return 0;
         if (ptr_list_size((struct ptr_list *)sm->possible) == 1)
                 return 0;
+        if (!is_kernel_success_fail(sm))
+                return 0;
 
         rl = estate_rl(sm->state);
         if (!rl)
                 return 0;
 
-        if (rl_min(rl).value < -4095 || rl_min(rl).value >= 0)
-                return 0;
-        if (rl_max(rl).value != 0)
-                return 0;
-        if (!has_possible_zero_null(sm))
-                return 0;
-
         __push_fake_cur_stree();
 
         final_pass = 0;
         __split_whole_condition(expr);
         final_pass = final_pass_orig;

@@ -1840,19 +1926,10 @@
         if (rl_min(rl).value == 0 && rl_max(rl).value == 1)
                 return 1;
         return 0;
 }
 
-static int is_conditional(struct expression *expr)
-{
-        if (!expr)
-                return 0;
-        if (expr->type == EXPR_CONDITIONAL || expr->type == EXPR_SELECT)
-                return 1;
-        return 0;
-}
-
 static int splitable_function_call(struct expression *expr)
 {
         struct sm_state *sm;
         char buf[64];
 

@@ -1906,25 +1983,18 @@
         struct returned_state_callback *cb;
         struct range_list *ret_rl;
         const char *return_ranges;
         struct sm_state *tmp;
         int ret = 0;
-        int nr_possible, nr_states;
         struct state_list *already_handled = NULL;
 
         if (!sm || !sm->merged)
                 return 0;
 
         if (too_many_possible(sm))
                 return 0;
 
-        /* bail if it gets too complicated */
-        nr_possible = ptr_list_size((struct ptr_list *)sm->possible);
-        nr_states = get_db_state_count();
-        if (nr_states * nr_possible >= 2000)
-                return 0;
-
         FOR_EACH_PTR(sm->possible, tmp) {
                 if (tmp->merged)
                         continue;
                 if (ptr_in_list(tmp, already_handled))
                         continue;

@@ -1959,20 +2029,22 @@
         if (!start_sm)
                 return 0;
         sm = get_sm_state(SMATCH_EXTRA, start_sm->name, start_sm->sym);
         if (!sm || estate_get_single_value(sm->state, &sval))
                 return 0;
+
+        if (get_db_state_count() * 2 >= 2000)
+                return 0;
+
         return split_on_bool_sm(sm, expr);
 }
 
 static int split_by_null_nonnull_param(struct expression *expr)
 {
         struct symbol *arg;
         struct sm_state *sm;
-        sval_t zero = {
-                .type = &ulong_ctype,
-        };
+        int nr_possible;
 
         /* function must only take one pointer */
         if (ptr_list_size((struct ptr_list *)cur_func_sym->ctype.base_type->arguments) != 1)
                 return 0;
         arg = first_ptr_list((struct ptr_list *)cur_func_sym->ctype.base_type->arguments);

@@ -1985,13 +2057,17 @@
                 return 0;
         sm = get_sm_state(SMATCH_EXTRA, arg->ident->name, arg);
         if (!sm)
                 return 0;
 
-        if (!rl_has_sval(estate_rl(sm->state), zero))
+        if (!has_separate_zero_null(sm))
                 return 0;
 
+        nr_possible = ptr_list_size((struct ptr_list *)sm->possible);
+        if (get_db_state_count() * nr_possible >= 2000)
+                return 0;
+
         return split_on_bool_sm(sm, expr);
 }
 
 struct expression *strip_expr_statement(struct expression *expr)
 {

@@ -2036,12 +2112,11 @@
         if (expr && (expr->type == EXPR_COMPARE ||
                      !get_implied_value(expr, &sval)) &&
             (is_condition(expr) || is_boolean(expr))) {
                 call_return_state_hooks_compare(expr);
                 return;
-        } else if (is_conditional(expr)) {
-                call_return_state_hooks_conditional(expr);
+        } else if (call_return_state_hooks_conditional(expr)) {
                 return;
         } else if (call_return_state_hooks_split_possible(expr)) {
                 return;
         } else if (split_positive_from_negative(expr)) {
                 return;

@@ -2490,11 +2565,11 @@
 
 char *get_variable_from_key(struct expression *arg, const char *key, struct symbol **sym)
 {
         char buf[256];
         char *tmp;
-        bool add_star = false;
+        int star_cnt = 0;
 
         if (!arg)
                 return NULL;
 
         arg = strip_expr(arg);

@@ -2514,29 +2589,34 @@
                         free_string(tmp);
                         return alloc_string(buf);
                 }
         }
 
-        if (key[0] == '*') {
-                add_star = true;
+        while (key[0] == '*') {
+                star_cnt++;
                 key++;
         }
 
+        if (arg->type == EXPR_PREOP && arg->op == '&' && star_cnt) {
+                arg = strip_expr(arg->unop);
+                star_cnt--;
+        }
+
         if (arg->type == EXPR_PREOP && arg->op == '&') {
                 arg = strip_expr(arg->unop);
                 tmp = expr_to_var_sym(arg, sym);
                 if (!tmp)
                         return NULL;
-                snprintf(buf, sizeof(buf), "%s%s.%s",
-                         add_star ? "*" : "", tmp, key + 3);
+                snprintf(buf, sizeof(buf), "%.*s%s.%s",
+                         star_cnt, "**********", tmp, key + 3);
                 return alloc_string(buf);
         }
 
         tmp = expr_to_var_sym(arg, sym);
         if (!tmp)
                 return NULL;
-        snprintf(buf, sizeof(buf), "%s%s%s", add_star ? "*" : "", tmp, key + 1);
+        snprintf(buf, sizeof(buf), "%.*s%s%s", star_cnt, "**********", tmp, key + 1);
         free_string(tmp);
         return alloc_string(buf);
 }
 
 char *get_chunk_from_key(struct expression *arg, char *key, struct symbol **sym, struct var_sym_list **vsl)

@@ -2548,30 +2628,33 @@
         return get_variable_from_key(arg, key, sym);
 }
 
 const char *state_name_to_param_name(const char *state_name, const char *param_name)
 {
+        int star_cnt = 0;
         int name_len;
-        static char buf[256];
-        bool add_star = false;
+        char buf[256];
 
         name_len = strlen(param_name);
 
-        if (state_name[0] == '*') {
-                add_star = true;
+        while (state_name[0] == '*') {
+                star_cnt++;
                 state_name++;
         }
 
+        /* ten out of ten stars! */
+        if (star_cnt > 10)
+                return NULL;
+
         if (strcmp(state_name, param_name) == 0) {
-                snprintf(buf, sizeof(buf), "%s$", add_star ? "*" : "");
+                snprintf(buf, sizeof(buf), "%.*s$", star_cnt, "**********");
                 return alloc_sname(buf);
         }
 
         if (state_name[name_len] == '-' && /* check for '-' from "->" */
             strncmp(state_name, param_name, name_len) == 0) {
-                snprintf(buf, sizeof(buf), "%s$%s",
-                         add_star ? "*" : "", state_name + name_len);
+                snprintf(buf, sizeof(buf), "%.*s$%s", star_cnt, "**********", state_name + name_len);
                 return alloc_sname(buf);
         }
         return NULL;
 }