From 7d56ab3300ca153198c661df6ffb530cb2fa1fc8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 5 Nov 2014 10:34:59 +0300 Subject: [PATCH] db,extra: fixes to param filtering I feel like maybe this code sucks and that maybe I just kept writing code until my test case passed and then stopped without really understanding the problem completely. In the original code, you would cast the range lists but if you casted a 64 bit value that was larger than 2*32 to 32 bits then it ends up saying that it could be any u32 value. So that wasn't right. Also I was using the wrong type part of the time... Anyway, I was trying to get kmalloc() to work like I wanted and it does so I'm pushing this garbage. Signed-off-by: Dan Carpenter --- smatch_extra.c | 15 +++++++++++---- smatch_ranges.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/smatch_extra.c b/smatch_extra.c index 5382fd76..a514fce5 100644 --- a/smatch_extra.c +++ b/smatch_extra.c @@ -1512,7 +1512,7 @@ static void db_param_limit_filter(struct expression *expr, int param, char *key, char *name; struct symbol *sym; struct sm_state *sm; - struct symbol *type; + struct symbol *compare_type, *var_type; struct range_list *rl; struct range_list *limit; struct range_list *new; @@ -1530,16 +1530,23 @@ static void db_param_limit_filter(struct expression *expr, int param, char *key, if (!name || !sym) goto free; + if (strcmp(key, "$$") == 0) + compare_type = get_arg_type(expr->fn, param); + else + compare_type = get_member_type_from_key(arg, key); + sm = get_sm_state(SMATCH_EXTRA, name, sym); - type = get_member_type_from_key(arg, key); if (sm) rl = estate_rl(sm->state); else - rl = alloc_whole_rl(type); + rl = alloc_whole_rl(compare_type); - call_results_to_rl(expr, type, value, &limit); + call_results_to_rl(expr, compare_type, value, &limit); new = rl_intersection(rl, limit); + var_type = get_member_type_from_key(arg, key); + new = cast_rl(var_type, new); + /* We want to preserve the implications here */ if (sm && rl_equiv(estate_rl(sm->state), new)) { __set_sm(sm); diff --git a/smatch_ranges.c b/smatch_ranges.c index f2fa77e2..e8b39c7a 100644 --- a/smatch_ranges.c +++ b/smatch_ranges.c @@ -1120,10 +1120,51 @@ struct range_list *rl_filter(struct range_list *rl, struct range_list *filter) struct range_list *rl_intersection(struct range_list *one, struct range_list *two) { + struct range_list *one_orig; + struct range_list *two_orig; + struct range_list *ret; + struct symbol *ret_type; + struct symbol *small_type; + struct symbol *large_type; + if (!two) return NULL; + if (!one) + return NULL; + + one_orig = one; + two_orig = two; + + ret_type = rl_type(one); + small_type = rl_type(one); + large_type = rl_type(two); + + if (type_bits(rl_type(two)) < type_bits(small_type)) { + small_type = rl_type(two); + large_type = rl_type(one); + } + + one = cast_rl(large_type, one); + two = cast_rl(large_type, two); + + ret = one; + one = rl_invert(one); two = rl_invert(two); - return rl_filter(one, two); + + ret = rl_filter(ret, one); + ret = rl_filter(ret, two); + + one = cast_rl(small_type, one_orig); + two = cast_rl(small_type, two_orig); + + one = rl_invert(one); + two = rl_invert(two); + + ret = cast_rl(small_type, ret); + ret = rl_filter(ret, one); + ret = rl_filter(ret, two); + + return cast_rl(ret_type, ret); } static struct range_list *handle_mod_rl(struct range_list *left, struct range_list *right) -- 2.11.4.GIT