Print this page
11506 smatch resync

@@ -639,11 +639,11 @@
 
         new_state = alloc_link_state(links);
         set_state(link_id, var, sym, new_state);
 }
 
-static void match_inc(struct sm_state *sm)
+static void match_inc(struct sm_state *sm, bool preserve)
 {
         struct string_list *links;
         struct smatch_state *state, *new;
         struct compare_data *data;
         char *tmp;

@@ -671,10 +671,12 @@
                 case SPECIAL_EQUAL:
                 case SPECIAL_GTE:
                 case SPECIAL_UNSIGNED_GTE:
                 case '>':
                 case SPECIAL_UNSIGNED_GT:
+                        if (preserve)
+                                break;
                         new = alloc_compare_state(
                                         data->left, data->left_var, data->left_vsl,
                                         flip ? '<' : '>',
                                         data->right, data->right_var, data->right_vsl);
                         set_state(compare_id, tmp, NULL, new);

@@ -691,11 +693,11 @@
                         set_state(compare_id, tmp, NULL, &undefined);
                 }
         } END_FOR_EACH_PTR(tmp);
 }
 
-static void match_dec(struct sm_state *sm)
+static void match_dec(struct sm_state *sm, bool preserve)
 {
         struct string_list *links;
         struct smatch_state *state;
         char *tmp;
 

@@ -711,10 +713,13 @@
                 case '<':
                 case SPECIAL_UNSIGNED_LT: {
                         struct compare_data *data = state->data;
                         struct smatch_state *new;
 
+                        if (preserve)
+                                break;
+
                         new = alloc_compare_state(
                                         data->left, data->left_var, data->left_vsl,
                                         '<',
                                         data->right, data->right_var, data->right_vsl);
                         set_state(compare_id, tmp, NULL, new);

@@ -724,24 +729,62 @@
                         set_state(compare_id, tmp, NULL, &undefined);
                 }
         } END_FOR_EACH_PTR(tmp);
 }
 
+static void reset_sm(struct sm_state *sm)
+{
+        struct string_list *links;
+        char *tmp;
+
+        links = sm->state->data;
+
+        FOR_EACH_PTR(links, tmp) {
+                set_state(compare_id, tmp, NULL, &undefined);
+        } END_FOR_EACH_PTR(tmp);
+        set_state(link_id, sm->name, sm->sym, &undefined);
+}
+
+static bool match_add_sub_assign(struct sm_state *sm, struct expression *expr)
+{
+        struct range_list *rl;
+        sval_t zero = { .type = &int_ctype };
+
+        if (!expr || expr->type != EXPR_ASSIGNMENT)
+                return false;
+        if (expr->op != SPECIAL_ADD_ASSIGN && expr->op != SPECIAL_SUB_ASSIGN)
+                return false;
+
+        get_absolute_rl(expr->right, &rl);
+        if (sval_is_negative(rl_min(rl))) {
+                reset_sm(sm);
+                return false;
+        }
+
+        if (expr->op == SPECIAL_ADD_ASSIGN)
+                match_inc(sm, rl_has_sval(rl, zero));
+        else
+                match_dec(sm, rl_has_sval(rl, zero));
+        return true;
+}
+
 static void match_inc_dec(struct sm_state *sm, struct expression *mod_expr)
 {
         /*
          * if (foo > bar) then ++foo is also > bar.
          */
         if (!mod_expr)
                 return;
+        if (match_add_sub_assign(sm, mod_expr))
+                return;
         if (mod_expr->type != EXPR_PREOP && mod_expr->type != EXPR_POSTOP)
                 return;
 
         if (mod_expr->op == SPECIAL_INCREMENT)
-                match_inc(sm);
+                match_inc(sm, false);
         else if (mod_expr->op == SPECIAL_DECREMENT)
-                match_dec(sm);
+                match_dec(sm, false);
 }
 
 static int is_self_assign(struct expression *expr)
 {
         if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')

@@ -749,28 +792,23 @@
         return expr_equiv(expr->left, expr->right);
 }
 
 static void match_modify(struct sm_state *sm, struct expression *mod_expr)
 {
-        struct string_list *links;
-        char *tmp;
-
         if (mod_expr && is_self_assign(mod_expr))
                 return;
 
         /* handled by match_inc_dec() */
         if (mod_expr &&
             ((mod_expr->type == EXPR_PREOP || mod_expr->type == EXPR_POSTOP) &&
              (mod_expr->op == SPECIAL_INCREMENT || mod_expr->op == SPECIAL_DECREMENT)))
                 return;
+        if (mod_expr && mod_expr->type == EXPR_ASSIGNMENT &&
+            (mod_expr->op == SPECIAL_ADD_ASSIGN || mod_expr->op == SPECIAL_SUB_ASSIGN))
+                return;
 
-        links = sm->state->data;
-
-        FOR_EACH_PTR(links, tmp) {
-                set_state(compare_id, tmp, NULL, &undefined);
-        } END_FOR_EACH_PTR(tmp);
-        set_state(link_id, sm->name, sm->sym, &undefined);
+        reset_sm(sm);
 }
 
 static void match_preop(struct expression *expr)
 {
         struct expression *parent;

@@ -1602,11 +1640,11 @@
                 ret = flip_comparison(ret);
 
         return ret;
 }
 
