Imagine we have code like: if ((1 << foo) & valid_bits) { The handle_bit_test() function is supposed to answer the question, "what does that condition mean about 'foo'"? This patch fixes several bugs: 1) The range is off by one. ffsll() returns 1 for BIT(0) so we need to subtract 1 from what ffsll() returns. 2) This code returns early for impossible conditions but it is better to set "foo" to the empty state. 3) The false state was not set. We can use rl_filter() for that. Signed-off-by: Harshvardhan Jha <harshvardhan.jha@xxxxxxxxxx> --- smatch_extra.c | 17 +++++++++-------- validation/sm_bits2.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 validation/sm_bits2.c diff --git a/smatch_extra.c b/smatch_extra.c index e864646a..27bf5a02 100644 --- a/smatch_extra.c +++ b/smatch_extra.c @@ -2061,7 +2061,7 @@ static void match_comparison(struct expression *expr) static bool handle_bit_test(struct expression *expr) { - struct range_list *orig_rl, *rl; + struct range_list *orig_rl, *rl, *true_rl, *false_rl; struct expression *shift, *mask, *var; struct bit_info *bit_info; sval_t sval; @@ -2083,23 +2083,24 @@ static bool handle_bit_test(struct expression *expr) bit_info = get_bit_info(mask); if (!bit_info) return false; - if (!bit_info->possible) + if (!bit_info->possible){ + set_true_false_states_expr(my_id, var, alloc_estate_empty(), NULL); return false; + } get_absolute_rl(var, &orig_rl); if (sval_is_negative(rl_min(orig_rl)) || rl_max(orig_rl).uvalue > type_bits(get_type(shift->left))) return false; - low.value = ffsll(bit_info->possible); - high.value = sm_fls64(bit_info->possible); + low.value = ffsll(bit_info->possible) - 1; + high.value = sm_fls64(bit_info->possible) - 1; rl = alloc_rl(low, high); rl = cast_rl(get_type(var), rl); - rl = rl_intersection(orig_rl, rl); - if (!rl) - return false; + true_rl = rl_intersection(orig_rl, rl); + false_rl = rl_filter(orig_rl, rl); - set_extra_expr_true_false(shift->right, alloc_estate_rl(rl), NULL); + set_extra_expr_true_false(shift->right, alloc_estate_rl(true_rl), alloc_estate_rl(false_rl)); return true; } diff --git a/validation/sm_bits2.c b/validation/sm_bits2.c new file mode 100644 index 00000000..1a43538a --- /dev/null +++ b/validation/sm_bits2.c @@ -0,0 +1,28 @@ +#include "../check_debug.h" + +unsigned int frob(); + +void test(void) +{ + unsigned int mask = 0xff0; + unsigned int x = frob(); + + if (x < 4 || x > 11) + return; + + if ((1 << x) & mask) { + __smatch_implied(x); + return; + } + __smatch_implied(x); +} + +/* + * check-name: smatch bits 2 + * check-command: smatch sm_bits2.c + * + * check-output-start +sm_bits2.c:14 test() implied: x = '4-11' +sm_bits2.c:17 test() implied: x = '' + * check-output-end + */ -- 2.32.0