extra: handle loops where without a hard max that don't have a break
authorDan Carpenter <dan.carpenter@oracle.com>
Fri, 23 Nov 2012 11:50:49 +0000 (23 14:50 +0300)
committerDan Carpenter <dan.carpenter@oracle.com>
Fri, 23 Nov 2012 11:50:49 +0000 (23 14:50 +0300)
If the loop doesn't have a hard max, then the value after the loop is
unknown-ish the same as it was before.  If we have a break statement this
works already, but if we don't then this was setting it to the max.

Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
smatch.h
smatch_extra.c
smatch_states.c

index be68265..3f7cc48 100644 (file)
--- a/smatch.h
+++ b/smatch.h
@@ -409,6 +409,7 @@ void __merge_continues(void);
 
 void __push_breaks(void);
 void __process_breaks(void);
+int __has_breaks(void);
 void __merge_breaks(void);
 void __use_breaks(void);
 
index ae3f8bb..5a6eb85 100644 (file)
@@ -370,7 +370,14 @@ void __extra_pre_loop_hook_after(struct sm_state *sm,
                limit = sval_binop(estate_min(sm->state), '-',
                                   sval_type_val(estate_type(sm->state), 1));
        }
-       state = alloc_estate(limit);
+       if (!estate_has_hard_max(sm->state) && !__has_breaks()) {
+               if (iter_expr->op == SPECIAL_INCREMENT)
+                       state = alloc_estate_range(estate_min(sm->state), limit);
+               else
+                       state = alloc_estate_range(limit, estate_max(sm->state));
+       } else {
+               state = alloc_estate(limit);
+       }
        if (!estate_has_hard_max(sm->state))
                estate_clear_hard_max(state);
        set_extra_mod(sm->name, sm->sym, state);
index 3811c28..0cf8bd2 100644 (file)
@@ -682,6 +682,17 @@ void __process_breaks(void)
        push_slist(&break_stack, slist);
 }
 
+int __has_breaks(void)
+{
+       struct state_list *slist;
+       int ret;
+
+       slist = pop_slist(&break_stack);
+       ret = !!slist;
+       push_slist(&break_stack, slist);
+       return ret;
+}
+
 void __merge_breaks(void)
 {
        struct state_list *slist;