Print this page
11972 resync smatch
@@ -55,10 +55,19 @@
return NULL;
vs = first_ptr_list((struct ptr_list *)vsl);
return vs->sym;
}
+static const char *show_comparison(int comparison)
+{
+ if (comparison == IMPOSSIBLE_COMPARISON)
+ return "impossible";
+ if (comparison == UNKNOWN_COMPARISON)
+ return "unknown";
+ return show_special(comparison);
+}
+
struct smatch_state *alloc_compare_state(
struct expression *left,
const char *left_var, struct var_sym_list *left_vsl,
int comparison,
struct expression *right,
@@ -66,11 +75,11 @@
{
struct smatch_state *state;
struct compare_data *data;
state = __alloc_smatch_state(0);
- state->name = alloc_sname(show_special(comparison));
+ state->name = alloc_sname(show_comparison(comparison));
data = __alloc_compare_data(0);
data->left = left;
data->left_var = alloc_sname(left_var);
data->left_vsl = clone_var_sym_list(left_vsl);
data->comparison = comparison;
@@ -82,22 +91,22 @@
}
int state_to_comparison(struct smatch_state *state)
{
if (!state || !state->data)
- return 0;
+ return UNKNOWN_COMPARISON;
return ((struct compare_data *)state->data)->comparison;
}
/*
* flip_comparison() reverses the op left and right. So "x >= y" becomes "y <= x".
*/
int flip_comparison(int op)
{
switch (op) {
- case 0:
- return 0;
+ case UNKNOWN_COMPARISON:
+ return UNKNOWN_COMPARISON;
case '<':
return '>';
case SPECIAL_UNSIGNED_LT:
return SPECIAL_UNSIGNED_GT;
case SPECIAL_LTE:
@@ -114,21 +123,23 @@
return SPECIAL_UNSIGNED_LTE;
case '>':
return '<';
case SPECIAL_UNSIGNED_GT:
return SPECIAL_UNSIGNED_LT;
+ case IMPOSSIBLE_COMPARISON:
+ return UNKNOWN_COMPARISON;
default:
sm_perror("unhandled comparison %d", op);
return op;
}
}
int negate_comparison(int op)
{
switch (op) {
- case 0:
- return 0;
+ case UNKNOWN_COMPARISON:
+ return UNKNOWN_COMPARISON;
case '<':
return SPECIAL_GTE;
case SPECIAL_UNSIGNED_LT:
return SPECIAL_UNSIGNED_GTE;
case SPECIAL_LTE:
@@ -145,10 +156,12 @@
return SPECIAL_UNSIGNED_LT;
case '>':
return SPECIAL_LTE;
case SPECIAL_UNSIGNED_GT:
return SPECIAL_UNSIGNED_LTE;
+ case IMPOSSIBLE_COMPARISON:
+ return UNKNOWN_COMPARISON;
default:
sm_perror("unhandled comparison %d", op);
return op;
}
}
@@ -157,11 +170,11 @@
{
sval_t left_min, left_max, right_min, right_max;
struct symbol *type = &int_ctype;
if (!left_rl || !right_rl)
- return 0;
+ return UNKNOWN_COMPARISON;
if (type_positive_bits(rl_type(left_rl)) > type_positive_bits(type))
type = rl_type(left_rl);
if (type_positive_bits(rl_type(right_rl)) > type_positive_bits(type))
type = rl_type(right_rl);
@@ -186,21 +199,21 @@
if (sval_cmp(left_min, right_max) > 0)
return '>';
if (sval_cmp(left_min, right_max) == 0)
return SPECIAL_GTE;
- return 0;
+ return UNKNOWN_COMPARISON;
}
static int comparison_from_extra(struct expression *a, struct expression *b)
{
struct range_list *left, *right;
if (!get_implied_rl(a, &left))
- return 0;
+ return UNKNOWN_COMPARISON;
if (!get_implied_rl(b, &right))
- return 0;
+ return UNKNOWN_COMPARISON;
return rl_comparison(left, right);
}
static struct range_list *get_orig_rl(struct var_sym_list *vsl)
@@ -219,33 +232,36 @@
static struct smatch_state *unmatched_comparison(struct sm_state *sm)
{
struct compare_data *data = sm->state->data;
struct range_list *left_rl, *right_rl;
- int op;
+ int op = UNKNOWN_COMPARISON;
if (!data)
return &undefined;
+ if (is_impossible_path()) {
+ op = IMPOSSIBLE_COMPARISON;
+ goto alloc;
+ }
+
if (strstr(data->left_var, " orig"))
left_rl = get_orig_rl(data->left_vsl);
else if (!get_implied_rl_var_sym(data->left_var, vsl_to_sym(data->left_vsl), &left_rl))
- return &undefined;
+ goto alloc;
if (strstr(data->right_var, " orig"))
right_rl = get_orig_rl(data->right_vsl);
else if (!get_implied_rl_var_sym(data->right_var, vsl_to_sym(data->right_vsl), &right_rl))
- return &undefined;
+ goto alloc;
op = rl_comparison(left_rl, right_rl);
- if (op)
- return alloc_compare_state(
- data->left, data->left_var, data->left_vsl,
+
+alloc:
+ return alloc_compare_state(data->left, data->left_var, data->left_vsl,
op,
data->right, data->right_var, data->right_vsl);
-
- return &undefined;
}
/* remove_unsigned_from_comparison() is obviously a hack. */
int remove_unsigned_from_comparison(int op)
{
@@ -269,13 +285,18 @@
*/
int merge_comparisons(int one, int two)
{
int LT, EQ, GT;
- if (!one || !two)
- return 0;
+ if (one == UNKNOWN_COMPARISON || two == UNKNOWN_COMPARISON)
+ return UNKNOWN_COMPARISON;
+ if (one == IMPOSSIBLE_COMPARISON)
+ return two;
+ if (two == IMPOSSIBLE_COMPARISON)
+ return one;
+
one = remove_unsigned_from_comparison(one);
two = remove_unsigned_from_comparison(two);
if (one == two)
return one;
@@ -319,11 +340,11 @@
case '>':
GT = 1;
}
if (LT && EQ && GT)
- return 0;
+ return UNKNOWN_COMPARISON;
if (LT && EQ)
return SPECIAL_LTE;
if (LT && GT)
return SPECIAL_NOTEQUAL;
if (LT)
@@ -330,21 +351,17 @@
return '<';
if (EQ && GT)
return SPECIAL_GTE;
if (GT)
return '>';
- return 0;
+ return UNKNOWN_COMPARISON;
}
/*
- * This is for if you have "a < b" and "b <= c". Or in other words,
- * "a < b <= c". You would call this like get_combined_comparison('<', '<=').
+ * This is for if you have "a < b" and "b <= c" and you want to see how "a
+ * compares to c". You would call this like get_combined_comparison('<', '<=').
* The return comparison would be '<'.
- *
- * This function is different from merge_comparisons(), for example:
- * merge_comparison('<', '==') returns '<='
- * get_combined_comparison('<', '==') returns '<'
*/
int combine_comparisons(int left_compare, int right_compare)
{
int LT, EQ, GT;
@@ -398,163 +415,168 @@
if (GT == 2) {
if (EQ == 2)
return SPECIAL_GTE;
return '>';
}
- return 0;
+ return UNKNOWN_COMPARISON;
}
-int filter_comparison(int orig, int op)
+/*
+ * This is mostly used when you know from extra state that a <= b but you
+ * know from comparisons that a != b so then if take the intersection then
+ * we know that a < b. The name is taken from the fact that the intersection
+ * of < and <= is <.
+ */
+int comparison_intersection(int left_compare, int right_compare)
{
- if (orig == op)
- return orig;
+ int LT, GT, EQ, NE, total;
- orig = remove_unsigned_from_comparison(orig);
- op = remove_unsigned_from_comparison(op);
+ if (left_compare == IMPOSSIBLE_COMPARISON ||
+ right_compare == IMPOSSIBLE_COMPARISON)
+ return IMPOSSIBLE_COMPARISON;
- switch (orig) {
- case 0:
- return op;
+ left_compare = remove_unsigned_from_comparison(left_compare);
+ right_compare = remove_unsigned_from_comparison(right_compare);
+
+ LT = GT = EQ = NE = total = 0;
+
+ /* Only one side is known. */
+ if (!left_compare)
+ return right_compare;
+ if (!right_compare)
+ return left_compare;
+
+ switch (left_compare) {
case '<':
- switch (op) {
- case '<':
+ LT++;
+ total += 1;
+ break;
case SPECIAL_LTE:
+ LT++;
+ EQ++;
+ total += 2;
+ break;
+ case SPECIAL_EQUAL:
+ EQ++;
+ total += 1;
+ break;
case SPECIAL_NOTEQUAL:
- return '<';
+ NE++;
+ total += 1;
+ break;
+ case SPECIAL_GTE:
+ GT++;
+ EQ++;
+ total += 2;
+ break;
+ case '>':
+ GT++;
+ total += 1;
+ break;
+ default:
+ return UNKNOWN_COMPARISON;
}
- return 0;
- case SPECIAL_LTE:
- switch (op) {
+
+ switch (right_compare) {
case '<':
+ LT++;
+ total += 1;
+ break;
case SPECIAL_LTE:
+ LT++;
+ EQ++;
+ total += 2;
+ break;
case SPECIAL_EQUAL:
- return op;
+ EQ++;
+ total += 1;
+ break;
case SPECIAL_NOTEQUAL:
- return '<';
- }
- return 0;
- case SPECIAL_EQUAL:
- switch (op) {
- case SPECIAL_LTE:
- case SPECIAL_EQUAL:
+ NE++;
+ total += 1;
+ break;
case SPECIAL_GTE:
- case SPECIAL_UNSIGNED_LTE:
- case SPECIAL_UNSIGNED_GTE:
- return SPECIAL_EQUAL;
+ GT++;
+ EQ++;
+ total += 2;
+ break;
+ case '>':
+ GT++;
+ total += 1;
+ break;
+ default:
+ return UNKNOWN_COMPARISON;
}
- return 0;
- case SPECIAL_NOTEQUAL:
- switch (op) {
- case '<':
- case SPECIAL_LTE:
+
+ if (LT == 2) {
+ if (EQ == 2)
+ return SPECIAL_LTE;
return '<';
- case SPECIAL_UNSIGNED_LT:
- case SPECIAL_UNSIGNED_LTE:
- return SPECIAL_UNSIGNED_LT;
- case SPECIAL_NOTEQUAL:
- return op;
- case '>':
- case SPECIAL_GTE:
- return '>';
- case SPECIAL_UNSIGNED_GT:
- case SPECIAL_UNSIGNED_GTE:
- return SPECIAL_UNSIGNED_GT;
}
- return 0;
- case SPECIAL_GTE:
- switch (op) {
- case SPECIAL_LTE:
- return SPECIAL_EQUAL;
- case '>':
- case SPECIAL_GTE:
- case SPECIAL_EQUAL:
- return op;
- case SPECIAL_NOTEQUAL:
+
+ if (GT == 2) {
+ if (EQ == 2)
+ return SPECIAL_GTE;
return '>';
}
- return 0;
- case '>':
- switch (op) {
- case '>':
- case SPECIAL_GTE:
- case SPECIAL_NOTEQUAL:
- return '>';
- }
- return 0;
- case SPECIAL_UNSIGNED_LT:
- switch (op) {
- case SPECIAL_UNSIGNED_LT:
- case SPECIAL_UNSIGNED_LTE:
- case SPECIAL_NOTEQUAL:
- return SPECIAL_UNSIGNED_LT;
- }
- return 0;
- case SPECIAL_UNSIGNED_LTE:
- switch (op) {
- case SPECIAL_UNSIGNED_LT:
- case SPECIAL_UNSIGNED_LTE:
- case SPECIAL_EQUAL:
- return op;
- case SPECIAL_NOTEQUAL:
- return SPECIAL_UNSIGNED_LT;
- case SPECIAL_UNSIGNED_GTE:
+ if (EQ == 2)
return SPECIAL_EQUAL;
- }
- return 0;
- case SPECIAL_UNSIGNED_GTE:
- switch (op) {
- case SPECIAL_UNSIGNED_LTE:
- return SPECIAL_EQUAL;
- case SPECIAL_NOTEQUAL:
- return SPECIAL_UNSIGNED_GT;
- case SPECIAL_EQUAL:
- case SPECIAL_UNSIGNED_GTE:
- case SPECIAL_UNSIGNED_GT:
- return op;
- }
- return 0;
- case SPECIAL_UNSIGNED_GT:
- switch (op) {
- case SPECIAL_UNSIGNED_GT:
- case SPECIAL_UNSIGNED_GTE:
- case SPECIAL_NOTEQUAL:
- return SPECIAL_UNSIGNED_GT;
- }
- return 0;
- }
- return 0;
+ if (total == 2 && EQ && NE)
+ return IMPOSSIBLE_COMPARISON;
+ if (GT && LT)
+ return IMPOSSIBLE_COMPARISON;
+ if (GT && NE)
+ return '>';
+ if (LT && NE)
+ return '<';
+ if (NE == 2)
+ return SPECIAL_NOTEQUAL;
+ if (total == 2 && (LT || GT) && EQ)
+ return IMPOSSIBLE_COMPARISON;
+
+ return UNKNOWN_COMPARISON;
}
-static void pre_merge_hook(struct sm_state *sm)
+static void pre_merge_hook(struct sm_state *cur, struct sm_state *other)
{
- struct compare_data *data = sm->state->data;
- int other;
+ struct compare_data *data = cur->state->data;
+ int extra, new;
+ static bool in_recurse;
if (!data)
return;
- other = get_comparison(data->left, data->right);
- if (!other)
+
+ if (in_recurse)
return;
+ in_recurse = true;
+ extra = comparison_from_extra(data->left, data->right);
+ in_recurse = false;
+ if (!extra)
+ return;
+ new = comparison_intersection(extra, data->comparison);
+ if (new == data->comparison)
+ return;
- set_state(compare_id, sm->name, NULL,
+ set_state(compare_id, cur->name, NULL,
alloc_compare_state(data->left, data->left_var, data->left_vsl,
- other,
+ new,
data->right, data->right_var, data->right_vsl));
}
struct smatch_state *merge_compare_states(struct smatch_state *s1, struct smatch_state *s2)
{
struct compare_data *data = s1->data;
int op;
+ if (!data)
+ return &undefined;
+
op = merge_comparisons(state_to_comparison(s1), state_to_comparison(s2));
- if (op)
return alloc_compare_state(
data->left, data->left_var, data->left_vsl,
op,
data->right, data->right_var, data->right_vsl);
- return &undefined;
}
static struct smatch_state *alloc_link_state(struct string_list *links)
{
struct smatch_state *state;
@@ -688,11 +710,15 @@
flip ? SPECIAL_GTE : SPECIAL_LTE,
data->right, data->right_var, data->right_vsl);
set_state(compare_id, tmp, NULL, new);
break;
default:
- set_state(compare_id, tmp, NULL, &undefined);
+ new = alloc_compare_state(
+ data->left, data->left_var, data->left_vsl,
+ UNKNOWN_COMPARISON,
+ data->right, data->right_var, data->right_vsl);
+ set_state(compare_id, tmp, NULL, new);
}
} END_FOR_EACH_PTR(tmp);
}
static void match_dec(struct sm_state *sm, bool preserve)
@@ -702,21 +728,25 @@
char *tmp;
links = sm->state->data;
FOR_EACH_PTR(links, tmp) {
+ struct compare_data *data;
+ struct smatch_state *new;
+
state = get_state(compare_id, tmp, NULL);
+ if (!state || !state->data)
+ continue;
+ data = state->data;
+
switch (state_to_comparison(state)) {
case SPECIAL_EQUAL:
case SPECIAL_LTE:
case SPECIAL_UNSIGNED_LTE:
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,
@@ -724,11 +754,15 @@
data->right, data->right_var, data->right_vsl);
set_state(compare_id, tmp, NULL, new);
break;
}
default:
- set_state(compare_id, tmp, NULL, &undefined);
+ new = alloc_compare_state(
+ data->left, data->left_var, data->left_vsl,
+ UNKNOWN_COMPARISON,
+ data->right, data->right_var, data->right_vsl);
+ set_state(compare_id, tmp, NULL, new);
}
} END_FOR_EACH_PTR(tmp);
}
static void reset_sm(struct sm_state *sm)
@@ -737,11 +771,24 @@
char *tmp;
links = sm->state->data;
FOR_EACH_PTR(links, tmp) {
- set_state(compare_id, tmp, NULL, &undefined);
+ struct smatch_state *old, *new;
+
+ old = get_state(compare_id, tmp, NULL);
+ if (!old || !old->data) {
+ new = &undefined;
+ } else {
+ struct compare_data *data = old->data;
+
+ new = alloc_compare_state(
+ data->left, data->left_var, data->left_vsl,
+ UNKNOWN_COMPARISON,
+ data->right, data->right_var, data->right_vsl);
+ }
+ set_state(compare_id, tmp, NULL, new);
} 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)
@@ -847,11 +894,11 @@
if (!get_implied_rl(expr->unop, &left) ||
!get_implied_rl(parent->right, &right))
return;
op = rl_comparison(left, right);
- if (!op)
+ if (op == UNKNOWN_COMPARISON)
return;
add_comparison(expr->unop, op, parent->right);
}
@@ -1014,12 +1061,12 @@
orig_comparison = get_orig_comparison(pre_stree, left_var, right_var);
true_comparison = combine_comparisons(left_comparison, right_comparison);
false_comparison = combine_comparisons(left_false_comparison, right_comparison);
- true_comparison = filter_comparison(orig_comparison, true_comparison);
- false_comparison = filter_comparison(orig_comparison, false_comparison);
+ true_comparison = comparison_intersection(orig_comparison, true_comparison);
+ false_comparison = comparison_intersection(orig_comparison, false_comparison);
if (strcmp(left_var, right_var) > 0) {
struct expression *tmp_expr = left_expr;
const char *tmp_var = left_var;
struct var_sym_list *tmp_vsl = left_vsl;
@@ -1274,12 +1321,12 @@
op = flip_comparison(op);
false_op = flip_comparison(false_op);
}
orig_comparison = get_comparison(left_expr, right_expr);
- op = filter_comparison(orig_comparison, op);
- false_op = filter_comparison(orig_comparison, false_op);
+ op = comparison_intersection(orig_comparison, op);
+ false_op = comparison_intersection(orig_comparison, false_op);
snprintf(state_name, sizeof(state_name), "%s vs %s", left, right);
true_state = alloc_compare_state(
left_expr, left, left_vsl,
op,
@@ -1332,11 +1379,10 @@
new_left = left->right;
new_right = binop_expression(right, '-', left->left);
handle_comparison(new_left, expr->op, new_right, NULL, NULL);
}
-
redo = 0;
left = strip_parens(expr->left);
right = strip_parens(expr->right);
if (get_last_expr_from_expression_stmt(expr->left)) {
left = get_last_expr_from_expression_stmt(expr->left);
@@ -1616,11 +1662,11 @@
struct smatch_state *state;
int invert = 0;
int ret = 0;
if (!one || !two)
- return 0;
+ return UNKNOWN_COMPARISON;
if (strcmp(one, two) == 0)
return SPECIAL_EQUAL;
if (strcmp(one, two) > 0) {
@@ -1644,14 +1690,16 @@
static int get_comparison_helper(struct expression *a, struct expression *b, bool use_extra)
{
char *one = NULL;
char *two = NULL;
- int ret = 0;
+ int ret = UNKNOWN_COMPARISON;
+ int extra = UNKNOWN_COMPARISON;
- if (!a || !b)
- return 0;
+ if (a == UNKNOWN_COMPARISON ||
+ b == UNKNOWN_COMPARISON)
+ return UNKNOWN_COMPARISON;
a = strip_parens(a);
b = strip_parens(b);
move_plus_to_minus(&a, &b);
@@ -1675,27 +1723,26 @@
free_string(two);
two = chunk_to_var(b->left);
ret = get_comparison_strings(one, two);
}
- if (!ret)
+ if (ret == UNKNOWN_COMPARISON)
goto free;
if ((is_plus_one(a) || is_minus_one(b)) && ret == '<')
ret = SPECIAL_LTE;
else if ((is_minus_one(a) || is_plus_one(b)) && ret == '>')
ret = SPECIAL_GTE;
else
- ret = 0;
+ ret = UNKNOWN_COMPARISON;
free:
free_string(one);
free_string(two);
- if (!ret && use_extra)
- return comparison_from_extra(a, b);
- return ret;
+ extra = comparison_from_extra(a, b);
+ return comparison_intersection(ret, extra);
}
int get_comparison(struct expression *a, struct expression *b)
{
return get_comparison_helper(a, b, true);
@@ -1903,15 +1950,15 @@
void __add_return_comparison(struct expression *call, const char *range)
{
struct expression *arg;
int comparison;
- char buf[4];
+ char buf[16];
if (!str_to_comparison_arg(range, call, &comparison, &arg))
return;
- snprintf(buf, sizeof(buf), "%s", show_special(comparison));
+ snprintf(buf, sizeof(buf), "%s", show_comparison(comparison));
update_links_from_call(call, comparison, arg);
add_comparison(call, comparison, arg);
}
void __add_comparison_info(struct expression *expr, struct expression *call, const char *range)
@@ -1969,15 +2016,16 @@
continue;
if (!param->ident)
continue;
snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
compare = get_comparison_strings(var, buf);
- if (!compare)
+ if (compare == UNKNOWN_COMPARISON ||
+ compare == IMPOSSIBLE_COMPARISON)
continue;
- if (show_special(compare)[0] != starts_with)
+ if (show_comparison(compare)[0] != starts_with)
continue;
- snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
+ snprintf(buf, sizeof(buf), "[%s$%d]", show_comparison(compare), i);
ret_str = alloc_sname(buf);
break;
} END_FOR_EACH_PTR(param);
free_string(var);
@@ -2004,13 +2052,14 @@
i++;
if (!param->ident)
continue;
snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
compare = get_comparison_strings(name, buf);
- if (!compare)
+ if (compare == UNKNOWN_COMPARISON ||
+ compare == IMPOSSIBLE_COMPARISON)
continue;
- snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
+ snprintf(buf, sizeof(buf), "[%s$%d]", show_comparison(compare), i);
return alloc_sname(buf);
} END_FOR_EACH_PTR(param);
return NULL;
}
@@ -2047,11 +2096,11 @@
continue;
snprintf(buf, sizeof(buf), "%s orig", param->ident->name);
compare = get_comparison_strings(var, buf);
if (!compare)
continue;
- snprintf(buf, sizeof(buf), "[%s$%d]", show_special(compare), i);
+ snprintf(buf, sizeof(buf), "[%s$%d]", show_comparison(compare), i);
ret_str = alloc_sname(buf);
break;
} END_FOR_EACH_PTR(param);
free:
@@ -2126,11 +2175,13 @@
continue;
sm = get_sm_state(compare_id, link, NULL);
if (!sm)
continue;
data = sm->state->data;
- if (!data || !data->comparison)
+ if (!data ||
+ data->comparison == UNKNOWN_COMPARISON ||
+ data->comparison == IMPOSSIBLE_COMPARISON)
continue;
arg_name = expr_to_var(arg);
if (!arg_name)
continue;
@@ -2151,11 +2202,11 @@
if (strcmp(right_vs->var, right_name) != 0)
goto free;
right_name = get_printed_param_name(expr, right_vs->var, right_vs->sym);
if (!right_name)
goto free;
- snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(comparison), right_name);
+ snprintf(info_buf, sizeof(info_buf), "%s %s", show_comparison(comparison), right_name);
sql_insert_caller_info(expr, PARAM_COMPARE, i, "$", info_buf);
free:
free_string(arg_name);
} END_FOR_EACH_PTR(link);
@@ -2201,11 +2252,11 @@
continue;
right_name = get_printed_param_name(call, right->var, right->sym);
if (!right_name)
continue;
- snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_name);
+ snprintf(info_buf, sizeof(info_buf), "%s %s", show_comparison(data->comparison), right_name);
sql_insert_caller_info(call, PARAM_COMPARE, param, printed_name, info_buf);
} END_FOR_EACH_PTR(link);
}
static void print_return_value_comparison(int return_id, char *return_ranges, struct expression *expr)
@@ -2272,11 +2323,13 @@
FOR_EACH_PTR(links, link) {
sm = get_sm_state(compare_id, link, NULL);
if (!sm)
continue;
data = sm->state->data;
- if (!data || !data->comparison)
+ if (!data ||
+ data->comparison == UNKNOWN_COMPARISON ||
+ data->comparison == IMPOSSIBLE_COMPARISON)
continue;
if (ptr_list_size((struct ptr_list *)data->left_vsl) != 1 ||
ptr_list_size((struct ptr_list *)data->right_vsl) != 1)
continue;
left = first_ptr_list((struct ptr_list *)data->left_vsl);
@@ -2314,11 +2367,11 @@
* FIXME: this should reject $ type variables (as
* opposed to $->foo type). Those should come from
* smatch_param_compare_limit.c.
*/
- snprintf(info_buf, sizeof(info_buf), "%s %s", show_special(data->comparison), right_buf);
+ snprintf(info_buf, sizeof(info_buf), "%s %s", show_comparison(data->comparison), right_buf);
sql_insert_return_states(return_id, return_ranges,
PARAM_COMPARE, left_param, left_buf, info_buf);
} END_FOR_EACH_PTR(link);
} END_FOR_EACH_SM(tmp);
@@ -2491,11 +2544,11 @@
goto free;
state_op = state_to_comparison(state);
if (!state_op)
goto free;
- if (!filter_comparison(remove_unsigned_from_comparison(state_op), op))
+ if (!comparison_intersection(remove_unsigned_from_comparison(state_op), op))
ret = 1;
free:
free_string(left_name);
free_string(right_name);
return ret;
@@ -2589,41 +2642,51 @@
static void filter_by_sm(struct sm_state *sm, int op,
struct state_list **true_stack,
struct state_list **false_stack)
{
struct compare_data *data;
- int istrue = 0;
- int isfalse = 0;
+ int is_true = 0;
+ int is_false = 0;
if (!sm)
return;
data = sm->state->data;
- if (!data) {
- if (sm->merged) {
- filter_by_sm(sm->left, op, true_stack, false_stack);
- filter_by_sm(sm->right, op, true_stack, false_stack);
- }
+ if (!data || data->comparison == UNKNOWN_COMPARISON)
+ goto split;
+ if (data->comparison == IMPOSSIBLE_COMPARISON)
return;
- }
- if (data->comparison &&
- data->comparison == filter_comparison(data->comparison, op))
- istrue = 1;
+ /*
+ * We want to check that "data->comparison" is totally inside "op". So
+ * if data->comparison is < and op is <= then that's true. Or if
+ * data->comparison is == and op is <= then that's true. But if
+ * data->comparison is <= and op is < than that's neither true nor
+ * false.
+ */
+ if (data->comparison == comparison_intersection(data->comparison, op))
+ is_true = 1;
+ if (data->comparison == comparison_intersection(data->comparison, negate_comparison(op)))
+ is_false = 1;
- if (data->comparison &&
- data->comparison == filter_comparison(data->comparison, negate_comparison(op)))
- isfalse = 1;
+ if (debug_implied()) {
+ sm_msg("%s: %s: op = '%s' negated '%s'. true_intersect = '%s' false_insersect = '%s' sm = '%s'",
+ __func__,
+ sm->state->name,
+ alloc_sname(show_comparison(op)),
+ alloc_sname(show_comparison(negate_comparison(op))),
+ alloc_sname(show_comparison(comparison_intersection(data->comparison, op))),
+ alloc_sname(show_comparison(comparison_intersection(data->comparison, negate_comparison(op)))),
+ show_sm(sm));
+ }
- if (istrue)
+ if (is_true)
add_ptr_list(true_stack, sm);
- if (isfalse)
+ if (is_false)
add_ptr_list(false_stack, sm);
-
- if (sm->merged) {
+split:
filter_by_sm(sm->left, op, true_stack, false_stack);
filter_by_sm(sm->right, op, true_stack, false_stack);
- }
}
struct sm_state *comparison_implication_hook(struct expression *expr,
struct state_list **true_stack,
struct state_list **false_stack)
@@ -2663,10 +2726,10 @@
filter_by_sm(sm, op, true_stack, false_stack);
if (!*true_stack && !*false_stack)
return NULL;
- if (option_debug)
+ if (debug_implied())
sm_msg("implications from comparison: (%s)", show_sm(sm));
return sm;
}