-int get_comparison(struct expression *a, struct expression *b)
+static int get_comparison_helper(struct expression *a, struct expression *b, bool use_extra)
 {
         char *one = NULL;
         char *two = NULL;
         int ret = 0;
 

@@ -1651,15 +1689,25 @@
 
 free:
         free_string(one);
         free_string(two);
 
-        if (!ret)
+        if (!ret && use_extra)
                 return comparison_from_extra(a, b);
         return ret;
 }
 
+int get_comparison(struct expression *a, struct expression *b)
+{
+        return get_comparison_helper(a, b, true);
+}
+
+int get_comparison_no_extra(struct expression *a, struct expression *b)
+{
+        return get_comparison_helper(a, b, false);
+}
+
 int possible_comparison(struct expression *a, int comparison, struct expression *b)
 {
         char *one = NULL;
         char *two = NULL;
         int ret = 0;

@@ -2325,11 +2373,11 @@
         char *p;
 
         if (!parse_comparison(&value, op))
                 return 0;
 
-        snprintf(buf, sizeof(buf), value);
+        snprintf(buf, sizeof(buf), "%s", value);
 
         p = buf;
         if (*p++ != '$')
                 return 0;
 

@@ -2493,10 +2541,11 @@
 }
 
 void register_comparison(int id)
 {
         compare_id = id;
+        set_dynamic_states(compare_id);
         add_hook(&save_start_states, AFTER_DEF_HOOK);
         add_unmatched_state_hook(compare_id, unmatched_comparison);
         add_pre_merge_hook(compare_id, &pre_merge_hook);
         add_merge_hook(compare_id, &merge_compare_states);
         add_hook(&free_data, AFTER_FUNC_HOOK);

@@ -2513,10 +2562,12 @@
 }
 
 void register_comparison_links(int id)
 {
         link_id = id;
+        db_ignore_states(link_id);
+        set_dynamic_states(link_id);
         add_merge_hook(link_id, &merge_links);
         add_modification_hook(link_id, &match_modify);
         add_modification_hook_late(link_id, match_inc_dec);
 
         add_member_info_callback(link_id, struct_member_callback);

@@ -2529,10 +2580,11 @@
 }
 
 void register_comparison_inc_dec_links(int id)
 {
         inc_dec_link_id = id;
+        set_dynamic_states(inc_dec_link_id);
         set_up_link_functions(inc_dec_id, inc_dec_link_id);
 }
 
 static void filter_by_sm(struct sm_state *sm, int op,
                        struct state_list **true_stack,