Print this page
11506 smatch resync

*** 48,71 **** #include <openssl/md5.h> static int my_id; - static struct smatch_state *alloc_tag_state(mtag_t tag) - { - struct smatch_state *state; - char buf[64]; - - state = __alloc_smatch_state(0); - snprintf(buf, sizeof(buf), "%lld", tag); - state->name = alloc_sname(buf); - state->data = malloc(sizeof(mtag_t)); - *(mtag_t *)state->data = tag; - - return state; - } - static mtag_t str_to_tag(const char *str) { unsigned char c[MD5_DIGEST_LENGTH]; unsigned long long *tag = (unsigned long long *)&c; MD5_CTX mdContext; --- 48,57 ----
*** 80,123 **** *tag &= ~MTAG_OFFSET_MASK; return *tag; } ! static void alloc_assign(const char *fn, struct expression *expr, void *unused) { struct expression *left, *right; char *left_name, *right_name; struct symbol *left_sym; char buf[256]; mtag_t tag; ! // FIXME: This should only happen when the size is not a paramter of ! // the caller ! return; - if (expr->type != EXPR_ASSIGNMENT || expr->op != '=') - return; left = strip_expr(expr->left); right = strip_expr(expr->right); - if (right->type != EXPR_CALL || right->fn->type != EXPR_SYMBOL) - return; left_name = expr_to_str_sym(left, &left_sym); right_name = expr_to_str(right); snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(), left_name, right_name); tag = str_to_tag(buf); ! sql_insert_mtag_about(tag, left_name, right_name); ! if (left_name && left_sym) ! set_state(my_id, left_name, left_sym, alloc_tag_state(tag)); free_string(left_name); free_string(right_name); } int get_string_mtag(struct expression *expr, mtag_t *tag) { mtag_t xor; --- 66,153 ---- *tag &= ~MTAG_OFFSET_MASK; return *tag; } ! const struct { ! const char *name; ! int size_arg; ! } allocator_info[] = { ! { "kmalloc", 0 }, ! { "kzalloc", 0 }, ! { "devm_kmalloc", 1}, ! { "devm_kzalloc", 1}, ! }; ! ! static bool is_mtag_call(struct expression *expr) { + struct expression *arg; + int i; + sval_t sval; + + if (expr->type != EXPR_CALL || + expr->fn->type != EXPR_SYMBOL || + !expr->fn->symbol) + return false; + + for (i = 0; i < ARRAY_SIZE(allocator_info); i++) { + if (strcmp(expr->fn->symbol->ident->name, allocator_info[i].name) == 0) + break; + } + if (i == ARRAY_SIZE(allocator_info)) + return false; + + arg = get_argument_from_call_expr(expr->args, allocator_info[i].size_arg); + if (!get_implied_value(arg, &sval)) + return false; + + return true; + } + + struct smatch_state *swap_mtag_return(struct expression *expr, struct smatch_state *state) + { struct expression *left, *right; char *left_name, *right_name; struct symbol *left_sym; + struct range_list *rl; char buf[256]; mtag_t tag; + sval_t tag_sval; + if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=') + return state; ! if (!estate_rl(state) || strcmp(state->name, "0,4096-ptr_max") != 0) ! return state; left = strip_expr(expr->left); right = strip_expr(expr->right); + if (!is_mtag_call(right)) + return state; + left_name = expr_to_str_sym(left, &left_sym); + if (!left_name || !left_sym) + return state; right_name = expr_to_str(right); snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(), left_name, right_name); tag = str_to_tag(buf); + tag_sval.type = estate_type(state); + tag_sval.uvalue = tag; ! rl = rl_filter(estate_rl(state), valid_ptr_rl); ! rl = clone_rl(rl); ! add_range(&rl, tag_sval, tag_sval); ! sql_insert_mtag_about(tag, left_name, buf); free_string(left_name); free_string(right_name); + + return alloc_estate_rl(rl); } int get_string_mtag(struct expression *expr, mtag_t *tag) { mtag_t xor;
*** 149,183 **** sym->ident->name); *tag = str_to_tag(buf); return 1; } ! int get_deref_mtag(struct expression *expr, mtag_t *tag) { ! mtag_t container_tag, member_tag; ! int offset; ! /* ! * I'm not totally sure what I'm doing... ! * ! * This is supposed to get something like "global_var->ptr", but I don't ! * feel like it's complete at all. ! * ! */ ! if (!get_mtag(expr->unop, &container_tag)) ! return 0; ! offset = get_member_offset_from_deref(expr); ! if (offset < 0) ! return 0; ! if (!mtag_map_select_tag(container_tag, -offset, &member_tag)) ! return 0; ! ! *tag = member_tag; ! return 1; } static void global_variable(struct symbol *sym) { mtag_t tag; --- 179,205 ---- sym->ident->name); *tag = str_to_tag(buf); return 1; } ! bool get_symbol_mtag(struct symbol *sym, mtag_t *tag) { ! char buf[256]; ! if (!sym || !sym->ident) ! return false; ! if (get_toplevel_mtag(sym, tag)) ! return true; ! if (get_param_num_from_sym(sym) >= 0) ! return false; ! snprintf(buf, sizeof(buf), "%s %s %s", ! get_filename(), get_function(), sym->ident->name); ! *tag = str_to_tag(buf); ! return true; } static void global_variable(struct symbol *sym) { mtag_t tag;
*** 188,278 **** sql_insert_mtag_about(tag, sym->ident->name, (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern"); } - static void db_returns_buf_size(struct expression *expr, int param, char *unused, char *math) - { - struct expression *call; - struct range_list *rl; - - if (expr->type != EXPR_ASSIGNMENT) - return; - call = strip_expr(expr->right); - - if (!parse_call_math_rl(call, math, &rl)) - return; - // rl = cast_rl(&int_ctype, rl); - // set_state_expr(my_size_id, expr->left, alloc_estate_rl(rl)); - } - - static void db_returns_memory_tag(struct expression *expr, int param, char *key, char *value) - { - struct expression *call, *arg; - mtag_t tag, alias; - char *name; - struct symbol *sym; - - call = strip_expr(expr); - while (call->type == EXPR_ASSIGNMENT) - call = strip_expr(call->right); - if (call->type != EXPR_CALL) - return; - - tag = strtoul(value, NULL, 10); - - if (!create_mtag_alias(tag, call, &alias)) - return; - - arg = get_argument_from_call_expr(call->args, param); - if (!arg) - return; - - name = get_variable_from_key(arg, key, &sym); - if (!name || !sym) - goto free; - - set_state(my_id, name, sym, alloc_tag_state(alias)); - free: - free_string(name); - } - - static void match_call_info(struct expression *expr) - { - struct smatch_state *state; - struct expression *arg; - int i = -1; - - FOR_EACH_PTR(expr->args, arg) { - i++; - state = get_state_expr(my_id, arg); - if (!state || !state->data) - continue; - sql_insert_caller_info(expr, MEMORY_TAG, i, "$", state->name); - } END_FOR_EACH_PTR(arg); - } - - static void save_caller_info(const char *name, struct symbol *sym, char *key, char *value) - { - struct smatch_state *state; - char fullname[256]; - mtag_t tag; - - if (strncmp(key, "$", 1) != 0) - return; - - tag = atoll(value); - snprintf(fullname, 256, "%s%s", name, key + 1); - state = alloc_tag_state(tag); - set_state(my_id, fullname, sym, state); - } - static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) { struct expression *array, *offset_expr; struct symbol *type; sval_t sval; if (!is_array(expr)) return 0; array = get_array_base(expr); --- 210,225 ---- sql_insert_mtag_about(tag, sym->ident->name, (sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern"); } static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) { struct expression *array, *offset_expr; struct symbol *type; sval_t sval; + int start_offset; if (!is_array(expr)) return 0; array = get_array_base(expr);
*** 283,395 **** return 0; type = get_real_base_type(type); if (!type_bytes(type)) return 0; ! if (!get_mtag(array, tag)) return 0; offset_expr = get_array_offset(expr); if (!get_value(offset_expr, &sval)) return 0; ! *offset = sval.value * type_bytes(type); return 1; } ! static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) { ! struct smatch_state *state; ! struct symbol *type; sval_t sval; ! type = get_type(expr); ! if (!type_is_ptr(type)) ! return 0; ! state = get_extra_state(expr); ! if (!state || !estate_get_single_value(state, &sval) || sval.value == 0) ! return 0; ! *tag = sval.uvalue & ~MTAG_OFFSET_MASK; ! *offset = sval.uvalue & MTAG_OFFSET_MASK; ! return 1; } - static int get_mtag_cnt; - int get_mtag(struct expression *expr, mtag_t *tag) - { - struct smatch_state *state; - int ret = 0; - - expr = strip_expr(expr); - if (!expr) - return 0; - - if (get_mtag_cnt > 0) - return 0; - - get_mtag_cnt++; - - switch (expr->type) { - case EXPR_STRING: - if (get_string_mtag(expr, tag)) { - ret = 1; - goto dec_cnt; - } - break; - case EXPR_SYMBOL: - if (get_toplevel_mtag(expr->symbol, tag)) { - ret = 1; - goto dec_cnt; - } - break; - case EXPR_DEREF: - if (get_deref_mtag(expr, tag)) { - ret = 1; - goto dec_cnt; - } - break; - } - - state = get_state_expr(my_id, expr); - if (!state) - goto dec_cnt; - if (state->data) { - *tag = *(mtag_t *)state->data; - ret = 1; - goto dec_cnt; - } - - dec_cnt: - get_mtag_cnt--; - return ret; - } - - int get_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) - { - int val; - - if (!expr) - return 0; - if (expr->type == EXPR_PREOP && expr->op == '*') - return get_mtag_offset(expr->unop, tag, offset); - if (get_implied_mtag_offset(expr, tag, offset)) - return 1; - if (!get_mtag(expr, tag)) - return 0; - expr = strip_expr(expr); - if (expr->type == EXPR_SYMBOL) { - *offset = 0; - return 1; - } - val = get_member_offset_from_deref(expr); - if (val < 0) - return 0; - *offset = val; - return 1; - } - int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new) { char buf[256]; int lines_from_start; char *str; --- 230,270 ---- return 0; type = get_real_base_type(type); if (!type_bytes(type)) return 0; ! if (!expr_to_mtag_offset(array, tag, &start_offset)) return 0; offset_expr = get_array_offset(expr); if (!get_value(offset_expr, &sval)) return 0; ! *offset = start_offset + sval.value * type_bytes(type); return 1; } ! struct range_list *swap_mtag_seed(struct expression *expr, struct range_list *rl) { ! char buf[256]; ! char *name; sval_t sval; + mtag_t tag; ! if (!rl_to_sval(rl, &sval)) ! return rl; ! if (sval.type->type != SYM_PTR || sval.uvalue != MTAG_SEED) ! return rl; ! name = expr_to_str(expr); ! snprintf(buf, sizeof(buf), "%s %s %s", get_filename(), get_function(), name); ! free_string(name); ! tag = str_to_tag(buf); ! sval.value = tag; ! return alloc_rl(sval, sval); } int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new) { char buf[256]; int lines_from_start; char *str;
*** 413,446 **** sql_insert_mtag_alias(tag, *new); return 1; } int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) { *offset = 0; expr = strip_expr(expr); if (!expr) return 0; if (is_array(expr)) return get_array_mtag_offset(expr, tag, offset); ! if (expr->type == EXPR_DEREF) { ! *offset = get_member_offset_from_deref(expr); ! if (*offset < 0) return 0; ! return get_mtag(expr->deref, tag); } ! if (get_implied_mtag_offset(expr, tag, offset)) return 1; ! ! return get_mtag(expr, tag); } int get_mtag_sval(struct expression *expr, sval_t *sval) { struct symbol *type; mtag_t tag; int offset = 0; --- 288,391 ---- sql_insert_mtag_alias(tag, *new); return 1; } + static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) + { + struct smatch_state *state; + struct symbol *type; + sval_t sval; + + type = get_type(expr); + if (!type_is_ptr(type)) + return 0; + state = get_extra_state(expr); + if (!state || !estate_get_single_value(state, &sval) || sval.value == 0) + return 0; + + *tag = sval.uvalue & ~MTAG_OFFSET_MASK; + *offset = sval.uvalue & MTAG_OFFSET_MASK; + return 1; + } + + /* + * The point of this function is to give you the mtag and the offset so + * you can look up the data in the DB. It takes an expression. + * + * So say you give it "foo->bar". Then it would give you the offset of "bar" + * and the implied value of "foo". Or if you lookup "*foo" then the offset is + * zero and we look up the implied value of "foo. But if the expression is + * foo, then if "foo" is a global variable, then we get the mtag and the offset + * is zero. If "foo" is a local variable, then there is nothing to look up in + * the mtag_data table because that's handled by smatch_extra.c to this returns + * false. + * + */ int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset) { + *tag = 0; *offset = 0; + if (bits_in_pointer != 64) + return 0; + expr = strip_expr(expr); if (!expr) return 0; if (is_array(expr)) return get_array_mtag_offset(expr, tag, offset); ! if (expr->type == EXPR_PREOP && expr->op == '*') { ! expr = strip_expr(expr->unop); ! return get_implied_mtag_offset(expr, tag, offset); ! } else if (expr->type == EXPR_DEREF) { ! int tmp, tmp_offset = 0; ! ! while (expr->type == EXPR_DEREF) { ! tmp = get_member_offset_from_deref(expr); ! if (tmp < 0) return 0; ! tmp_offset += tmp; ! expr = expr->deref; } + *offset = tmp_offset; + if (expr->type == EXPR_PREOP && expr->op == '*') { + expr = strip_expr(expr->unop); ! if (get_implied_mtag_offset(expr, tag, &tmp_offset)) { ! // FIXME: look it up recursively? ! if (tmp_offset) ! return 0; return 1; ! } ! return 0; ! } else if (expr->type == EXPR_SYMBOL) { ! return get_symbol_mtag(expr->symbol, tag); ! } ! return 0; ! } else if (expr->type == EXPR_SYMBOL) { ! return get_symbol_mtag(expr->symbol, tag); ! } ! return 0; } + /* + * This function takes an address and returns an sval. Let's take some + * example things you might pass to it: + * foo->bar: + * If we were only called from smatch_math, we wouldn't need to bother with + * this because it's already been looked up in smatch_extra.c but this is + * also called from other places so we have to check smatch_extra.c. + * &foo + * If "foo" is global return the mtag for "foo". + * &foo.bar + * If "foo" is global return the mtag for "foo" + the offset of ".bar". + * It also handles string literals. + * + */ int get_mtag_sval(struct expression *expr, sval_t *sval) { struct symbol *type; mtag_t tag; int offset = 0;
*** 452,536 **** type = get_type(expr); if (!type_is_ptr(type)) return 0; /* ! * There are only three options: * ! * 1) An array address: ! * p = array; ! * 2) An address like so: ! * p = &my_struct->member; ! * 3) A pointer: ! * p = pointer; * */ if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag)) goto found; ! if (type->type == SYM_ARRAY && get_toplevel_mtag(expr->symbol, &tag)) goto found; if (get_implied_mtag_offset(expr, &tag, &offset)) goto found; - if (expr->type != EXPR_PREOP || expr->op != '&') return 0; ! expr = strip_expr(expr->unop); ! ! if (!expr_to_mtag_offset(expr, &tag, &offset)) return 0; - if (offset > MTAG_OFFSET_MASK) - offset = MTAG_OFFSET_MASK; - found: sval->type = type; sval->uvalue = tag | offset; return 1; } - static struct expression *remove_dereference(struct expression *expr) - { - expr = strip_expr(expr); - - if (expr->type == EXPR_PREOP && expr->op == '*') - return strip_expr(expr->unop); - return preop_expression(expr, '&'); - } - - int get_mtag_addr_sval(struct expression *expr, sval_t *sval) - { - return get_mtag_sval(remove_dereference(expr), sval); - } - - static void print_stored_to_mtag(int return_id, char *return_ranges, struct expression *expr) - { - struct sm_state *sm; - char buf[256]; - const char *param_name; - int param; - - FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) { - if (!sm->state->data) - continue; - - param = get_param_num_from_sym(sm->sym); - if (param < 0) - continue; - param_name = get_param_name(sm); - if (!param_name) - continue; - if (strcmp(param_name, "$") == 0) - continue; - - snprintf(buf, sizeof(buf), "%lld", *(mtag_t *)sm->state->data); - sql_insert_return_states(return_id, return_ranges, MEMORY_TAG, param, param_name, buf); - } END_FOR_EACH_SM(sm); - } - void register_mtag(int id) { my_id = id; --- 397,443 ---- type = get_type(expr); if (!type_is_ptr(type)) return 0; /* ! * There are several options: * ! * If the expr is a string literal, that's an address/mtag. ! * SYM_ARRAY and SYM_FN are mtags. There are "&foo" type addresses. ! * And there are saved pointers "p = &foo;" * */ if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag)) goto found; ! if (expr->type == EXPR_SYMBOL && ! (type->type == SYM_ARRAY || type->type == SYM_FN) && ! get_toplevel_mtag(expr->symbol, &tag)) goto found; + if (expr->type == EXPR_PREOP && expr->op == '&') { + expr = strip_expr(expr->unop); + if (expr_to_mtag_offset(expr, &tag, &offset)) + goto found; + return 0; + } + if (get_implied_mtag_offset(expr, &tag, &offset)) goto found; return 0; ! found: ! if (offset >= MTAG_OFFSET_MASK) return 0; sval->type = type; sval->uvalue = tag | offset; return 1; } void register_mtag(int id) { my_id = id;
*** 540,559 **** * bit 63 : set for alias mtags * bit 62-12: mtag hash * bit 11-0 : offset * */ - if (bits_in_pointer != 64) - return; add_hook(&global_variable, BASE_HOOK); - - add_function_assign_hook("kmalloc", &alloc_assign, NULL); - add_function_assign_hook("kzalloc", &alloc_assign, NULL); - - select_return_states_hook(BUF_SIZE, &db_returns_buf_size); - - add_hook(&match_call_info, FUNCTION_CALL_HOOK); - select_caller_info_hook(save_caller_info, MEMORY_TAG); - add_split_return_callback(&print_stored_to_mtag); - select_return_states_hook(MEMORY_TAG, db_returns_memory_tag); } --- 447,454 ----