Powered by Linux
[PATCH] extra: Fix handle_bit_test so that null set condition is taken care of — Semantic Matching Tool

[PATCH] extra: Fix handle_bit_test so that null set condition is taken care of

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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. This patch handles false_state.

Signed-off-by: Harshvardhan Jha <harshvardhan.jha@xxxxxxxxxx>
---
 smatch.h       |  8 ++++++++
 smatch_bits.c  |  8 ++++----
 smatch_extra.c | 26 ++++++++++++++++----------
 3 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/smatch.h b/smatch.h
index 025ad1a8..882e3927 100644
--- a/smatch.h
+++ b/smatch.h
@@ -1311,10 +1311,18 @@ int get_mtag_sval(struct expression *expr, sval_t *sval);
 /* Trinity fuzzer stuff */
 const char *get_syscall_arg_type(struct symbol *sym);
 
+/* smatch_bits.c */
+int binfo_equiv(struct bit_info *one, struct bit_info *two);
+struct bit_info *alloc_bit_info(unsigned long long set, unsigned long long possible);
+struct smatch_state *alloc_bstate(unsigned long long set, unsigned long long possible);
+struct smatch_state *merge_bstates(struct smatch_state *one_state, struct smatch_state *two_state);
+
+
 /* smatch_bit_info.c */
 struct bit_info *rl_to_binfo(struct range_list *rl);
 struct bit_info *get_bit_info(struct expression *expr);
 struct bit_info *get_bit_info_var_sym(const char *name, struct symbol *sym);
+
 /* smatch_mem_tracker.c */
 extern int option_mem;
 unsigned long get_mem_kb(void);
diff --git a/smatch_bits.c b/smatch_bits.c
index 5e310a13..2f92ecd7 100644
--- a/smatch_bits.c
+++ b/smatch_bits.c
@@ -31,7 +31,7 @@ static const struct bit_info unknown_bit_info = {
 };
 
 ALLOCATOR(bit_info, "bit data");
-static struct bit_info *alloc_bit_info(unsigned long long set, unsigned long long possible)
+struct bit_info *alloc_bit_info(unsigned long long set, unsigned long long possible)
 {
 	struct bit_info *bit_info = __alloc_bit_info(0);
 
@@ -41,7 +41,7 @@ static struct bit_info *alloc_bit_info(unsigned long long set, unsigned long lon
 	return bit_info;
 }
 
-static struct smatch_state *alloc_bstate(unsigned long long set, unsigned long long possible)
+struct smatch_state *alloc_bstate(unsigned long long set, unsigned long long possible)
 {
 	struct smatch_state *state;
 	char buf[64];
@@ -154,7 +154,7 @@ static void match_modify(struct sm_state *sm, struct expression *mod_expr)
 	set_state(my_id, sm->name, sm->sym, alloc_bstate(0, -1ULL));
 }
 
-static int binfo_equiv(struct bit_info *one, struct bit_info *two)
+int binfo_equiv(struct bit_info *one, struct bit_info *two)
 {
 	if (one->set == two->set &&
 	    one->possible == two->possible)
@@ -162,7 +162,7 @@ static int binfo_equiv(struct bit_info *one, struct bit_info *two)
 	return 0;
 }
 
-static struct smatch_state *merge_bstates(struct smatch_state *one_state, struct smatch_state *two_state)
+struct smatch_state *merge_bstates(struct smatch_state *one_state, struct smatch_state *two_state)
 {
 	struct bit_info *one, *two;
 
diff --git a/smatch_extra.c b/smatch_extra.c
index 25c1c990..c2e2735c 100644
--- a/smatch_extra.c
+++ b/smatch_extra.c
@@ -2059,7 +2059,7 @@ static sval_t get_high_mask(sval_t known)
 
 static bool handle_bit_test(struct expression *expr)
 {
-	struct range_list *orig_rl, *rl;
+	struct range_list *orig_rl, *rlt, *rlf, *true_rl, *false_rl;
 	struct expression *shift, *mask, *var;
 	struct bit_info *bit_info;
 	sval_t sval;
@@ -2081,23 +2081,29 @@ 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);
-	rl = alloc_rl(low, high);
-	rl = cast_rl(get_type(var), rl);
-	rl = rl_intersection(orig_rl, rl);
-	if (!rl)
-		return false;
+	low.value = ffsll(bit_info->possible) - 1;
+	high.value = sm_fls64(bit_info->possible) - 1;
+	rlt = alloc_rl(low, high);
+	rlt = cast_rl(get_type(var), rlt);
+	true_rl = rl_intersection(orig_rl, rlt);
+
+	low.value = ffsll(bit_info->set) - 1;
+	high.value = sm_fls64(bit_info->set) - 1;
+	rlf = alloc_rl(low, high);
+	rlf = cast_rl(get_type(var), rlf);
+	false_rl = rl_filter(orig_rl, rlf);
 
-	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;
 }
-- 
2.32.0




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux