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 void get_value_ranges(char *value
, struct range_list
**rl
)
70 if (!strncmp(start
, "min", 3)) {
74 while (*c
&& *c
!= ',' && *c
!= '-')
76 val1
= strtoll(start
, &c
, 10);
81 add_range(rl
, val1
, val1
);
85 add_range(rl
, val1
, val1
);
90 c
++; /* skip the dash in eg. 4-5 */
94 if (!strncmp(start
, "max", 3)) {
99 while (*c
&& *c
!= ',' && *c
!= '-')
101 val2
= strtoll(start
, &c
, 10);
103 add_range(rl
, val1
, val2
);
108 c
++; /* skip the comma in eg: 4-5,7 */
113 static struct data_range range_zero
= {
118 static struct data_range range_one
= {
123 int is_whole_range_rl(struct range_list
*rl
)
125 struct data_range
*drange
;
127 if (ptr_list_empty(rl
))
129 drange
= first_ptr_list((struct ptr_list
*)rl
);
130 if (drange
->min
== whole_range
.min
&& drange
->max
== whole_range
.max
)
135 long long rl_min(struct range_list
*rl
)
137 struct data_range
*drange
;
139 if (ptr_list_empty(rl
))
140 return whole_range
.min
;
141 drange
= first_ptr_list((struct ptr_list
*)rl
);
145 long long rl_max(struct range_list
*rl
)
147 struct data_range
*drange
;
149 if (ptr_list_empty(rl
))
150 return whole_range
.max
;
151 drange
= last_ptr_list((struct ptr_list
*)rl
);
155 static struct data_range
*alloc_range_helper(long long min
, long long max
, int perm
)
157 struct data_range
*ret
;
160 sm_msg("Error invalid range %lld to %lld", min
, max
);
161 min
= whole_range
.min
;
162 max
= whole_range
.max
;
164 if (min
== whole_range
.min
&& max
== whole_range
.max
)
166 if (min
== 0 && max
== 0)
168 if (min
== 1 && max
== 1)
172 ret
= __alloc_perm_data_range(0);
174 ret
= __alloc_data_range(0);
180 struct data_range
*alloc_range(long long min
, long long max
)
182 return alloc_range_helper(min
, max
, 0);
185 struct data_range
*alloc_range_perm(long long min
, long long max
)
187 return alloc_range_helper(min
, max
, 1);
190 struct range_list
*alloc_range_list(long long min
, long long max
)
192 struct range_list
*rl
= NULL
;
194 add_range(&rl
, min
, max
);
198 void add_range(struct range_list
**list
, long long min
, long long max
)
200 struct data_range
*tmp
= NULL
;
201 struct data_range
*new = NULL
;
205 * FIXME: This has a problem merging a range_list like: min-0,3-max
206 * with a range like 1-2. You end up with min-2,3-max instead of
209 FOR_EACH_PTR(*list
, tmp
) {
211 /* Sometimes we overlap with more than one range
212 so we have to delete or modify the next range. */
213 if (max
+ 1 == tmp
->min
) {
214 /* join 2 ranges here */
216 DELETE_CURRENT_PTR(tmp
);
220 /* Doesn't overlap with the next one. */
223 /* Partially overlaps with the next one. */
224 if (max
< tmp
->max
) {
228 /* Completely overlaps with the next one. */
229 if (max
>= tmp
->max
) {
230 DELETE_CURRENT_PTR(tmp
);
231 /* there could be more ranges to delete */
235 if (max
!= whole_range
.max
&& max
+ 1 == tmp
->min
) {
236 /* join 2 ranges into a big range */
237 new = alloc_range(min
, tmp
->max
);
238 REPLACE_CURRENT_PTR(tmp
, new);
241 if (max
< tmp
->min
) { /* new range entirely below */
242 new = alloc_range(min
, max
);
243 INSERT_CURRENT(new, tmp
);
246 if (min
< tmp
->min
) { /* new range partially below */
251 new = alloc_range(min
, max
);
252 REPLACE_CURRENT_PTR(tmp
, new);
257 if (max
<= tmp
->max
) /* new range already included */
259 if (min
<= tmp
->max
) { /* new range partially above */
261 new = alloc_range(min
, max
);
262 REPLACE_CURRENT_PTR(tmp
, new);
266 if (min
!= whole_range
.min
&& min
- 1 == tmp
->max
) {
267 /* join 2 ranges into a big range */
268 new = alloc_range(tmp
->min
, max
);
269 REPLACE_CURRENT_PTR(tmp
, new);
273 /* the new range is entirely above the existing ranges */
274 } END_FOR_EACH_PTR(tmp
);
277 new = alloc_range(min
, max
);
278 add_ptr_list(list
, new);
281 struct range_list
*clone_range_list(struct range_list
*list
)
283 struct data_range
*tmp
;
284 struct range_list
*ret
= NULL
;
286 FOR_EACH_PTR(list
, tmp
) {
287 add_ptr_list(&ret
, tmp
);
288 } END_FOR_EACH_PTR(tmp
);
292 struct range_list
*range_list_union(struct range_list
*one
, struct range_list
*two
)
294 struct data_range
*tmp
;
295 struct range_list
*ret
= NULL
;
297 FOR_EACH_PTR(one
, tmp
) {
298 add_range(&ret
, tmp
->min
, tmp
->max
);
299 } END_FOR_EACH_PTR(tmp
);
300 FOR_EACH_PTR(two
, tmp
) {
301 add_range(&ret
, tmp
->min
, tmp
->max
);
302 } END_FOR_EACH_PTR(tmp
);
306 struct range_list
*remove_range(struct range_list
*list
, long long min
, long long max
)
308 struct data_range
*tmp
;
309 struct range_list
*ret
= NULL
;
311 FOR_EACH_PTR(list
, tmp
) {
312 if (tmp
->max
< min
) {
313 add_range(&ret
, tmp
->min
, tmp
->max
);
316 if (tmp
->min
> max
) {
317 add_range(&ret
, tmp
->min
, tmp
->max
);
320 if (tmp
->min
>= min
&& tmp
->max
<= max
)
322 if (tmp
->min
>= min
) {
323 add_range(&ret
, max
+ 1, tmp
->max
);
324 } else if (tmp
->max
<= max
) {
325 add_range(&ret
, tmp
->min
, min
- 1);
327 add_range(&ret
, tmp
->min
, min
- 1);
328 add_range(&ret
, max
+ 1, tmp
->max
);
330 } END_FOR_EACH_PTR(tmp
);
334 long long get_dinfo_min(struct data_info
*dinfo
)
337 return whole_range
.min
;
338 return rl_min(dinfo
->value_ranges
);
341 long long get_dinfo_max(struct data_info
*dinfo
)
344 return whole_range
.max
;
345 return rl_max(dinfo
->value_ranges
);
349 * if it can be only one and only value return 1, else return 0
351 int get_single_value_from_dinfo(struct data_info
*dinfo
, long long *val
)
353 struct data_range
*tmp
;
356 if (dinfo
->type
!= DATA_RANGE
)
359 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
361 if (tmp
->min
!= tmp
->max
)
367 } END_FOR_EACH_PTR(tmp
);
371 int true_comparison_range(struct data_range
*left
, int comparison
, struct data_range
*right
)
373 switch (comparison
) {
375 case SPECIAL_UNSIGNED_LT
:
376 if (left
->min
< right
->max
)
379 case SPECIAL_UNSIGNED_LTE
:
381 if (left
->min
<= right
->max
)
385 if (left
->max
< right
->min
)
387 if (left
->min
> right
->max
)
390 case SPECIAL_UNSIGNED_GTE
:
392 if (left
->max
>= right
->min
)
396 case SPECIAL_UNSIGNED_GT
:
397 if (left
->max
> right
->min
)
400 case SPECIAL_NOTEQUAL
:
401 if (left
->min
!= left
->max
)
403 if (right
->min
!= right
->max
)
405 if (left
->min
!= right
->min
)
409 sm_msg("unhandled comparison %d\n", comparison
);
415 int true_comparison_range_lr(int comparison
, struct data_range
*var
, struct data_range
*val
, int left
)
418 return true_comparison_range(var
, comparison
, val
);
420 return true_comparison_range(val
, comparison
, var
);
423 static int false_comparison_range(struct data_range
*left
, int comparison
, struct data_range
*right
)
425 switch (comparison
) {
427 case SPECIAL_UNSIGNED_LT
:
428 if (left
->max
>= right
->min
)
431 case SPECIAL_UNSIGNED_LTE
:
433 if (left
->max
> right
->min
)
437 if (left
->min
!= left
->max
)
439 if (right
->min
!= right
->max
)
441 if (left
->min
!= right
->min
)
444 case SPECIAL_UNSIGNED_GTE
:
446 if (left
->min
< right
->max
)
450 case SPECIAL_UNSIGNED_GT
:
451 if (left
->min
<= right
->max
)
454 case SPECIAL_NOTEQUAL
:
455 if (left
->max
< right
->min
)
457 if (left
->min
> right
->max
)
461 sm_msg("unhandled comparison %d\n", comparison
);
467 int false_comparison_range_lr(int comparison
, struct data_range
*var
, struct data_range
*val
, int left
)
470 return false_comparison_range(var
, comparison
, val
);
472 return false_comparison_range(val
, comparison
, var
);
475 int possibly_true(int comparison
, struct expression
*expr
, long long num
, int left
)
477 struct data_range
*tmp
;
478 struct data_range drange
;
479 struct range_list
*rl
;
481 if (!get_implied_range_list(expr
, &rl
))
487 FOR_EACH_PTR(rl
, tmp
) {
488 if (true_comparison_range_lr(comparison
, tmp
, &drange
, left
))
490 } END_FOR_EACH_PTR(tmp
);
494 int possibly_false(int comparison
, struct expression
*expr
, long long num
, int left
)
496 struct data_range
*tmp
;
497 struct data_range drange
;
498 struct range_list
*rl
;
500 if (!get_implied_range_list(expr
, &rl
))
506 FOR_EACH_PTR(rl
, tmp
) {
507 if (false_comparison_range_lr(comparison
, tmp
, &drange
, left
))
509 } END_FOR_EACH_PTR(tmp
);
513 int possibly_true_range_lists(struct range_list
*left_ranges
, int comparison
, struct range_list
*right_ranges
)
515 struct data_range
*left_tmp
, *right_tmp
;
517 if (!left_ranges
|| !right_ranges
)
520 FOR_EACH_PTR(left_ranges
, left_tmp
) {
521 FOR_EACH_PTR(right_ranges
, right_tmp
) {
522 if (true_comparison_range(left_tmp
, comparison
, right_tmp
))
524 } END_FOR_EACH_PTR(right_tmp
);
525 } END_FOR_EACH_PTR(left_tmp
);
529 int possibly_true_range_list_lr(int comparison
, struct data_info
*dinfo
, struct range_list
*values
, int left
)
531 struct data_range
*tmp
, *tmp2
;
533 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
534 FOR_EACH_PTR(values
, tmp2
) {
535 if (true_comparison_range_lr(comparison
, tmp
, tmp2
, left
))
537 } END_FOR_EACH_PTR(tmp2
);
538 } END_FOR_EACH_PTR(tmp
);
542 int possibly_false_range_lists(struct range_list
*left_ranges
, int comparison
, struct range_list
*right_ranges
)
544 struct data_range
*left_tmp
, *right_tmp
;
546 if (!left_ranges
|| !right_ranges
)
549 FOR_EACH_PTR(left_ranges
, left_tmp
) {
550 FOR_EACH_PTR(right_ranges
, right_tmp
) {
551 if (false_comparison_range(left_tmp
, comparison
, right_tmp
))
553 } END_FOR_EACH_PTR(right_tmp
);
554 } END_FOR_EACH_PTR(left_tmp
);
558 int possibly_false_range_list_lr(int comparison
, struct data_info
*dinfo
, struct range_list
*values
, int left
)
560 struct data_range
*tmp
, *tmp2
;
562 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
563 FOR_EACH_PTR(values
, tmp2
) {
564 if (false_comparison_range_lr(comparison
, tmp
, tmp2
, left
))
566 } END_FOR_EACH_PTR(tmp2
);
567 } END_FOR_EACH_PTR(tmp
);
571 void tack_on(struct range_list
**list
, struct data_range
*drange
)
573 add_ptr_list(list
, drange
);
576 int in_list_exact(struct range_list
*list
, struct data_range
*drange
)
578 struct data_range
*tmp
;
580 FOR_EACH_PTR(list
, tmp
) {
581 if (tmp
->min
== drange
->min
&& tmp
->max
== drange
->max
)
583 } END_FOR_EACH_PTR(tmp
);
588 void push_range_list(struct range_list_stack
**rl_stack
, struct range_list
*rl
)
590 add_ptr_list(rl_stack
, rl
);
593 struct range_list
*pop_range_list(struct range_list_stack
**rl_stack
)
595 struct range_list
*rl
;
597 rl
= last_ptr_list((struct ptr_list
*)*rl_stack
);
598 delete_ptr_list_last((struct ptr_list
**)rl_stack
);
602 struct range_list
*top_range_list(struct range_list_stack
*rl_stack
)
604 struct range_list
*rl
;
606 rl
= last_ptr_list((struct ptr_list
*)rl_stack
);
610 void filter_top_range_list(struct range_list_stack
**rl_stack
, long long num
)
612 struct range_list
*rl
;
614 rl
= pop_range_list(rl_stack
);
615 rl
= remove_range(rl
, num
, num
);
616 push_range_list(rl_stack
, rl
);
619 void free_range_list(struct range_list
**rlist
)
621 __free_ptr_list((struct ptr_list
**)rlist
);
624 static void free_single_dinfo(struct data_info
*dinfo
)
626 if (dinfo
->type
== DATA_RANGE
)
627 free_range_list(&dinfo
->value_ranges
);
630 static void free_dinfos(struct allocation_blob
*blob
)
632 unsigned int size
= sizeof(struct data_info
);
633 unsigned int offset
= 0;
635 while (offset
< blob
->offset
) {
636 free_single_dinfo((struct data_info
*)(blob
->data
+ offset
));
641 void free_data_info_allocs(void)
643 struct allocator_struct
*desc
= &data_info_allocator
;
644 struct allocation_blob
*blob
= desc
->blobs
;
647 desc
->allocations
= 0;
648 desc
->total_bytes
= 0;
649 desc
->useful_bytes
= 0;
650 desc
->freelist
= NULL
;
652 struct allocation_blob
*next
= blob
->next
;
654 blob_free(blob
, desc
->chunking
);
657 clear_data_range_alloc();