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
)
101 if (expr
->op
!= '=') {
102 set_state_expr(absolute_id
, expr
->left
, &undefined
);
106 type
= get_type(expr
->left
);
110 if (!get_absolute_min(expr
->right
, &min
))
111 min
= whole_range
.min
;
112 if (!get_absolute_max(expr
->right
, &max
))
113 max
= whole_range
.max
;
115 /* handle wrapping. sort of sloppy */
116 if (type_max(type
) < max
)
117 min
= type_min(type
);
118 if (type_min(type
) > min
)
119 max
= type_max(type
);
121 if (min
<= type_min(type
) && max
>= type_max(type
))
122 set_state_expr(absolute_id
, expr
->left
, &undefined
);
124 set_state_expr(absolute_id
, expr
->left
, alloc_absolute(min
, 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
) {
155 if (!get_absolute_min(arg
, &min
))
157 if (!get_absolute_max(arg
, &max
))
159 if (min
== whole_range
.min
&& max
== whole_range
.max
)
162 /* fixme: determine the type of the paramter */
163 sm_msg("info: passes absolute_limits '%s' %d '$$' %s %s",
164 name
, i
, show_range(min
, max
),
165 is_static(expr
->fn
) ? "static" : "global");
166 } END_FOR_EACH_PTR(arg
);
171 static void set_param_limits(const char *name
, struct symbol
*sym
, char *key
, char *value
)
173 struct range_list
*rl
= NULL
;
177 if (strncmp(key
, "$$", 2))
180 snprintf(fullname
, 256, "%s%s", name
, key
+ 2);
181 get_value_ranges(value
, &rl
);
184 set_state(absolute_id
, fullname
, sym
, alloc_absolute(min
, max
));
187 void register_absolute(int id
)
191 add_merge_hook(absolute_id
, &merge_func
);
192 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
194 add_hook(&match_call_info
, FUNCTION_CALL_HOOK
);
195 add_member_info_callback(absolute_id
, struct_member_callback
);
197 add_definition_db_callback(set_param_limits
, ABSOLUTE_LIMITS
);
200 void register_absolute_late(int id
)
202 add_modification_hook(absolute_id
, reset_state
);