From 850ca49f882c4d8720c67e7ff9b10d1d390f69b5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 10 Sep 2018 15:13:28 +0300 Subject: [PATCH] array: store possible array values for simple arrays The concept is simple enough. We want smatch to be able to handle __smatch_implied(array[idx]);. This is a very limited first implementation because it only handles file scoped arrays. I will add more later. Also the table in the DB is called "sink_info" because I hope that it will eventually be more general purpose than just handling arrays. Hopefully, it will hand lists as well later. Where we store information about what we're putting into a list and what we pull out from the list. Signed-off-by: Dan Carpenter --- Makefile | 2 +- check_list.h | 1 + smatch.h | 2 + smatch_array_values.c | 135 ++++++++++++++++++++++++++++++++++++ smatch_data/db/build_early_index.sh | 1 + smatch_data/db/sink_info.schema | 1 + smatch_db.c | 2 + smatch_math.c | 4 ++ 8 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 smatch_array_values.c create mode 100644 smatch_data/db/sink_info.schema diff --git a/Makefile b/Makefile index c592e50c..110d1804 100644 --- a/Makefile +++ b/Makefile @@ -88,7 +88,7 @@ SMATCH_FILES=smatch_flow.o smatch_conditions.o smatch_slist.o smatch_states.o \ smatch_constraints.o smatch_constraints_required.o \ smatch_fn_arg_link.o smatch_about_fn_ptr_arg.o smatch_mtag.o \ smatch_mtag_map.o smatch_mtag_data.o \ - smatch_param_to_mtag_data.o smatch_mem_tracker.o + smatch_param_to_mtag_data.o smatch_mem_tracker.o smatch_array_values.o SMATCH_CHECKS=$(shell ls check_*.c | sed -e 's/\.c/.o/') SMATCH_DATA=smatch_data/kernel.allocation_funcs \ diff --git a/check_list.h b/check_list.h index 88a62f70..207cbd5b 100644 --- a/check_list.h +++ b/check_list.h @@ -66,6 +66,7 @@ CK(register_mtag) CK(register_mtag_map) CK(register_mtag_data) CK(register_param_to_mtag_data) +CK(register_array_values) CK(check_debug) diff --git a/smatch.h b/smatch.h index e59ac470..497c9141 100644 --- a/smatch.h +++ b/smatch.h @@ -600,6 +600,8 @@ int get_local_min_helper(struct expression *expr, sval_t *sval); int get_db_type_rl(struct expression *expr, struct range_list **rl); /* smatch_data_val.c */ int get_mtag_rl(struct expression *expr, struct range_list **rl); +/* smatch_array_values.c */ +int get_array_rl(struct expression *expr, struct range_list **rl); /* smatch_states.c */ void __swap_cur_stree(struct stree *stree); diff --git a/smatch_array_values.c b/smatch_array_values.c new file mode 100644 index 00000000..9e4b5967 --- /dev/null +++ b/smatch_array_values.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2018 Oracle. All rights reserved. + * + * 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_extra.h" + +static int my_id; + +static int get_vals(void *_db_vals, int argc, char **argv, char **azColName) +{ + char **db_vals = _db_vals; + + *db_vals = alloc_string(argv[0]); + return 0; +} + +int get_array_rl(struct expression *expr, struct range_list **rl) +{ + struct expression *array; + struct symbol *type; + char buf[128]; + char *rl_str = NULL; + char *name; + + array = get_array_base(expr); + if (!array || array->type != EXPR_SYMBOL) + return 0; + if (!(array->symbol->ctype.modifiers & MOD_TOPLEVEL) || + !(array->symbol->ctype.modifiers & MOD_STATIC)) + return 0; + + type = get_type(expr); + if (!type || type->type != SYM_BASETYPE) + return 0; + + name = expr_to_str(array); + snprintf(buf, sizeof(buf), "%s[]", name); + free_string(name); + + run_sql(&get_vals, &rl_str, + "select value from sink_info where file = '%s' and static = 1 and sink_name = '%s' and type = %d;", + get_filename(), buf, DATA_VALUE); + if (!rl_str) + return 0; + + str_to_rl(type, rl_str, rl); + free_string(rl_str); + return 1; +} + +static struct range_list *get_saved_rl(struct symbol *type, char *name) +{ + struct range_list *rl; + char *str = NULL; + + cache_sql(&get_vals, &str, "select value from sink_info where file = '%s' and static = 1 and sink_name = '%s' and type = %d;", + get_filename(), name, DATA_VALUE); + if (!str) + return NULL; + + str_to_rl(type, str, &rl); + free_string(str); + + return rl; +} + +static void update_cache(char *name, struct range_list *rl) +{ + cache_sql(NULL, NULL, "delete from sink_info where file = '%s' and static = 1 and sink_name = '%s' and type = %d;", + get_filename(), name, DATA_VALUE); + cache_sql(NULL, NULL, "insert into sink_info values ('%s', 1, '%s', %d, '', '%s');", + get_filename(), name, DATA_VALUE, show_rl(rl)); +} + +static void match_assign(struct expression *expr) +{ + struct expression *left, *array; + struct symbol *type; + struct range_list *orig_rl, *rl; + char *name; + char buf[128]; + + left = strip_expr(expr->left); + if (!is_array(left)) + return; + array = get_array_base(left); + if (!array || array->type != EXPR_SYMBOL) + return; + if (!(array->symbol->ctype.modifiers & MOD_TOPLEVEL) || + !(array->symbol->ctype.modifiers & MOD_STATIC)) + return; + type = get_type(array); + if (!type || type->type != SYM_ARRAY) + return; + type = get_real_base_type(type); + if (!type || type->type != SYM_BASETYPE) + return; + + name = expr_to_str(array); + snprintf(buf, sizeof(buf), "%s[]", name); + free_string(name); + + if (expr->op != '=') { + rl = alloc_whole_rl(type); + } else { + get_absolute_rl(expr->right, &rl); + rl = cast_rl(type, rl); + orig_rl = get_saved_rl(type, buf); + rl = rl_union(orig_rl, rl); + } + + update_cache(buf, rl); +} + +void register_array_values(int id) +{ + my_id = id; + + add_hook(&match_assign, ASSIGNMENT_HOOK); + add_hook(&match_assign, GLOBAL_ASSIGNMENT_HOOK); +} diff --git a/smatch_data/db/build_early_index.sh b/smatch_data/db/build_early_index.sh index 58e7f2b2..bb1faaee 100755 --- a/smatch_data/db/build_early_index.sh +++ b/smatch_data/db/build_early_index.sh @@ -39,6 +39,7 @@ CREATE INDEX mtag_about_idx on mtag_about (tag); CREATE INDEX mtag_data_idx on mtag_data (tag); CREATE INDEX mtag_map_idx1 on mtag_map (tag); CREATE INDEX mtag_map_idx2 on mtag_map (container); +CREATE INDEX sink_index on sink_info (file, sink_name); EOF diff --git a/smatch_data/db/sink_info.schema b/smatch_data/db/sink_info.schema new file mode 100644 index 00000000..dc2a285a --- /dev/null +++ b/smatch_data/db/sink_info.schema @@ -0,0 +1 @@ +CREATE TABLE sink_info (file varchar(128), static boolean, sink_name varchar(64), type integer, key varchar(256), value varchar(256)); diff --git a/smatch_db.c b/smatch_db.c index 4492e971..cdc0ade7 100644 --- a/smatch_db.c +++ b/smatch_db.c @@ -2155,6 +2155,7 @@ static void init_cachedb(void) "db/return_implies.schema", "db/type_info.schema", "db/mtag_data.schema", + "db/sink_info.schema", }; static char buf[4096]; int fd; @@ -2226,6 +2227,7 @@ static void dump_cache(struct symbol_list *sym_list) cache_sql(&save_cache_data, (char *)"return_implies", "select * from return_implies;"); cache_sql(&save_cache_data, (char *)"call_implies", "select * from call_implies;"); cache_sql(&save_cache_data, (char *)"mtag_data", "select * from mtag_data;"); + cache_sql(&save_cache_data, (char *)"sink_info", "select * from sink_info;"); } void open_smatch_db(char *db_file) diff --git a/smatch_math.c b/smatch_math.c index e581e522..c68705d8 100644 --- a/smatch_math.c +++ b/smatch_math.c @@ -909,6 +909,8 @@ static struct range_list *handle_variable(struct expression *expr, int implied, return rl; if (get_db_type_rl(expr, &rl)) return rl; + if (is_array(expr) && get_array_rl(expr, &rl)) + return rl; return NULL; } if (implied == RL_HARD && !estate_has_hard_max(state)) @@ -955,6 +957,8 @@ static struct range_list *handle_variable(struct expression *expr, int implied, return rl; if (get_db_type_rl(expr, &rl)) return rl; + if (is_array(expr) && get_array_rl(expr, &rl)) + return rl; return NULL; } case RL_FUZZY: -- 2.11.4.GIT