Print this page
11506 smatch resync

*** 110,120 **** offset = get_offset_from_container_of(__mptr); return offset; } ! static char *get_container_name(struct sm_state *sm, int offset) { static char buf[256]; const char *name; name = get_param_name(sm); --- 110,120 ---- offset = get_offset_from_container_of(__mptr); return offset; } ! static char *get_container_name_sm(struct sm_state *sm, int offset) { static char buf[256]; const char *name; name = get_param_name(sm);
*** 171,181 **** FOR_EACH_SM(used_stree, tmp) { arg = get_container_arg(tmp->sym); offset = get_container_offset(tmp->sym); if (arg < 0 || offset < 0) continue; ! name = get_container_name(tmp, offset); if (!name) continue; sql_insert_return_implies(CONTAINER, arg, name, ""); } END_FOR_EACH_SM(tmp); --- 171,181 ---- FOR_EACH_SM(used_stree, tmp) { arg = get_container_arg(tmp->sym); offset = get_container_offset(tmp->sym); if (arg < 0 || offset < 0) continue; ! name = get_container_name_sm(tmp, offset); if (!name) continue; sql_insert_return_implies(CONTAINER, arg, name, ""); } END_FOR_EACH_SM(tmp);
*** 247,323 **** return; snprintf(buf, sizeof(buf), "$(%d)", offset); sql_insert_return_implies(CONTAINER, param, buf, ""); } ! static int get_shared_cnt(const char *one, const char *two) { ! int i; ! int on_end = false; ! i = 0; ! while (true) { ! if (!one[i] || !two[i]) { ! on_end = true; ! break; } ! if (one[i] != two[i]) ! break; ! i++; } ! if (i == 0) ! return 0; ! i--; ! while (i > 0 && (one[i] == '>' || one[i] == '-' || one[i] == '.')) { ! on_end = true; ! i--; } - if (!on_end) - return 0; ! return i + 1; } ! static int build_offset_str(struct expression *expr, const char *name, ! int shared, char *buf, int size, int op) { ! int chop = 0; ! int offset; ! int i; ! i = shared; ! while (name[i]) { ! if (name[i] == '.' || name[i] == '-') ! chop++; ! i++; } ! // FIXME: Handle more chops ! if (chop > 1) ! return 0; ! if (chop == 0) { ! offset = 0; ! } else { ! offset = get_member_offset_from_deref(expr); ! if (offset < 0) ! return 0; } ! snprintf(buf, size, "%c%d", (op == '+') ? '+' : '-', offset); ! return 1; } static void match_call(struct expression *call) { struct expression *fn, *arg; ! char *fn_name, *arg_name; ! int param, shared; ! char minus_str[64]; ! char plus_str[64]; ! char offset_str[64]; ! bool star; /* * We're trying to link the function with the parameter. There are a * couple ways this can be passed: * foo->func(foo, ...); --- 247,400 ---- return; snprintf(buf, sizeof(buf), "$(%d)", offset); sql_insert_return_implies(CONTAINER, param, buf, ""); } ! static int get_deref_count(struct expression *expr) { ! int cnt = 0; ! while (expr && expr->type == EXPR_DEREF) { ! expr = expr->deref; ! if (expr->type == EXPR_PREOP && expr->op == '*') ! expr = expr->unop; ! cnt++; ! if (cnt > 100) ! return -1; } ! return cnt; ! } ! ! static struct expression *get_partial_deref(struct expression *expr, int cnt) ! { ! while (--cnt >= 0) { ! if (!expr || expr->type != EXPR_DEREF) ! return expr; ! expr = expr->deref; ! if (expr->type == EXPR_PREOP && expr->op == '*') ! expr = expr->unop; } ! return expr; ! } ! ! static int partial_deref_to_offset_str(struct expression *expr, int cnt, char op, char *buf, int size) ! { ! int n, offset; ! ! if (cnt == 0) ! return snprintf(buf, size, "%c0", op); ! ! n = 0; ! while (--cnt >= 0) { ! offset = get_member_offset_from_deref(expr); ! if (offset < 0) ! return -1; ! n += snprintf(buf + n, size - n, "%c%d", op, offset); ! if (expr->type != EXPR_DEREF) ! return -1; ! expr = expr->deref; ! if (expr->type == EXPR_PREOP && expr->op == '*') ! expr = expr->unop; } ! return n; } ! static char *get_shared_str(struct expression *container, struct expression *expr) { ! struct expression *one, *two; ! int cont, exp, min, ret, n; ! static char buf[48]; ! cont = get_deref_count(container); ! exp = get_deref_count(expr); ! if (cont < 0 || exp < 0) ! return NULL; ! ! min = (cont < exp) ? cont : exp; ! while (min >= 0) { ! one = get_partial_deref(container, cont - min); ! two = get_partial_deref(expr, exp - min); ! if (expr_equiv(one, two)) ! goto found; ! min--; } ! return NULL; ! found: ! ret = partial_deref_to_offset_str(container, cont - min, '-', buf, sizeof(buf)); ! if (ret < 0) ! return NULL; ! n = ret; ! ret = partial_deref_to_offset_str(expr, exp - min, '+', buf + ret, sizeof(buf) - ret); ! if (ret < 0) ! return NULL; ! n += ret; ! if (n >= sizeof(buf)) ! return NULL; ! ! return buf; ! } ! ! char *get_container_name(struct expression *container, struct expression *expr) ! { ! struct symbol *container_sym, *sym; ! struct expression *tmp; ! static char buf[64]; ! char *shared; ! bool star; ! int cnt; ! ! container_sym = expr_to_sym(container); ! sym = expr_to_sym(expr); ! if (container_sym && container_sym == sym) ! goto found; ! ! cnt = 0; ! while ((tmp = get_assigned_expr(expr))) { ! expr = tmp; ! if (cnt++ > 3) ! break; } ! cnt = 0; ! while ((tmp = get_assigned_expr(container))) { ! container = tmp; ! if (cnt++ > 3) ! break; ! } ! ! found: ! expr = strip_expr(expr); ! star = true; ! if (expr->type == EXPR_PREOP && expr->op == '&') { ! expr = strip_expr(expr->unop); ! star = false; ! } ! ! container_sym = expr_to_sym(container); ! if (!container_sym) ! return NULL; ! sym = expr_to_sym(expr); ! if (!sym || container_sym != sym) ! return NULL; ! ! shared = get_shared_str(container, expr); ! if (star) ! snprintf(buf, sizeof(buf), "*(%s)", shared); ! else ! snprintf(buf, sizeof(buf), "%s", shared); ! ! return buf; } static void match_call(struct expression *call) { struct expression *fn, *arg; ! char *name; ! int param; /* * We're trying to link the function with the parameter. There are a * couple ways this can be passed: * foo->func(foo, ...);
*** 330,405 **** * * If we're taking an address then the offset math is not stared, * otherwise it is. Starred means dereferenced. */ fn = strip_expr(call->fn); - fn_name = expr_to_var(fn); - if (!fn_name) - return; param = -1; FOR_EACH_PTR(call->args, arg) { param++; ! arg = strip_expr(arg); ! star = true; ! if (arg->type == EXPR_PREOP && arg->op == '&') { ! arg = strip_expr(arg->unop); ! star = false; ! } ! ! arg_name = expr_to_var(arg); ! if (!arg_name) continue; - shared = get_shared_cnt(fn_name, arg_name); - if (!shared) - goto free_arg_name; - if (!build_offset_str(fn, fn_name, shared, minus_str, sizeof(minus_str), '-')) - goto free_arg_name; - if (!build_offset_str(arg, arg_name, shared, plus_str, sizeof(plus_str), '+')) - goto free_arg_name; - if (star) - snprintf(offset_str, sizeof(offset_str), "*(%s%s)", minus_str, plus_str); - else - snprintf(offset_str, sizeof(offset_str), "%s%s", minus_str, plus_str); - sql_insert_caller_info(call, CONTAINER, param, offset_str, "$(-1)"); - free_arg_name: - free_string(arg_name); - } END_FOR_EACH_PTR(arg); ! free_string(fn_name); } static void db_passed_container(const char *name, struct symbol *sym, char *key, char *value) { ! sval_t offset = { ! .type = &int_ctype, ! }; ! const char *arg_offset; ! int star = 0; ! int val; ! ! if (key[0] == '*') { ! star = 1; ! key += 2; ! } ! ! val = atoi(key); ! if (val < -4095 || val > 0) ! return; ! offset.value = -val; ! arg_offset = strchr(key, '+'); ! if (!arg_offset) ! return; ! val = atoi(arg_offset + 1); ! if (val > 4095 || val < 0) ! return; ! offset.value |= val << 16; ! if (star) ! offset.value |= 1ULL << 31; ! ! set_state(param_id, name, sym, alloc_estate_sval(offset)); } struct db_info { struct symbol *arg; int prev_offset; --- 407,432 ---- * * If we're taking an address then the offset math is not stared, * otherwise it is. Starred means dereferenced. */ fn = strip_expr(call->fn); param = -1; FOR_EACH_PTR(call->args, arg) { param++; ! name = get_container_name(fn, arg); ! if (!name) continue; ! sql_insert_caller_info(call, CONTAINER, param, name, "$(-1)"); ! } END_FOR_EACH_PTR(arg); } static void db_passed_container(const char *name, struct symbol *sym, char *key, char *value) { ! set_state(param_id, name, sym, alloc_state_str(key)); } struct db_info { struct symbol *arg; int prev_offset;
*** 572,610 **** set_state_stree(&db_info.stree, SMATCH_EXTRA, arg->ident->name, arg, alloc_estate_sval(sval)); } return db_info.stree; } ! static void handle_passed_container(struct symbol *sym) { ! struct symbol *arg; ! struct smatch_state *state; struct sm_state *sm; struct stree *stree; ! mtag_t fn_tag, container_tag, arg_tag; ! sval_t offset; ! int container_offset, arg_offset; ! int star; ! FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) { ! state = get_state(param_id, arg->ident->name, arg); ! if (state) ! goto found; ! } END_FOR_EACH_PTR(arg); return; ! found: ! if (!estate_get_single_value(state, &offset)) return; ! container_offset = -(offset.value & 0xffff); ! arg_offset = (offset.value & 0xfff0000) >> 16; ! star = !!(offset.value & (1ULL << 31)); ! if (!get_toplevel_mtag(cur_func_sym, &fn_tag)) return; ! if (!mtag_map_select_container(fn_tag, container_offset, &container_tag)) return; if (!arg_offset || star) { arg_tag = container_tag; } else { if (!mtag_map_select_tag(container_tag, -arg_offset, &arg_tag)) return; --- 599,651 ---- set_state_stree(&db_info.stree, SMATCH_EXTRA, arg->ident->name, arg, alloc_estate_sval(sval)); } return db_info.stree; } ! static void load_container_data(struct symbol *arg, const char *info) { ! mtag_t cur_tag, container_tag, arg_tag; ! int container_offset, arg_offset; ! char *p = (char *)info; struct sm_state *sm; struct stree *stree; ! bool star = 0; ! if (p[0] == '*') { ! star = 1; ! p += 2; ! } + if (!get_toplevel_mtag(cur_func_sym, &cur_tag)) return; ! ! while (true) { ! container_offset = strtoul(p, &p, 0); ! if (local_debug) ! sm_msg("%s: cur_tag = %llu container_offset = %d", ! __func__, cur_tag, container_offset); ! if (!mtag_map_select_container(cur_tag, container_offset, &container_tag)) return; ! cur_tag = container_tag; ! if (local_debug) ! sm_msg("%s: container_tag = %llu p = '%s'", ! __func__, container_tag, p); ! if (!p) ! return; ! if (p[0] != '-') ! break; ! p++; ! } ! if (p[0] != '+') return; ! ! p++; ! arg_offset = strtoul(p, &p, 0); ! if (p && *p && *p != ')') return; + if (!arg_offset || star) { arg_tag = container_tag; } else { if (!mtag_map_select_tag(container_tag, -arg_offset, &arg_tag)) return;
*** 615,624 **** --- 656,678 ---- set_state(sm->owner, sm->name, sm->sym, sm->state); } END_FOR_EACH_SM(sm); free_stree(&stree); } + static void handle_passed_container(struct symbol *sym) + { + struct symbol *arg; + struct smatch_state *state; + + FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) { + state = get_state(param_id, arg->ident->name, arg); + if (!state || state == &merged) + continue; + load_container_data(arg, state->name); + } END_FOR_EACH_PTR(arg); + } + void register_container_of(int id) { my_id = id; add_hook(&match_function_def, FUNC_DEF_HOOK);
*** 635,654 **** select_return_states_hook(CONTAINER, &returns_container_of); add_hook(&match_call, FUNCTION_CALL_HOOK); } - static struct smatch_state *unmatched_state(struct sm_state *sm) - { - return alloc_estate_whole(estate_type(sm->state)); - } - void register_container_of2(int id) { param_id = id; select_caller_info_hook(db_passed_container, CONTAINER); add_hook(&handle_passed_container, AFTER_DEF_HOOK); - add_unmatched_state_hook(param_id, &unmatched_state); - add_merge_hook(param_id, &merge_estates); } --- 689,703 ---- select_return_states_hook(CONTAINER, &returns_container_of); add_hook(&match_call, FUNCTION_CALL_HOOK); } void register_container_of2(int id) { param_id = id; + set_dynamic_states(param_id); select_caller_info_hook(db_passed_container, CONTAINER); + add_merge_hook(param_id, &merge_str_state); add_hook(&handle_passed_container, AFTER_DEF_HOOK); }