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 struct data_range whole_range
= {
25 static char *show_num(long long num
)
27 static char buff
[256];
29 if (num
== whole_range
.min
)
30 snprintf(buff
, 255, "min");
31 else if (num
== whole_range
.max
)
32 snprintf(buff
, 255, "max");
34 snprintf(buff
, 255, "(%lld)", num
);
36 snprintf(buff
, 255, "%lld", num
);
42 char *show_ranges(struct range_list
*list
)
44 struct data_range
*tmp
;
50 FOR_EACH_PTR(list
, tmp
) {
52 strncat(full
, ",", 254 - strlen(full
));
53 if (tmp
->min
== tmp
->max
) {
54 strncat(full
, show_num(tmp
->min
), 254 - strlen(full
));
57 strncat(full
, show_num(tmp
->min
), 254 - strlen(full
));
58 strncat(full
, "-", 254 - strlen(full
));
59 strncat(full
, show_num(tmp
->max
), 254 - strlen(full
));
60 } END_FOR_EACH_PTR(tmp
);
61 return alloc_sname(full
);
64 void get_value_ranges(char *value
, struct range_list
**rl
)
75 if (!strncmp(start
, "min", 3)) {
79 while (*c
&& *c
!= ',' && *c
!= '-')
81 val1
= strtoll(start
, &c
, 10);
86 add_range(rl
, val1
, val1
);
90 add_range(rl
, val1
, val1
);
95 c
++; /* skip the dash in eg. 4-5 */
99 if (!strncmp(start
, "max", 3)) {
104 while (*c
&& *c
!= ',' && *c
!= '-')
106 val2
= strtoll(start
, &c
, 10);
108 add_range(rl
, val1
, val2
);
113 c
++; /* skip the comma in eg: 4-5,7 */
118 static struct data_range range_zero
= {
123 static struct data_range range_one
= {
128 int is_whole_range_rl(struct range_list
*rl
)
130 struct data_range
*drange
;
132 if (ptr_list_empty(rl
))
134 drange
= first_ptr_list((struct ptr_list
*)rl
);
135 if (drange
->min
== whole_range
.min
&& drange
->max
== whole_range
.max
)
140 long long rl_min(struct range_list
*rl
)
142 struct data_range
*drange
;
144 if (ptr_list_empty(rl
))
145 return whole_range
.min
;
146 drange
= first_ptr_list((struct ptr_list
*)rl
);
150 long long rl_max(struct range_list
*rl
)
152 struct data_range
*drange
;
154 if (ptr_list_empty(rl
))
155 return whole_range
.max
;
156 drange
= last_ptr_list((struct ptr_list
*)rl
);
160 static struct data_range
*alloc_range_helper(long long min
, long long max
, int perm
)
162 struct data_range
*ret
;
165 sm_msg("Error invalid range %lld to %lld", min
, max
);
166 min
= whole_range
.min
;
167 max
= whole_range
.max
;
169 if (min
== whole_range
.min
&& max
== whole_range
.max
)
171 if (min
== 0 && max
== 0)
173 if (min
== 1 && max
== 1)
177 ret
= __alloc_perm_data_range(0);
179 ret
= __alloc_data_range(0);
185 struct data_range
*alloc_range(long long min
, long long max
)
187 return alloc_range_helper(min
, max
, 0);
190 struct data_range
*alloc_range_perm(long long min
, long long max
)
192 return alloc_range_helper(min
, max
, 1);
195 struct range_list
*alloc_range_list(long long min
, long long max
)
197 struct range_list
*rl
= NULL
;
199 add_range(&rl
, min
, max
);
203 void add_range(struct range_list
**list
, long long min
, long long max
)
205 struct data_range
*tmp
= NULL
;
206 struct data_range
*new = NULL
;
210 * FIXME: This has a problem merging a range_list like: min-0,3-max
211 * with a range like 1-2. You end up with min-2,3-max instead of
214 FOR_EACH_PTR(*list
, tmp
) {
216 /* Sometimes we overlap with more than one range
217 so we have to delete or modify the next range. */
218 if (max
+ 1 == tmp
->min
) {
219 /* join 2 ranges here */
221 DELETE_CURRENT_PTR(tmp
);
225 /* Doesn't overlap with the next one. */
228 /* Partially overlaps with the next one. */
229 if (max
< tmp
->max
) {
233 /* Completely overlaps with the next one. */
234 if (max
>= tmp
->max
) {
235 DELETE_CURRENT_PTR(tmp
);
236 /* there could be more ranges to delete */
240 if (max
!= whole_range
.max
&& max
+ 1 == tmp
->min
) {
241 /* join 2 ranges into a big range */
242 new = alloc_range(min
, tmp
->max
);
243 REPLACE_CURRENT_PTR(tmp
, new);
246 if (max
< tmp
->min
) { /* new range entirely below */
247 new = alloc_range(min
, max
);
248 INSERT_CURRENT(new, tmp
);
251 if (min
< tmp
->min
) { /* new range partially below */
256 new = alloc_range(min
, max
);
257 REPLACE_CURRENT_PTR(tmp
, new);
262 if (max
<= tmp
->max
) /* new range already included */
264 if (min
<= tmp
->max
) { /* new range partially above */
266 new = alloc_range(min
, max
);
267 REPLACE_CURRENT_PTR(tmp
, new);
271 if (min
!= whole_range
.min
&& min
- 1 == tmp
->max
) {
272 /* join 2 ranges into a big range */
273 new = alloc_range(tmp
->min
, max
);
274 REPLACE_CURRENT_PTR(tmp
, new);
278 /* the new range is entirely above the existing ranges */
279 } END_FOR_EACH_PTR(tmp
);
282 new = alloc_range(min
, max
);
283 add_ptr_list(list
, new);
286 struct range_list
*clone_range_list(struct range_list
*list
)
288 struct data_range
*tmp
;
289 struct range_list
*ret
= NULL
;
291 FOR_EACH_PTR(list
, tmp
) {
292 add_ptr_list(&ret
, tmp
);
293 } END_FOR_EACH_PTR(tmp
);
297 struct range_list
*range_list_union(struct range_list
*one
, struct range_list
*two
)
299 struct data_range
*tmp
;
300 struct range_list
*ret
= NULL
;
302 FOR_EACH_PTR(one
, tmp
) {
303 add_range(&ret
, tmp
->min
, tmp
->max
);
304 } END_FOR_EACH_PTR(tmp
);
305 FOR_EACH_PTR(two
, tmp
) {
306 add_range(&ret
, tmp
->min
, tmp
->max
);
307 } END_FOR_EACH_PTR(tmp
);
311 struct range_list
*remove_range(struct range_list
*list
, long long min
, long long max
)
313 struct data_range
*tmp
;
314 struct range_list
*ret
= NULL
;
316 FOR_EACH_PTR(list
, tmp
) {
317 if (tmp
->max
< min
) {
318 add_range(&ret
, tmp
->min
, tmp
->max
);
321 if (tmp
->min
> max
) {
322 add_range(&ret
, tmp
->min
, tmp
->max
);
325 if (tmp
->min
>= min
&& tmp
->max
<= max
)
327 if (tmp
->min
>= min
) {
328 add_range(&ret
, max
+ 1, tmp
->max
);
329 } else if (tmp
->max
<= max
) {
330 add_range(&ret
, tmp
->min
, min
- 1);
332 add_range(&ret
, tmp
->min
, min
- 1);
333 add_range(&ret
, max
+ 1, tmp
->max
);
335 } END_FOR_EACH_PTR(tmp
);
340 * if it can be only one and only value return 1, else return 0
342 int estate_get_single_value(struct smatch_state
*state
, long long *val
)
344 struct data_info
*dinfo
;
345 struct data_range
*tmp
;
348 dinfo
= get_dinfo(state
);
349 if (!dinfo
|| dinfo
->type
!= DATA_RANGE
)
352 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
354 if (tmp
->min
!= tmp
->max
)
360 } END_FOR_EACH_PTR(tmp
);
364 int true_comparison_range(struct data_range
*left
, int comparison
, struct data_range
*right
)
366 switch (comparison
) {
368 case SPECIAL_UNSIGNED_LT
:
369 if (left
->min
< right
->max
)
372 case SPECIAL_UNSIGNED_LTE
:
374 if (left
->min
<= right
->max
)
378 if (left
->max
< right
->min
)
380 if (left
->min
> right
->max
)
383 case SPECIAL_UNSIGNED_GTE
:
385 if (left
->max
>= right
->min
)
389 case SPECIAL_UNSIGNED_GT
:
390 if (left
->max
> right
->min
)
393 case SPECIAL_NOTEQUAL
:
394 if (left
->min
!= left
->max
)
396 if (right
->min
!= right
->max
)
398 if (left
->min
!= right
->min
)
402 sm_msg("unhandled comparison %d\n", comparison
);
408 int true_comparison_range_lr(int comparison
, struct data_range
*var
, struct data_range
*val
, int left
)
411 return true_comparison_range(var
, comparison
, val
);
413 return true_comparison_range(val
, comparison
, var
);
416 static int false_comparison_range(struct data_range
*left
, int comparison
, struct data_range
*right
)
418 switch (comparison
) {
420 case SPECIAL_UNSIGNED_LT
:
421 if (left
->max
>= right
->min
)
424 case SPECIAL_UNSIGNED_LTE
:
426 if (left
->max
> right
->min
)
430 if (left
->min
!= left
->max
)
432 if (right
->min
!= right
->max
)
434 if (left
->min
!= right
->min
)
437 case SPECIAL_UNSIGNED_GTE
:
439 if (left
->min
< right
->max
)
443 case SPECIAL_UNSIGNED_GT
:
444 if (left
->min
<= right
->max
)
447 case SPECIAL_NOTEQUAL
:
448 if (left
->max
< right
->min
)
450 if (left
->min
> right
->max
)
454 sm_msg("unhandled comparison %d\n", comparison
);
460 int false_comparison_range_lr(int comparison
, struct data_range
*var
, struct data_range
*val
, int left
)
463 return false_comparison_range(var
, comparison
, val
);
465 return false_comparison_range(val
, comparison
, var
);
468 int possibly_true(struct expression
*left
, int comparison
, struct expression
*right
)
470 struct range_list
*rl_left
, *rl_right
;
471 struct data_range
*tmp_left
, *tmp_right
;
473 if (!get_implied_range_list(left
, &rl_left
))
475 if (!get_implied_range_list(right
, &rl_right
))
478 FOR_EACH_PTR(rl_left
, tmp_left
) {
479 FOR_EACH_PTR(rl_right
, tmp_right
) {
480 if (true_comparison_range(tmp_left
, comparison
, tmp_right
))
482 } END_FOR_EACH_PTR(tmp_right
);
483 } END_FOR_EACH_PTR(tmp_left
);
487 int possibly_false(struct expression
*left
, int comparison
, struct expression
*right
)
489 struct range_list
*rl_left
, *rl_right
;
490 struct data_range
*tmp_left
, *tmp_right
;
492 if (!get_implied_range_list(left
, &rl_left
))
494 if (!get_implied_range_list(right
, &rl_right
))
497 FOR_EACH_PTR(rl_left
, tmp_left
) {
498 FOR_EACH_PTR(rl_right
, tmp_right
) {
499 if (false_comparison_range(tmp_left
, comparison
, tmp_right
))
501 } END_FOR_EACH_PTR(tmp_right
);
502 } END_FOR_EACH_PTR(tmp_left
);
506 int possibly_true_range_lists(struct range_list
*left_ranges
, int comparison
, struct range_list
*right_ranges
)
508 struct data_range
*left_tmp
, *right_tmp
;
510 if (!left_ranges
|| !right_ranges
)
513 FOR_EACH_PTR(left_ranges
, left_tmp
) {
514 FOR_EACH_PTR(right_ranges
, right_tmp
) {
515 if (true_comparison_range(left_tmp
, comparison
, right_tmp
))
517 } END_FOR_EACH_PTR(right_tmp
);
518 } END_FOR_EACH_PTR(left_tmp
);
522 int possibly_true_range_list_lr(int comparison
, struct smatch_state
*state
, struct range_list
*values
, int left
)
524 struct data_range
*tmp
, *tmp2
;
526 FOR_EACH_PTR(estate_ranges(state
), tmp
) {
527 FOR_EACH_PTR(values
, tmp2
) {
528 if (true_comparison_range_lr(comparison
, tmp
, tmp2
, left
))
530 } END_FOR_EACH_PTR(tmp2
);
531 } END_FOR_EACH_PTR(tmp
);
535 int possibly_false_range_lists(struct range_list
*left_ranges
, int comparison
, struct range_list
*right_ranges
)
537 struct data_range
*left_tmp
, *right_tmp
;
539 if (!left_ranges
|| !right_ranges
)
542 FOR_EACH_PTR(left_ranges
, left_tmp
) {
543 FOR_EACH_PTR(right_ranges
, right_tmp
) {
544 if (false_comparison_range(left_tmp
, comparison
, right_tmp
))
546 } END_FOR_EACH_PTR(right_tmp
);
547 } END_FOR_EACH_PTR(left_tmp
);
551 int possibly_false_range_list_lr(int comparison
, struct smatch_state
*state
, struct range_list
*values
, int left
)
553 struct data_range
*tmp
, *tmp2
;
555 FOR_EACH_PTR(estate_ranges(state
), tmp
) {
556 FOR_EACH_PTR(values
, tmp2
) {
557 if (false_comparison_range_lr(comparison
, tmp
, tmp2
, left
))
559 } END_FOR_EACH_PTR(tmp2
);
560 } END_FOR_EACH_PTR(tmp
);
564 void tack_on(struct range_list
**list
, struct data_range
*drange
)
566 add_ptr_list(list
, drange
);
569 int in_list_exact(struct range_list
*list
, struct data_range
*drange
)
571 struct data_range
*tmp
;
573 FOR_EACH_PTR(list
, tmp
) {
574 if (tmp
->min
== drange
->min
&& tmp
->max
== drange
->max
)
576 } END_FOR_EACH_PTR(tmp
);
581 void push_range_list(struct range_list_stack
**rl_stack
, struct range_list
*rl
)
583 add_ptr_list(rl_stack
, rl
);
586 struct range_list
*pop_range_list(struct range_list_stack
**rl_stack
)
588 struct range_list
*rl
;
590 rl
= last_ptr_list((struct ptr_list
*)*rl_stack
);
591 delete_ptr_list_last((struct ptr_list
**)rl_stack
);
595 struct range_list
*top_range_list(struct range_list_stack
*rl_stack
)
597 struct range_list
*rl
;
599 rl
= last_ptr_list((struct ptr_list
*)rl_stack
);
603 void filter_top_range_list(struct range_list_stack
**rl_stack
, long long num
)
605 struct range_list
*rl
;
607 rl
= pop_range_list(rl_stack
);
608 rl
= remove_range(rl
, num
, num
);
609 push_range_list(rl_stack
, rl
);
612 void free_range_list(struct range_list
**rlist
)
614 __free_ptr_list((struct ptr_list
**)rlist
);
617 static void free_single_dinfo(struct data_info
*dinfo
)
619 if (dinfo
->type
== DATA_RANGE
)
620 free_range_list(&dinfo
->value_ranges
);
623 static void free_dinfos(struct allocation_blob
*blob
)
625 unsigned int size
= sizeof(struct data_info
);
626 unsigned int offset
= 0;
628 while (offset
< blob
->offset
) {
629 free_single_dinfo((struct data_info
*)(blob
->data
+ offset
));
634 void free_data_info_allocs(void)
636 struct allocator_struct
*desc
= &data_info_allocator
;
637 struct allocation_blob
*blob
= desc
->blobs
;
640 desc
->allocations
= 0;
641 desc
->total_bytes
= 0;
642 desc
->useful_bytes
= 0;
643 desc
->freelist
= NULL
;
645 struct allocation_blob
*next
= blob
->next
;
647 blob_free(blob
, desc
->chunking
);
650 clear_data_range_alloc();