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 static char *show_num(long long num
)
22 static char buff
[256];
24 if (num
== whole_range
.min
) {
25 snprintf(buff
, 255, "min");
26 } else if (num
== whole_range
.max
) {
27 snprintf(buff
, 255, "max");
29 snprintf(buff
, 255, "(%lld)", num
);
31 snprintf(buff
, 255, "%lld", num
);
37 char *show_ranges(struct range_list
*list
)
39 struct data_range
*tmp
;
45 FOR_EACH_PTR(list
, tmp
) {
47 strncat(full
, ",", 254 - strlen(full
));
48 if (tmp
->min
== tmp
->max
) {
49 strncat(full
, show_num(tmp
->min
), 254 - strlen(full
));
52 strncat(full
, show_num(tmp
->min
), 254 - strlen(full
));
53 strncat(full
, "-", 254 - strlen(full
));
54 strncat(full
, show_num(tmp
->max
), 254 - strlen(full
));
55 } END_FOR_EACH_PTR(tmp
);
56 return alloc_sname(full
);
59 static struct data_range range_zero
= {
64 static struct data_range range_one
= {
69 struct data_range
*alloc_range(long long min
, long long max
)
71 struct data_range
*ret
;
74 printf("Error invalid range %lld to %lld\n", min
, max
);
76 if (min
== whole_range
.min
&& max
== whole_range
.max
)
78 if (min
== 0 && max
== 0)
80 if (min
== 1 && max
== 1)
82 ret
= __alloc_data_range(0);
88 struct data_range
*alloc_range_perm(long long min
, long long max
)
90 struct data_range
*ret
;
93 printf("Error invalid range %lld to %lld\n", min
, max
);
95 if (min
== whole_range
.min
&& max
== whole_range
.max
)
97 if (min
== 0 && max
== 0)
99 if (min
== 1 && max
== 1)
101 ret
= __alloc_perm_data_range(0);
107 struct data_info
*alloc_dinfo_range(long long min
, long long max
)
109 struct data_info
*ret
;
111 ret
= __alloc_data_info(0);
112 ret
->type
= DATA_RANGE
;
113 ret
->value_ranges
= NULL
;
114 add_range(&ret
->value_ranges
, min
, max
);
118 struct data_info
*alloc_dinfo_range_list(struct range_list
*rl
)
120 struct data_info
*ret
;
122 ret
= __alloc_data_info(0);
123 ret
->type
= DATA_RANGE
;
124 ret
->value_ranges
= rl
;
128 void add_range(struct range_list
**list
, long long min
, long long max
)
130 struct data_range
*tmp
= NULL
;
131 struct data_range
*new = NULL
;
134 FOR_EACH_PTR(*list
, tmp
) {
136 /* Sometimes we overlap with more than one range
137 so we have to delete or modify the next range. */
138 if (max
+ 1 == tmp
->min
) {
139 /* join 2 ranges here */
141 DELETE_CURRENT_PTR(tmp
);
145 /* Doesn't overlap with the next one. */
148 /* Partially overlaps with the next one. */
149 if (max
< tmp
->max
) {
153 /* Completely overlaps with the next one. */
154 if (max
>= tmp
->max
) {
155 DELETE_CURRENT_PTR(tmp
);
156 /* there could be more ranges to delete */
160 if (max
!= whole_range
.max
&& max
+ 1 == tmp
->min
) {
161 /* join 2 ranges into a big range */
162 new = alloc_range(min
, tmp
->max
);
163 REPLACE_CURRENT_PTR(tmp
, new);
166 if (max
< tmp
->min
) { /* new range entirely below */
167 new = alloc_range(min
, max
);
168 INSERT_CURRENT(new, tmp
);
171 if (min
< tmp
->min
) { /* new range partially below */
176 new = alloc_range(min
, max
);
177 REPLACE_CURRENT_PTR(tmp
, new);
182 if (max
<= tmp
->max
) /* new range already included */
184 if (min
<= tmp
->max
) { /* new range partially above */
186 new = alloc_range(min
, max
);
187 REPLACE_CURRENT_PTR(tmp
, new);
191 if (min
!= whole_range
.min
&& min
- 1 == tmp
->max
) {
192 /* join 2 ranges into a big range */
193 new = alloc_range(tmp
->min
, max
);
194 REPLACE_CURRENT_PTR(tmp
, new);
198 /* the new range is entirely above the existing ranges */
199 } END_FOR_EACH_PTR(tmp
);
202 new = alloc_range(min
, max
);
203 add_ptr_list(list
, new);
206 struct range_list
*clone_range_list(struct range_list
*list
)
208 struct data_range
*tmp
;
209 struct range_list
*ret
= NULL
;
211 FOR_EACH_PTR(list
, tmp
) {
212 add_ptr_list(&ret
, tmp
);
213 } END_FOR_EACH_PTR(tmp
);
217 struct range_list
*range_list_union(struct range_list
*one
, struct range_list
*two
)
219 struct data_range
*tmp
;
220 struct range_list
*ret
= NULL
;
222 if (!one
|| !two
) /*having nothing in a list means everything is in */
225 FOR_EACH_PTR(one
, tmp
) {
226 add_range(&ret
, tmp
->min
, tmp
->max
);
227 } END_FOR_EACH_PTR(tmp
);
228 FOR_EACH_PTR(two
, tmp
) {
229 add_range(&ret
, tmp
->min
, tmp
->max
);
230 } END_FOR_EACH_PTR(tmp
);
234 struct range_list
*remove_range(struct range_list
*list
, long long min
, long long max
)
236 struct data_range
*tmp
;
237 struct range_list
*ret
= NULL
;
239 FOR_EACH_PTR(list
, tmp
) {
240 if (tmp
->max
< min
) {
241 add_range(&ret
, tmp
->min
, tmp
->max
);
244 if (tmp
->min
> max
) {
245 add_range(&ret
, tmp
->min
, tmp
->max
);
248 if (tmp
->min
>= min
&& tmp
->max
<= max
)
250 if (tmp
->min
>= min
) {
251 add_range(&ret
, max
+ 1, tmp
->max
);
252 } else if (tmp
->max
<= max
) {
253 add_range(&ret
, tmp
->min
, min
- 1);
255 add_range(&ret
, tmp
->min
, min
- 1);
256 add_range(&ret
, max
+ 1, tmp
->max
);
258 } END_FOR_EACH_PTR(tmp
);
262 long long get_dinfo_min(struct data_info
*dinfo
)
264 struct data_range
*drange
;
266 if (!dinfo
|| !dinfo
->value_ranges
)
267 return whole_range
.min
;
268 drange
= first_ptr_list((struct ptr_list
*)dinfo
->value_ranges
);
272 long long get_dinfo_max(struct data_info
*dinfo
)
274 struct data_range
*drange
;
276 if (!dinfo
|| !dinfo
->value_ranges
)
277 return whole_range
.max
;
278 drange
= first_ptr_list((struct ptr_list
*)dinfo
->value_ranges
);
283 * if it can be only one and only value return 1, else return 0
285 int get_single_value_from_range(struct data_info
*dinfo
, long long *val
)
287 struct data_range
*tmp
;
290 if (dinfo
->type
!= DATA_RANGE
)
293 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
295 if (tmp
->min
!= tmp
->max
)
301 } END_FOR_EACH_PTR(tmp
);
305 int true_comparison_range(struct data_range
*left
, int comparison
, struct data_range
*right
)
309 case SPECIAL_UNSIGNED_LT
:
310 if (left
->min
< right
->max
)
313 case SPECIAL_UNSIGNED_LTE
:
315 if (left
->min
<= right
->max
)
319 if (left
->max
< right
->min
)
321 if (left
->min
> right
->max
)
324 case SPECIAL_UNSIGNED_GTE
:
326 if (left
->max
>= right
->min
)
330 case SPECIAL_UNSIGNED_GT
:
331 if (left
->max
> right
->min
)
334 case SPECIAL_NOTEQUAL
:
335 if (left
->min
!= left
->max
)
337 if (right
->min
!= right
->max
)
339 if (left
->min
!= right
->min
)
343 sm_msg("unhandled comparison %d\n", comparison
);
349 int true_comparison_range_lr(int comparison
, struct data_range
*var
, struct data_range
*val
, int left
)
352 return true_comparison_range(var
, comparison
, val
);
354 return true_comparison_range(val
, comparison
, var
);
357 static int false_comparison_range(struct data_range
*left
, int comparison
, struct data_range
*right
)
361 case SPECIAL_UNSIGNED_LT
:
362 if (left
->max
>= right
->min
)
365 case SPECIAL_UNSIGNED_LTE
:
367 if (left
->max
> right
->min
)
371 if (left
->min
!= left
->max
)
373 if (right
->min
!= right
->max
)
375 if (left
->min
!= right
->min
)
378 case SPECIAL_UNSIGNED_GTE
:
380 if (left
->min
< right
->max
)
384 case SPECIAL_UNSIGNED_GT
:
385 if (left
->min
<= right
->max
)
388 case SPECIAL_NOTEQUAL
:
389 if (left
->max
< right
->min
)
391 if (left
->min
> right
->max
)
395 sm_msg("unhandled comparison %d\n", comparison
);
401 int false_comparison_range_lr(int comparison
, struct data_range
*var
, struct data_range
*val
, int left
)
404 return false_comparison_range(var
, comparison
, val
);
406 return false_comparison_range(val
, comparison
, var
);
409 int possibly_true(int comparison
, struct data_info
*dinfo
, int num
, int left
)
411 struct data_range
*tmp
;
412 struct data_range drange
;
417 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
418 if (true_comparison_range_lr(comparison
, tmp
, &drange
, left
))
420 } END_FOR_EACH_PTR(tmp
);
424 int possibly_false(int comparison
, struct data_info
*dinfo
, int num
, int left
)
426 struct data_range
*tmp
;
427 struct data_range drange
;
432 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
433 if (false_comparison_range_lr(comparison
, tmp
, &drange
, left
))
435 } END_FOR_EACH_PTR(tmp
);
439 int possibly_true_range_list(int comparison
, struct data_info
*dinfo
, struct range_list
*values
, int left
)
441 struct data_range
*tmp
, *tmp2
;
443 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
444 FOR_EACH_PTR(values
, tmp2
) {
445 if (true_comparison_range_lr(comparison
, tmp
, tmp2
, left
))
447 } END_FOR_EACH_PTR(tmp2
);
448 } END_FOR_EACH_PTR(tmp
);
452 int possibly_false_range_list(int comparison
, struct data_info
*dinfo
, struct range_list
*values
, int left
)
454 struct data_range
*tmp
, *tmp2
;
456 FOR_EACH_PTR(dinfo
->value_ranges
, tmp
) {
457 FOR_EACH_PTR(values
, tmp2
) {
458 if (false_comparison_range_lr(comparison
, tmp
, tmp2
, left
))
460 } END_FOR_EACH_PTR(tmp2
);
461 } END_FOR_EACH_PTR(tmp
);
465 void tack_on(struct range_list
**list
, struct data_range
*drange
)
467 add_ptr_list(list
, drange
);
470 int in_list_exact(struct range_list
*list
, struct data_range
*drange
)
472 struct data_range
*tmp
;
474 FOR_EACH_PTR(list
, tmp
) {
475 if (tmp
->min
== drange
->min
&& tmp
->max
== drange
->max
)
477 } END_FOR_EACH_PTR(tmp
);
482 void push_range_list(struct range_list_stack
**rl_stack
, struct range_list
*rl
)
484 add_ptr_list(rl_stack
, rl
);
487 struct range_list
*pop_range_list(struct range_list_stack
**rl_stack
)
489 struct range_list
*rl
;
491 rl
= last_ptr_list((struct ptr_list
*)*rl_stack
);
492 delete_ptr_list_last((struct ptr_list
**)rl_stack
);
496 struct range_list
*top_range_list(struct range_list_stack
*rl_stack
)
498 struct range_list
*rl
;
500 rl
= last_ptr_list((struct ptr_list
*)rl_stack
);
504 void filter_top_range_list(struct range_list_stack
**rl_stack
, long long num
)
506 struct range_list
*rl
;
508 rl
= pop_range_list(rl_stack
);
509 rl
= remove_range(rl
, num
, num
);
510 push_range_list(rl_stack
, rl
);
513 static void free_single_dinfo(struct data_info
*dinfo
)
515 if (dinfo
->type
== DATA_RANGE
)
516 __free_ptr_list((struct ptr_list
**)&dinfo
->value_ranges
);
519 static void free_dinfos(struct allocation_blob
*blob
)
521 unsigned int size
= sizeof(struct data_info
);
522 unsigned int offset
= 0;
524 while (offset
< blob
->offset
) {
525 free_single_dinfo((struct data_info
*)(blob
->data
+ offset
));
530 void free_data_info_allocs(void)
532 struct allocator_struct
*desc
= &data_info_allocator
;
533 struct allocation_blob
*blob
= desc
->blobs
;
536 desc
->allocations
= 0;
537 desc
->total_bytes
= 0;
538 desc
->useful_bytes
= 0;
539 desc
->freelist
= NULL
;
541 struct allocation_blob
*next
= blob
->next
;
543 blob_free(blob
, desc
->chunking
);
546 clear_data_range_alloc();