From 0fa6db5149c6757f1a4613931fb84bb446733cd3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 24 Nov 2014 15:39:25 +0300 Subject: [PATCH] type_val: improve the type/value information in the database Smatch tries to record the possible values of "(struct whatever)->foo" in the database. The problem is that sometimes we store "(struct whatever)->foo" into some other "void *bar". This makes a link between ->foo and bar so that if we get a ->foo out of bar, then we're going to assume it's the same thing that we put there. This works ok in testing. Also I'm putting "ignored" in the function_type_value table just so I can see which things are affected and to help debug any problems. Signed-off-by: Dan Carpenter --- Makefile | 3 +- smatch.h | 1 + smatch_data/db/fill_db_type_value.pl | 3 ++ smatch_type_links.c | 74 ++++++++++++++++++++++++++++++++++++ smatch_type_val.c | 45 ++++++++++++++++++++-- 5 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 smatch_type_links.c diff --git a/Makefile b/Makefile index 1edc978f..3e34ff32 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,8 @@ SMATCH_FILES=smatch_flow.o smatch_conditions.o smatch_slist.o smatch_states.o \ smatch_recurse.o smatch_data_source.o smatch_type_val.o \ smatch_common_functions.o smatch_struct_assignment.o \ smatch_unknown_value.o smatch_stored_conditions.o avl.o \ - smatch_function_info.o smatch_links.o smatch_auto_copy.o + smatch_function_info.o smatch_links.o smatch_auto_copy.o \ + smatch_type_links.o SMATCH_CHECKS=$(shell ls check_*.c | sed -e 's/\.c/.o/') SMATCH_DATA=smatch_data/kernel.allocation_funcs smatch_data/kernel.balanced_funcs \ diff --git a/smatch.h b/smatch.h index 3d7fe9b6..0123a3ac 100644 --- a/smatch.h +++ b/smatch.h @@ -582,6 +582,7 @@ enum info_type { ARRAY_LEN = 1017, CAPABLE = 1018, NS_CAPABLE = 1019, + TYPE_LINK = 1022, /* put random temporary stuff in the 7000-7999 range for testing */ USER_DATA2 = 9017, diff --git a/smatch_data/db/fill_db_type_value.pl b/smatch_data/db/fill_db_type_value.pl index f7225807..5bb2fb79 100755 --- a/smatch_data/db/fill_db_type_value.pl +++ b/smatch_data/db/fill_db_type_value.pl @@ -166,6 +166,9 @@ while (@row = $sth->fetchrow_array()) { @ranges = split(/,/, $row[3]); foreach $range_txt (@ranges) { + if ($range_txt =~ /ignore/) { + next; + } if ($range_txt =~ /(.*[^(])-(.*)/) { $min = text_to_int($1); $max = text_to_int($2); diff --git a/smatch_type_links.c b/smatch_type_links.c new file mode 100644 index 00000000..49eb4fb9 --- /dev/null +++ b/smatch_type_links.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 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 + */ + +/* + * The plan here is to save all the possible values store to a given struct + * member. + * + * We will load all the values in to the function_type_val table first then + * run a script on that and load all the resulting values into the type_val + * table. + * + * So in this file we want to take the union of everything assigned to the + * struct member and insert it into the function_type_val at the end. + * + * You would think that we could use smatch_modification_hooks.c or + * extra_modification_hook() here to get the information here but in the end we + * need to code everything again a third time. + * + */ + +/* + * Remember links like: + * + * foo->void_ptr = some_struct. + * + * If we get a some_struct pointer from foo->void_ptr then assume it's the same + * stuff. + */ + +#include "smatch.h" +#include "smatch_slist.h" +#include "smatch_extra.h" + +static int my_id; + +static void match_assign(struct expression *expr) +{ + struct symbol *type; + + if (!is_void_pointer(expr->left)) + return; + + type = get_type(expr->right); + if (!type || type->type != SYM_PTR) + return; + type = get_real_base_type(type); + if (!type || type->type != SYM_STRUCT) + return; + + sql_insert_data_info(expr->left, TYPE_LINK, type_to_str(type)); +} + +void register_type_links(int id) +{ + if (!option_info) + return; + my_id = id; + + add_hook(&match_assign, ASSIGNMENT_HOOK); +} diff --git a/smatch_type_val.c b/smatch_type_val.c index b3765db5..fbe5fe66 100644 --- a/smatch_type_val.c +++ b/smatch_type_val.c @@ -100,7 +100,7 @@ static void add_type_val(char *member, struct range_list *rl) set_state_stree(&fn_type_val, my_id, member, NULL, new); } -static void add_fake_type_val(char *member, struct range_list *rl) +static void add_fake_type_val(char *member, struct range_list *rl, int ignore) { struct smatch_state *old, *add, *new; @@ -108,12 +108,17 @@ static void add_fake_type_val(char *member, struct range_list *rl) old = get_state_stree(fn_type_val, my_id, member, NULL); if (old && strcmp(old->name, "min-max") == 0) return; + if (ignore && old && strcmp(old->name, "ignore") == 0) + return; add = alloc_estate_rl(rl); if (old) { new = merge_estates(old, add); } else { new = add; - new->name = alloc_string("min-max"); + if (ignore) + new->name = alloc_string("ignore"); + else + new->name = alloc_string("min-max"); } set_state_stree(&fn_type_val, my_id, member, NULL, new); } @@ -133,6 +138,40 @@ static void add_global_type_val(char *member, struct range_list *rl) set_state_stree_perm(&global_type_val, my_id, member, NULL, new); } +static int has_link_cb(void *has_link, int argc, char **argv, char **azColName) +{ + *(int *)has_link = 1; + return 0; +} +static int is_ignored_fake_assignment(void) +{ + struct expression *expr; + struct symbol *type; + char *member_name; + int has_link = 0; + + expr = get_faked_expression(); + if (!expr || expr->type != EXPR_ASSIGNMENT) + return 0; + if (!is_void_pointer(expr->right)) + return 0; + member_name = get_member_name(expr->right); + if (!member_name) + return 0; + + type = get_type(expr->left); + if (!type || type->type != SYM_PTR) + return 0; + type = get_real_base_type(type); + if (!type || type->type != SYM_STRUCT) + return 0; + + run_sql(has_link_cb, &has_link, + "select * from data_info where type = %d and data = '%s' and value = '%s';", + TYPE_LINK, member_name, type_to_str(type)); + return has_link; +} + static void match_assign_value(struct expression *expr) { char *member, *right_member; @@ -153,7 +192,7 @@ static void match_assign_value(struct expression *expr) goto free; if (is_fake_call(expr->right)) { - add_fake_type_val(member, alloc_whole_rl(get_type(expr->left))); + add_fake_type_val(member, alloc_whole_rl(get_type(expr->left)), is_ignored_fake_assignment()); goto free; } -- 2.11.4.GIT