Print this page
11506 smatch resync
@@ -110,11 +110,11 @@
offset = get_offset_from_container_of(__mptr);
return offset;
}
-static char *get_container_name(struct sm_state *sm, int 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,11 +171,11 @@
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);
+ name = get_container_name_sm(tmp, offset);
if (!name)
continue;
sql_insert_return_implies(CONTAINER, arg, name, "");
} END_FOR_EACH_SM(tmp);
@@ -247,77 +247,154 @@
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)
+static int get_deref_count(struct expression *expr)
{
- int i;
- int on_end = false;
+ int cnt = 0;
- i = 0;
- while (true) {
- if (!one[i] || !two[i]) {
- on_end = true;
- break;
+ 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;
}
- if (one[i] != two[i])
- break;
- i++;
+ 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;
}
- if (i == 0)
- return 0;
- i--;
- while (i > 0 && (one[i] == '>' || one[i] == '-' || one[i] == '.')) {
- on_end = true;
- i--;
+ 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;
}
- if (!on_end)
- return 0;
- return i + 1;
+ return n;
}
-static int build_offset_str(struct expression *expr, const char *name,
- int shared, char *buf, int size, int op)
+static char *get_shared_str(struct expression *container, struct expression *expr)
{
- int chop = 0;
- int offset;
- int i;
+ struct expression *one, *two;
+ int cont, exp, min, ret, n;
+ static char buf[48];
- i = shared;
- while (name[i]) {
- if (name[i] == '.' || name[i] == '-')
- chop++;
- i++;
+ 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--;
}
- // FIXME: Handle more chops
- if (chop > 1)
- return 0;
+ return NULL;
- if (chop == 0) {
- offset = 0;
- } else {
- offset = get_member_offset_from_deref(expr);
- if (offset < 0)
- return 0;
+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;
}
- snprintf(buf, size, "%c%d", (op == '+') ? '+' : '-', offset);
- return 1;
+ 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 *fn_name, *arg_name;
- int param, shared;
- char minus_str[64];
- char plus_str[64];
- char offset_str[64];
- bool star;
+ 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,76 +407,26 @@
*
* 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)
+ name = get_container_name(fn, arg);
+ if (!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);
+ 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)
{
- 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));
+ set_state(param_id, name, sym, alloc_state_str(key));
}
struct db_info {
struct symbol *arg;
int prev_offset;
@@ -572,39 +599,53 @@
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)
+static void load_container_data(struct symbol *arg, const char *info)
{
- struct symbol *arg;
- struct smatch_state *state;
+ mtag_t cur_tag, container_tag, arg_tag;
+ int container_offset, arg_offset;
+ char *p = (char *)info;
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;
+ bool star = 0;
- 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);
+ if (p[0] == '*') {
+ star = 1;
+ p += 2;
+ }
+ if (!get_toplevel_mtag(cur_func_sym, &cur_tag))
return;
-found:
- if (!estate_get_single_value(state, &offset))
+
+ 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;
- container_offset = -(offset.value & 0xffff);
- arg_offset = (offset.value & 0xfff0000) >> 16;
- star = !!(offset.value & (1ULL << 31));
+ 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 (!get_toplevel_mtag(cur_func_sym, &fn_tag))
+ if (p[0] != '+')
return;
- if (!mtag_map_select_container(fn_tag, container_offset, &container_tag))
+
+ 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,10 +656,23 @@
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,20 +689,15 @@
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;
+ 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);
- add_unmatched_state_hook(param_id, &unmatched_state);
- add_merge_hook(param_id, &merge_estates);
}