From db73713e1d803452796d7e4365a4c836b4196587 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 29 May 2014 15:05:57 +0300 Subject: [PATCH] struct_assignment: handle memcpy(foo, ...) where foo is not a struct The code in question looks like this: __be32 foo = 0; memcpy(&foo, skb->data, sizeof(foo)); We want to say that "foo" is no longer zero so we create a fake assignment for that. Most of the time we won't know what the end value of "foo" is but it's important to record that it changed. I know that the name of this function said "struct" but this seemed like the most natural place to put this. Signed-off-by: Dan Carpenter --- smatch_struct_assignment.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/smatch_struct_assignment.c b/smatch_struct_assignment.c index bfa02615..8ef2e170 100644 --- a/smatch_struct_assignment.c +++ b/smatch_struct_assignment.c @@ -99,6 +99,15 @@ static struct expression *get_matching_member_expr(struct symbol *left_type, str return member_expression(right, op, left_member->ident); } +static struct expression *remove_addr(struct expression *expr) +{ + expr = strip_expr(expr); + + if (expr->type == EXPR_PREOP && expr->op == '&') + return strip_expr(expr->unop); + return expr; +} + void __struct_members_copy(int mode, struct expression *left, struct expression *right) { struct symbol *struct_type, *tmp, *type; @@ -115,8 +124,28 @@ void __struct_members_copy(int mode, struct expression *left, struct expression right = strip_expr(right); struct_type = get_struct_type(left); - if (!struct_type) + if (!struct_type) { + /* + * This is not a struct assignment obviously. But this is where + * memcpy() is handled so it feels like a good place to add this + * code. + */ + + type = get_type(left); + if (!type || type->type != SYM_BASETYPE) + return; + + right = strip_expr(right); + if (right && right->type == EXPR_PREOP && right->op == '&') + right = remove_addr(right); + else + right = unknown_value_expression(left); + assign = assign_expression(left, right); + __in_fake_assign++; + __split_expr(assign); + __in_fake_assign--; return; + } if (is_pointer(left)) { left = deref_expression(left); @@ -150,19 +179,16 @@ void __struct_members_copy(int mode, struct expression *left, struct expression void __fake_struct_member_assignments(struct expression *expr) { + struct symbol *struct_type; + if (is_zero(expr->right)) return; - __struct_members_copy(COPY_NORMAL, expr->left, expr->right); -} - -static struct expression *remove_addr(struct expression *expr) -{ - expr = strip_expr(expr); + struct_type = get_struct_type(expr->left); + if (!struct_type) + return; - if (expr->type == EXPR_PREOP && expr->op == '&') - return strip_expr(expr->unop); - return expr; + __struct_members_copy(COPY_NORMAL, expr->left, expr->right); } static void match_memset(const char *fn, struct expression *expr, void *_size_arg) -- 2.11.4.GIT