2 * sparse/smatch_ranges.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
12 #include "smatch_extra.h"
13 #include "smatch_slist.h"
15 ALLOCATOR(data_info
, "smatch extra data");
16 ALLOCATOR(data_range
, "data range");
17 __DO_ALLOCATOR(struct data_range
, sizeof(struct data_range
), __alignof__(struct data_range
),
18 "permanent ranges", perm_data_range
);
20 static char *show_num(long long num
)
22 static char buff
[256];
24 if (num
== whole_range
.min
) {
25 snprintf(buff
, 255, "min");
26 } else if (num
== whole_range
.max
) {
27 snprintf(buff
, 255, "max");
29 snprintf(buff
, 255, "(%lld)", num
);
31 snprintf(buff
, 255, "%lld", num
);
37 char *show_ranges(struct range_list
*list
)
39 struct data_range
*tmp
;
45 FOR_EACH_PTR(list
, tmp
) {
47 strncat(full
, ",", 254 - strlen(full
));
48 if (tmp
->min
== tmp
->max
) {
49 strncat(full
, show_num(tmp
->min
), 254 - strlen(full
));
52 strncat(full
, show_num(tmp
->min
), 254 - strlen(full
));
53 strncat(full
, "-", 254 - strlen(full
));
54 strncat(full
, show_num(tmp
->max
), 254 - strlen(full
));
55 } END_FOR_EACH_PTR(tmp
);
56 return alloc_sname(full
);
59 static struct data_range range_zero
= {
64 static struct data_range range_one
= {
69 int is_whole_range_rl(struct range_list
*rl
)
71 struct data_range
*drange
;
73 if (ptr_list_empty(rl
))
75 drange
= first_ptr_list((struct ptr_list
*)rl
);
76 if (drange
->min
== whole_range
.min
&& drange
->max
== whole_range
.max
)
81 struct data_range
*alloc_range(long long min
, long long max
)
83 struct data_range
*ret
;
86 sm_msg("Error invalid range %lld to %lld", min
, max
);
87 min
= whole_range
.min
;
88 max
= whole_range
.max
;
90 if (min
== whole_range
.min
&& max
== whole_range
.max
)
92 if (min
== 0 && max
== 0)
94 if (min
== 1 && max
== 1)
96 ret
= __alloc_data_range(0);
102 struct data_range
*alloc_range_perm(long long min
, long long max
)
104 struct data_range
*ret
;
107 sm_msg("Error invalid range %lld to %lld", min
, max
);
108 min
= whole_range
.min
;
109 max
= whole_range
.max
;
111 if (min
== whole_range
.min
&& max
== whole_range
.max
)
113 if (min
== 0 && max
== 0)
115 if (min
== 1 && max
== 1)
117 ret
= __alloc_perm_data_range(0);
123 void add_range(struct range_list
**list
, long long min
, long long max
)
125 struct data_range
*tmp
= NULL
;
126 struct data_range
*new = NULL
;
129 FOR_EACH_PTR(*list
, tmp
) {
131 /* Sometimes we overlap with more than one range
132 so we have to delete or modify the next range. */
133 if (max
+ 1 == tmp
->min
) {
134 /* join 2 ranges here */
136 DELETE_CURRENT_PTR(tmp
);
140 /* Doesn't overlap with the next one. */
143 /* Partially overlaps with the next one. */
144 if (max
< tmp
->max
) {
148 /* Completely overlaps with the next one. */
149 if (max
>= tmp
->max
) {
150 DELETE_CURRENT_PTR(tmp
);
151 /* there could be more ranges to delete */
155 if (max
!= whole_range
.max
&& max
+ 1 == tmp
->min
) {
156 /* join 2 ranges into a big range */
157 new = alloc_range(min
, tmp
->max
);
158 REPLACE_CURRENT_PTR(tmp
, new);
161 if (max
< tmp
->min
) { /* new range entirely below */
162 new = alloc_range(min
, max
);
163 INSERT_CURRENT(new, tmp
);
166 if (min
< tmp
->min
) { /* new range partially below */
171 new = alloc_range(min
, max
);
172 REPLACE_CURRENT_PTR(tmp
, new);
177 if (max
<= tmp
->max
) /* new range already included */
179 if (min
<= tmp
->max
) { /* new range partially above */
181 new = alloc_range(min
, max
);
182 REPLACE_CURRENT_PTR(tmp
, new);
186 if (min
!= whole_range
.min
&& min
- 1 == tmp
->max
) {
187 /* join 2 ranges into a big range */
188 new = alloc_range(tmp
->min
, max
);
189 REPLACE_CURRENT_PTR(tmp
, new);
193 /* the new range is entirely above the existing ranges */
194 } END_FOR_EACH_PTR(tmp
);
197 new = alloc_range(min
, max
);
198 add_ptr_list(list
, new);
201 struct range_list
*clone_range_list(struct range_list
*list
)
203 struct data_range
*tmp
;
204 struct range_list
*ret
= NULL
;
206 FOR_EACH_PTR(list
, tmp
) {
207 add_ptr_list(&ret
, tmp
);
208 } END_FOR_EACH_PTR(tmp
);
212 struct range_list
*range_list_union(struct range_list
*one
, struct range_list
*two
)
214 struct data_range
*tmp
;
215 struct range_list
*ret
= NULL
;
217 FOR_EACH_PTR(one
, tmp
) {
218 add_range(&ret
, tmp
->min
, tmp
->max
);
219 } END_FOR_EACH_PTR(tmp
);
220 FOR_EACH_PTR(two
, tmp
) {
221 add_range(&ret
, tmp
->min
, tmp
->max
);
222 } END_FOR_EACH_PTR(tmp
);
226 struct range_list
*remove_range(struct range_list
*list
, long long min
, long long max
)
228 struct data_range
*tmp
;
229 struct range_list
*ret
= NULL
;
231 FOR_EACH_PTR(list
, tmp
) {
232 if (tmp
->max
< min
) {
233 add_range(&ret
, tmp
->min
, tmp
->max
);
236 if (tmp
->min
> max
) {
237 add_range(&ret
, tmp
->min
, tmp
->max
);
240 if (tmp
->min
>= min
&& tmp
->max
<= max
)
242 if (tmp
->min
>= min
) {
243 add_range(&ret
, max
+ 1, tmp
->max
);
244 } else if (tmp
->max
<= max
) {
245 add_range(&ret
, tmp
->min
, min
- 1);
247 add_range(&ret
, tmp
->min
, min
- 1);
248 add_range(&ret
, max
+ 1, tmp
->max
);
250 } END_FOR_EACH_PTR(tmp
);
254 long long get_dinfo_min(struct data_info
*dinfo
)
256 struct data_range
*drange
;
258 if (!dinfo
|| !dinfo
->value_ranges
)
259 return whole_range
.min
;
260 drange
= first_ptr_list((struct ptr_list
*)dinfo
->value_ranges
);
264 long long get_dinfo_max(struct data_info
*dinfo
)
266 struct data_range
*drange
;
268 if (!dinfo
|| !dinfo
->value_ranges
)
269 return whole_range
.max
;
270 drange
= last_ptr_list((struct ptr_list
*)dinfo
->value_ranges
);
275 * if it can be only one and only value return 1, else return 0
277 int get_single_value_from_dinfo(struct data_info
*dinfo
, long long *val
)
279 struct data_range
*tmp
;
282 if (dinfo
->type
!= DATA_RANGE
)
285 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
287 if (tmp
->min
!= tmp
->max
)
293 } END_FOR_EACH_PTR(tmp
);
297 int true_comparison_range(struct data_range
*left
, int comparison
, struct data_range
*right
)
299 switch (comparison
) {
301 case SPECIAL_UNSIGNED_LT
:
302 if (left
->min
< right
->max
)
305 case SPECIAL_UNSIGNED_LTE
:
307 if (left
->min
<= right
->max
)
311 if (left
->max
< right
->min
)
313 if (left
->min
> right
->max
)
316 case SPECIAL_UNSIGNED_GTE
:
318 if (left
->max
>= right
->min
)
322 case SPECIAL_UNSIGNED_GT
:
323 if (left
->max
> right
->min
)
326 case SPECIAL_NOTEQUAL
:
327 if (left
->min
!= left
->max
)
329 if (right
->min
!= right
->max
)
331 if (left
->min
!= right
->min
)
335 sm_msg("unhandled comparison %d\n", comparison
);
341 int true_comparison_range_lr(int comparison
, struct data_range
*var
, struct data_range
*val
, int left
)
344 return true_comparison_range(var
, comparison
, val
);
346 return true_comparison_range(val
, comparison
, var
);
349 static int false_comparison_range(struct data_range
*left
, int comparison
, struct data_range
*right
)
351 switch (comparison
) {
353 case SPECIAL_UNSIGNED_LT
:
354 if (left
->max
>= right
->min
)
357 case SPECIAL_UNSIGNED_LTE
:
359 if (left
->max
> right
->min
)
363 if (left
->min
!= left
->max
)
365 if (right
->min
!= right
->max
)
367 if (left
->min
!= right
->min
)
370 case SPECIAL_UNSIGNED_GTE
:
372 if (left
->min
< right
->max
)
376 case SPECIAL_UNSIGNED_GT
:
377 if (left
->min
<= right
->max
)
380 case SPECIAL_NOTEQUAL
:
381 if (left
->max
< right
->min
)
383 if (left
->min
> right
->max
)
387 sm_msg("unhandled comparison %d\n", comparison
);
393 int false_comparison_range_lr(int comparison
, struct data_range
*var
, struct data_range
*val
, int left
)
396 return false_comparison_range(var
, comparison
, val
);
398 return false_comparison_range(val
, comparison
, var
);
401 int possibly_true(int comparison
, struct data_info
*dinfo
, long long num
, int left
)
403 struct data_range
*tmp
;
404 struct data_range drange
;
412 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
413 if (true_comparison_range_lr(comparison
, tmp
, &drange
, left
))
415 } END_FOR_EACH_PTR(tmp
);
419 int possibly_false(int comparison
, struct data_info
*dinfo
, long long num
, int left
)
421 struct data_range
*tmp
;
422 struct data_range drange
;
430 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
431 if (false_comparison_range_lr(comparison
, tmp
, &drange
, left
))
433 } END_FOR_EACH_PTR(tmp
);
437 int possibly_true_range_lists(struct range_list
*left_ranges
, int comparison
, struct range_list
*right_ranges
)
439 struct data_range
*left_tmp
, *right_tmp
;
441 if (!left_ranges
|| !right_ranges
)
444 FOR_EACH_PTR(left_ranges
, left_tmp
) {
445 FOR_EACH_PTR(right_ranges
, right_tmp
) {
446 if (true_comparison_range(left_tmp
, comparison
, right_tmp
))
448 } END_FOR_EACH_PTR(right_tmp
);
449 } END_FOR_EACH_PTR(left_tmp
);
453 int possibly_true_range_list_lr(int comparison
, struct data_info
*dinfo
, struct range_list
*values
, int left
)
455 struct data_range
*tmp
, *tmp2
;
457 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
458 FOR_EACH_PTR(values
, tmp2
) {
459 if (true_comparison_range_lr(comparison
, tmp
, tmp2
, left
))
461 } END_FOR_EACH_PTR(tmp2
);
462 } END_FOR_EACH_PTR(tmp
);
466 int possibly_false_range_lists(struct range_list
*left_ranges
, int comparison
, struct range_list
*right_ranges
)
468 struct data_range
*left_tmp
, *right_tmp
;
470 if (!left_ranges
|| !right_ranges
)
473 FOR_EACH_PTR(left_ranges
, left_tmp
) {
474 FOR_EACH_PTR(right_ranges
, right_tmp
) {
475 if (false_comparison_range(left_tmp
, comparison
, right_tmp
))
477 } END_FOR_EACH_PTR(right_tmp
);
478 } END_FOR_EACH_PTR(left_tmp
);
482 int possibly_false_range_list_lr(int comparison
, struct data_info
*dinfo
, struct range_list
*values
, int left
)
484 struct data_range
*tmp
, *tmp2
;
486 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
487 FOR_EACH_PTR(values
, tmp2
) {
488 if (false_comparison_range_lr(comparison
, tmp
, tmp2
, left
))
490 } END_FOR_EACH_PTR(tmp2
);
491 } END_FOR_EACH_PTR(tmp
);
495 void tack_on(struct range_list
**list
, struct data_range
*drange
)
497 add_ptr_list(list
, drange
);
500 int in_list_exact(struct range_list
*list
, struct data_range
*drange
)
502 struct data_range
*tmp
;
504 FOR_EACH_PTR(list
, tmp
) {
505 if (tmp
->min
== drange
->min
&& tmp
->max
== drange
->max
)
507 } END_FOR_EACH_PTR(tmp
);
512 void push_range_list(struct range_list_stack
**rl_stack
, struct range_list
*rl
)
514 add_ptr_list(rl_stack
, rl
);
517 struct range_list
*pop_range_list(struct range_list_stack
**rl_stack
)
519 struct range_list
*rl
;
521 rl
= last_ptr_list((struct ptr_list
*)*rl_stack
);
522 delete_ptr_list_last((struct ptr_list
**)rl_stack
);
526 struct range_list
*top_range_list(struct range_list_stack
*rl_stack
)
528 struct range_list
*rl
;
530 rl
= last_ptr_list((struct ptr_list
*)rl_stack
);
534 void filter_top_range_list(struct range_list_stack
**rl_stack
, long long num
)
536 struct range_list
*rl
;
538 rl
= pop_range_list(rl_stack
);
539 rl
= remove_range(rl
, num
, num
);
540 push_range_list(rl_stack
, rl
);
543 void free_range_list(struct range_list
**rlist
)
545 __free_ptr_list((struct ptr_list
**)rlist
);
548 static void free_single_dinfo(struct data_info
*dinfo
)
550 if (dinfo
->type
== DATA_RANGE
)
551 free_range_list(&dinfo
->value_ranges
);
554 static void free_dinfos(struct allocation_blob
*blob
)
556 unsigned int size
= sizeof(struct data_info
);
557 unsigned int offset
= 0;
559 while (offset
< blob
->offset
) {
560 free_single_dinfo((struct data_info
*)(blob
->data
+ offset
));
565 void free_data_info_allocs(void)
567 struct allocator_struct
*desc
= &data_info_allocator
;
568 struct allocation_blob
*blob
= desc
->blobs
;
571 desc
->allocations
= 0;
572 desc
->total_bytes
= 0;
573 desc
->useful_bytes
= 0;
574 desc
->freelist
= NULL
;
576 struct allocation_blob
*next
= blob
->next
;
578 blob_free(blob
, desc
->chunking
);
581 clear_data_range_alloc();