sval: move cast_rl() into parse_value_ranges_type()
[smatch.git] / smatch_ranges.c
blob7c66f5a4004c4f01e0c615a0f97bad5b7237225d
1 /*
2 * sparse/smatch_ranges.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "parse.h"
11 #include "smatch.h"
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;
23 char full[256];
24 int i = 0;
26 full[0] = '\0';
27 full[255] = '\0';
28 FOR_EACH_PTR(list, tmp) {
29 if (i++)
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));
33 continue;
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)
44 long long val1, val2;
45 sval_t tmp;
46 char *start;
47 char *c;
49 *rl = NULL;
51 c = value;
52 while (*c) {
53 if (*c == '(')
54 c++;
55 start = c;
57 if (!strncmp(start, "max", 3)) {
58 tmp = sval_type_max(type);
59 val1 = tmp.value;
60 c += 3;
61 } else if (!strncmp(start, "u64max", 6)) {
62 val1 = LLONG_MAX; // FIXME
63 c += 6;
64 } else if (!strncmp(start, "s64max", 6)) {
65 val1 = LLONG_MAX;
66 c += 6;
67 } else if (!strncmp(start, "u32max", 6)) {
68 val1 = UINT_MAX;
69 c += 6;
70 } else if (!strncmp(start, "s32max", 6)) {
71 val1 = INT_MAX;
72 c += 6;
73 } else if (!strncmp(start, "u16max", 6)) {
74 val1 = USHRT_MAX;
75 c += 6;
76 } else if (!strncmp(start, "s16max", 6)) {
77 val1 = SHRT_MAX;
78 c += 6;
79 } else if (!strncmp(start, "min", 3)) {
80 tmp = sval_type_min(type);
81 val1 = tmp.value;
82 c += 3;
83 } else if (!strncmp(start, "s64min", 6)) {
84 val1 = LLONG_MIN;
85 c += 6;
86 } else if (!strncmp(start, "s32min", 6)) {
87 val1 = INT_MIN;
88 c += 6;
89 } else if (!strncmp(start, "s16min", 6)) {
90 val1 = SHRT_MIN;
91 c += 6;
92 } else {
93 while (*c && *c != ',' && *c != '-')
94 c++;
95 val1 = strtoll(start, &c, 10);
97 if (*c == ')')
98 c++;
99 if (!*c) {
100 add_range(rl, sval_type_val(type, val1), sval_type_val(type, val1));
101 break;
103 if (*c == ',') {
104 add_range(rl, sval_type_val(type, val1), sval_type_val(type, val1));
105 c++;
106 start = c;
107 continue;
109 c++; /* skip the dash in eg. 4-5 */
110 if (*c == '(')
111 c++;
112 start = c;
113 if (!strncmp(start, "max", 3)) {
114 tmp = sval_type_max(type);
115 val2 = tmp.value;
116 c += 3;
117 } else {
119 while (*c && *c != ',' && *c != '-')
120 c++;
121 val2 = strtoll(start, &c, 10);
123 add_range(rl, sval_type_val(type, val1), sval_type_val(type, val2));
124 if (!*c)
125 break;
126 if (*c == ')')
127 c++;
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))
144 return 1;
145 drange = first_ptr_list((struct ptr_list *)rl);
146 if (sval_is_min(drange->min) && sval_is_max(drange->max))
147 return 1;
148 return 0;
151 sval_t rl_min(struct range_list *rl)
153 struct data_range *drange;
154 sval_t ret;
156 ret.type = &llong_ctype;
157 ret.value = LLONG_MIN;
158 if (ptr_list_empty(rl))
159 return ret;
160 drange = first_ptr_list((struct ptr_list *)rl);
161 return drange->min;
164 sval_t rl_max(struct range_list *rl)
166 struct data_range *drange;
167 sval_t ret;
169 ret.type = &llong_ctype;
170 ret.value = LLONG_MAX;
171 if (ptr_list_empty(rl))
172 return ret;
173 drange = last_ptr_list((struct ptr_list *)rl);
174 return drange->max;
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;
187 if (perm)
188 ret = __alloc_perm_data_range(0);
189 else
190 ret = __alloc_data_range(0);
191 ret->min = min;
192 ret->max = max;
193 return ret;
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);
211 return rl;
214 struct range_list *whole_range_list(struct symbol *type)
216 if (!type)
217 type = &llong_ctype;
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;
226 int check_next = 0;
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
231 * just min-max.
233 FOR_EACH_PTR(*list, tmp) {
234 if (check_next) {
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 */
239 new->max = tmp->max;
240 DELETE_CURRENT_PTR(tmp);
241 return;
244 /* Doesn't overlap with the next one. */
245 if (sval_cmp(max, tmp->min) < 0)
246 return;
247 /* Partially overlaps with the next one. */
248 if (sval_cmp(max, tmp->max) < 0) {
249 tmp->min.value = max.value + 1;
250 return;
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 */
256 continue;
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);
263 return;
265 if (sval_cmp(max, tmp->min) < 0) { /* new range entirely below */
266 new = alloc_range(min, max);
267 INSERT_CURRENT(new, tmp);
268 return;
270 if (sval_cmp(min, tmp->min) < 0) { /* new range partially below */
271 if (sval_cmp(max, tmp->max) < 0)
272 max = tmp->max;
273 else
274 check_next = 1;
275 new = alloc_range(min, max);
276 REPLACE_CURRENT_PTR(tmp, new);
277 if (!check_next)
278 return;
279 continue;
281 if (sval_cmp(max, tmp->max) <= 0) /* new range already included */
282 return;
283 if (sval_cmp(min, tmp->max) <= 0) { /* new range partially above */
284 min = tmp->min;
285 new = alloc_range(min, max);
286 REPLACE_CURRENT_PTR(tmp, new);
287 check_next = 1;
288 continue;
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);
294 check_next = 1;
295 continue;
297 /* the new range is entirely above the existing ranges */
298 } END_FOR_EACH_PTR(tmp);
299 if (check_next)
300 return;
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);
313 return ret;
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);
326 return ret;
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);
340 return ret;
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);
351 continue;
353 if (sval_cmp(tmp->min, max) > 0) {
354 add_range(&ret, tmp->min, tmp->max);
355 continue;
357 if (sval_cmp(tmp->min, min) >= 0 && sval_cmp(tmp->max, max) <= 0)
358 continue;
359 if (sval_cmp(tmp->min, min) >= 0) {
360 max.value++;
361 add_range(&ret, max, tmp->max);
362 } else if (sval_cmp(tmp->max, max) <= 0) {
363 min.value--;
364 add_range(&ret, tmp->min, min);
365 } else {
366 min.value--;
367 max.value++;
368 add_range(&ret, tmp->min, min);
369 add_range(&ret, max, tmp->max);
371 } END_FOR_EACH_PTR(tmp);
372 return ret;
375 int ranges_equiv(struct data_range *one, struct data_range *two)
377 if (!one && !two)
378 return 1;
379 if (!one || !two)
380 return 0;
381 if (sval_cmp(one->min, two->min) != 0)
382 return 0;
383 if (sval_cmp(one->max, two->max) != 0)
384 return 0;
385 return 1;
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);
395 for (;;) {
396 if (!one_range && !two_range)
397 return 1;
398 if (!ranges_equiv(one_range, two_range))
399 return 0;
400 NEXT_PTR_LIST(one_range);
401 NEXT_PTR_LIST(two_range);
403 FINISH_PTR_LIST(two_range);
404 FINISH_PTR_LIST(one_range);
406 return 1;
409 int true_comparison_range(struct data_range *left, int comparison, struct data_range *right)
411 switch (comparison) {
412 case '<':
413 case SPECIAL_UNSIGNED_LT:
414 if (sval_cmp(left->min, right->max) < 0)
415 return 1;
416 return 0;
417 case SPECIAL_UNSIGNED_LTE:
418 case SPECIAL_LTE:
419 if (sval_cmp(left->min, right->max) <= 0)
420 return 1;
421 return 0;
422 case SPECIAL_EQUAL:
423 if (sval_cmp(left->max, right->min) < 0)
424 return 0;
425 if (sval_cmp(left->min, right->max) > 0)
426 return 0;
427 return 1;
428 case SPECIAL_UNSIGNED_GTE:
429 case SPECIAL_GTE:
430 if (sval_cmp(left->max, right->min) >= 0)
431 return 1;
432 return 0;
433 case '>':
434 case SPECIAL_UNSIGNED_GT:
435 if (sval_cmp(left->max, right->min) > 0)
436 return 1;
437 return 0;
438 case SPECIAL_NOTEQUAL:
439 if (sval_cmp(left->min, left->max) != 0)
440 return 1;
441 if (sval_cmp(right->min, right->max) != 0)
442 return 1;
443 if (sval_cmp(left->min, right->min) != 0)
444 return 1;
445 return 0;
446 default:
447 sm_msg("unhandled comparison %d\n", comparison);
448 return 0;
450 return 0;
453 int true_comparison_range_lr(int comparison, struct data_range *var, struct data_range *val, int left)
455 if (left)
456 return true_comparison_range(var, comparison, val);
457 else
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) {
464 case '<':
465 case SPECIAL_UNSIGNED_LT:
466 if (sval_cmp(left->max, right->min) >= 0)
467 return 1;
468 return 0;
469 case SPECIAL_UNSIGNED_LTE:
470 case SPECIAL_LTE:
471 if (sval_cmp(left->max, right->min) > 0)
472 return 1;
473 return 0;
474 case SPECIAL_EQUAL:
475 if (sval_cmp(left->min, left->max) != 0)
476 return 1;
477 if (sval_cmp(right->min, right->max) != 0)
478 return 1;
479 if (sval_cmp(left->min, right->min) != 0)
480 return 1;
481 return 0;
482 case SPECIAL_UNSIGNED_GTE:
483 case SPECIAL_GTE:
484 if (sval_cmp(left->min, right->max) < 0)
485 return 1;
486 return 0;
487 case '>':
488 case SPECIAL_UNSIGNED_GT:
489 if (sval_cmp(left->min, right->max) <= 0)
490 return 1;
491 return 0;
492 case SPECIAL_NOTEQUAL:
493 if (sval_cmp(left->max, right->min) < 0)
494 return 0;
495 if (sval_cmp(left->min, right->max) > 0)
496 return 0;
497 return 1;
498 default:
499 sm_msg("unhandled comparison %d\n", comparison);
500 return 0;
502 return 0;
505 int false_comparison_range_lr(int comparison, struct data_range *var, struct data_range *val, int left)
507 if (left)
508 return false_comparison_range_sval(var, comparison, val);
509 else
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))
519 return 1;
520 if (!get_implied_range_list(right, &rl_right))
521 return 1;
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))
526 return 1;
527 } END_FOR_EACH_PTR(tmp_right);
528 } END_FOR_EACH_PTR(tmp_left);
529 return 0;
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))
538 return 1;
539 if (!get_implied_range_list(right, &rl_right))
540 return 1;
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))
545 return 1;
546 } END_FOR_EACH_PTR(tmp_right);
547 } END_FOR_EACH_PTR(tmp_left);
548 return 0;
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)
556 return 1;
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))
561 return 1;
562 } END_FOR_EACH_PTR(right_tmp);
563 } END_FOR_EACH_PTR(left_tmp);
564 return 0;
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)
572 return 1;
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))
577 return 1;
578 } END_FOR_EACH_PTR(right_tmp);
579 } END_FOR_EACH_PTR(left_tmp);
580 return 0;
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)
586 if (left)
587 return possibly_true_range_lists(a, comparison, b);
588 else
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)
594 if (left)
595 return possibly_false_range_lists(a, comparison, b);
596 else
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);
616 return rl;
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);
624 return rl;
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;
643 if (!rl)
644 return NULL;
646 if (!type)
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);
654 set_max = 0;
655 if (type_unsigned(type) && sval_cmp_val(rl_min(rl), 0) < 0)
656 set_max = 1;
658 set_min = 0;
659 if (type_signed(type) && sval_cmp(rl_max(rl), sval_type_max(type)) > 0)
660 set_min = 1;
662 FOR_EACH_PTR(rl, tmp) {
663 sval_t min, max;
665 min = tmp->min;
666 max = tmp->max;
668 if (sval_cmp_t(type, max, sval_type_min(type)) < 0)
669 continue;
670 if (sval_cmp_t(type, min, sval_type_max(type)) > 0)
671 continue;
672 if (sval_cmp_val(min, 0) < 0 && type_unsigned(type))
673 min.value = 0;
674 new = alloc_range(sval_cast(type, min), sval_cast(type, max));
675 add_ptr_list(&ret, new);
676 } END_FOR_EACH_PTR(tmp);
678 if (!ret)
679 return whole_range_list(type);
681 if (set_min) {
682 tmp = first_ptr_list((struct ptr_list *)ret);
683 tmp->min = sval_type_min(type);
685 if (set_max) {
686 tmp = last_ptr_list((struct ptr_list *)ret);
687 tmp->max = sval_type_max(type);
690 return ret;
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));
711 offset += size;
715 void free_data_info_allocs(void)
717 struct allocator_struct *desc = &data_info_allocator;
718 struct allocation_blob *blob = desc->blobs;
720 desc->blobs = NULL;
721 desc->allocations = 0;
722 desc->total_bytes = 0;
723 desc->useful_bytes = 0;
724 desc->freelist = NULL;
725 while (blob) {
726 struct allocation_blob *next = blob->next;
727 free_dinfos(blob);
728 blob_free(blob, desc->chunking);
729 blob = next;
731 clear_data_range_alloc();