From 212a4fba20be97d2e6af3f19f3fcdd754469e4e2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 16 Feb 2018 15:27:23 +0300 Subject: [PATCH] comparison: handle __smatch_compare(foo, bar - 1) It's pretty common to have a code like this: for (i = 0; i < limit; i++) { ... if (i == limit - 1) last_item_stuff(); } In other words, comparing with "limit - 1" is a very common special case and I'm adding support for that. This change is not directly useful by itself. Signed-off-by: Dan Carpenter --- smatch_comparison.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/smatch_comparison.c b/smatch_comparison.c index a7826b76..8661ed9a 100644 --- a/smatch_comparison.c +++ b/smatch_comparison.c @@ -1390,12 +1390,37 @@ int get_comparison_strings(const char *one, const char *two) return ret; } +static int is_plus_one(struct expression *expr) +{ + sval_t sval; + + if (expr->type != EXPR_BINOP || expr->op != '+') + return 0; + if (!get_implied_value(expr->right, &sval) || sval.value != 1) + return 0; + return 1; +} + +static int is_minus_one(struct expression *expr) +{ + sval_t sval; + + if (expr->type != EXPR_BINOP || expr->op != '-') + return 0; + if (!get_implied_value(expr->right, &sval) || sval.value != 1) + return 0; + return 1; +} + int get_comparison(struct expression *a, struct expression *b) { char *one = NULL; char *two = NULL; int ret = 0; + a = strip_parens(a); + b = strip_parens(b); + one = chunk_to_var(a); if (!one) goto free; @@ -1404,6 +1429,29 @@ int get_comparison(struct expression *a, struct expression *b) goto free; ret = get_comparison_strings(one, two); + if (ret) + goto free; + + if (is_plus_one(a) || is_minus_one(a)) { + free_string(one); + one = chunk_to_var(a->left); + ret = get_comparison_strings(one, two); + } else if (is_plus_one(b) || is_minus_one(b)) { + free_string(two); + two = chunk_to_var(b->left); + ret = get_comparison_strings(one, two); + } + + if (!ret) + 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; + free: free_string(one); free_string(two); -- 2.11.4.GIT