From 07d92a38d283f20cc489ec11af73fe406be4f710 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 10 Feb 2021 14:38:58 +0300 Subject: [PATCH] param_set/clear: Use memset() of struct members What this is is, imagine you have a function which memset as struct member: void one(struct outer *outer) { memset(&outer->foo, 0, sizeof(outer->foo)); } That data is recorded in the database but we also record it as a series of assignments. outer->foo.a = 0; outer->foo.b = 0; It's a waste of space to record this duplicate information. Originally this param_clear was not used in smatch_struct_assignment.c but now we can use the gen_expr_from_param_key() function to do it easily. Signed-off-by: Dan Carpenter --- smatch.h | 4 +++ smatch_extra.h | 1 + smatch_param_cleared.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++ smatch_param_set.c | 5 +++ smatch_ranges.c | 9 ++++++ smatch_struct_assignment.c | 15 +-------- 6 files changed, 96 insertions(+), 14 deletions(-) diff --git a/smatch.h b/smatch.h index 581f55ba..a0c08a2f 100644 --- a/smatch.h +++ b/smatch.h @@ -1278,6 +1278,10 @@ int get_formatted_string_min_size(struct expression *call, int arg); int param_was_set(struct expression *expr); int param_was_set_var_sym(const char *name, struct symbol *sym); void print_limited_param_set(int return_id, char *return_ranges, struct expression *expr); +/* param_clear */ +bool parent_was_PARAM_CLEAR(const char *name, struct symbol *sym); +bool parent_was_PARAM_CLEAR_ZERO(const char *name, struct symbol *sym); + /* smatch_param_filter.c */ int param_has_filter_data(struct sm_state *sm); diff --git a/smatch_extra.h b/smatch_extra.h index 263066dc..368c6d88 100644 --- a/smatch_extra.h +++ b/smatch_extra.h @@ -78,6 +78,7 @@ int ranges_equiv(struct data_range *one, struct data_range *two); bool is_err_ptr(sval_t sval); bool is_err_or_null(struct range_list *rl); bool is_noderef_ptr_rl(struct range_list *rl); +bool rl_is_zero(struct range_list *rl); int rl_equiv(struct range_list *one, struct range_list *two); int is_whole_rl(struct range_list *rl); diff --git a/smatch_param_cleared.c b/smatch_param_cleared.c index 0abd02ee..633fc240 100644 --- a/smatch_param_cleared.c +++ b/smatch_param_cleared.c @@ -100,6 +100,82 @@ static void print_return_value_param(int return_id, char *return_ranges, struct } END_FOR_EACH_SM(sm); } +bool parent_was_PARAM_CLEAR(const char *name, struct symbol *sym) +{ + struct sm_state *sm; + char buf[80]; + int len, i; + + if (!name) + return 0; + + len = strlen(name); + if (len >= sizeof(buf)) + len = sizeof(buf) - 1; + + for (i = len - 2; i >= 1; i--) { + if (name[i] != '-' && name[i] != '.') + continue; + + memcpy(buf, name, i); + buf[i] = '\0'; + sm = get_sm_state(my_id, buf, sym); + if (sm && sm->state == &cleared) + return true; + if (sm) + return false; + + buf[0] = '&'; + memcpy(buf + 1, name, i); + buf[i + 1] = '\0'; + sm = get_sm_state(my_id, buf, sym); + if (sm && sm->state == &cleared) + return true; + if (sm) + return false; + } + + return false; +} + +bool parent_was_PARAM_CLEAR_ZERO(const char *name, struct symbol *sym) +{ + struct sm_state *sm; + char buf[80]; + int len, i; + + if (!name) + return 0; + + len = strlen(name); + if (len >= sizeof(buf)) + len = sizeof(buf) - 1; + + for (i = len - 2; i >= 1; i--) { + if (name[i] != '-' && name[i] != '.') + continue; + + memcpy(buf, name, i); + buf[i] = '\0'; + sm = get_sm_state(my_id, buf, sym); + if (sm && sm->state == &zeroed) + return true; + if (sm) + return false; + + buf[0] = '&'; + memcpy(buf + 1, name, i); + buf[i + 1] = '\0'; + sm = get_sm_state(my_id, buf, sym); + if (sm && sm->state == &zeroed) + return true; + if (sm) + return false; + } + + return false; +} + static void register_clears_param(void) { struct token *token; diff --git a/smatch_param_set.c b/smatch_param_set.c index 40cc27c7..41f3ba0f 100644 --- a/smatch_param_set.c +++ b/smatch_param_set.c @@ -278,6 +278,11 @@ static void print_return_value_param_helper(int return_id, char *return_ranges, /* no useful information here. */ if (is_whole_rl(rl) && parent_set(set_list, sm->name)) continue; + if (is_whole_rl(rl) && parent_was_PARAM_CLEAR(sm->name, sm->sym)) + continue; + if (rl_is_zero(rl) && parent_was_PARAM_CLEAR_ZERO(sm->name, sm->sym)) + continue; + insert_string(&set_list, (char *)sm->name); sql_insert_return_states(return_id, return_ranges, diff --git a/smatch_ranges.c b/smatch_ranges.c index c80e707d..a84d3ddf 100644 --- a/smatch_ranges.c +++ b/smatch_ranges.c @@ -82,6 +82,15 @@ bool is_noderef_ptr_rl(struct range_list *rl) return false; } +bool rl_is_zero(struct range_list *rl) +{ + if (!rl) + return false; + if (rl_min(rl).value == 0 && rl_max(rl).value == 0) + return true; + return false; +} + static char *get_err_pointer_str(struct data_range *drange) { static char buf[20]; diff --git a/smatch_struct_assignment.c b/smatch_struct_assignment.c index a6e46ccb..79118435 100644 --- a/smatch_struct_assignment.c +++ b/smatch_struct_assignment.c @@ -538,20 +538,7 @@ static void db_param_cleared(struct expression *expr, int param, char *key, char { struct expression *arg; - while (expr->type == EXPR_ASSIGNMENT) - expr = strip_expr(expr->right); - if (expr->type != EXPR_CALL) - return; - - /* - * FIXME: __struct_members_copy() requires an expression but - * get_variable_from_key() returns a name/sym pair so that doesn't - * work here. - */ - if (strcmp(key, "$") != 0) - return; - - arg = get_argument_from_call_expr(expr->args, param); + arg = gen_expr_from_param_key(expr, param, key); if (!arg) return; -- 2.11.4.GIT