From 75079d5b29d9ffbea0a2c538c3f48dfb8a025fd3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 26 May 2010 12:31:23 +0200 Subject: [PATCH] *new* check_macros: find macro precedence bugs This check is for find code like: #define add(a, b) a + b x = add(1, 1) * 5 The multiply has precedence over the add so x is 6 instead of 10 at the end. The way this check works is that it looks at which operations sparse does first. The problem with this approach is that it can lead to false positives. "x = (1 + 2) + 3;" is the same as "x = 1 + (2 + 3)" so adding or removing parenthesis doesn't cause a problem. I made adding, multiplying, bitwise AND and bitwise OR special cases to cut down on the number of false positives. There are still some other false positives, but my feeling now is that it's best to just add parenthesis in the kernel source to silence the warnings. Signed-off-by: Dan Carpenter --- check_list.h | 1 + check_macros.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++ validation/sm_macros.c | 31 +++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 check_macros.c create mode 100644 validation/sm_macros.c diff --git a/check_list.h b/check_list.h index 22507cdf..e1079654 100644 --- a/check_list.h +++ b/check_list.h @@ -43,6 +43,7 @@ CK(check_freeing_null) CK(check_no_effect) CK(check_kunmap) CK(check_snprintf) +CK(check_macros) /* <- your test goes here */ /* CK(register_template) */ diff --git a/check_macros.c b/check_macros.c new file mode 100644 index 00000000..7bf31fb0 --- /dev/null +++ b/check_macros.c @@ -0,0 +1,81 @@ +/* + * smatch/check_macros.c + * + * Copyright (C) 2010 Dan Carpenter. + * + * Licensed under the Open Software License version 1.1 + * + */ + +#include "smatch.h" + +static int my_id; + +static int same_pos(struct position *pos1, struct position *pos2) +{ + if (pos1->stream != pos2->stream) + return 0; + if (pos1->line != pos2->line) + return 0; + if (pos1->pos != pos2->pos) + return 0; + return 1; +} + +static void match_inside(struct expression *expr, struct position *pos) +{ + char *name; + int matched = 0; + + if (same_pos(&expr->pos, pos)) + matched++; + if (same_pos(&expr->unop->pos, pos)) + matched++; + if (matched != 1) + return; + name = get_macro_name(pos); + if (!name) + return; + sm_msg("warn: the '%s' macro might need parens", name); +} + +static void match_one_side(struct expression *expr, struct position *pos, int op) +{ + char *name; + int matched = 0; + + if ((op == '+' || op == '*' || op == '|' || op == '&') && expr->op == op) + return; + if (same_pos(&expr->right->pos, pos)) + matched++; + if (same_pos(&expr->left->pos, pos)) + matched++; + if (matched != 1) + return; + name = get_macro_name(pos); + if (!name) + return; + if (option_project == PROJ_WINE && !strcmp("BEGIN", name)) + return; + sm_msg("warn: the '%s' macro might need parens", name); +} + +static void match_join(struct expression *expr) +{ + if (expr->left->type == EXPR_PREOP) + match_inside(expr->left, &expr->pos); + if (expr->right->type == EXPR_POSTOP) + match_inside(expr->right, &expr->pos); + + if (expr->left->type == EXPR_BINOP) + match_one_side(expr->left, &expr->pos, expr->op); + if (expr->right->type == EXPR_BINOP) + match_one_side(expr->right, &expr->pos, expr->op); +} + +void check_macros(int id) +{ + my_id = id; + add_hook(&match_join, BINOP_HOOK); + add_hook(&match_join, LOGIC_HOOK); +} diff --git a/validation/sm_macros.c b/validation/sm_macros.c new file mode 100644 index 00000000..2f467658 --- /dev/null +++ b/validation/sm_macros.c @@ -0,0 +1,31 @@ +#include "check_debug.h" + +#define add(x, y) x + y +#define sub(x, y) x - y + +void func(int *p) +{ + int a = 1; + int b = 2; + + x = 4 * add(2, 3); + x = 4 + add(2, 3); + x = 4 * add(2, 3) * 8; + x = add(2, 3) * 4; + x = add(2, 3) - 4; + x = -sub(2, 3); + x = sub(2, 3)++; +} +/* + * check-name: Smatch macro precedence bugs + * check-command: smatch -I.. sm_macros.c + * + * check-output-start +sm_macros.c +11 func(5) warn: the 'add' macro might need parens +sm_macros.c +13 func(7) warn: the 'add' macro might need parens +sm_macros.c +13 func(7) warn: the 'add' macro might need parens +sm_macros.c +14 func(8) warn: the 'add' macro might need parens +sm_macros.c +16 func(10) warn: the 'sub' macro might need parens +sm_macros.c +17 func(11) warn: the 'sub' macro might need parens + * check-output-end + */ -- 2.11.4.GIT