From 4cbf1feaaf09cfa2fc713198234a62fd56ddbcd1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 30 Mar 2009 19:18:30 +0300 Subject: [PATCH] Add check_type.c (disabled) You are supposed to use kfree_skb() to free sk_buffs not kfree(). There was a bug to do with this in a 2.6.29-rc kernel. Check type.c checks for these kinds of bugs. The script finds the bug which was fixed in the final kernel but it doesn't find any other bugs besides this. It's disabled by default. Signed-off-by: Dan Carpenter --- check_type.c | 36 ++++++++++++++++++++++++++ smatch.c | 2 ++ smatch.h | 1 + smatch_helper.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 check_type.c diff --git a/check_type.c b/check_type.c new file mode 100644 index 00000000..5f2605bd --- /dev/null +++ b/check_type.c @@ -0,0 +1,36 @@ +/* + * sparse/check_type.c + * + * Copyright (C) 2009 Dan Carpenter. + * + * Licensed under the Open Software License version 1.1 + * + */ + +#include "smatch.h" + +static int my_id; + +static void match_free(const char *fn, struct expression *expr, void *data) +{ + struct expression *arg_expr; + char *name; + struct symbol *sym; + struct symbol *type; + + arg_expr = get_argument_from_call_expr(expr->args, 0); + name = get_variable_from_expr(arg_expr, &sym); + if (!name ||!sym) + goto exit; + type = get_ptr_type(arg_expr); + if (type && type->ident && !strcmp("sk_buff", type->ident->name)) + smatch_msg("error: use kfree_skb() here instead of kfree()"); +exit: + free_string(name); +} + +void check_type(int id) +{ + my_id = id; + add_function_hook("kfree", &match_free, NULL); +} diff --git a/smatch.c b/smatch.c index d0e74648..d0666680 100644 --- a/smatch.c +++ b/smatch.c @@ -24,6 +24,7 @@ void check_locking(int id); void check_memory(int id); void check_frees_argument(int id); void check_leaks(int id); +void check_type(int id); void check_allocation_funcs(int id); /* <- your test goes here */ /* void register_template(int id); */ @@ -35,6 +36,7 @@ static const reg_func reg_funcs[] = { &check_overflow, &check_locking, &check_memory, + // &check_type, // &check_allocation_funcs, // &check_leaks, // &check_frees_argument, diff --git a/smatch.h b/smatch.h index 52e3aa7f..8e3c8244 100644 --- a/smatch.h +++ b/smatch.h @@ -116,6 +116,7 @@ char *get_variable_from_expr_complex(struct expression *expr, struct symbol **sym_ptr); char *get_variable_from_expr(struct expression *expr, struct symbol **sym_ptr); +struct symbol *get_ptr_type(struct expression *expr); int sym_name_is(const char *name, struct expression *expr); int get_value(struct expression *expr); int is_zero(struct expression *expr); diff --git a/smatch_helper.c b/smatch_helper.c index d51c03df..a3ae6b2b 100644 --- a/smatch_helper.c +++ b/smatch_helper.c @@ -263,6 +263,86 @@ char *get_variable_from_expr(struct expression *expr, return alloc_string(var_name); } +struct symbol *get_ptr_type_ptr(struct symbol *sym) +{ + if (!sym) { + return NULL; + } + + if (sym->type != SYM_NODE) + return NULL; + sym = get_base_type(sym); + if (sym->type != SYM_PTR) + return NULL; + sym = get_base_type(sym); + return sym; +} + +static struct symbol *get_struct_sym(struct expression *expr) +{ + struct symbol *base_type; + struct symbol *parent_struct; + struct symbol *tmp; + + if (expr->type != EXPR_PREOP) + return NULL; + + expr = expr->unop; + if (expr->type == EXPR_DEREF) { + parent_struct = get_struct_sym(expr->deref); + if (!parent_struct) + return NULL; + tmp = NULL; + FOR_EACH_PTR(parent_struct->symbol_list, tmp) { + if (tmp->ident == expr->member) + break; + } END_FOR_EACH_PTR(tmp); + if (!tmp || tmp->ident != expr->member) + return NULL; + base_type = get_base_type(tmp); + } else if (expr->type == EXPR_SYMBOL) { + base_type = get_base_type(expr->symbol); + } else { + return NULL; + } + if (base_type->type != SYM_PTR) + return NULL; + base_type = get_base_type(base_type); + if (base_type->type != SYM_STRUCT && base_type->type != SYM_UNION) + return NULL; + return base_type; +} + +struct symbol *get_deref_type(struct expression *expr) +{ + struct ident *member = expr->member; + struct symbol *struct_sym; + struct symbol *tmp; + + struct_sym = get_struct_sym(expr->deref); + if (!struct_sym || (struct_sym->type != SYM_STRUCT + && struct_sym->type != SYM_UNION)) + return NULL; + FOR_EACH_PTR(struct_sym->symbol_list, tmp) { + if (tmp->ident == member) + return get_ptr_type_ptr(tmp); + } END_FOR_EACH_PTR(tmp); + return NULL; +} + +struct symbol *get_ptr_type(struct expression *expr) +{ + struct symbol *ptr_type = NULL; + + if (!expr) + return NULL; + if (expr->type == EXPR_DEREF) + ptr_type = get_deref_type(expr); + if (expr->type == EXPR_SYMBOL) + ptr_type = get_ptr_type_ptr(expr->symbol); + return ptr_type; +} + int sym_name_is(const char *name, struct expression *expr) { if (!expr) -- 2.11.4.GIT