From 2242c23b2937695e71caba61c9e434292967240d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 11 Apr 2009 09:13:54 +0300 Subject: [PATCH] Fix range comparison. The checking for if things were not equal was wrong. Also things are supposed to be both possibly true and possibly false but the possibly_false() function was just checking !true_comparison_range() so I created a false_comparison_range() check. Signed-off-by: Dan Carpenter --- smatch_extra.c | 73 +++++++++++++++++++++++++++++++++++++++--------- smatch_extra.h | 1 + smatch_extra_helper.c | 4 +-- validation/sm_implied5.c | 27 ++++++++++++++++++ 4 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 validation/sm_implied5.c diff --git a/smatch_extra.c b/smatch_extra.c index cad3273f..0e85bdc4 100644 --- a/smatch_extra.c +++ b/smatch_extra.c @@ -34,16 +34,6 @@ static struct smatch_state *alloc_extra_state_no_name(int val) return state; } -struct smatch_state *alloc_extra_state(int val) -{ - struct smatch_state *state; - - state = alloc_extra_state_no_name(val); - state->name = show_ranges(((struct data_info *)state->data)->value_ranges); - return state; -} - - /* We do this because ->value_ranges is a list */ struct smatch_state *extra_undefined() { @@ -57,6 +47,17 @@ struct smatch_state *extra_undefined() return ret; } +struct smatch_state *alloc_extra_state(int val) +{ + struct smatch_state *state; + + if (val == UNDEFINED) + return extra_undefined(); + state = alloc_extra_state_no_name(val); + state->name = show_ranges(((struct data_info *)state->data)->value_ranges); + return state; +} + struct smatch_state *filter_ranges(struct smatch_state *orig, long long filter_min, long long filter_max) { @@ -344,11 +345,57 @@ int true_comparison_range(struct data_range *left, int comparison, struct data_r return 1; return 0; case SPECIAL_NOTEQUAL: - if (left->max < right->min) + if (left->min != left->max) return 1; - if (left->min > right->max) + if (right->min != right->max) + return 1; + if (left->min != right->min) + return 1; + return 0; + default: + smatch_msg("unhandled comparison %d\n", comparison); + return UNDEFINED; + } + return 0; +} + +int false_comparison_range(struct data_range *left, int comparison, struct data_range *right) +{ + switch(comparison){ + case '<': + case SPECIAL_UNSIGNED_LT: + if (left->max >= right->min) + return 1; + return 0; + case SPECIAL_UNSIGNED_LTE: + case SPECIAL_LTE: + if (left->max > right->min) + return 1; + return 0; + case SPECIAL_EQUAL: + if (left->min != left->max) + return 1; + if (right->min != right->max) + return 1; + if (left->min != right->min) return 1; return 0; + case SPECIAL_UNSIGNED_GTE: + case SPECIAL_GTE: + if (left->min < right->max) + return 1; + return 0; + case '>': + case SPECIAL_UNSIGNED_GT: + if (left->min >= right->max) + return 1; + return 0; + case SPECIAL_NOTEQUAL: + if (left->max < right->min) + return 0; + if (left->min > right->max) + return 0; + return 1; default: smatch_msg("unhandled comparison %d\n", comparison); return UNDEFINED; @@ -390,7 +437,7 @@ int last_stmt_val(struct statement *stmt) static void match_comparison(struct expression *expr) { - int value; + long long value; char *name = NULL; struct symbol *sym; struct smatch_state *eq_state; diff --git a/smatch_extra.h b/smatch_extra.h index 24dfc3a9..b9ca5949 100644 --- a/smatch_extra.h +++ b/smatch_extra.h @@ -49,4 +49,5 @@ struct smatch_state *add_filter(struct smatch_state *orig, long long filter); struct data_info *alloc_dinfo_range(long long min, long long max); struct range_list *range_list_union(struct range_list *one, struct range_list *two); int true_comparison_range(struct data_range *left, int comparison, struct data_range *right); +int false_comparison_range(struct data_range *left, int comparison, struct data_range *right); long long get_single_value_from_range(struct data_info *dinfo); diff --git a/smatch_extra_helper.c b/smatch_extra_helper.c index 82718d89..4fbbf131 100644 --- a/smatch_extra_helper.c +++ b/smatch_extra_helper.c @@ -216,9 +216,9 @@ int possibly_false(int comparison, struct data_info *dinfo, int num, int left) FOR_EACH_PTR(dinfo->value_ranges, tmp) { if (left) - ret = !true_comparison_range(tmp, comparison, &drange); + ret = false_comparison_range(tmp, comparison, &drange); else - ret = !true_comparison_range(&drange, comparison, tmp); + ret = false_comparison_range(&drange, comparison, tmp); if (ret) return ret; } END_FOR_EACH_PTR(tmp); diff --git a/validation/sm_implied5.c b/validation/sm_implied5.c new file mode 100644 index 00000000..edf61d04 --- /dev/null +++ b/validation/sm_implied5.c @@ -0,0 +1,27 @@ +struct ture { + int a; +}; + +int out_a; + +void func (void) +{ + struct ture *aa; + int a = 0; + + if (out_a) { + aa = returns_nonnull(); + a = something(); + } + if (a) + aa->a = 1; + aa->a = 0xF00D; +} +/* + * check-name: Smatch implied #5 + * check-command: smatch sm_implied5.c + * + * check-output-start +sm_implied5.c +18 func(11) error: dereferencing undefined: 'aa' + * check-output-end + */ -- 2.11.4.GIT