Print this page
new smatch

@@ -97,16 +97,90 @@
 void call_extra_nomod_hooks(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
 {
         call_extra_hooks(extra_nomod_hooks, name, sym, expr, state);
 }
 
+static void set_union_info(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
+{
+        struct symbol *type, *tmp, *inner_type, *inner, *new_type;
+        struct expression *deref, *member_expr;
+        struct smatch_state *new;
+        int offset, inner_offset;
+        static bool in_recurse;
+        char *member_name;
+
+        if (__in_fake_assign)
+                return;
+
+        if (in_recurse)
+                return;
+        in_recurse = true;
+
+        if (!expr || expr->type != EXPR_DEREF || !expr->member)
+                goto done;
+        offset = get_member_offset_from_deref(expr);
+        if (offset < 0)
+                goto done;
+
+        deref = strip_expr(expr->deref);
+        type = get_type(deref);
+        if (type_is_ptr(type))
+                type = get_real_base_type(type);
+        if (!type || type->type != SYM_STRUCT)
+                goto done;
+
+        FOR_EACH_PTR(type->symbol_list, tmp) {
+                inner_type = get_real_base_type(tmp);
+                if (!inner_type || inner_type->type != SYM_UNION)
+                        continue;
+
+                inner = first_ptr_list((struct ptr_list *)inner_type->symbol_list);
+                if (!inner || !inner->ident)
+                        continue;
+
+                inner_offset = get_member_offset(type, inner->ident->name);
+                if (inner_offset < offset)
+                        continue;
+                if (inner_offset > offset)
+                        goto done;
+
+                FOR_EACH_PTR(inner_type->symbol_list, inner) {
+                        struct symbol *tmp_type;
+
+                        if (!inner->ident || inner->ident == expr->member)
+                                continue;
+                        tmp_type = get_real_base_type(inner);
+                        if (tmp_type && tmp_type->type == SYM_STRUCT)
+                                continue;
+                        member_expr = deref;
+                        if (tmp->ident)
+                                member_expr = member_expression(member_expr, '.', tmp->ident);
+                        member_expr = member_expression(member_expr, expr->op, inner->ident);
+                        member_name = expr_to_var(member_expr);
+                        if (!member_name)
+                                continue;
+                        new_type = get_real_base_type(inner);
+                        new = alloc_estate_rl(cast_rl(new_type, estate_rl(state)));
+                        set_extra_mod_helper(member_name, sym, member_expr, new);
+                        free_string(member_name);
+                } END_FOR_EACH_PTR(inner);
+        } END_FOR_EACH_PTR(tmp);
+
+done:
+        in_recurse = false;
+}
+
 static bool in_param_set;
 void set_extra_mod_helper(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
 {
+        if (!expr)
+                expr = gen_expression_from_name_sym(name, sym);
         remove_from_equiv(name, sym);
+        set_union_info(name, sym, expr, state);
         call_extra_mod_hooks(name, sym, expr, state);
-        if ((__in_fake_assign || in_param_set) &&
+        update_mtag_data(expr, state);
+        if (in_param_set &&
             estate_is_unknown(state) && !get_state(SMATCH_EXTRA, name, sym))
                 return;
         set_state(SMATCH_EXTRA, name, sym, state);
 }
 

@@ -170,11 +244,11 @@
 free:
         free_string(orig_name);
         return NULL;
 }
 
-static char *get_long_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
+static char *get_long_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym, bool use_stack)
 {
         struct expression *tmp;
         struct sm_state *sm;
         char buf[256];
 

@@ -194,10 +268,12 @@
         } END_FOR_EACH_SM(sm);
 
         return NULL;
 
 found:
+        if (!use_stack && name[tmp->symbol->ident->len] != '-')
+                return NULL;
         snprintf(buf, sizeof(buf), "%s%s", sm->name, name + tmp->symbol->ident->len);
         *new_sym = sm->sym;
         return alloc_string(buf);
 }
 

@@ -222,11 +298,11 @@
 
         len = snprintf(buf, sizeof(buf), "%s", name);
         if (len >= sizeof(buf) - 2)
                 return NULL;
 
-        while (len >= 1) {
+        while (use_stack && len >= 1) {
                 if (buf[len] == '>' && buf[len - 1] == '-') {
                         len--;
                         buf[len] = '\0';
                         ret = get_other_name_sym_from_chunk(name, buf, len + 2, sym, new_sym);
                         if (ret)

@@ -233,11 +309,11 @@
                                 return ret;
                 }
                 len--;
         }
 
-        ret = get_long_name_sym(name, sym, new_sym);
+        ret = get_long_name_sym(name, sym, new_sym, use_stack);
         if (ret)
                 return ret;
 
         return NULL;
 }

@@ -256,13 +332,13 @@
 {
         char *new_name;
         struct symbol *new_sym;
 
         set_extra_mod_helper(name, sym, expr, state);
-        new_name = get_other_name_sym(name, sym, &new_sym);
+        new_name = get_other_name_sym_nostack(name, sym, &new_sym);
         if (new_name && new_sym)
-                set_extra_mod_helper(new_name, new_sym, expr, state);
+                set_extra_mod_helper(new_name, new_sym, NULL, state);
         free_string(new_name);
 }
 
 static struct expression *chunk_get_array_base(struct expression *expr)
 {

@@ -1229,24 +1305,18 @@
 static void asm_expr(struct statement *stmt)
 {
 
         struct expression *expr;
         struct symbol *type;
-        int state = 0;
 
         FOR_EACH_PTR(stmt->asm_outputs, expr) {
-                switch (state) {
-                case 0: /* identifier */
-                case 1: /* constraint */
-                        state++;
+                if (expr->type != EXPR_ASM_OPERAND) {
+                        sm_perror("unexpected asm param type %d", expr->type);
                         continue;
-                case 2: /* expression */
-                        state = 0;
-                        type = get_type(strip_expr(expr));
-                        set_extra_expr_mod(expr, alloc_estate_whole(type));
-                        continue;
                 }
+                type = get_type(strip_expr(expr->expr));
+                set_extra_expr_mod(expr->expr, alloc_estate_whole(type));
         } END_FOR_EACH_PTR(expr);
 }
 
 static void check_dereference(struct expression *expr)
 {

@@ -1278,10 +1348,12 @@
 
 static void match_dereferences(struct expression *expr)
 {
         if (expr->type != EXPR_PREOP)
                 return;
+        if (getting_address(expr))
+                return;
         /* it's saying that foo[1] = bar dereferences foo[1] */
         if (is_array(expr))
                 return;
         check_dereference(expr->unop);
 }

@@ -2201,11 +2273,11 @@
         buf[sizeof(buf) - 1] = '\0';
 
         start = &buf[0];
         while (*start == '*') {
                 start++;
-                state = get_state(SMATCH_EXTRA, start, sym);
+                state = __get_state(SMATCH_EXTRA, start, sym);
                 if (!state)
                         continue;
                 if (!estate_rl(state))
                         return 1;
                 if (estate_min(state).value == 0 &&

@@ -2371,16 +2443,18 @@
 static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm)
 {
         struct range_list *rl;
         sval_t dummy;
 
-        if (estate_is_whole(sm->state))
+        if (estate_is_whole(sm->state) || !estate_rl(sm->state))
                 return;
         if (filter_unused_param_value_info(call, param, printed_name, sm))
                 return;
         rl = estate_rl(sm->state);
         rl = intersect_with_real_abs_var_sym(sm->name, sm->sym, rl);
+        if (!rl)
+                return;
         sql_insert_caller_info(call, PARAM_VALUE, param, printed_name, show_rl(rl));
         if (!estate_get_single_value(sm->state, &dummy)) {
                 if (estate_has_hard_max(sm->state))
                         sql_insert_caller_info(call, HARD_MAX, param, printed_name,
                                                sval_to_str(estate_max(sm->state)));

@@ -2567,11 +2641,11 @@
         db_param_limit_filter(expr, param, key, value, PARAM_FILTER);
 }
 
 static void db_param_add_set(struct expression *expr, int param, char *key, char *value, enum info_type op)
 {
-        struct expression *arg;
+        struct expression *arg, *gen_expr;
         char *name;
         char *other_name = NULL;
         struct symbol *sym, *other_sym;
         struct symbol *param_type, *arg_type;
         struct smatch_state *state;

@@ -2587,13 +2661,16 @@
         if (!arg)
                 return;
 
         arg_type = get_arg_type_from_key(expr->fn, param, arg, key);
         param_type = get_member_type_from_key(arg, key);
+        if (param_type && param_type->type == SYM_STRUCT)
+                return;
         name = get_variable_from_key(arg, key, &sym);
         if (!name || !sym)
                 goto free;
+        gen_expr = gen_expression_from_key(arg, key);
 
         state = get_state(SMATCH_EXTRA, name, sym);
         if (state)
                 new = estate_rl(state);
 

@@ -2603,13 +2680,13 @@
                 new = added;
         else
                 new = rl_union(new, added);
 
         other_name = get_other_name_sym_nostack(name, sym, &other_sym);
-        set_extra_mod(name, sym, NULL, alloc_estate_rl(new));
+        set_extra_mod(name, sym, gen_expr, alloc_estate_rl(new));
         if (other_name && other_sym)
-                set_extra_mod(other_name, other_sym, NULL, alloc_estate_rl(new));
+                set_extra_mod(other_name, other_sym, gen_expr, alloc_estate_rl(new));
 free:
         free_string(other_name);
         free_string(name);
 }