From ff84c4142894620d19a914a44401080272ff07b7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Mar 2009 07:11:18 +0300 Subject: [PATCH] new api: add_conditional_hook(), set_cond_states(); add_conditional_hook() if for code where the condition is a function call like this: if(foo()) { ... instead of calling set_true_false_states() inside a condition hook you call set_cond_states(). Currently that is the exact same as set_true_false_states() but later it will let us handle things like: x = _spin_trylock(); if (x) { ... Signed-off-by: Dan Carpenter --- Makefile | 3 +- check_locking.c | 67 ++++++++++++++-------------- smatch.c | 2 + smatch.h | 13 ++++++ smatch_condition_functions.c | 101 +++++++++++++++++++++++++++++++++++++++++++ smatch_function_hooks.c | 17 +++----- 6 files changed, 158 insertions(+), 45 deletions(-) create mode 100644 smatch_condition_functions.c diff --git a/Makefile b/Makefile index 837e18b6..5f382a3a 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ PKGCONFIGDIR=$(LIBDIR)/pkgconfig PROGRAMS=test-lexing test-parsing obfuscate compile graph sparse test-linearize example \ test-unssa test-dissect ctags smatch -SMATCH_FILES=smatch_flow.o smatch_conditions.o smatch_slist.o smatch_states.o smatch_helper.o smatch_hooks.o smatch_function_hooks.o smatch_extra.o smatch_implied.o smatch_ignore.o smatch_tracker.o +SMATCH_FILES=smatch_flow.o smatch_conditions.o smatch_slist.o smatch_states.o smatch_helper.o smatch_hooks.o smatch_function_hooks.o smatch_condition_functions.o smatch_extra.o smatch_implied.o smatch_ignore.o smatch_tracker.o SMATCH_CHECKS=$(shell ls check_*.c | sed -e 's/\.c/.o/') @@ -176,6 +176,7 @@ smatch_ignore.o: $(LIB_H) smatch.h smatch_tracker.o: $(LIB_H) smatch.h smatch_hooks.o: $(LIB_H) smatch.h smatch_function_hooks.o: $(LIB_H) smatch.h +smatch_condition_functions.o: $(LIB_H) smatch.h smatch_helper.o: $(LIB_H) smatch.h smatch_slist.o: $(LIB_H) smatch.h smatch_slist.h smatch_states.o: $(LIB_H) smatch.h smatch_slist.h diff --git a/check_locking.c b/check_locking.c index 00579467..65530277 100644 --- a/check_locking.c +++ b/check_locking.c @@ -139,21 +139,6 @@ static struct smatch_state *unmatched_state(struct sm_state *sm) return &start_state; } -static char *match_func(const char *list[], char *fn_name, - struct expression_list *args) -{ - struct expression *lock_expr; - int i; - - for (i = 0; list[i]; i++) { - if (!strcmp(fn_name, list[i])) { - lock_expr = get_argument_from_call_expr(args, 0); - return get_variable_from_expr(lock_expr, NULL); - } - } - return NULL; -} - static char *get_lock_name(struct expression *expr, void *data) { struct expression *lock_expr; @@ -220,31 +205,36 @@ static void match_lock_needed(const char *fn, struct expression *expr, free_string(fn_name); } -static void match_condition(struct expression *expr) +static void match_locks_on_zero(const char *fn, struct expression *expr, + void *data) { - char *fn_name; char *lock_name; + struct sm_state *sm; - if (expr->type != EXPR_CALL) + lock_name = get_lock_name(expr, data); + if (!lock_name) return; + sm = get_sm_state(lock_name, my_id, NULL); + if (!sm) + add_tracker(&starts_unlocked, lock_name, my_id, NULL); + set_cond_states(lock_name, my_id, NULL, &unlocked, &locked); + free_string(lock_name); +} - fn_name = get_variable_from_expr(expr->fn, NULL); - if (!fn_name) - return; +static void match_locks_on_non_zero(const char *fn, struct expression *expr, + void *data) +{ + char *lock_name; + struct sm_state *sm; - if ((lock_name = match_func(conditional_funcs, fn_name, expr->args))) { - if (!get_state(lock_name, my_id, NULL)) - add_tracker(&starts_unlocked, lock_name, my_id, NULL); - set_true_false_states(lock_name, my_id, NULL, &locked, &unlocked); - } - if ((lock_name = match_func(reverse_cond_funcs, fn_name, expr->args))) { - if (!get_state(lock_name, my_id, NULL)) - add_tracker(&starts_unlocked, lock_name, my_id, NULL); - set_true_false_states(lock_name, my_id, NULL, &unlocked, &locked); - } + lock_name = get_lock_name(expr, data); + if (!lock_name) + return; + sm = get_sm_state(lock_name, my_id, NULL); + if (!sm) + add_tracker(&starts_unlocked, lock_name, my_id, NULL); + set_cond_states(lock_name, my_id, NULL, &locked, &unlocked); free_string(lock_name); - free_string(fn_name); - return; } static struct locks_on_return *alloc_return(int line) @@ -401,7 +391,6 @@ void check_locking(int id) my_id = id; add_unmatched_state_hook(my_id, &unmatched_state); - add_hook(&match_condition, CONDITION_HOOK); add_hook(&match_return, RETURN_HOOK); add_hook(&match_func_end, END_FUNC_HOOK); @@ -417,4 +406,14 @@ void check_locking(int id) add_function_hook(lock_needed[i].function, &match_lock_needed, (void *)lock_needed[i].lock); } + + for (i = 0; conditional_funcs[i]; i++) { + add_conditional_hook(conditional_funcs[i], + &match_locks_on_non_zero, NULL); + } + + for (i = 0; reverse_cond_funcs[i]; i++) { + add_conditional_hook(reverse_cond_funcs[i], + &match_locks_on_zero, NULL); + } } diff --git a/smatch.c b/smatch.c index 433933f5..5082fb63 100644 --- a/smatch.c +++ b/smatch.c @@ -15,6 +15,7 @@ void register_smatch_extra(int id); void register_smatch_ignore(int id); void register_implications(int id); void register_function_hooks(int id); +void register_conditional_function_hooks(int id); void check_null_deref(int id); void check_overflow(int id); void check_locking(int id); @@ -55,6 +56,7 @@ int main(int argc, char **argv) reg_func func; register_function_hooks(-1); + register_conditional_function_hooks(-1); /* The script IDs start at 1. 0 is used for internal stuff. */ for(i = 0; (func = reg_funcs[i]); i++){ diff --git a/smatch.h b/smatch.h index 4e0f7e6e..e43102c3 100644 --- a/smatch.h +++ b/smatch.h @@ -69,6 +69,11 @@ void add_unmatched_state_hook(int client_id, unmatched_func_t *func); typedef void (func_hook)(const char *fn, struct expression *expr, void *data); void add_function_hook(const char *lock_for, func_hook *call_back, void *data); +void add_conditional_hook(const char *look_for, func_hook *call_back, void *data); +void set_cond_states(const char *name, int owner, struct symbol *sym, + struct smatch_state *true_state, + struct smatch_state *false_state); + #define smatch_msg(msg...) \ do { \ printf("%s +%d %s(%d) ", get_filename(), get_lineno(), \ @@ -238,4 +243,12 @@ struct smatch_state *__client_merge_function(int owner, const char *name, struct smatch_state *s2); struct smatch_state *__client_unmatched_state_function(struct sm_state *sm); +/* smatch_function_hooks.c */ +struct fcall_back { + func_hook *call_back; + void *data; +}; +DECLARE_ALLOCATOR(fcall_back); +DECLARE_PTR_LIST(call_back_list, struct fcall_back); + #endif /* !SMATCH_H_ */ diff --git a/smatch_condition_functions.c b/smatch_condition_functions.c new file mode 100644 index 00000000..c03236ee --- /dev/null +++ b/smatch_condition_functions.c @@ -0,0 +1,101 @@ +#define _GNU_SOURCE +#include +#include +#include +#include "smatch.h" +#include "smatch_slist.h" + +static struct state_list *cond_true = NULL; +static struct state_list *cond_false = NULL; +static struct hsearch_data func_hash; +static int in_hook = 0; + +void add_conditional_hook(const char *look_for, func_hook *call_back, + void *data) +{ + ENTRY e, *ep; + struct fcall_back *cb; + + cb = __alloc_fcall_back(0); + cb->call_back = call_back; + cb->data = data; + e.key = alloc_string(look_for); + hsearch_r(e, FIND, &ep, &func_hash); + if (!ep) { + struct call_back_list *list = NULL; + + add_ptr_list(&list, cb); + e.data = list; + } else { + free_string(ep->key); + add_ptr_list((struct call_back_list **)&ep->data, cb); + e.data = ep->data; + } + hsearch_r(e, ENTER, &ep, &func_hash); +} + +void set_cond_states(const char *name, int owner, struct symbol *sym, + struct smatch_state *true_state, + struct smatch_state *false_state) +{ + if (!in_hook) { + printf("Error: call set_true_false_states() not" + "set_cond_states()\n"); + return; + } + + if (debug_states) { + struct smatch_state *tmp; + + tmp = get_state(name, owner, sym); + SM_DEBUG("%d set_true_false '%s'. Was %s. Now T:%s F:%s\n", + get_lineno(), name, show_state(tmp), + show_state(true_state), show_state(false_state)); + } + + if (true_state) { + set_state_slist(&cond_true, name, owner, sym, true_state); + } + if (false_state) + set_state_slist(&cond_false, name, owner, sym, false_state); +} + +static void match_conditional_call(struct expression *expr) +{ + ENTRY e, *ep; + struct fcall_back *tmp; + struct sm_state *sm; + + if (expr->type != EXPR_CALL) + return; + + if (expr->fn->type != EXPR_SYMBOL || !expr->fn->symbol) + return; + + e.key = expr->fn->symbol->ident->name; + hsearch_r(e, FIND, &ep, &func_hash); + if (!ep) + return; + in_hook = 1; + FOR_EACH_PTR((struct call_back_list *)ep->data, tmp) { + (tmp->call_back)(e.key, expr, tmp->data); + + FOR_EACH_PTR(cond_true, sm) { + __set_true_false_sm(sm, NULL); + } END_FOR_EACH_PTR(sm); + free_slist(&cond_true); + + FOR_EACH_PTR(cond_false, sm) { + __set_true_false_sm(NULL, sm); + } END_FOR_EACH_PTR(sm); + free_slist(&cond_false); + + } END_FOR_EACH_PTR(tmp); + in_hook = 0; +} + +void register_conditional_function_hooks(int id) +{ + hcreate_r(500, &func_hash); + add_hook(&match_conditional_call, CONDITION_HOOK); +} diff --git a/smatch_function_hooks.c b/smatch_function_hooks.c index f13edf44..bef65e09 100644 --- a/smatch_function_hooks.c +++ b/smatch_function_hooks.c @@ -1,15 +1,12 @@ +#define _GNU_SOURCE #include #include #include #include "smatch.h" -struct fcall_back { - func_hook *call_back; - void *data; -}; - ALLOCATOR(fcall_back, "call backs"); -DECLARE_PTR_LIST(call_back_list, struct fcall_back); + +static struct hsearch_data func_hash; void add_function_hook(const char *look_for, func_hook *call_back, void *data) { @@ -20,7 +17,7 @@ void add_function_hook(const char *look_for, func_hook *call_back, void *data) cb->call_back = call_back; cb->data = data; e.key = alloc_string(look_for); - ep = hsearch(e, FIND); + hsearch_r(e, FIND, &ep, &func_hash); if (!ep) { struct call_back_list *list = NULL; @@ -31,7 +28,7 @@ void add_function_hook(const char *look_for, func_hook *call_back, void *data) add_ptr_list((struct call_back_list **)&ep->data, cb); e.data = ep->data; } - hsearch(e, ENTER); + hsearch_r(e, ENTER, &ep, &func_hash); } static void match_function_call(struct expression *expr) @@ -43,7 +40,7 @@ static void match_function_call(struct expression *expr) return; e.key = expr->fn->symbol->ident->name; - ep = hsearch(e, FIND); + hsearch_r(e, FIND, &ep, &func_hash); if (!ep) return; @@ -54,6 +51,6 @@ static void match_function_call(struct expression *expr) void register_function_hooks(int id) { - hcreate(1000); // We will track maybe 1000 functions. + hcreate_r(1000, &func_hash); // We will track maybe 1000 functions. add_hook(&match_function_call, FUNCTION_CALL_HOOK); } -- 2.11.4.GIT