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,