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 ALLOCATOR(data_range_sval
, "data range sval");
18 __DO_ALLOCATOR(struct data_range_sval
, sizeof(struct data_range_sval
), __alignof__(struct data_range_sval
),
19 "permanent ranges sval", perm_data_range_sval
);
21 struct data_range whole_range
= {
26 char *show_ranges_sval(struct range_list_sval
*list
)
28 struct data_range_sval
*tmp
;
34 FOR_EACH_PTR(list
, tmp
) {
36 strncat(full
, ",", 254 - strlen(full
));
37 if (sval_cmp(tmp
->min
, tmp
->max
) == 0) {
38 strncat(full
, sval_to_str(tmp
->min
), 254 - strlen(full
));
41 strncat(full
, sval_to_str(tmp
->min
), 254 - strlen(full
));
42 strncat(full
, "-", 254 - strlen(full
));
43 strncat(full
, sval_to_str(tmp
->max
), 254 - strlen(full
));
44 } END_FOR_EACH_PTR(tmp
);
45 return alloc_sname(full
);
48 void get_value_ranges_sval(char *value
, struct range_list_sval
**rl
)
62 if (!strncmp(start
, "max", 3)) {
65 } else if (!strncmp(start
, "u64max", 6)) {
66 val1
= LLONG_MAX
; // FIXME
68 } else if (!strncmp(start
, "s64max", 6)) {
71 } else if (!strncmp(start
, "u32max", 6)) {
74 } else if (!strncmp(start
, "s32max", 6)) {
77 } else if (!strncmp(start
, "u16max", 6)) {
80 } else if (!strncmp(start
, "s16max", 6)) {
83 } else if (!strncmp(start
, "min", 3)) {
86 } else if (!strncmp(start
, "s64min", 6)) {
89 } else if (!strncmp(start
, "s32min", 6)) {
92 } else if (!strncmp(start
, "s16min", 6)) {
96 while (*c
&& *c
!= ',' && *c
!= '-')
98 val1
= strtoll(start
, &c
, 10);
103 add_range_sval(rl
, ll_to_sval(val1
), ll_to_sval(val1
));
107 add_range_sval(rl
, ll_to_sval(val1
), ll_to_sval(val1
));
112 c
++; /* skip the dash in eg. 4-5 */
116 if (!strncmp(start
, "max", 3)) {
121 while (*c
&& *c
!= ',' && *c
!= '-')
123 val2
= strtoll(start
, &c
, 10);
125 add_range_sval(rl
, ll_to_sval(val1
), ll_to_sval(val2
));
130 c
++; /* skip the comma in eg: 4-5,7 */
134 int is_whole_range_rl_sval(struct range_list_sval
*rl
)
136 struct data_range_sval
*drange
;
138 if (ptr_list_empty(rl
))
140 drange
= first_ptr_list((struct ptr_list
*)rl
);
141 if (sval_is_min(drange
->min
) && sval_is_max(drange
->max
))
146 sval_t
rl_min_sval(struct range_list_sval
*rl
)
148 struct data_range_sval
*drange
;
151 ret
.type
= &llong_ctype
;
152 ret
.value
= LLONG_MIN
;
153 if (ptr_list_empty(rl
))
155 drange
= first_ptr_list((struct ptr_list
*)rl
);
159 sval_t
rl_max_sval(struct range_list_sval
*rl
)
161 struct data_range_sval
*drange
;
164 ret
.type
= &llong_ctype
;
165 ret
.value
= LLONG_MAX
;
166 if (ptr_list_empty(rl
))
168 drange
= last_ptr_list((struct ptr_list
*)rl
);
172 static struct data_range_sval
*alloc_range_helper_sval(sval_t min
, sval_t max
, int perm
)
174 struct data_range_sval
*ret
;
176 if (sval_cmp(min
, max
) > 0) {
177 // sm_msg("debug invalid range %lld to %lld", min, max);
178 min
.value
= LLONG_MIN
; /* fixme: need a way to represent unknown svals */
179 max
.value
= LLONG_MAX
;
183 ret
= __alloc_perm_data_range_sval(0);
185 ret
= __alloc_data_range_sval(0);
191 struct data_range_sval
*alloc_range_sval(sval_t min
, sval_t max
)
193 return alloc_range_helper_sval(min
, max
, 0);
196 struct data_range_sval
*alloc_range_perm_sval(sval_t min
, sval_t max
)
198 return alloc_range_helper_sval(min
, max
, 1);
201 struct range_list_sval
*alloc_range_list_sval(sval_t min
, sval_t max
)
203 struct range_list_sval
*rl
= NULL
;
205 add_range_sval(&rl
, min
, max
);
209 struct range_list_sval
*whole_range_list_sval(struct symbol
*type
)
214 return alloc_range_list_sval(sval_type_min(type
), sval_type_max(type
));
217 void add_range_sval(struct range_list_sval
**list
, sval_t min
, sval_t max
)
219 struct data_range_sval
*tmp
= NULL
;
220 struct data_range_sval
*new = NULL
;
224 * FIXME: This has a problem merging a range_list like: min-0,3-max
225 * with a range like 1-2. You end up with min-2,3-max instead of
228 FOR_EACH_PTR(*list
, tmp
) {
230 /* Sometimes we overlap with more than one range
231 so we have to delete or modify the next range. */
232 if (max
.value
+ 1 == tmp
->min
.value
) {
233 /* join 2 ranges here */
235 DELETE_CURRENT_PTR(tmp
);
239 /* Doesn't overlap with the next one. */
240 if (sval_cmp(max
, tmp
->min
) < 0)
242 /* Partially overlaps with the next one. */
243 if (sval_cmp(max
, tmp
->max
) < 0) {
244 tmp
->min
.value
= max
.value
+ 1;
247 /* Completely overlaps with the next one. */
248 if (sval_cmp(max
, tmp
->max
) >= 0) {
249 DELETE_CURRENT_PTR(tmp
);
250 /* there could be more ranges to delete */
254 if (!sval_is_max(max
) && max
.value
+ 1 == tmp
->min
.value
) {
255 /* join 2 ranges into a big range */
256 new = alloc_range_sval(min
, tmp
->max
);
257 REPLACE_CURRENT_PTR(tmp
, new);
260 if (sval_cmp(max
, tmp
->min
) < 0) { /* new range entirely below */
261 new = alloc_range_sval(min
, max
);
262 INSERT_CURRENT(new, tmp
);
265 if (sval_cmp(min
, tmp
->min
) < 0) { /* new range partially below */
266 if (sval_cmp(max
, tmp
->max
) < 0)
270 new = alloc_range_sval(min
, max
);
271 REPLACE_CURRENT_PTR(tmp
, new);
276 if (sval_cmp(max
, tmp
->max
) <= 0) /* new range already included */
278 if (sval_cmp(min
, tmp
->max
) <= 0) { /* new range partially above */
280 new = alloc_range_sval(min
, max
);
281 REPLACE_CURRENT_PTR(tmp
, new);
285 if (!sval_is_min(min
) && min
.value
- 1 == tmp
->max
.value
) {
286 /* join 2 ranges into a big range */
287 new = alloc_range_sval(tmp
->min
, max
);
288 REPLACE_CURRENT_PTR(tmp
, new);
292 /* the new range is entirely above the existing ranges */
293 } END_FOR_EACH_PTR(tmp
);
296 new = alloc_range_sval(min
, max
);
297 add_ptr_list(list
, new);
300 struct range_list_sval
*clone_range_list_sval(struct range_list_sval
*list
)
302 struct data_range_sval
*tmp
;
303 struct range_list_sval
*ret
= NULL
;
305 FOR_EACH_PTR(list
, tmp
) {
306 add_ptr_list(&ret
, tmp
);
307 } END_FOR_EACH_PTR(tmp
);
311 struct range_list_sval
*clone_permanent_sval(struct range_list_sval
*list
)
313 struct data_range_sval
*tmp
;
314 struct data_range_sval
*new;
315 struct range_list_sval
*ret
= NULL
;
317 FOR_EACH_PTR(list
, tmp
) {
318 new = alloc_range_perm_sval(tmp
->min
, tmp
->max
);
319 add_ptr_list(&ret
, new);
320 } END_FOR_EACH_PTR(tmp
);
324 struct range_list_sval
*range_list_union_sval(struct range_list_sval
*one
, struct range_list_sval
*two
)
326 struct data_range_sval
*tmp
;
327 struct range_list_sval
*ret
= NULL
;
329 FOR_EACH_PTR(one
, tmp
) {
330 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
331 } END_FOR_EACH_PTR(tmp
);
332 FOR_EACH_PTR(two
, tmp
) {
333 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
334 } END_FOR_EACH_PTR(tmp
);
338 struct range_list_sval
*remove_range_sval(struct range_list_sval
*list
, sval_t min
, sval_t max
)
340 struct data_range_sval
*tmp
;
341 struct range_list_sval
*ret
= NULL
;
343 FOR_EACH_PTR(list
, tmp
) {
344 if (sval_cmp(tmp
->max
, min
) < 0) {
345 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
348 if (sval_cmp(tmp
->min
, max
) > 0) {
349 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
352 if (sval_cmp(tmp
->min
, min
) >= 0 && sval_cmp(tmp
->max
, max
) <= 0)
354 if (sval_cmp(tmp
->min
, min
) >= 0) {
356 add_range_sval(&ret
, max
, tmp
->max
);
357 } else if (sval_cmp(tmp
->max
, max
) <= 0) {
359 add_range_sval(&ret
, tmp
->min
, min
);
363 add_range_sval(&ret
, tmp
->min
, min
);
364 add_range_sval(&ret
, max
, tmp
->max
);
366 } END_FOR_EACH_PTR(tmp
);
370 int estate_get_single_value_sval(struct smatch_state
*state
, sval_t
*sval
)
374 min
= rl_min_sval(estate_ranges_sval(state
));
375 max
= rl_max_sval(estate_ranges_sval(state
));
376 if (sval_cmp(min
, max
) != 0)
382 int ranges_equiv_sval(struct data_range_sval
*one
, struct data_range_sval
*two
)
388 if (sval_cmp(one
->min
, two
->min
) != 0)
390 if (sval_cmp(one
->max
, two
->max
) != 0)
395 int range_lists_equiv_sval(struct range_list_sval
*one
, struct range_list_sval
*two
)
397 struct data_range_sval
*one_range
;
398 struct data_range_sval
*two_range
;
400 PREPARE_PTR_LIST(one
, one_range
);
401 PREPARE_PTR_LIST(two
, two_range
);
403 if (!one_range
&& !two_range
)
405 if (!ranges_equiv_sval(one_range
, two_range
))
407 NEXT_PTR_LIST(one_range
);
408 NEXT_PTR_LIST(two_range
);
410 FINISH_PTR_LIST(two_range
);
411 FINISH_PTR_LIST(one_range
);
416 int true_comparison_range_sval(struct data_range_sval
*left
, int comparison
, struct data_range_sval
*right
)
418 switch (comparison
) {
420 case SPECIAL_UNSIGNED_LT
:
421 if (sval_cmp(left
->min
, right
->max
) < 0)
424 case SPECIAL_UNSIGNED_LTE
:
426 if (sval_cmp(left
->min
, right
->max
) <= 0)
430 if (sval_cmp(left
->max
, right
->min
) < 0)
432 if (sval_cmp(left
->min
, right
->max
) > 0)
435 case SPECIAL_UNSIGNED_GTE
:
437 if (sval_cmp(left
->max
, right
->min
) >= 0)
441 case SPECIAL_UNSIGNED_GT
:
442 if (sval_cmp(left
->max
, right
->min
) > 0)
445 case SPECIAL_NOTEQUAL
:
446 if (sval_cmp(left
->min
, left
->max
) != 0)
448 if (sval_cmp(right
->min
, right
->max
) != 0)
450 if (sval_cmp(left
->min
, right
->min
) != 0)
454 sm_msg("unhandled comparison %d\n", comparison
);
460 int true_comparison_range_lr_sval(int comparison
, struct data_range_sval
*var
, struct data_range_sval
*val
, int left
)
463 return true_comparison_range_sval(var
, comparison
, val
);
465 return true_comparison_range_sval(val
, comparison
, var
);
468 static int false_comparison_range_sval(struct data_range_sval
*left
, int comparison
, struct data_range_sval
*right
)
470 switch (comparison
) {
472 case SPECIAL_UNSIGNED_LT
:
473 if (sval_cmp(left
->max
, right
->min
) >= 0)
476 case SPECIAL_UNSIGNED_LTE
:
478 if (sval_cmp(left
->max
, right
->min
) > 0)
482 if (sval_cmp(left
->min
, left
->max
) != 0)
484 if (sval_cmp(right
->min
, right
->max
) != 0)
486 if (sval_cmp(left
->min
, right
->min
) != 0)
489 case SPECIAL_UNSIGNED_GTE
:
491 if (sval_cmp(left
->min
, right
->max
) < 0)
495 case SPECIAL_UNSIGNED_GT
:
496 if (sval_cmp(left
->min
, right
->max
) <= 0)
499 case SPECIAL_NOTEQUAL
:
500 if (sval_cmp(left
->max
, right
->min
) < 0)
502 if (sval_cmp(left
->min
, right
->max
) > 0)
506 sm_msg("unhandled comparison %d\n", comparison
);
512 int false_comparison_range_lr_sval(int comparison
, struct data_range_sval
*var
, struct data_range_sval
*val
, int left
)
515 return false_comparison_range_sval(var
, comparison
, val
);
517 return false_comparison_range_sval(val
, comparison
, var
);
520 int possibly_true(struct expression
*left
, int comparison
, struct expression
*right
)
522 struct range_list_sval
*rl_left
, *rl_right
;
523 struct data_range_sval
*tmp_left
, *tmp_right
;
525 if (!get_implied_range_list_sval(left
, &rl_left
))
527 if (!get_implied_range_list_sval(right
, &rl_right
))
530 FOR_EACH_PTR(rl_left
, tmp_left
) {
531 FOR_EACH_PTR(rl_right
, tmp_right
) {
532 if (true_comparison_range_sval(tmp_left
, comparison
, tmp_right
))
534 } END_FOR_EACH_PTR(tmp_right
);
535 } END_FOR_EACH_PTR(tmp_left
);
539 int possibly_false(struct expression
*left
, int comparison
, struct expression
*right
)
541 struct range_list_sval
*rl_left
, *rl_right
;
542 struct data_range_sval
*tmp_left
, *tmp_right
;
544 if (!get_implied_range_list_sval(left
, &rl_left
))
546 if (!get_implied_range_list_sval(right
, &rl_right
))
549 FOR_EACH_PTR(rl_left
, tmp_left
) {
550 FOR_EACH_PTR(rl_right
, tmp_right
) {
551 if (false_comparison_range_sval(tmp_left
, comparison
, tmp_right
))
553 } END_FOR_EACH_PTR(tmp_right
);
554 } END_FOR_EACH_PTR(tmp_left
);
558 int possibly_true_range_lists_sval(struct range_list_sval
*left_ranges
, int comparison
, struct range_list_sval
*right_ranges
)
560 struct data_range_sval
*left_tmp
, *right_tmp
;
562 if (!left_ranges
|| !right_ranges
)
565 FOR_EACH_PTR(left_ranges
, left_tmp
) {
566 FOR_EACH_PTR(right_ranges
, right_tmp
) {
567 if (true_comparison_range_sval(left_tmp
, comparison
, right_tmp
))
569 } END_FOR_EACH_PTR(right_tmp
);
570 } END_FOR_EACH_PTR(left_tmp
);
574 int possibly_false_range_lists_sval(struct range_list_sval
*left_ranges
, int comparison
, struct range_list_sval
*right_ranges
)
576 struct data_range_sval
*left_tmp
, *right_tmp
;
578 if (!left_ranges
|| !right_ranges
)
581 FOR_EACH_PTR(left_ranges
, left_tmp
) {
582 FOR_EACH_PTR(right_ranges
, right_tmp
) {
583 if (false_comparison_range_sval(left_tmp
, comparison
, right_tmp
))
585 } END_FOR_EACH_PTR(right_tmp
);
586 } END_FOR_EACH_PTR(left_tmp
);
590 /* FIXME: the _rl here stands for right left so really it should be _lr */
591 int possibly_true_range_lists_rl_sval(int comparison
, struct range_list_sval
*a
, struct range_list_sval
*b
, int left
)
594 return possibly_true_range_lists_sval(a
, comparison
, b
);
596 return possibly_true_range_lists_sval(b
, comparison
, a
);
599 int possibly_false_range_lists_rl_sval(int comparison
, struct range_list_sval
*a
, struct range_list_sval
*b
, int left
)
602 return possibly_false_range_lists_sval(a
, comparison
, b
);
604 return possibly_false_range_lists_sval(b
, comparison
, a
);
607 void tack_on_sval(struct range_list_sval
**list
, struct data_range_sval
*drange
)
609 add_ptr_list(list
, drange
);
612 void push_range_list_sval(struct range_list_stack_sval
**rl_stack
, struct range_list_sval
*rl
)
614 add_ptr_list(rl_stack
, rl
);
617 struct range_list_sval
*pop_range_list_sval(struct range_list_stack_sval
**rl_stack
)
619 struct range_list_sval
*rl
;
621 rl
= last_ptr_list((struct ptr_list
*)*rl_stack
);
622 delete_ptr_list_last((struct ptr_list
**)rl_stack
);
626 struct range_list_sval
*top_range_list_sval(struct range_list_stack_sval
*rl_stack
)
628 struct range_list_sval
*rl
;
630 rl
= last_ptr_list((struct ptr_list
*)rl_stack
);
634 void filter_top_range_list_sval(struct range_list_stack_sval
**rl_stack
, sval_t sval
)
636 struct range_list_sval
*rl
;
638 rl
= pop_range_list_sval(rl_stack
);
639 rl
= remove_range_sval(rl
, sval
, sval
);
640 push_range_list_sval(rl_stack
, rl
);
643 struct range_list_sval
*cast_rl(struct range_list_sval
*rl
, struct symbol
*type
)
645 struct data_range_sval
*tmp
;
646 struct data_range_sval
*new;
647 struct range_list_sval
*ret
= NULL
;
648 int set_min
, set_max
;
654 return clone_range_list_sval(rl
);
657 if (type_unsigned(type
) && sval_cmp_val(rl_min_sval(rl
), 0) < 0)
661 if (type_signed(type
) && sval_cmp(rl_max_sval(rl
), sval_type_max(type
)) > 0)
664 FOR_EACH_PTR(rl
, tmp
) {
665 if (sval_cmp_t(type
, tmp
->max
, sval_type_min(type
)) < 0)
667 if (sval_cmp_t(type
, tmp
->min
, sval_type_max(type
)) > 0)
669 new = alloc_range_sval(sval_cast(tmp
->min
, type
), sval_cast(tmp
->max
, type
));
670 add_ptr_list(&ret
, new);
671 } END_FOR_EACH_PTR(tmp
);
674 return whole_range_list_sval(type
);
677 tmp
= first_ptr_list((struct ptr_list
*)ret
);
678 tmp
->min
= sval_type_min(type
);
681 tmp
= last_ptr_list((struct ptr_list
*)ret
);
682 tmp
->min
= sval_type_max(type
);
688 void free_range_list_sval(struct range_list_sval
**rlist
)
690 __free_ptr_list((struct ptr_list
**)rlist
);
693 static void free_single_dinfo(struct data_info
*dinfo
)
695 if (dinfo
->type
== DATA_RANGE
)
696 free_range_list_sval(&dinfo
->value_ranges
);
699 static void free_dinfos(struct allocation_blob
*blob
)
701 unsigned int size
= sizeof(struct data_info
);
702 unsigned int offset
= 0;
704 while (offset
< blob
->offset
) {
705 free_single_dinfo((struct data_info
*)(blob
->data
+ offset
));
710 void free_data_info_allocs(void)
712 struct allocator_struct
*desc
= &data_info_allocator
;
713 struct allocation_blob
*blob
= desc
->blobs
;
716 desc
->allocations
= 0;
717 desc
->total_bytes
= 0;
718 desc
->useful_bytes
= 0;
719 desc
->freelist
= NULL
;
721 struct allocation_blob
*next
= blob
->next
;
723 blob_free(blob
, desc
->chunking
);
726 clear_data_range_alloc();