From 88fd7579929d7d605d0ef76c839bf3542a8b54ba Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 2 Feb 2009 12:44:20 +0300 Subject: [PATCH] Add a new check_locking script that checks spinlocks. Signed-off-by: Dan Carpenter --- check_locking.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ smatch.c | 2 + 2 files changed, 128 insertions(+) create mode 100644 check_locking.c diff --git a/check_locking.c b/check_locking.c new file mode 100644 index 00000000..506880e8 --- /dev/null +++ b/check_locking.c @@ -0,0 +1,126 @@ +/* + * sparse/check_locking.c + * + * Copyright (C) 2009 Dan Carpenter. + * + * Licensed under the Open Software License version 1.1 + * + */ + +/* + * For this test let's look for functions that return a negative value + * with a spinlock held. + * + * One short coming is that it assumes a function isn't supposed + * to return negative with a lock held. Perhaps the function was + * called with the lock held. A more complicated script could check that. + * + */ + +#include "parse.h" +#include "smatch.h" +#include "smatch_slist.h" // blast this was supposed to be internal only stuff + +static int my_id; + +STATE(lock); +STATE(unlock); + +/* + * merge_func() can go away when we fix the core to just store all the possible + * states. + * + * The parameters are passed in alphabetical order with NULL at the beginning + * of the alphabet. (s2 is never NULL). + */ + +static struct smatch_state *merge_func(const char *name, struct symbol *sym, + struct smatch_state *s1, + struct smatch_state *s2) +{ + if (s1 == NULL) + return s2; + return &undefined; + +} + +static void match_call(struct expression *expr) +{ + char *fn_name; + struct expression *spin_expr; + char *spin_name; + + fn_name = get_variable_from_expr(expr->fn, NULL); + if (!fn_name || (strcmp(fn_name, "_spin_lock") && strcmp(fn_name, "_spin_unlock"))) + return; + + spin_expr = get_argument_from_call_expr(expr->args, 0); + spin_name = get_variable_from_expr(spin_expr, NULL); + if (!strcmp(fn_name, "_spin_lock")) { + set_state(spin_name, my_id, NULL, &lock); + } else { + set_state(spin_name, my_id, NULL, &unlock); + } + free_string(fn_name); +} + +static void match_condition(struct expression *expr) +{ + /* __raw_spin_is_locked */ +} + +static int possibly_negative(struct expression *expr) +{ + char *name; + struct symbol *sym; + struct state_list *slist; + struct sm_state *tmp; + + name = get_variable_from_expr(expr, &sym); + if (!name || !sym) + return 0; + slist = get_possible_states(name, SMATCH_EXTRA, sym); + FOR_EACH_PTR(slist, tmp) { + int value = 0; + + if (tmp->state->data) + value = *(int *)tmp->state->data; + + if (value < 0) { + return 1; + } + 1; + } END_FOR_EACH_PTR(tmp); + return 0; +} + +static void match_return(struct statement *stmt) +{ + int ret_val; + struct state_list *slist; + struct sm_state *tmp; + + ret_val = get_value(stmt->ret_value); + if (ret_val >= 0) { + return; + } + if (ret_val == UNDEFINED) { + if (!possibly_negative(stmt->ret_value)) + return; + } + + slist = get_all_states(my_id); + FOR_EACH_PTR(slist, tmp) { + if (tmp->state != &unlock) + smatch_msg("returned negative with %s spinlock held", + tmp->name); + } END_FOR_EACH_PTR(tmp); +} + +void register_locking(int id) +{ + my_id = id; + add_merge_hook(my_id, &merge_func); + add_hook(&match_call, FUNCTION_CALL_HOOK); + add_hook(&match_return, RETURN_HOOK); +} diff --git a/smatch.c b/smatch.c index 5a7e992d..03b29ee8 100644 --- a/smatch.c +++ b/smatch.c @@ -16,6 +16,7 @@ void register_null_deref(int id); void register_smatch_extra(int id); void register_smatch_ignore(int id); void register_overflow(int id); +void register_locking(int id); /* <- your test goes here */ /* void register_template(int id); */ @@ -24,6 +25,7 @@ const reg_func reg_funcs[] = { ®ister_smatch_ignore, ®ister_null_deref, ®ister_overflow, + ®ister_locking, /* <- your test goes here */ /* ®ister_template, */ NULL -- 2.11.4.GIT