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 char *show_num(long long num
)
27 sprintf(buf
, "(%lld)", num
);
29 sprintf(buf
, "%lld", num
);
33 static char *show_range(long long min
, long long max
)
38 if (min
== whole_range
.min
)
39 p
+= sprintf(p
, "min");
40 else if (min
== whole_range
.max
)
41 p
+= sprintf(p
, "max");
43 p
+= sprintf(p
, "%s", show_num(min
));
45 if (max
== whole_range
.max
)
48 sprintf(p
, "-%s", show_num(max
));
54 static struct smatch_state
*alloc_absolute(long long min
, long long max
)
56 struct smatch_state
*state
;
58 if (min
== whole_range
.min
&& max
== whole_range
.max
)
61 state
= __alloc_smatch_state(0);
62 state
->name
= alloc_string(show_range(min
, max
));
63 state
->data
= alloc_range(min
, max
);
67 static struct smatch_state
*merge_func(struct smatch_state
*s1
, struct smatch_state
*s2
)
69 struct data_range
*r1
, *r2
;
72 if (!s1
->data
|| !s2
->data
)
78 if (r1
->min
== r2
->min
&& r1
->max
== r2
->max
)
88 return alloc_absolute(min
, max
);
91 static void reset_state(struct sm_state
*sm
)
93 set_state(absolute_id
, sm
->name
, sm
->sym
, &undefined
);
96 static void match_assign(struct expression
*expr
)
98 struct symbol
*left_type
;
99 sval_t left_min
, left_max
, right_min
, right_max
;
101 if (expr
->op
!= '=') {
102 set_state_expr(absolute_id
, expr
->left
, &undefined
);
106 left_type
= get_type(expr
->left
);
109 left_min
= sval_type_min(left_type
);
110 left_max
= sval_type_max(left_type
);
112 get_absolute_min_sval(expr
->right
, &right_min
);
113 get_absolute_max_sval(expr
->right
, &right_max
);
115 /* handle wrapping. sort of sloppy */
116 if (sval_cmp(left_max
, right_max
) < 0)
117 right_min
= left_min
;
118 if (sval_cmp(left_min
, right_min
) > 0)
119 right_max
= left_max
;
121 if (sval_cmp(right_min
, sval_type_min(left_type
)) <= 0 && sval_cmp(right_max
, sval_type_max(left_type
)) >= 0)
122 set_state_expr(absolute_id
, expr
->left
, &undefined
);
124 set_state_expr(absolute_id
, expr
->left
, alloc_absolute(sval_to_ll(right_min
), sval_to_ll(right_max
)));
127 static void struct_member_callback(char *fn
, char *global_static
, int param
, char *printed_name
, struct smatch_state
*state
)
129 struct data_range
*range
;
134 if (range
->min
== whole_range
.min
&& range
->max
== whole_range
.max
)
136 sm_msg("info: passes absolute_limits '%s' %d '%s' %s %s", fn
, param
, printed_name
, state
->name
, global_static
);
139 static void match_call_info(struct expression
*expr
)
141 struct expression
*arg
;
145 name
= get_fnptr_name(expr
->fn
);
150 FOR_EACH_PTR(expr
->args
, arg
) {
156 if (!get_absolute_min(arg
, &min
))
158 if (!get_absolute_max_sval(arg
, &max
))
160 if (min
== whole_range
.min
&& sval_cmp_val(max
, whole_range
.max
) >= 0)
163 /* fixme: determine the type of the paramter */
164 sm_msg("info: passes absolute_limits '%s' %d '$$' %s %s",
165 name
, i
, show_range(min
, sval_to_ll(max
)),
166 is_static(expr
->fn
) ? "static" : "global");
167 } END_FOR_EACH_PTR(arg
);
172 static void set_param_limits(const char *name
, struct symbol
*sym
, char *key
, char *value
)
174 struct range_list
*rl
= NULL
;
178 if (strncmp(key
, "$$", 2))
181 snprintf(fullname
, 256, "%s%s", name
, key
+ 2);
182 get_value_ranges(value
, &rl
);
185 set_state(absolute_id
, fullname
, sym
, alloc_absolute(min
, max
));
188 void register_absolute(int id
)
192 add_merge_hook(absolute_id
, &merge_func
);
193 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
195 add_hook(&match_call_info
, FUNCTION_CALL_HOOK
);
196 add_member_info_callback(absolute_id
, struct_member_callback
);
198 add_definition_db_callback(set_param_limits
, ABSOLUTE_LIMITS
);
201 void register_absolute_late(int id
)
203 add_modification_hook(absolute_id
, reset_state
);