Print this page
new smatch

@@ -225,17 +225,50 @@
         if (offset < 0)
                 return 0;
         return 1;
 }
 
-static int is_ignored_macro(void)
+static bool is_driver_data(void)
 {
+        static struct expression *prev_expr;
         struct expression *expr;
         char *name;
+        static bool prev_ret;
+        bool ret = false;
 
         expr = get_faked_expression();
         if (!expr || expr->type != EXPR_ASSIGNMENT)
+                return false;
+
+        if (expr == prev_expr)
+                return prev_ret;
+        prev_expr = expr;
+
+        name = expr_to_str(expr->right);
+        if (!name) {
+                prev_ret = false;
+                return false;
+        }
+
+        if (strstr(name, "get_drvdata(") ||
+            strstr(name, "dev.driver_data") ||
+            strstr(name, "dev->driver_data"))
+                ret = true;
+
+        free_string(name);
+
+        prev_ret = ret;
+        return ret;
+}
+
+static int is_ignored_macro(void)
+{
+        struct expression *expr;
+        char *name;
+
+        expr = get_faked_expression();
+        if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')
                 return 0;
         name = get_macro_name(expr->right->pos);
         if (!name)
                 return 0;
         if (strcmp(name, "container_of") == 0)

@@ -246,10 +279,24 @@
                 return 1;
         if (strcmp(name, "list_first_entry") == 0)
                 return 1;
         if (strcmp(name, "hlist_entry") == 0)
                 return 1;
+        if (strcmp(name, "per_cpu_ptr") == 0)
+                return 1;
+        if (strcmp(name, "raw_cpu_ptr") == 0)
+                return 1;
+        if (strcmp(name, "this_cpu_ptr") == 0)
+                return 1;
+
+        if (strcmp(name, "TRACE_EVENT") == 0)
+                return 1;
+        if (strcmp(name, "DECLARE_EVENT_CLASS") == 0)
+                return 1;
+        if (strcmp(name, "DEFINE_EVENT") == 0)
+                return 1;
+
         if (strstr(name, "for_each"))
                 return 1;
         return 0;
 }
 

@@ -264,14 +311,34 @@
         if (!expr || expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL)
                 return 0;
 
         if (sym_name_is("kmalloc", expr->fn))
                 return 1;
+        if (sym_name_is("vmalloc", expr->fn))
+                return 1;
+        if (sym_name_is("kvmalloc", expr->fn))
+                return 1;
+        if (sym_name_is("kmalloc_array", expr->fn))
+                return 1;
+        if (sym_name_is("vmalloc_array", expr->fn))
+                return 1;
+        if (sym_name_is("kvmalloc_array", expr->fn))
+                return 1;
+
+        if (sym_name_is("mmu_memory_cache_alloc", expr->fn))
+                return 1;
+        if (sym_name_is("kmem_alloc", expr->fn))
+                return 1;
+        if (sym_name_is("alloc_pages", expr->fn))
+                return 1;
+
         if (sym_name_is("netdev_priv", expr->fn))
                 return 1;
         if (sym_name_is("dev_get_drvdata", expr->fn))
                 return 1;
+        if (sym_name_is("i2c_get_clientdata", expr->fn))
+                return 1;
 
         return 0;
 }
 
 static int is_uncasted_pointer_assign(void)

@@ -292,10 +359,13 @@
         right_type = get_type(expr->right);
 
         if (!left_type || !right_type)
                 return 0;
 
+        if (left_type->type == SYM_STRUCT && left_type == right_type)
+                return 1;
+
         if (left_type->type != SYM_PTR &&
             left_type->type != SYM_ARRAY)
                 return 0;
         if (right_type->type != SYM_PTR &&
             right_type->type != SYM_ARRAY)

@@ -394,10 +464,12 @@
 
         if (!cur_func_sym)
                 return;
 
         type = get_type(expr->left);
+        if (type && type->type == SYM_STRUCT)
+                return;
         member = get_member_name(expr->left);
         if (!member)
                 return;
 
         /* if we're saying foo->mtu = bar->mtu then that doesn't add information */

@@ -414,10 +486,12 @@
                         goto free;
                 if (is_uncasted_fn_param_from_db())
                         goto free;
                 if (is_container_of())
                         goto free;
+                if (is_driver_data())
+                        goto free;
                 add_fake_type_val(member, alloc_whole_rl(get_type(expr->left)), is_ignored_fake_assignment());
                 goto free;
         }
 
         if (expr->op == '=') {

@@ -499,28 +573,18 @@
 static void asm_expr(struct statement *stmt)
 {
         struct expression *expr;
         struct range_list *rl;
         char *member;
-        int state = 0;
 
         FOR_EACH_PTR(stmt->asm_outputs, expr) {
-                switch (state) {
-                case 0: /* identifier */
-                case 1: /* constraint */
-                        state++;
-                        continue;
-                case 2: /* expression */
-                        state = 0;
-                        member = get_member_name(expr);
+                member = get_member_name(expr->expr);
                         if (!member)
                                 continue;
-                        rl = alloc_whole_rl(get_type(expr));
+                rl = alloc_whole_rl(get_type(expr->expr));
                         add_type_val(member, rl);
                         free_string(member);
-                        continue;
-                }
         } END_FOR_EACH_PTR(expr);
 }
 
 static void db_param_add(struct expression *expr, int param, char *key, char *value)
 {

@@ -540,10 +604,23 @@
         arg = get_argument_from_call_expr(expr->args, param);
         arg = strip_expr(arg);
         if (!arg)
                 return;
         type = get_member_type_from_key(arg, key);
+        /*
+         * The situation here is that say we memset() a void pointer to zero
+         * then that's returned to the called as "*$ = 0;" but on the caller's
+         * side it's not void, it's a struct.
+         *
+         * So the question is should we be passing that slightly bogus
+         * information back to the caller?  Maybe, maybe not, but either way we
+         * are not going to record it here because a struct can't be zero.
+         *
+         */
+        if (type && type->type == SYM_STRUCT)
+                return;
+
         if (arg->type != EXPR_PREOP || arg->op != '&')
                 return;
         arg = strip_expr(arg->unop);
 
         member = get_member_name(arg);