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 char *show_ranges(struct range_list
*list
)
22 struct data_range
*tmp
;
28 FOR_EACH_PTR(list
, tmp
) {
30 strncat(full
, ",", 254 - strlen(full
));
31 if (sval_cmp(tmp
->min
, tmp
->max
) == 0) {
32 strncat(full
, sval_to_str(tmp
->min
), 254 - strlen(full
));
35 strncat(full
, sval_to_str(tmp
->min
), 254 - strlen(full
));
36 strncat(full
, "-", 254 - strlen(full
));
37 strncat(full
, sval_to_str(tmp
->max
), 254 - strlen(full
));
38 } END_FOR_EACH_PTR(tmp
);
39 return alloc_sname(full
);
42 void parse_value_ranges_type(struct symbol
*type
, char *value
, struct range_list
**rl
)
57 if (!strncmp(start
, "max", 3)) {
58 tmp
= sval_type_max(type
);
61 } else if (!strncmp(start
, "u64max", 6)) {
62 val1
= LLONG_MAX
; // FIXME
64 } else if (!strncmp(start
, "s64max", 6)) {
67 } else if (!strncmp(start
, "u32max", 6)) {
70 } else if (!strncmp(start
, "s32max", 6)) {
73 } else if (!strncmp(start
, "u16max", 6)) {
76 } else if (!strncmp(start
, "s16max", 6)) {
79 } else if (!strncmp(start
, "min", 3)) {
80 tmp
= sval_type_min(type
);
83 } else if (!strncmp(start
, "s64min", 6)) {
86 } else if (!strncmp(start
, "s32min", 6)) {
89 } else if (!strncmp(start
, "s16min", 6)) {
93 while (*c
&& *c
!= ',' && *c
!= '-')
95 val1
= strtoll(start
, &c
, 10);
100 add_range(rl
, sval_type_val(type
, val1
), sval_type_val(type
, val1
));
104 add_range(rl
, sval_type_val(type
, val1
), sval_type_val(type
, val1
));
109 c
++; /* skip the dash in eg. 4-5 */
113 if (!strncmp(start
, "max", 3)) {
114 tmp
= sval_type_max(type
);
119 while (*c
&& *c
!= ',' && *c
!= '-')
121 val2
= strtoll(start
, &c
, 10);
123 add_range(rl
, sval_type_val(type
, val1
), sval_type_val(type
, val2
));
128 c
++; /* skip the comma in eg: 4-5,7 */
131 *rl
= cast_rl(type
, *rl
);
134 void parse_value_ranges(char *value
, struct range_list
**rl
)
136 parse_value_ranges_type(&llong_ctype
, value
, rl
);
139 int is_whole_range_rl(struct range_list
*rl
)
141 struct data_range
*drange
;
143 if (ptr_list_empty(rl
))
145 drange
= first_ptr_list((struct ptr_list
*)rl
);
146 if (sval_is_min(drange
->min
) && sval_is_max(drange
->max
))
151 sval_t
rl_min(struct range_list
*rl
)
153 struct data_range
*drange
;
156 ret
.type
= &llong_ctype
;
157 ret
.value
= LLONG_MIN
;
158 if (ptr_list_empty(rl
))
160 drange
= first_ptr_list((struct ptr_list
*)rl
);
164 sval_t
rl_max(struct range_list
*rl
)
166 struct data_range
*drange
;
169 ret
.type
= &llong_ctype
;
170 ret
.value
= LLONG_MAX
;
171 if (ptr_list_empty(rl
))
173 drange
= last_ptr_list((struct ptr_list
*)rl
);
177 static struct data_range
*alloc_range_helper_sval(sval_t min
, sval_t max
, int perm
)
179 struct data_range
*ret
;
181 if (sval_cmp(min
, max
) > 0) {
182 // sm_msg("debug invalid range %lld to %lld", min, max);
183 min
.value
= LLONG_MIN
; /* fixme: need a way to represent unknown svals */
184 max
.value
= LLONG_MAX
;
188 ret
= __alloc_perm_data_range(0);
190 ret
= __alloc_data_range(0);
196 struct data_range
*alloc_range(sval_t min
, sval_t max
)
198 return alloc_range_helper_sval(min
, max
, 0);
201 struct data_range
*alloc_range_perm(sval_t min
, sval_t max
)
203 return alloc_range_helper_sval(min
, max
, 1);
206 struct range_list
*alloc_range_list(sval_t min
, sval_t max
)
208 struct range_list
*rl
= NULL
;
210 add_range(&rl
, min
, max
);
214 struct range_list
*whole_range_list(struct symbol
*type
)
219 return alloc_range_list(sval_type_min(type
), sval_type_max(type
));
222 void add_range(struct range_list
**list
, sval_t min
, sval_t max
)
224 struct data_range
*tmp
= NULL
;
225 struct data_range
*new = NULL
;
229 * FIXME: This has a problem merging a range_list like: min-0,3-max
230 * with a range like 1-2. You end up with min-2,3-max instead of
233 FOR_EACH_PTR(*list
, tmp
) {
235 /* Sometimes we overlap with more than one range
236 so we have to delete or modify the next range. */
237 if (max
.value
+ 1 == tmp
->min
.value
) {
238 /* join 2 ranges here */
240 DELETE_CURRENT_PTR(tmp
);
244 /* Doesn't overlap with the next one. */
245 if (sval_cmp(max
, tmp
->min
) < 0)
247 /* Partially overlaps with the next one. */
248 if (sval_cmp(max
, tmp
->max
) < 0) {
249 tmp
->min
.value
= max
.value
+ 1;
252 /* Completely overlaps with the next one. */
253 if (sval_cmp(max
, tmp
->max
) >= 0) {
254 DELETE_CURRENT_PTR(tmp
);
255 /* there could be more ranges to delete */
259 if (!sval_is_max(max
) && max
.value
+ 1 == tmp
->min
.value
) {
260 /* join 2 ranges into a big range */
261 new = alloc_range(min
, tmp
->max
);
262 REPLACE_CURRENT_PTR(tmp
, new);
265 if (sval_cmp(max
, tmp
->min
) < 0) { /* new range entirely below */
266 new = alloc_range(min
, max
);
267 INSERT_CURRENT(new, tmp
);
270 if (sval_cmp(min
, tmp
->min
) < 0) { /* new range partially below */
271 if (sval_cmp(max
, tmp
->max
) < 0)
275 new = alloc_range(min
, max
);
276 REPLACE_CURRENT_PTR(tmp
, new);
281 if (sval_cmp(max
, tmp
->max
) <= 0) /* new range already included */
283 if (sval_cmp(min
, tmp
->max
) <= 0) { /* new range partially above */
285 new = alloc_range(min
, max
);
286 REPLACE_CURRENT_PTR(tmp
, new);
290 if (!sval_is_min(min
) && min
.value
- 1 == tmp
->max
.value
) {
291 /* join 2 ranges into a big range */
292 new = alloc_range(tmp
->min
, max
);
293 REPLACE_CURRENT_PTR(tmp
, new);
297 /* the new range is entirely above the existing ranges */
298 } END_FOR_EACH_PTR(tmp
);
301 new = alloc_range(min
, max
);
302 add_ptr_list(list
, new);
305 struct range_list
*clone_range_list(struct range_list
*list
)
307 struct data_range
*tmp
;
308 struct range_list
*ret
= NULL
;
310 FOR_EACH_PTR(list
, tmp
) {
311 add_ptr_list(&ret
, tmp
);
312 } END_FOR_EACH_PTR(tmp
);
316 struct range_list
*clone_permanent(struct range_list
*list
)
318 struct data_range
*tmp
;
319 struct data_range
*new;
320 struct range_list
*ret
= NULL
;
322 FOR_EACH_PTR(list
, tmp
) {
323 new = alloc_range_perm(tmp
->min
, tmp
->max
);
324 add_ptr_list(&ret
, new);
325 } END_FOR_EACH_PTR(tmp
);
329 struct range_list
*range_list_union(struct range_list
*one
, struct range_list
*two
)
331 struct data_range
*tmp
;
332 struct range_list
*ret
= NULL
;
334 FOR_EACH_PTR(one
, tmp
) {
335 add_range(&ret
, tmp
->min
, tmp
->max
);
336 } END_FOR_EACH_PTR(tmp
);
337 FOR_EACH_PTR(two
, tmp
) {
338 add_range(&ret
, tmp
->min
, tmp
->max
);
339 } END_FOR_EACH_PTR(tmp
);
343 struct range_list
*remove_range(struct range_list
*list
, sval_t min
, sval_t max
)
345 struct data_range
*tmp
;
346 struct range_list
*ret
= NULL
;
348 FOR_EACH_PTR(list
, tmp
) {
349 if (sval_cmp(tmp
->max
, min
) < 0) {
350 add_range(&ret
, tmp
->min
, tmp
->max
);
353 if (sval_cmp(tmp
->min
, max
) > 0) {
354 add_range(&ret
, tmp
->min
, tmp
->max
);
357 if (sval_cmp(tmp
->min
, min
) >= 0 && sval_cmp(tmp
->max
, max
) <= 0)
359 if (sval_cmp(tmp
->min
, min
) >= 0) {
361 add_range(&ret
, max
, tmp
->max
);
362 } else if (sval_cmp(tmp
->max
, max
) <= 0) {
364 add_range(&ret
, tmp
->min
, min
);
368 add_range(&ret
, tmp
->min
, min
);
369 add_range(&ret
, max
, tmp
->max
);
371 } END_FOR_EACH_PTR(tmp
);
375 int ranges_equiv(struct data_range
*one
, struct data_range
*two
)
381 if (sval_cmp(one
->min
, two
->min
) != 0)
383 if (sval_cmp(one
->max
, two
->max
) != 0)
388 int range_lists_equiv(struct range_list
*one
, struct range_list
*two
)
390 struct data_range
*one_range
;
391 struct data_range
*two_range
;
393 PREPARE_PTR_LIST(one
, one_range
);
394 PREPARE_PTR_LIST(two
, two_range
);
396 if (!one_range
&& !two_range
)
398 if (!ranges_equiv(one_range
, two_range
))
400 NEXT_PTR_LIST(one_range
);
401 NEXT_PTR_LIST(two_range
);
403 FINISH_PTR_LIST(two_range
);
404 FINISH_PTR_LIST(one_range
);
409 int true_comparison_range(struct data_range
*left
, int comparison
, struct data_range
*right
)
411 switch (comparison
) {
413 case SPECIAL_UNSIGNED_LT
:
414 if (sval_cmp(left
->min
, right
->max
) < 0)
417 case SPECIAL_UNSIGNED_LTE
:
419 if (sval_cmp(left
->min
, right
->max
) <= 0)
423 if (sval_cmp(left
->max
, right
->min
) < 0)
425 if (sval_cmp(left
->min
, right
->max
) > 0)
428 case SPECIAL_UNSIGNED_GTE
:
430 if (sval_cmp(left
->max
, right
->min
) >= 0)
434 case SPECIAL_UNSIGNED_GT
:
435 if (sval_cmp(left
->max
, right
->min
) > 0)
438 case SPECIAL_NOTEQUAL
:
439 if (sval_cmp(left
->min
, left
->max
) != 0)
441 if (sval_cmp(right
->min
, right
->max
) != 0)
443 if (sval_cmp(left
->min
, right
->min
) != 0)
447 sm_msg("unhandled comparison %d\n", comparison
);
453 int true_comparison_range_lr(int comparison
, struct data_range
*var
, struct data_range
*val
, int left
)
456 return true_comparison_range(var
, comparison
, val
);
458 return true_comparison_range(val
, comparison
, var
);
461 static int false_comparison_range_sval(struct data_range
*left
, int comparison
, struct data_range
*right
)
463 switch (comparison
) {
465 case SPECIAL_UNSIGNED_LT
:
466 if (sval_cmp(left
->max
, right
->min
) >= 0)
469 case SPECIAL_UNSIGNED_LTE
:
471 if (sval_cmp(left
->max
, right
->min
) > 0)
475 if (sval_cmp(left
->min
, left
->max
) != 0)
477 if (sval_cmp(right
->min
, right
->max
) != 0)
479 if (sval_cmp(left
->min
, right
->min
) != 0)
482 case SPECIAL_UNSIGNED_GTE
:
484 if (sval_cmp(left
->min
, right
->max
) < 0)
488 case SPECIAL_UNSIGNED_GT
:
489 if (sval_cmp(left
->min
, right
->max
) <= 0)
492 case SPECIAL_NOTEQUAL
:
493 if (sval_cmp(left
->max
, right
->min
) < 0)
495 if (sval_cmp(left
->min
, right
->max
) > 0)
499 sm_msg("unhandled comparison %d\n", comparison
);
505 int false_comparison_range_lr(int comparison
, struct data_range
*var
, struct data_range
*val
, int left
)
508 return false_comparison_range_sval(var
, comparison
, val
);
510 return false_comparison_range_sval(val
, comparison
, var
);
513 int possibly_true(struct expression
*left
, int comparison
, struct expression
*right
)
515 struct range_list
*rl_left
, *rl_right
;
516 struct data_range
*tmp_left
, *tmp_right
;
518 if (!get_implied_range_list(left
, &rl_left
))
520 if (!get_implied_range_list(right
, &rl_right
))
523 FOR_EACH_PTR(rl_left
, tmp_left
) {
524 FOR_EACH_PTR(rl_right
, tmp_right
) {
525 if (true_comparison_range(tmp_left
, comparison
, tmp_right
))
527 } END_FOR_EACH_PTR(tmp_right
);
528 } END_FOR_EACH_PTR(tmp_left
);
532 int possibly_false(struct expression
*left
, int comparison
, struct expression
*right
)
534 struct range_list
*rl_left
, *rl_right
;
535 struct data_range
*tmp_left
, *tmp_right
;
537 if (!get_implied_range_list(left
, &rl_left
))
539 if (!get_implied_range_list(right
, &rl_right
))
542 FOR_EACH_PTR(rl_left
, tmp_left
) {
543 FOR_EACH_PTR(rl_right
, tmp_right
) {
544 if (false_comparison_range_sval(tmp_left
, comparison
, tmp_right
))
546 } END_FOR_EACH_PTR(tmp_right
);
547 } END_FOR_EACH_PTR(tmp_left
);
551 int possibly_true_range_lists(struct range_list
*left_ranges
, int comparison
, struct range_list
*right_ranges
)
553 struct data_range
*left_tmp
, *right_tmp
;
555 if (!left_ranges
|| !right_ranges
)
558 FOR_EACH_PTR(left_ranges
, left_tmp
) {
559 FOR_EACH_PTR(right_ranges
, right_tmp
) {
560 if (true_comparison_range(left_tmp
, comparison
, right_tmp
))
562 } END_FOR_EACH_PTR(right_tmp
);
563 } END_FOR_EACH_PTR(left_tmp
);
567 int possibly_false_range_lists(struct range_list
*left_ranges
, int comparison
, struct range_list
*right_ranges
)
569 struct data_range
*left_tmp
, *right_tmp
;
571 if (!left_ranges
|| !right_ranges
)
574 FOR_EACH_PTR(left_ranges
, left_tmp
) {
575 FOR_EACH_PTR(right_ranges
, right_tmp
) {
576 if (false_comparison_range_sval(left_tmp
, comparison
, right_tmp
))
578 } END_FOR_EACH_PTR(right_tmp
);
579 } END_FOR_EACH_PTR(left_tmp
);
583 /* FIXME: the _rl here stands for right left so really it should be _lr */
584 int possibly_true_range_lists_lr(int comparison
, struct range_list
*a
, struct range_list
*b
, int left
)
587 return possibly_true_range_lists(a
, comparison
, b
);
589 return possibly_true_range_lists(b
, comparison
, a
);
592 int possibly_false_range_lists_lr(int comparison
, struct range_list
*a
, struct range_list
*b
, int left
)
595 return possibly_false_range_lists(a
, comparison
, b
);
597 return possibly_false_range_lists(b
, comparison
, a
);
600 void tack_on(struct range_list
**list
, struct data_range
*drange
)
602 add_ptr_list(list
, drange
);
605 void push_range_list(struct range_list_stack
**rl_stack
, struct range_list
*rl
)
607 add_ptr_list(rl_stack
, rl
);
610 struct range_list
*pop_range_list(struct range_list_stack
**rl_stack
)
612 struct range_list
*rl
;
614 rl
= last_ptr_list((struct ptr_list
*)*rl_stack
);
615 delete_ptr_list_last((struct ptr_list
**)rl_stack
);
619 struct range_list
*top_range_list(struct range_list_stack
*rl_stack
)
621 struct range_list
*rl
;
623 rl
= last_ptr_list((struct ptr_list
*)rl_stack
);
627 void filter_top_range_list(struct range_list_stack
**rl_stack
, sval_t sval
)
629 struct range_list
*rl
;
631 rl
= pop_range_list(rl_stack
);
632 rl
= remove_range(rl
, sval
, sval
);
633 push_range_list(rl_stack
, rl
);
636 struct range_list
*cast_rl(struct symbol
*type
, struct range_list
*rl
)
638 struct data_range
*tmp
;
639 struct data_range
*new;
640 struct range_list
*ret
= NULL
;
641 int set_min
, set_max
;
647 return clone_range_list(rl
);
649 if (sval_cmp(rl_min(rl
), rl_max(rl
)) == 0) {
650 sval_t sval
= sval_cast(type
, rl_min(rl
));
651 return alloc_range_list(sval
, sval
);
655 if (type_unsigned(type
) && sval_cmp_val(rl_min(rl
), 0) < 0)
659 if (type_signed(type
) && sval_cmp(rl_max(rl
), sval_type_max(type
)) > 0)
662 FOR_EACH_PTR(rl
, tmp
) {
668 if (sval_cmp_t(type
, max
, sval_type_min(type
)) < 0)
670 if (sval_cmp_t(type
, min
, sval_type_max(type
)) > 0)
672 if (sval_cmp_val(min
, 0) < 0 && type_unsigned(type
))
674 new = alloc_range(sval_cast(type
, min
), sval_cast(type
, max
));
675 add_ptr_list(&ret
, new);
676 } END_FOR_EACH_PTR(tmp
);
679 return whole_range_list(type
);
682 tmp
= first_ptr_list((struct ptr_list
*)ret
);
683 tmp
->min
= sval_type_min(type
);
686 tmp
= last_ptr_list((struct ptr_list
*)ret
);
687 tmp
->max
= sval_type_max(type
);
693 void free_range_list(struct range_list
**rlist
)
695 __free_ptr_list((struct ptr_list
**)rlist
);
698 static void free_single_dinfo(struct data_info
*dinfo
)
700 if (dinfo
->type
== DATA_RANGE
)
701 free_range_list(&dinfo
->value_ranges
);
704 static void free_dinfos(struct allocation_blob
*blob
)
706 unsigned int size
= sizeof(struct data_info
);
707 unsigned int offset
= 0;
709 while (offset
< blob
->offset
) {
710 free_single_dinfo((struct data_info
*)(blob
->data
+ offset
));
715 void free_data_info_allocs(void)
717 struct allocator_struct
*desc
= &data_info_allocator
;
718 struct allocation_blob
*blob
= desc
->blobs
;
721 desc
->allocations
= 0;
722 desc
->total_bytes
= 0;
723 desc
->useful_bytes
= 0;
724 desc
->freelist
= NULL
;
726 struct allocation_blob
*next
= blob
->next
;
728 blob_free(blob
, desc
->chunking
);
731 clear_data_range_alloc();