db, extra, user_data: handle: *x = 1; return x;"
authorDan Carpenter <dan.carpenter@oracle.com>
Mon, 16 Sep 2013 10:08:46 +0000 (16 13:08 +0300)
committerDan Carpenter <dan.carpenter@oracle.com>
Mon, 16 Sep 2013 10:08:46 +0000 (16 13:08 +0300)
Say you have code like:

int *frob(void)
{
*x = 42;
return x;
}

It's good to know to record that *x is 42.  But the real reason for this
is because of memdup_user() which does:

void *memdup_user(void *src, size_t size)
{
...
copy_from_user(dest, src, size);
return dest;
}

In the old code, there was no way to record that the data it was returning
was user data.

Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
check_user_data.c
smatch_db.c
smatch_extra.c

index 9d590f5..b627ab4 100644 (file)
@@ -530,6 +530,11 @@ static void db_return_states_userdata(struct expression *expr, int param, char *
        char *name;
        struct symbol *sym;
 
+       if (expr->type == EXPR_ASSIGNMENT && param == -1 && strcmp(key, "*$$") == 0) {
+               tag_as_user_data(expr->left);
+               return;
+       }
+
        name = return_state_to_var_sym(expr, param, key, &sym);
        if (!name || !sym)
                goto free;
index 7ca344b..0216e56 100644 (file)
@@ -932,9 +932,6 @@ static void print_returned_struct_members(int return_id, char *return_ranges, st
        type = get_type(expr);
        if (!type || type->type != SYM_PTR)
                return;
-       type = get_real_base_type(type);
-       if (!type || type->type != SYM_STRUCT)
-               return;
        name = expr_to_var(expr);
        if (!name)
                return;
@@ -946,10 +943,16 @@ static void print_returned_struct_members(int return_id, char *return_ranges, st
        FOR_EACH_PTR(returned_member_callbacks, cb) {
                my_slist = get_all_states(cb->owner);
                FOR_EACH_PTR(my_slist, sm) {
+                       if (sm->name[0] == '*' && strcmp(sm->name + 1, name) == 0) {
+                               strcpy(member_name, "*$$");
+                               cb->callback(return_id, return_ranges, member_name, sm->state);
+                               continue;
+                       }
                        if (strncmp(sm->name, name, len) != 0)
                                continue;
                        if (strncmp(sm->name + len, "->", 2) != 0)
                                continue;
+                       strcpy(member_name, "$$");
                        strncpy(member_name + 2, sm->name + len, sizeof(member_name) - 2);
                        cb->callback(return_id, return_ranges, member_name, sm->state);
                } END_FOR_EACH_PTR(sm);
@@ -1096,14 +1099,20 @@ char *return_state_to_var_sym(struct expression *expr, int param, char *key, str
        *sym = NULL;
 
        if (param == -1) {
+               const char *star = "";
+
                if (expr->type != EXPR_ASSIGNMENT)
                        return NULL;
                name = expr_to_var_sym(expr->left, sym);
                if (!name)
                        return NULL;
+               if (key[0] == '*') {
+                       star = "*";
+                       key++;
+               }
                if (strncmp(key, "$$", 2) != 0)
                        return name;
-               snprintf(member_name, sizeof(member_name), "%s%s", name, key + 2);
+               snprintf(member_name, sizeof(member_name), "%s%s%s", star, name, key + 2);
                free_string(name);
                return alloc_string(member_name);
        }
index 8ae8abd..46f4cd9 100644 (file)
@@ -1318,21 +1318,19 @@ static void db_returned_member_info(struct expression *expr, int param, char *ke
        struct symbol *type;
        struct symbol *sym;
        char *name;
-       char member_name[256];
        struct range_list *rl;
 
        if (expr->type != EXPR_ASSIGNMENT)
                return;
 
-       name = expr_to_var_sym(expr->left, &sym);
+       name = return_state_to_var_sym(expr, param, key, &sym);
        if (!name || !sym)
                goto free;
-       snprintf(member_name, sizeof(member_name), "%s%s", name, key + 2);
        type = get_member_type_from_key(expr->left, key);
        if (!type)
                return;
        call_results_to_rl(expr->right, type, value, &rl);
-       set_extra_mod(member_name, sym, alloc_estate_rl(rl));
+       set_extra_mod(name, sym, alloc_estate_rl(rl));
 
 free:
        free_string(name);
@@ -1343,6 +1341,11 @@ static void returned_member_callback(int return_id, char *return_ranges, char *p
        if (estate_is_whole(state))
                return;
 
+       /* these are handled in smatch_param_filter/set/limit.c */
+       if (printed_name[0] != '*' &&
+           !strchr(printed_name, '.') && !strchr(printed_name, '-'))
+               return;
+
        sql_insert_return_states(return_id, return_ranges, RETURN_VALUE, -1,
                        printed_name, state->name);
 }