struct_assignment: handle memcpy(foo, ...) where foo is not a struct
authorDan Carpenter <dan.carpenter@oracle.com>
Thu, 29 May 2014 12:05:57 +0000 (29 15:05 +0300)
committerDan Carpenter <dan.carpenter@oracle.com>
Thu, 29 May 2014 12:05:57 +0000 (29 15:05 +0300)
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 <dan.carpenter@oracle.com>
smatch_struct_assignment.c

index bfa0261..8ef2e17 100644 (file)
@@ -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)