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
);
19 ALLOCATOR(data_range_sval
, "data range sval");
20 __DO_ALLOCATOR(struct data_range_sval
, sizeof(struct data_range_sval
), __alignof__(struct data_range_sval
),
21 "permanent ranges sval", perm_data_range_sval
);
23 struct data_range whole_range
= {
28 char *show_ranges_sval(struct range_list_sval
*list
)
30 struct data_range_sval
*tmp
;
36 FOR_EACH_PTR(list
, tmp
) {
38 strncat(full
, ",", 254 - strlen(full
));
39 if (sval_cmp(tmp
->min
, tmp
->max
) == 0) {
40 strncat(full
, sval_to_str(tmp
->min
), 254 - strlen(full
));
43 strncat(full
, sval_to_str(tmp
->min
), 254 - strlen(full
));
44 strncat(full
, "-", 254 - strlen(full
));
45 strncat(full
, sval_to_str(tmp
->max
), 254 - strlen(full
));
46 } END_FOR_EACH_PTR(tmp
);
47 return alloc_sname(full
);
50 void get_value_ranges_sval(char *value
, struct range_list_sval
**rl
)
64 if (!strncmp(start
, "max", 3)) {
67 } else if (!strncmp(start
, "u64max", 6)) {
68 val1
= LLONG_MAX
; // FIXME
70 } else if (!strncmp(start
, "s64max", 6)) {
73 } else if (!strncmp(start
, "u32max", 6)) {
76 } else if (!strncmp(start
, "s32max", 6)) {
79 } else if (!strncmp(start
, "u16max", 6)) {
82 } else if (!strncmp(start
, "s16max", 6)) {
85 } else if (!strncmp(start
, "min", 3)) {
88 } else if (!strncmp(start
, "s64min", 6)) {
91 } else if (!strncmp(start
, "s32min", 6)) {
94 } else if (!strncmp(start
, "s16min", 6)) {
98 while (*c
&& *c
!= ',' && *c
!= '-')
100 val1
= strtoll(start
, &c
, 10);
105 add_range_sval(rl
, ll_to_sval(val1
), ll_to_sval(val1
));
109 add_range_sval(rl
, ll_to_sval(val1
), ll_to_sval(val1
));
114 c
++; /* skip the dash in eg. 4-5 */
118 if (!strncmp(start
, "max", 3)) {
123 while (*c
&& *c
!= ',' && *c
!= '-')
125 val2
= strtoll(start
, &c
, 10);
127 add_range_sval(rl
, ll_to_sval(val1
), ll_to_sval(val2
));
132 c
++; /* skip the comma in eg: 4-5,7 */
136 static struct data_range range_zero
= {
141 static struct data_range range_one
= {
146 int is_whole_range_rl_sval(struct range_list_sval
*rl
)
148 struct data_range_sval
*drange
;
150 if (ptr_list_empty(rl
))
152 drange
= first_ptr_list((struct ptr_list
*)rl
);
153 if (sval_is_min(drange
->min
) && sval_is_max(drange
->max
))
158 sval_t
rl_min_sval(struct range_list_sval
*rl
)
160 struct data_range_sval
*drange
;
163 ret
.type
= &llong_ctype
;
164 ret
.value
= LLONG_MIN
;
165 if (ptr_list_empty(rl
))
167 drange
= first_ptr_list((struct ptr_list
*)rl
);
171 sval_t
rl_max_sval(struct range_list_sval
*rl
)
173 struct data_range_sval
*drange
;
176 ret
.type
= &llong_ctype
;
177 ret
.value
= LLONG_MAX
;
178 if (ptr_list_empty(rl
))
180 drange
= last_ptr_list((struct ptr_list
*)rl
);
184 static struct data_range
*alloc_range_helper(long long min
, long long max
, int perm
)
186 struct data_range
*ret
;
189 // sm_msg("debug invalid range %lld to %lld", min, max);
190 min
= whole_range
.min
;
191 max
= whole_range
.max
;
193 if (min
== whole_range
.min
&& max
== whole_range
.max
)
195 if (min
== 0 && max
== 0)
197 if (min
== 1 && max
== 1)
201 ret
= __alloc_perm_data_range(0);
203 ret
= __alloc_data_range(0);
209 static struct data_range_sval
*alloc_range_helper_sval(sval_t min
, sval_t max
, int perm
)
211 struct data_range_sval
*ret
;
213 if (sval_cmp(min
, max
) > 0) {
214 // sm_msg("debug invalid range %lld to %lld", min, max);
215 min
.value
= LLONG_MIN
; /* fixme: need a way to represent unknown svals */
216 max
.value
= LLONG_MAX
;
220 ret
= __alloc_perm_data_range_sval(0);
222 ret
= __alloc_data_range_sval(0);
228 struct data_range
*alloc_range(long long min
, long long max
)
230 return alloc_range_helper(min
, max
, 0);
233 struct data_range_sval
*alloc_range_sval(sval_t min
, sval_t max
)
235 return alloc_range_helper_sval(min
, max
, 0);
238 struct data_range_sval
*drange_to_drange_sval(struct data_range
*drange
)
240 return alloc_range_helper_sval(ll_to_sval(drange
->min
), ll_to_sval(drange
->max
), 0);
243 struct data_range
*drange_sval_to_drange(struct data_range_sval
*drange
)
245 return alloc_range_helper(sval_to_ll(drange
->min
), sval_to_ll(drange
->max
), 0);
248 struct data_range
*alloc_range_perm(long long min
, long long max
)
250 return alloc_range_helper(min
, max
, 1);
253 struct data_range_sval
*alloc_range_perm_sval(sval_t min
, sval_t max
)
255 return alloc_range_helper_sval(min
, max
, 1);
258 struct range_list_sval
*alloc_range_list_sval(sval_t min
, sval_t max
)
260 struct range_list_sval
*rl
= NULL
;
262 add_range_sval(&rl
, min
, max
);
266 struct range_list_sval
*whole_range_list_sval(void)
268 return alloc_range_list_sval(ll_to_sval(whole_range
.min
), ll_to_sval(whole_range
.max
));
271 void add_range_sval(struct range_list_sval
**list
, sval_t min
, sval_t max
)
273 struct data_range_sval
*tmp
= NULL
;
274 struct data_range_sval
*new = NULL
;
278 * FIXME: This has a problem merging a range_list like: min-0,3-max
279 * with a range like 1-2. You end up with min-2,3-max instead of
282 FOR_EACH_PTR(*list
, tmp
) {
284 /* Sometimes we overlap with more than one range
285 so we have to delete or modify the next range. */
286 if (max
.value
+ 1 == tmp
->min
.value
) {
287 /* join 2 ranges here */
289 DELETE_CURRENT_PTR(tmp
);
293 /* Doesn't overlap with the next one. */
294 if (sval_cmp(max
, tmp
->min
) < 0)
296 /* Partially overlaps with the next one. */
297 if (sval_cmp(max
, tmp
->max
) < 0) {
298 tmp
->min
.value
= max
.value
+ 1;
301 /* Completely overlaps with the next one. */
302 if (sval_cmp(max
, tmp
->max
) >= 0) {
303 DELETE_CURRENT_PTR(tmp
);
304 /* there could be more ranges to delete */
308 if (!sval_is_max(max
) && max
.value
+ 1 == tmp
->min
.value
) {
309 /* join 2 ranges into a big range */
310 new = alloc_range_sval(min
, tmp
->max
);
311 REPLACE_CURRENT_PTR(tmp
, new);
314 if (sval_cmp(max
, tmp
->min
) < 0) { /* new range entirely below */
315 new = alloc_range_sval(min
, max
);
316 INSERT_CURRENT(new, tmp
);
319 if (sval_cmp(min
, tmp
->min
) < 0) { /* new range partially below */
320 if (sval_cmp(max
, tmp
->max
) < 0)
324 new = alloc_range_sval(min
, max
);
325 REPLACE_CURRENT_PTR(tmp
, new);
330 if (sval_cmp(max
, tmp
->max
) <= 0) /* new range already included */
332 if (sval_cmp(min
, tmp
->max
) <= 0) { /* new range partially above */
334 new = alloc_range_sval(min
, max
);
335 REPLACE_CURRENT_PTR(tmp
, new);
339 if (!sval_is_min(min
) && min
.value
- 1 == tmp
->max
.value
) {
340 /* join 2 ranges into a big range */
341 new = alloc_range_sval(tmp
->min
, max
);
342 REPLACE_CURRENT_PTR(tmp
, new);
346 /* the new range is entirely above the existing ranges */
347 } END_FOR_EACH_PTR(tmp
);
350 new = alloc_range_sval(min
, max
);
351 add_ptr_list(list
, new);
354 struct range_list_sval
*clone_range_list_sval(struct range_list_sval
*list
)
356 struct data_range_sval
*tmp
;
357 struct range_list_sval
*ret
= NULL
;
359 FOR_EACH_PTR(list
, tmp
) {
360 add_ptr_list(&ret
, tmp
);
361 } END_FOR_EACH_PTR(tmp
);
365 struct range_list_sval
*clone_permanent_sval(struct range_list_sval
*list
)
367 struct data_range_sval
*tmp
;
368 struct data_range_sval
*new;
369 struct range_list_sval
*ret
= NULL
;
371 FOR_EACH_PTR(list
, tmp
) {
372 new = alloc_range_perm_sval(tmp
->min
, tmp
->max
);
373 add_ptr_list(&ret
, new);
374 } END_FOR_EACH_PTR(tmp
);
378 struct range_list_sval
*range_list_union_sval(struct range_list_sval
*one
, struct range_list_sval
*two
)
380 struct data_range_sval
*tmp
;
381 struct range_list_sval
*ret
= NULL
;
383 FOR_EACH_PTR(one
, tmp
) {
384 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
385 } END_FOR_EACH_PTR(tmp
);
386 FOR_EACH_PTR(two
, tmp
) {
387 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
388 } END_FOR_EACH_PTR(tmp
);
392 struct range_list_sval
*remove_range_sval(struct range_list_sval
*list
, sval_t min
, sval_t max
)
394 struct data_range_sval
*tmp
;
395 struct range_list_sval
*ret
= NULL
;
397 FOR_EACH_PTR(list
, tmp
) {
398 if (sval_cmp(tmp
->max
, min
) < 0) {
399 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
402 if (sval_cmp(tmp
->min
, max
) > 0) {
403 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
406 if (sval_cmp(tmp
->min
, min
) >= 0 && sval_cmp(tmp
->max
, max
) <= 0)
408 if (sval_cmp(tmp
->min
, min
) >= 0) {
410 add_range_sval(&ret
, max
, tmp
->max
);
411 } else if (sval_cmp(tmp
->max
, max
) <= 0) {
413 add_range_sval(&ret
, tmp
->min
, min
);
417 add_range_sval(&ret
, tmp
->min
, min
);
418 add_range_sval(&ret
, max
, tmp
->max
);
420 } END_FOR_EACH_PTR(tmp
);
424 int estate_get_single_value_sval(struct smatch_state
*state
, sval_t
*sval
)
428 min
= rl_min_sval(estate_ranges_sval(state
));
429 max
= rl_max_sval(estate_ranges_sval(state
));
430 if (sval_cmp(min
, max
) != 0)
436 int ranges_equiv_sval(struct data_range_sval
*one
, struct data_range_sval
*two
)
442 if (sval_cmp(one
->min
, two
->min
) != 0)
444 if (sval_cmp(one
->max
, two
->max
) != 0)
449 int range_lists_equiv_sval(struct range_list_sval
*one
, struct range_list_sval
*two
)
451 struct data_range_sval
*one_range
;
452 struct data_range_sval
*two_range
;
454 PREPARE_PTR_LIST(one
, one_range
);
455 PREPARE_PTR_LIST(two
, two_range
);
457 if (!one_range
&& !two_range
)
459 if (!ranges_equiv_sval(one_range
, two_range
))
461 NEXT_PTR_LIST(one_range
);
462 NEXT_PTR_LIST(two_range
);
464 FINISH_PTR_LIST(two_range
);
465 FINISH_PTR_LIST(one_range
);
470 int true_comparison_range_sval(struct data_range_sval
*left
, int comparison
, struct data_range_sval
*right
)
472 switch (comparison
) {
474 case SPECIAL_UNSIGNED_LT
:
475 if (sval_cmp(left
->min
, right
->max
) < 0)
478 case SPECIAL_UNSIGNED_LTE
:
480 if (sval_cmp(left
->min
, right
->max
) <= 0)
484 if (sval_cmp(left
->max
, right
->min
) < 0)
486 if (sval_cmp(left
->min
, right
->max
) > 0)
489 case SPECIAL_UNSIGNED_GTE
:
491 if (sval_cmp(left
->max
, right
->min
) >= 0)
495 case SPECIAL_UNSIGNED_GT
:
496 if (sval_cmp(left
->max
, right
->min
) > 0)
499 case SPECIAL_NOTEQUAL
:
500 if (sval_cmp(left
->min
, left
->max
) != 0)
502 if (sval_cmp(right
->min
, right
->max
) != 0)
504 if (sval_cmp(left
->min
, right
->min
) != 0)
508 sm_msg("unhandled comparison %d\n", comparison
);
514 int true_comparison_range_lr_sval(int comparison
, struct data_range_sval
*var
, struct data_range_sval
*val
, int left
)
517 return true_comparison_range_sval(var
, comparison
, val
);
519 return true_comparison_range_sval(val
, comparison
, var
);
522 static int false_comparison_range_sval(struct data_range_sval
*left
, int comparison
, struct data_range_sval
*right
)
524 switch (comparison
) {
526 case SPECIAL_UNSIGNED_LT
:
527 if (sval_cmp(left
->max
, right
->min
) >= 0)
530 case SPECIAL_UNSIGNED_LTE
:
532 if (sval_cmp(left
->max
, right
->min
) > 0)
536 if (sval_cmp(left
->min
, left
->max
) != 0)
538 if (sval_cmp(right
->min
, right
->max
) != 0)
540 if (sval_cmp(left
->min
, right
->min
) != 0)
543 case SPECIAL_UNSIGNED_GTE
:
545 if (sval_cmp(left
->min
, right
->max
) < 0)
549 case SPECIAL_UNSIGNED_GT
:
550 if (sval_cmp(left
->min
, right
->max
) <= 0)
553 case SPECIAL_NOTEQUAL
:
554 if (sval_cmp(left
->max
, right
->min
) < 0)
556 if (sval_cmp(left
->min
, right
->max
) > 0)
560 sm_msg("unhandled comparison %d\n", comparison
);
566 int false_comparison_range_lr_sval(int comparison
, struct data_range_sval
*var
, struct data_range_sval
*val
, int left
)
569 return false_comparison_range_sval(var
, comparison
, val
);
571 return false_comparison_range_sval(val
, comparison
, var
);
574 int possibly_true(struct expression
*left
, int comparison
, struct expression
*right
)
576 struct range_list_sval
*rl_left
, *rl_right
;
577 struct data_range_sval
*tmp_left
, *tmp_right
;
579 if (!get_implied_range_list_sval(left
, &rl_left
))
581 if (!get_implied_range_list_sval(right
, &rl_right
))
584 FOR_EACH_PTR(rl_left
, tmp_left
) {
585 FOR_EACH_PTR(rl_right
, tmp_right
) {
586 if (true_comparison_range_sval(tmp_left
, comparison
, tmp_right
))
588 } END_FOR_EACH_PTR(tmp_right
);
589 } END_FOR_EACH_PTR(tmp_left
);
593 int possibly_false(struct expression
*left
, int comparison
, struct expression
*right
)
595 struct range_list_sval
*rl_left
, *rl_right
;
596 struct data_range_sval
*tmp_left
, *tmp_right
;
598 if (!get_implied_range_list_sval(left
, &rl_left
))
600 if (!get_implied_range_list_sval(right
, &rl_right
))
603 FOR_EACH_PTR(rl_left
, tmp_left
) {
604 FOR_EACH_PTR(rl_right
, tmp_right
) {
605 if (false_comparison_range_sval(tmp_left
, comparison
, tmp_right
))
607 } END_FOR_EACH_PTR(tmp_right
);
608 } END_FOR_EACH_PTR(tmp_left
);
612 int possibly_true_range_lists_sval(struct range_list_sval
*left_ranges
, int comparison
, struct range_list_sval
*right_ranges
)
614 struct data_range_sval
*left_tmp
, *right_tmp
;
616 if (!left_ranges
|| !right_ranges
)
619 FOR_EACH_PTR(left_ranges
, left_tmp
) {
620 FOR_EACH_PTR(right_ranges
, right_tmp
) {
621 if (true_comparison_range_sval(left_tmp
, comparison
, right_tmp
))
623 } END_FOR_EACH_PTR(right_tmp
);
624 } END_FOR_EACH_PTR(left_tmp
);
628 int possibly_false_range_lists_sval(struct range_list_sval
*left_ranges
, int comparison
, struct range_list_sval
*right_ranges
)
630 struct data_range_sval
*left_tmp
, *right_tmp
;
632 if (!left_ranges
|| !right_ranges
)
635 FOR_EACH_PTR(left_ranges
, left_tmp
) {
636 FOR_EACH_PTR(right_ranges
, right_tmp
) {
637 if (false_comparison_range_sval(left_tmp
, comparison
, right_tmp
))
639 } END_FOR_EACH_PTR(right_tmp
);
640 } END_FOR_EACH_PTR(left_tmp
);
644 /* FIXME: the _rl here stands for right left so really it should be _lr */
645 int possibly_true_range_lists_rl_sval(int comparison
, struct range_list_sval
*a
, struct range_list_sval
*b
, int left
)
648 return possibly_true_range_lists_sval(a
, comparison
, b
);
650 return possibly_true_range_lists_sval(b
, comparison
, a
);
653 int possibly_false_range_lists_rl_sval(int comparison
, struct range_list_sval
*a
, struct range_list_sval
*b
, int left
)
656 return possibly_false_range_lists_sval(a
, comparison
, b
);
658 return possibly_false_range_lists_sval(b
, comparison
, a
);
661 void tack_on_sval(struct range_list_sval
**list
, struct data_range_sval
*drange
)
663 add_ptr_list(list
, drange
);
666 void push_range_list_sval(struct range_list_stack_sval
**rl_stack
, struct range_list_sval
*rl
)
668 add_ptr_list(rl_stack
, rl
);
671 struct range_list_sval
*pop_range_list_sval(struct range_list_stack_sval
**rl_stack
)
673 struct range_list_sval
*rl
;
675 rl
= last_ptr_list((struct ptr_list
*)*rl_stack
);
676 delete_ptr_list_last((struct ptr_list
**)rl_stack
);
680 struct range_list_sval
*top_range_list_sval(struct range_list_stack_sval
*rl_stack
)
682 struct range_list_sval
*rl
;
684 rl
= last_ptr_list((struct ptr_list
*)rl_stack
);
688 void filter_top_range_list_sval(struct range_list_stack_sval
**rl_stack
, sval_t sval
)
690 struct range_list_sval
*rl
;
692 rl
= pop_range_list_sval(rl_stack
);
693 rl
= remove_range_sval(rl
, sval
, sval
);
694 push_range_list_sval(rl_stack
, rl
);
697 void free_range_list_sval(struct range_list_sval
**rlist
)
699 __free_ptr_list((struct ptr_list
**)rlist
);
702 static void free_single_dinfo(struct data_info
*dinfo
)
704 if (dinfo
->type
== DATA_RANGE
)
705 free_range_list_sval(&dinfo
->value_ranges
);
708 static void free_dinfos(struct allocation_blob
*blob
)
710 unsigned int size
= sizeof(struct data_info
);
711 unsigned int offset
= 0;
713 while (offset
< blob
->offset
) {
714 free_single_dinfo((struct data_info
*)(blob
->data
+ offset
));
719 void free_data_info_allocs(void)
721 struct allocator_struct
*desc
= &data_info_allocator
;
722 struct allocation_blob
*blob
= desc
->blobs
;
725 desc
->allocations
= 0;
726 desc
->total_bytes
= 0;
727 desc
->useful_bytes
= 0;
728 desc
->freelist
= NULL
;
730 struct allocation_blob
*next
= blob
->next
;
732 blob_free(blob
, desc
->chunking
);
735 clear_data_range_alloc();
738 struct range_list_sval
*range_list_to_sval(struct range_list
*list
)
740 struct data_range
*tmp
;
741 struct data_range_sval
*tmp_sval
;
742 struct range_list_sval
*ret
= NULL
;
744 FOR_EACH_PTR(list
, tmp
) {
745 tmp_sval
= drange_to_drange_sval(tmp
);
746 add_ptr_list(&ret
, tmp_sval
);
747 } END_FOR_EACH_PTR(tmp
);
751 struct range_list
*rl_sval_to_rl(struct range_list_sval
*list
)
753 struct data_range
*tmp
;
754 struct data_range_sval
*tmp_sval
;
755 struct range_list
*ret
= NULL
;
757 FOR_EACH_PTR(list
, tmp_sval
) {
758 tmp
= drange_sval_to_drange(tmp_sval
);
759 add_ptr_list(&ret
, tmp
);
760 } END_FOR_EACH_PTR(tmp_sval
);