2 * smatch/smatch_absolute.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
8 * This is to track the absolute max that variables can be. It's a bit like
9 * smatch_extra.c but it only tracks the absolute max and min. So for example,
10 * if you have "int x = (unsigned char)y;" then the absolute max of x is 255.
12 * I imagine this will be useful for find integer overflows.
17 #include "smatch_slist.h"
18 #include "smatch_extra.h"
22 static const char *show_range(sval_t min
, sval_t max
)
26 if (sval_cmp(min
, max
))
27 return sval_to_str(min
);
28 snprintf(buf
, sizeof(buf
), "%s-%s", sval_to_str(min
), sval_to_str(max
));
33 static struct smatch_state
*alloc_absolute(sval_t min
, sval_t max
)
35 struct smatch_state
*state
;
37 if (sval_is_min(min
) && sval_is_max(max
))
40 state
= __alloc_smatch_state(0);
41 state
->name
= alloc_string(show_range(min
, max
));
42 state
->data
= alloc_range_sval(min
, max
);
46 static struct smatch_state
*merge_func(struct smatch_state
*s1
, struct smatch_state
*s2
)
48 struct data_range_sval
*r1
, *r2
;
51 if (!s1
->data
|| !s2
->data
)
57 if (r1
->min
.value
== r2
->min
.value
&& r1
->max
.value
== r2
->max
.value
)
61 if (sval_cmp(r2
->min
, min
) < 0)
64 if (sval_cmp(r2
->max
, max
) > 0)
67 return alloc_absolute(min
, max
);
70 static void reset_state(struct sm_state
*sm
)
72 set_state(absolute_id
, sm
->name
, sm
->sym
, &undefined
);
75 static void match_assign(struct expression
*expr
)
77 struct symbol
*left_type
;
78 sval_t left_min
, left_max
, right_min
, right_max
;
80 if (expr
->op
!= '=') {
81 set_state_expr(absolute_id
, expr
->left
, &undefined
);
85 left_type
= get_type(expr
->left
);
88 left_min
= sval_type_min(left_type
);
89 left_max
= sval_type_max(left_type
);
91 get_absolute_min_sval(expr
->right
, &right_min
);
92 get_absolute_max_sval(expr
->right
, &right_max
);
94 /* handle wrapping. sort of sloppy */
95 if (sval_cmp(left_max
, right_max
) < 0)
97 if (sval_cmp(left_min
, right_min
) > 0)
100 if (sval_cmp(right_min
, sval_type_min(left_type
)) <= 0 && sval_cmp(right_max
, sval_type_max(left_type
)) >= 0)
101 set_state_expr(absolute_id
, expr
->left
, &undefined
);
103 set_state_expr(absolute_id
, expr
->left
, alloc_absolute(right_min
, right_max
));
106 static void struct_member_callback(char *fn
, char *global_static
, int param
, char *printed_name
, struct smatch_state
*state
)
108 struct data_range_sval
*range
;
113 if (sval_is_min(range
->min
) && sval_is_max(range
->max
))
115 sm_msg("info: passes absolute_limits '%s' %d '%s' %s %s", fn
, param
, printed_name
, state
->name
, global_static
);
118 static void match_call_info(struct expression
*expr
)
120 struct expression
*arg
;
124 name
= get_fnptr_name(expr
->fn
);
129 FOR_EACH_PTR(expr
->args
, arg
) {
134 if (!get_absolute_min_sval(arg
, &min
))
136 if (!get_absolute_max_sval(arg
, &max
))
138 if (sval_is_min(min
) && sval_is_max(max
))
141 /* fixme: determine the type of the paramter */
142 sm_msg("info: passes absolute_limits '%s' %d '$$' %s %s",
143 name
, i
, show_range(min
, max
),
144 is_static(expr
->fn
) ? "static" : "global");
145 } END_FOR_EACH_PTR(arg
);
150 static void set_param_limits(const char *name
, struct symbol
*sym
, char *key
, char *value
)
152 struct range_list_sval
*rl
= NULL
;
156 if (strncmp(key
, "$$", 2))
159 snprintf(fullname
, 256, "%s%s", name
, key
+ 2);
160 get_value_ranges_sval(value
, &rl
);
161 min
= rl_min_sval(rl
);
162 max
= rl_max_sval(rl
);
163 set_state(absolute_id
, fullname
, sym
, alloc_absolute(min
, max
));
166 void register_absolute(int id
)
170 add_merge_hook(absolute_id
, &merge_func
);
171 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
173 add_hook(&match_call_info
, FUNCTION_CALL_HOOK
);
174 add_member_info_callback(absolute_id
, struct_member_callback
);
176 add_definition_db_callback(set_param_limits
, ABSOLUTE_LIMITS
);
179 void register_absolute_late(int id
)
181 add_modification_hook(absolute_id
, reset_state
);