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(void)
211 return alloc_range_list_sval(ll_to_sval(whole_range
.min
), ll_to_sval(whole_range
.max
));
214 void add_range_sval(struct range_list_sval
**list
, sval_t min
, sval_t max
)
216 struct data_range_sval
*tmp
= NULL
;
217 struct data_range_sval
*new = NULL
;
221 * FIXME: This has a problem merging a range_list like: min-0,3-max
222 * with a range like 1-2. You end up with min-2,3-max instead of
225 FOR_EACH_PTR(*list
, tmp
) {
227 /* Sometimes we overlap with more than one range
228 so we have to delete or modify the next range. */
229 if (max
.value
+ 1 == tmp
->min
.value
) {
230 /* join 2 ranges here */
232 DELETE_CURRENT_PTR(tmp
);
236 /* Doesn't overlap with the next one. */
237 if (sval_cmp(max
, tmp
->min
) < 0)
239 /* Partially overlaps with the next one. */
240 if (sval_cmp(max
, tmp
->max
) < 0) {
241 tmp
->min
.value
= max
.value
+ 1;
244 /* Completely overlaps with the next one. */
245 if (sval_cmp(max
, tmp
->max
) >= 0) {
246 DELETE_CURRENT_PTR(tmp
);
247 /* there could be more ranges to delete */
251 if (!sval_is_max(max
) && max
.value
+ 1 == tmp
->min
.value
) {
252 /* join 2 ranges into a big range */
253 new = alloc_range_sval(min
, tmp
->max
);
254 REPLACE_CURRENT_PTR(tmp
, new);
257 if (sval_cmp(max
, tmp
->min
) < 0) { /* new range entirely below */
258 new = alloc_range_sval(min
, max
);
259 INSERT_CURRENT(new, tmp
);
262 if (sval_cmp(min
, tmp
->min
) < 0) { /* new range partially below */
263 if (sval_cmp(max
, tmp
->max
) < 0)
267 new = alloc_range_sval(min
, max
);
268 REPLACE_CURRENT_PTR(tmp
, new);
273 if (sval_cmp(max
, tmp
->max
) <= 0) /* new range already included */
275 if (sval_cmp(min
, tmp
->max
) <= 0) { /* new range partially above */
277 new = alloc_range_sval(min
, max
);
278 REPLACE_CURRENT_PTR(tmp
, new);
282 if (!sval_is_min(min
) && min
.value
- 1 == tmp
->max
.value
) {
283 /* join 2 ranges into a big range */
284 new = alloc_range_sval(tmp
->min
, max
);
285 REPLACE_CURRENT_PTR(tmp
, new);
289 /* the new range is entirely above the existing ranges */
290 } END_FOR_EACH_PTR(tmp
);
293 new = alloc_range_sval(min
, max
);
294 add_ptr_list(list
, new);
297 struct range_list_sval
*clone_range_list_sval(struct range_list_sval
*list
)
299 struct data_range_sval
*tmp
;
300 struct range_list_sval
*ret
= NULL
;
302 FOR_EACH_PTR(list
, tmp
) {
303 add_ptr_list(&ret
, tmp
);
304 } END_FOR_EACH_PTR(tmp
);
308 struct range_list_sval
*clone_permanent_sval(struct range_list_sval
*list
)
310 struct data_range_sval
*tmp
;
311 struct data_range_sval
*new;
312 struct range_list_sval
*ret
= NULL
;
314 FOR_EACH_PTR(list
, tmp
) {
315 new = alloc_range_perm_sval(tmp
->min
, tmp
->max
);
316 add_ptr_list(&ret
, new);
317 } END_FOR_EACH_PTR(tmp
);
321 struct range_list_sval
*range_list_union_sval(struct range_list_sval
*one
, struct range_list_sval
*two
)
323 struct data_range_sval
*tmp
;
324 struct range_list_sval
*ret
= NULL
;
326 FOR_EACH_PTR(one
, tmp
) {
327 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
328 } END_FOR_EACH_PTR(tmp
);
329 FOR_EACH_PTR(two
, tmp
) {
330 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
331 } END_FOR_EACH_PTR(tmp
);
335 struct range_list_sval
*remove_range_sval(struct range_list_sval
*list
, sval_t min
, sval_t max
)
337 struct data_range_sval
*tmp
;
338 struct range_list_sval
*ret
= NULL
;
340 FOR_EACH_PTR(list
, tmp
) {
341 if (sval_cmp(tmp
->max
, min
) < 0) {
342 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
345 if (sval_cmp(tmp
->min
, max
) > 0) {
346 add_range_sval(&ret
, tmp
->min
, tmp
->max
);
349 if (sval_cmp(tmp
->min
, min
) >= 0 && sval_cmp(tmp
->max
, max
) <= 0)
351 if (sval_cmp(tmp
->min
, min
) >= 0) {
353 add_range_sval(&ret
, max
, tmp
->max
);
354 } else if (sval_cmp(tmp
->max
, max
) <= 0) {
356 add_range_sval(&ret
, tmp
->min
, min
);
360 add_range_sval(&ret
, tmp
->min
, min
);
361 add_range_sval(&ret
, max
, tmp
->max
);
363 } END_FOR_EACH_PTR(tmp
);
367 int estate_get_single_value_sval(struct smatch_state
*state
, sval_t
*sval
)
371 min
= rl_min_sval(estate_ranges_sval(state
));
372 max
= rl_max_sval(estate_ranges_sval(state
));
373 if (sval_cmp(min
, max
) != 0)
379 int ranges_equiv_sval(struct data_range_sval
*one
, struct data_range_sval
*two
)
385 if (sval_cmp(one
->min
, two
->min
) != 0)
387 if (sval_cmp(one
->max
, two
->max
) != 0)
392 int range_lists_equiv_sval(struct range_list_sval
*one
, struct range_list_sval
*two
)
394 struct data_range_sval
*one_range
;
395 struct data_range_sval
*two_range
;
397 PREPARE_PTR_LIST(one
, one_range
);
398 PREPARE_PTR_LIST(two
, two_range
);
400 if (!one_range
&& !two_range
)
402 if (!ranges_equiv_sval(one_range
, two_range
))
404 NEXT_PTR_LIST(one_range
);
405 NEXT_PTR_LIST(two_range
);
407 FINISH_PTR_LIST(two_range
);
408 FINISH_PTR_LIST(one_range
);
413 int true_comparison_range_sval(struct data_range_sval
*left
, int comparison
, struct data_range_sval
*right
)
415 switch (comparison
) {
417 case SPECIAL_UNSIGNED_LT
:
418 if (sval_cmp(left
->min
, right
->max
) < 0)
421 case SPECIAL_UNSIGNED_LTE
:
423 if (sval_cmp(left
->min
, right
->max
) <= 0)
427 if (sval_cmp(left
->max
, right
->min
) < 0)
429 if (sval_cmp(left
->min
, right
->max
) > 0)
432 case SPECIAL_UNSIGNED_GTE
:
434 if (sval_cmp(left
->max
, right
->min
) >= 0)
438 case SPECIAL_UNSIGNED_GT
:
439 if (sval_cmp(left
->max
, right
->min
) > 0)
442 case SPECIAL_NOTEQUAL
:
443 if (sval_cmp(left
->min
, left
->max
) != 0)
445 if (sval_cmp(right
->min
, right
->max
) != 0)
447 if (sval_cmp(left
->min
, right
->min
) != 0)
451 sm_msg("unhandled comparison %d\n", comparison
);
457 int true_comparison_range_lr_sval(int comparison
, struct data_range_sval
*var
, struct data_range_sval
*val
, int left
)
460 return true_comparison_range_sval(var
, comparison
, val
);
462 return true_comparison_range_sval(val
, comparison
, var
);
465 static int false_comparison_range_sval(struct data_range_sval
*left
, int comparison
, struct data_range_sval
*right
)
467 switch (comparison
) {
469 case SPECIAL_UNSIGNED_LT
:
470 if (sval_cmp(left
->max
, right
->min
) >= 0)
473 case SPECIAL_UNSIGNED_LTE
:
475 if (sval_cmp(left
->max
, right
->min
) > 0)
479 if (sval_cmp(left
->min
, left
->max
) != 0)
481 if (sval_cmp(right
->min
, right
->max
) != 0)
483 if (sval_cmp(left
->min
, right
->min
) != 0)
486 case SPECIAL_UNSIGNED_GTE
:
488 if (sval_cmp(left
->min
, right
->max
) < 0)
492 case SPECIAL_UNSIGNED_GT
:
493 if (sval_cmp(left
->min
, right
->max
) <= 0)
496 case SPECIAL_NOTEQUAL
:
497 if (sval_cmp(left
->max
, right
->min
) < 0)
499 if (sval_cmp(left
->min
, right
->max
) > 0)
503 sm_msg("unhandled comparison %d\n", comparison
);
509 int false_comparison_range_lr_sval(int comparison
, struct data_range_sval
*var
, struct data_range_sval
*val
, int left
)
512 return false_comparison_range_sval(var
, comparison
, val
);
514 return false_comparison_range_sval(val
, comparison
, var
);
517 int possibly_true(struct expression
*left
, int comparison
, struct expression
*right
)
519 struct range_list_sval
*rl_left
, *rl_right
;
520 struct data_range_sval
*tmp_left
, *tmp_right
;
522 if (!get_implied_range_list_sval(left
, &rl_left
))
524 if (!get_implied_range_list_sval(right
, &rl_right
))
527 FOR_EACH_PTR(rl_left
, tmp_left
) {
528 FOR_EACH_PTR(rl_right
, tmp_right
) {
529 if (true_comparison_range_sval(tmp_left
, comparison
, tmp_right
))
531 } END_FOR_EACH_PTR(tmp_right
);
532 } END_FOR_EACH_PTR(tmp_left
);
536 int possibly_false(struct expression
*left
, int comparison
, struct expression
*right
)
538 struct range_list_sval
*rl_left
, *rl_right
;
539 struct data_range_sval
*tmp_left
, *tmp_right
;
541 if (!get_implied_range_list_sval(left
, &rl_left
))
543 if (!get_implied_range_list_sval(right
, &rl_right
))
546 FOR_EACH_PTR(rl_left
, tmp_left
) {
547 FOR_EACH_PTR(rl_right
, tmp_right
) {
548 if (false_comparison_range_sval(tmp_left
, comparison
, tmp_right
))
550 } END_FOR_EACH_PTR(tmp_right
);
551 } END_FOR_EACH_PTR(tmp_left
);
555 int possibly_true_range_lists_sval(struct range_list_sval
*left_ranges
, int comparison
, struct range_list_sval
*right_ranges
)
557 struct data_range_sval
*left_tmp
, *right_tmp
;
559 if (!left_ranges
|| !right_ranges
)
562 FOR_EACH_PTR(left_ranges
, left_tmp
) {
563 FOR_EACH_PTR(right_ranges
, right_tmp
) {
564 if (true_comparison_range_sval(left_tmp
, comparison
, right_tmp
))
566 } END_FOR_EACH_PTR(right_tmp
);
567 } END_FOR_EACH_PTR(left_tmp
);
571 int possibly_false_range_lists_sval(struct range_list_sval
*left_ranges
, int comparison
, struct range_list_sval
*right_ranges
)
573 struct data_range_sval
*left_tmp
, *right_tmp
;
575 if (!left_ranges
|| !right_ranges
)
578 FOR_EACH_PTR(left_ranges
, left_tmp
) {
579 FOR_EACH_PTR(right_ranges
, right_tmp
) {
580 if (false_comparison_range_sval(left_tmp
, comparison
, right_tmp
))
582 } END_FOR_EACH_PTR(right_tmp
);
583 } END_FOR_EACH_PTR(left_tmp
);
587 /* FIXME: the _rl here stands for right left so really it should be _lr */
588 int possibly_true_range_lists_rl_sval(int comparison
, struct range_list_sval
*a
, struct range_list_sval
*b
, int left
)
591 return possibly_true_range_lists_sval(a
, comparison
, b
);
593 return possibly_true_range_lists_sval(b
, comparison
, a
);
596 int possibly_false_range_lists_rl_sval(int comparison
, struct range_list_sval
*a
, struct range_list_sval
*b
, int left
)
599 return possibly_false_range_lists_sval(a
, comparison
, b
);
601 return possibly_false_range_lists_sval(b
, comparison
, a
);
604 void tack_on_sval(struct range_list_sval
**list
, struct data_range_sval
*drange
)
606 add_ptr_list(list
, drange
);
609 void push_range_list_sval(struct range_list_stack_sval
**rl_stack
, struct range_list_sval
*rl
)
611 add_ptr_list(rl_stack
, rl
);
614 struct range_list_sval
*pop_range_list_sval(struct range_list_stack_sval
**rl_stack
)
616 struct range_list_sval
*rl
;
618 rl
= last_ptr_list((struct ptr_list
*)*rl_stack
);
619 delete_ptr_list_last((struct ptr_list
**)rl_stack
);
623 struct range_list_sval
*top_range_list_sval(struct range_list_stack_sval
*rl_stack
)
625 struct range_list_sval
*rl
;
627 rl
= last_ptr_list((struct ptr_list
*)rl_stack
);
631 void filter_top_range_list_sval(struct range_list_stack_sval
**rl_stack
, sval_t sval
)
633 struct range_list_sval
*rl
;
635 rl
= pop_range_list_sval(rl_stack
);
636 rl
= remove_range_sval(rl
, sval
, sval
);
637 push_range_list_sval(rl_stack
, rl
);
640 struct range_list_sval
*cast_rl(struct range_list_sval
*rl
, struct symbol
*type
)
642 struct data_range_sval
*tmp
;
643 struct data_range_sval
*new;
644 struct range_list_sval
*ret
= NULL
;
648 return clone_range_list_sval(rl
);
650 sval
= sval_cast(rl_min_sval(rl
), type
);
651 if (sval_cmp(sval
, rl_min_sval(rl
)) != 0)
652 return alloc_range_list_sval(sval_type_min(type
), sval_type_max(type
));
653 sval
= sval_cast(rl_min_sval(rl
), type
);
654 if (sval_cmp(sval
, rl_min_sval(rl
)) != 0)
655 return alloc_range_list_sval(sval_type_min(type
), sval_type_max(type
));
657 FOR_EACH_PTR(rl
, tmp
) {
658 new = alloc_range_sval(sval_cast(tmp
->min
, type
), sval_cast(tmp
->max
, type
));
659 add_ptr_list(&ret
, new);
660 } END_FOR_EACH_PTR(tmp
);
665 void free_range_list_sval(struct range_list_sval
**rlist
)
667 __free_ptr_list((struct ptr_list
**)rlist
);
670 static void free_single_dinfo(struct data_info
*dinfo
)
672 if (dinfo
->type
== DATA_RANGE
)
673 free_range_list_sval(&dinfo
->value_ranges
);
676 static void free_dinfos(struct allocation_blob
*blob
)
678 unsigned int size
= sizeof(struct data_info
);
679 unsigned int offset
= 0;
681 while (offset
< blob
->offset
) {
682 free_single_dinfo((struct data_info
*)(blob
->data
+ offset
));
687 void free_data_info_allocs(void)
689 struct allocator_struct
*desc
= &data_info_allocator
;
690 struct allocation_blob
*blob
= desc
->blobs
;
693 desc
->allocations
= 0;
694 desc
->total_bytes
= 0;
695 desc
->useful_bytes
= 0;
696 desc
->freelist
= NULL
;
698 struct allocation_blob
*next
= blob
->next
;
700 blob_free(blob
, desc
->chunking
);
703 clear_data_range_alloc();