From 4e7ea6dff588ac741226e2d259da27a1627e1d79 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 16 Oct 2017 14:22:07 +0300 Subject: [PATCH] param_used/container_of: split this into two files The container_of() stuff is not a natural fit for param_used. I just put it there because some code was there initially. Now that I split it apart, I had to create a proper add_get_state_hook() function. Signed-off-by: Dan Carpenter --- Makefile | 2 +- check_list.h | 3 +- smatch.h | 1 + smatch_param_used.c => smatch_container_of.c | 55 +--- smatch_param_used.c | 420 +++++++-------------------- smatch_states.c | 30 +- 6 files changed, 149 insertions(+), 362 deletions(-) copy smatch_param_used.c => smatch_container_of.c (86%) rewrite smatch_param_used.c (65%) diff --git a/Makefile b/Makefile index e806a7be..0034b0d0 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ SMATCH_FILES=smatch_flow.o smatch_conditions.o smatch_slist.o smatch_states.o \ smatch_unknown_value.o smatch_stored_conditions.o avl.o \ smatch_function_info.o smatch_links.o smatch_auto_copy.o \ smatch_type_links.o smatch_untracked_param.o smatch_impossible.o \ - smatch_strings.o smatch_param_used.o smatch_address.o \ + smatch_strings.o smatch_param_used.o smatch_container_of.o smatch_address.o \ smatch_buf_comparison.o smatch_real_absolute.o smatch_scope.o \ smatch_imaginary_absolute.o smatch_parameter_names.o \ smatch_return_to_param.o smatch_passes_array_size.o \ diff --git a/check_list.h b/check_list.h index b3d60ad8..e6f83932 100644 --- a/check_list.h +++ b/check_list.h @@ -4,7 +4,8 @@ #endif CK(register_db_call_marker) /* always has to be first */ -CK(register_param_used) /* has to be before smatch_extra */ +CK(register_param_used) /* get_state_hooks have to be registered before smatch_extra */ +CK(register_container_of) CK(register_smatch_extra) /* smatch_extra always has to be SMATCH_EXTRA */ CK(register_smatch_extra_links) CK(register_modification_hooks) diff --git a/smatch.h b/smatch.h index c45db7f7..25b4c14d 100644 --- a/smatch.h +++ b/smatch.h @@ -282,6 +282,7 @@ struct stree *get_all_states_from_stree(int owner, struct stree *source); struct stree *get_all_states_stree(int id); struct stree *__get_cur_stree(void); int is_reachable(void); +void add_get_state_hook(void (*fn)(int owner, const char *name, struct symbol *sym)); /* smatch_helper.c */ DECLARE_PTR_LIST(int_stack, int); diff --git a/smatch_param_used.c b/smatch_container_of.c similarity index 86% copy from smatch_param_used.c copy to smatch_container_of.c index 2860ee6e..5f941385 100644 --- a/smatch_param_used.c +++ b/smatch_container_of.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Oracle. + * Copyright (C) 2017 Oracle. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,8 +25,6 @@ static struct stree_stack *saved_stack; STATE(used); -int recursion; - static int get_param_from_container_of(struct expression *expr) { struct expression *param_expr; @@ -136,11 +134,7 @@ static char *get_container_name(struct sm_state *sm, int offset) return buf; } -/* - * I am a loser. This should be a proper hook, but I am too lazy. I'll add - * that stuff if we have a second user. - */ -void __get_state_hook(int owner, const char *name, struct symbol *sym) +static void get_state_hook(int owner, const char *name, struct symbol *sym) { int arg; @@ -148,22 +142,10 @@ void __get_state_hook(int owner, const char *name, struct symbol *sym) return; if (__in_fake_assign) return; - if (recursion) - return; - recursion = 1; arg = get_container_arg(sym); if (arg >= 0) - goto save; - - arg = get_param_num_from_sym(sym); - if (arg < 0) - goto end_recursion; - -save: - set_state_stree(&used_stree, my_id, name, sym, &used); -end_recursion: - recursion = 0; + set_state_stree(&used_stree, my_id, name, sym, &used); } static void set_param_used(struct expression *call, struct expression *arg, char *key, char *unused) @@ -172,27 +154,15 @@ static void set_param_used(struct expression *call, struct expression *arg, char char *name; int arg_nr; - if (recursion) - return; - recursion = 1; - name = get_variable_from_key(arg, key, &sym); if (!name || !sym) goto free; arg_nr = get_container_arg(sym); if (arg_nr >= 0) - goto save; - - arg_nr = get_param_num_from_sym(sym); - if (arg_nr < 0) - goto free; - -save: - set_state(my_id, name, sym, &used); + set_state(my_id, name, sym, &used); free: free_string(name); - recursion = 0; } static void process_states(void) @@ -201,17 +171,7 @@ static void process_states(void) int arg, offset; const char *name; - recursion++; - FOR_EACH_SM(used_stree, tmp) { - arg = get_param_num_from_sym(tmp->sym); - if (arg >= 0) { - name = get_param_name(tmp); - if (!name) - continue; - goto insert; - } - arg = get_container_arg(tmp->sym); offset = get_container_offset(tmp->sym); if (arg < 0 || offset < 0) @@ -219,13 +179,10 @@ static void process_states(void) name = get_container_name(tmp, offset); if (!name) continue; -insert: sql_insert_call_implies(PARAM_USED, arg, name, ""); } END_FOR_EACH_SM(tmp); free_stree(&used_stree); - - recursion--; } static void match_function_def(struct symbol *sym) @@ -294,12 +251,14 @@ static void returns_container_of(struct expression *expr, int param, char *key, sql_insert_call_implies(PARAM_USED, param, buf, ""); } -void register_param_used(int id) +void register_container_of(int id) { my_id = id; add_hook(&match_function_def, FUNC_DEF_HOOK); + add_get_state_hook(&get_state_hook); + add_hook(&match_save_states, INLINE_FN_START); add_hook(&match_restore_states, INLINE_FN_END); diff --git a/smatch_param_used.c b/smatch_param_used.c dissimilarity index 65% index 2860ee6e..19bf2f3b 100644 --- a/smatch_param_used.c +++ b/smatch_param_used.c @@ -1,311 +1,109 @@ -/* - * Copyright (C) 2015 Oracle. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt - */ - -#include "smatch.h" -#include "smatch_slist.h" - -static int my_id; - -struct stree *used_stree; -static struct stree_stack *saved_stack; - -STATE(used); - -int recursion; - -static int get_param_from_container_of(struct expression *expr) -{ - struct expression *param_expr; - struct symbol *type; - sval_t sval; - int param; - - - type = get_type(expr); - if (!type || type->type != SYM_PTR) - return -1; - - expr = strip_expr(expr); - if (expr->type != EXPR_BINOP || expr->op != '-') - return -1; - - if (!get_value(expr->right, &sval)) - return -1; - if (sval.value < 0 || sval.value > 4096) - return -1; - - param_expr = get_assigned_expr(expr->left); - if (!param_expr) - return -1; - param = get_param_num(param_expr); - if (param < 0) - return -1; - - return param; -} - -static int get_offset_from_container_of(struct expression *expr) -{ - struct expression *param_expr; - struct symbol *type; - sval_t sval; - int param; - - - type = get_type(expr); - if (!type || type->type != SYM_PTR) - return -1; - - expr = strip_expr(expr); - if (expr->type != EXPR_BINOP || expr->op != '-') - return -1; - - if (!get_value(expr->right, &sval)) - return -1; - if (sval.value < 0 || sval.value > 4096) - return -1; - - param_expr = get_assigned_expr(expr->left); - if (!param_expr) - return -1; - param = get_param_num(param_expr); - if (param < 0) - return -1; - - return sval.value; -} - -static int get_container_arg(struct symbol *sym) -{ - struct expression *__mptr; - int param; - - if (!sym || !sym->ident) - return -1; - - __mptr = get_assigned_expr_name_sym(sym->ident->name, sym); - param = get_param_from_container_of(__mptr); - - return param; -} - -static int get_container_offset(struct symbol *sym) -{ - struct expression *__mptr; - int offset; - - if (!sym || !sym->ident) - return -1; - - __mptr = get_assigned_expr_name_sym(sym->ident->name, sym); - offset = get_offset_from_container_of(__mptr); - - return offset; -} - -static char *get_container_name(struct sm_state *sm, int offset) -{ - static char buf[256]; - const char *name; - - name = get_param_name(sm); - if (!name) - return NULL; - - if (name[0] == '$') - snprintf(buf, sizeof(buf), "$(-%d)%s", offset, name + 1); - else if (name[0] == '*' || name[1] == '$') - snprintf(buf, sizeof(buf), "*$(-%d)%s", offset, name + 2); - else - return NULL; - - return buf; -} - -/* - * I am a loser. This should be a proper hook, but I am too lazy. I'll add - * that stuff if we have a second user. - */ -void __get_state_hook(int owner, const char *name, struct symbol *sym) -{ - int arg; - - if (!option_info) - return; - if (__in_fake_assign) - return; - if (recursion) - return; - recursion = 1; - - arg = get_container_arg(sym); - if (arg >= 0) - goto save; - - arg = get_param_num_from_sym(sym); - if (arg < 0) - goto end_recursion; - -save: - set_state_stree(&used_stree, my_id, name, sym, &used); -end_recursion: - recursion = 0; -} - -static void set_param_used(struct expression *call, struct expression *arg, char *key, char *unused) -{ - struct symbol *sym; - char *name; - int arg_nr; - - if (recursion) - return; - recursion = 1; - - name = get_variable_from_key(arg, key, &sym); - if (!name || !sym) - goto free; - - arg_nr = get_container_arg(sym); - if (arg_nr >= 0) - goto save; - - arg_nr = get_param_num_from_sym(sym); - if (arg_nr < 0) - goto free; - -save: - set_state(my_id, name, sym, &used); -free: - free_string(name); - recursion = 0; -} - -static void process_states(void) -{ - struct sm_state *tmp; - int arg, offset; - const char *name; - - recursion++; - - FOR_EACH_SM(used_stree, tmp) { - arg = get_param_num_from_sym(tmp->sym); - if (arg >= 0) { - name = get_param_name(tmp); - if (!name) - continue; - goto insert; - } - - arg = get_container_arg(tmp->sym); - offset = get_container_offset(tmp->sym); - if (arg < 0 || offset < 0) - continue; - name = get_container_name(tmp, offset); - if (!name) - continue; -insert: - sql_insert_call_implies(PARAM_USED, arg, name, ""); - } END_FOR_EACH_SM(tmp); - - free_stree(&used_stree); - - recursion--; -} - -static void match_function_def(struct symbol *sym) -{ - free_stree(&used_stree); -} - -static void match_save_states(struct expression *expr) -{ - push_stree(&saved_stack, used_stree); - used_stree = NULL; -} - -static void match_restore_states(struct expression *expr) -{ - free_stree(&used_stree); - used_stree = pop_stree(&saved_stack); -} - -static void print_returns_container_of(int return_id, char *return_ranges, struct expression *expr) -{ - int offset; - int param; - char key[64]; - char value[64]; - - param = get_param_from_container_of(expr); - if (param < 0) - return; - offset = get_offset_from_container_of(expr); - if (offset < 0) - return; - - snprintf(key, sizeof(key), "%d", param); - snprintf(value, sizeof(value), "-%d", offset); - - sql_insert_return_states(return_id, return_ranges, CONTAINER, -1, - key, value); -} - -static void returns_container_of(struct expression *expr, int param, char *key, char *value) -{ - struct expression *call, *arg; - int offset; - char buf[64]; - - if (expr->type != EXPR_ASSIGNMENT || expr->op != '=') - return; - call = strip_expr(expr->right); - if (call->type != EXPR_CALL) - return; - if (param != -1) - return; - param = atoi(key); - offset = atoi(value); - - arg = get_argument_from_call_expr(call->args, param); - if (!arg) - return; - if (arg->type != EXPR_SYMBOL) - return; - param = get_param_num(arg); - if (param < 0) - return; - snprintf(buf, sizeof(buf), "$(%d)", offset); - sql_insert_call_implies(PARAM_USED, param, buf, ""); -} - -void register_param_used(int id) -{ - my_id = id; - - add_hook(&match_function_def, FUNC_DEF_HOOK); - - add_hook(&match_save_states, INLINE_FN_START); - add_hook(&match_restore_states, INLINE_FN_END); - - select_call_implies_hook(PARAM_USED, &set_param_used); - all_return_states_hook(&process_states); - - add_split_return_callback(&print_returns_container_of); - select_return_states_hook(CONTAINER, &returns_container_of); -} +/* + * Copyright (C) 2015 Oracle. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt + */ + +#include "smatch.h" +#include "smatch_slist.h" + +static int my_id; + +struct stree *used_stree; +static struct stree_stack *saved_stack; + +STATE(used); + +static void get_state_hook(int owner, const char *name, struct symbol *sym) +{ + int arg; + + if (!option_info) + return; + if (__in_fake_assign) + return; + + arg = get_param_num_from_sym(sym); + if (arg >= 0) + set_state_stree(&used_stree, my_id, name, sym, &used); +} + +static void set_param_used(struct expression *call, struct expression *arg, char *key, char *unused) +{ + struct symbol *sym; + char *name; + int arg_nr; + + name = get_variable_from_key(arg, key, &sym); + if (!name || !sym) + goto free; + + arg_nr = get_param_num_from_sym(sym); + if (arg_nr >= 0) + set_state(my_id, name, sym, &used); +free: + free_string(name); +} + +static void process_states(void) +{ + struct sm_state *tmp; + int arg; + const char *name; + + FOR_EACH_SM(used_stree, tmp) { + arg = get_param_num_from_sym(tmp->sym); + if (arg < 0) + continue; + name = get_param_name(tmp); + if (!name) + continue; + + sql_insert_call_implies(PARAM_USED, arg, name, ""); + } END_FOR_EACH_SM(tmp); + + free_stree(&used_stree); +} + +static void match_function_def(struct symbol *sym) +{ + free_stree(&used_stree); +} + +static void match_save_states(struct expression *expr) +{ + push_stree(&saved_stack, used_stree); + used_stree = NULL; +} + +static void match_restore_states(struct expression *expr) +{ + free_stree(&used_stree); + used_stree = pop_stree(&saved_stack); +} + +void register_param_used(int id) +{ + my_id = id; + + add_hook(&match_function_def, FUNC_DEF_HOOK); + + add_get_state_hook(&get_state_hook); + + add_hook(&match_save_states, INLINE_FN_START); + add_hook(&match_restore_states, INLINE_FN_END); + + select_call_implies_hook(PARAM_USED, &set_param_used); + all_return_states_hook(&process_states); +} diff --git a/smatch_states.c b/smatch_states.c index 49844c96..045afce6 100644 --- a/smatch_states.c +++ b/smatch_states.c @@ -259,9 +259,37 @@ void __set_sm_fake_stree(struct sm_state *sm) overwrite_sm_state_stree_stack(&fake_cur_stree_stack, sm); } + +typedef void (get_state_hook)(int owner, const char *name, struct symbol *sym); +DECLARE_PTR_LIST(fn_list, get_state_hook *); +static struct fn_list *get_state_hooks; + +void add_get_state_hook(get_state_hook *fn) +{ + get_state_hook **p = malloc(sizeof(get_state_hook *)); + *p = fn; + add_ptr_list(&get_state_hooks, p); +} + +static void call_get_state_hooks(int owner, const char *name, struct symbol *sym) +{ + static int recursion; + get_state_hook **fn; + + if (recursion) + return; + recursion = 1; + + FOR_EACH_PTR(get_state_hooks, fn) { + (*fn)(owner, name, sym); + } END_FOR_EACH_PTR(fn); + + recursion = 0; +} + struct smatch_state *get_state(int owner, const char *name, struct symbol *sym) { - __get_state_hook(owner, name, sym); + call_get_state_hooks(owner, name, sym); return get_state_stree(cur_stree, owner, name, sym); } -- 2.11.4.GIT