From d95d60047de039829fe424e4ed86762b0c66f58e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 14 Feb 2010 23:19:08 +0300 Subject: [PATCH] check_overflow: don't complain about if (ptr < &array[ARRAY_SIZE(array)]) This is a common way of looping over an array. for (p = a; p < &a[ARRAY_SIZE(a)]; p++) printf("%d\n", *p); I was strict about which places to not complain about. The offset has to be known at compile time. It has to be a comparison. The bad bit is that if you dereference p after the end of the array smatch will not complain. That should maybe be added to another check. Signed-off-by: Dan Carpenter --- check_overflow.c | 35 +++++++++++++++++++++++++++++++++++ validation/sm_array_overflow3.c | 23 +++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 validation/sm_array_overflow3.c diff --git a/check_overflow.c b/check_overflow.c index 169059c2..1f43eccd 100644 --- a/check_overflow.c +++ b/check_overflow.c @@ -183,6 +183,38 @@ static int get_array_size(struct expression *expr) return ret; } +static int definitely_just_used_as_limiter(struct expression *array, struct expression *offset) +{ + long long val; + struct expression *tmp; + int step = 0; + int dot_ops = 0; + + if (!get_value(offset, &val)) + return 0; + if (get_array_size(array) != val) + return 0; + + FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) { + if (step == 0) { + step = 1; + continue; + } + if (tmp->type == EXPR_PREOP && tmp->op == '(') + continue; + if (tmp->op == '.' && !dot_ops++) + continue; + if (step == 1 && tmp->op == '&') { + step = 2; + continue; + } + if (step == 2 && tmp->type == EXPR_COMPARE) + return 1; + return 0; + } END_FOR_EACH_PTR_REVERSE(tmp); + return 0; +} + static void array_check(struct expression *expr) { struct expression *array_expr; @@ -213,6 +245,9 @@ static void array_check(struct expression *expr) if (getting_address()) level = "warn"; + if (definitely_just_used_as_limiter(array_expr, offset)) + return; + name = get_variable_from_expr_complex(array_expr, NULL); /* Blast. Smatch can't figure out glibc's strcmp __strcmp_cg() * so it prints an error every time you compare to a string diff --git a/validation/sm_array_overflow3.c b/validation/sm_array_overflow3.c new file mode 100644 index 00000000..555c670e --- /dev/null +++ b/validation/sm_array_overflow3.c @@ -0,0 +1,23 @@ +#include + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) + +int a[] = {1, 2, 3, 4}; + +int main(void) +{ + int *p; + + for (p = a; p < &a[ARRAY_SIZE(a)]; p++) + printf("%d\n", *p); + p = &a[4]; + return 0; +} +/* + * check-name: smatch array check #3 + * check-command: smatch sm_array_overflow3.c + * + * check-output-start +sm_array_overflow3.c +13 main(6) warn: buffer overflow 'a' 4 <= 4 + * check-output-end + */ -- 2.11.4.GIT