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);
}