From 7eef9cb8ad48bea196b10b4cb0c13f2cd0e92512 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 16 Jun 2012 16:41:16 +0300 Subject: [PATCH] buf_size: return the size of &foo Also this tries to return the correct size for: &foo.buf[0] because that is a common idiom instead of just passing the address. Signed-off-by: Dan Carpenter --- smatch_buf_size.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ validation/sm_buf_size5.c | 29 +++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 validation/sm_buf_size5.c diff --git a/smatch_buf_size.c b/smatch_buf_size.c index 7fdeba3a..7137206d 100644 --- a/smatch_buf_size.c +++ b/smatch_buf_size.c @@ -191,6 +191,53 @@ static int get_stored_size_bytes(struct expression *expr) return max; } +static struct expression *get_pointer_expression(struct expression *expr) +{ + long long val; + + while (expr->type == EXPR_PREOP && expr->op == '&') { + expr = strip_expr(expr->unop); + if (expr->type != EXPR_PREOP || expr->op != '*') + break; + expr = strip_expr(expr->unop); + } + + if (expr->type == EXPR_BINOP && expr->op == '+') { + if (get_value(expr->right, &val) && val == 0) { + return expr->left; + } + return NULL; + } + + if (expr->type == EXPR_SYMBOL) + return expr; + return NULL; +} + +static int get_bytes_from_address(struct expression *expr) +{ + struct symbol *type; + int ret; + + if (expr->type != EXPR_PREOP || expr->op != '&') + return 0; + expr = get_pointer_expression(expr); + type = get_type(expr); + if (!type) + return 0; + + if (type->type == SYM_PTR) + type = get_base_type(type); + + ret = bits_to_bytes(type->bit_size); + if (ret == -1) + return 0; + if (ret == 1) + return 0; /* ignore char pointers */ + + return ret; +} + static int get_size_from_strlen(struct expression *expr) { struct smatch_state *state; @@ -231,6 +278,10 @@ int get_array_size_bytes(struct expression *expr) if (size) return elements_to_bytes(expr, size); + size = get_bytes_from_address(expr); + if (size) + return size; + /* if (strlen(foo) > 4) */ size = get_size_from_strlen(expr); if (size) diff --git a/validation/sm_buf_size5.c b/validation/sm_buf_size5.c new file mode 100644 index 00000000..7f5bd68c --- /dev/null +++ b/validation/sm_buf_size5.c @@ -0,0 +1,29 @@ +#include "check_debug.h" + +struct foo { + char buf[42]; + int x[4]; +}; + +int function(void) +{ + struct foo foo; + + __smatch_buf_size(&foo); + __smatch_buf_size(&(foo.buf[0])); + __smatch_buf_size(&foo.x[0]); + __smatch_buf_size(&foo.x[1]); + + return 0; +} +/* + * check-name: smatch buf size #5 + * check-command: smatch -I.. sm_buf_size5.c + * + * check-output-start +sm_buf_size5.c:12 function() buf size: '&foo' 1 elements, 60 bytes +sm_buf_size5.c:13 function() buf size: '&(foo.buf[0])' 42 elements, 42 bytes +sm_buf_size5.c:14 function() buf size: '&foo.x[0]' 4 elements, 16 bytes +sm_buf_size5.c:15 function() buf size: '&foo.x[1]' 0 elements, 0 bytes + * check-output-end + */ -- 2.11.4.GIT