[PATCH 2/2] extra: Fix handle_bit_test so that null set condition is taken care of
Harshvardhan Jha <[email protected]> Tue, 13 Jul 2021 18:20:06 +0530
| Newsgroups | org.kernel.vger.smatch |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]>
---
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