Or vs and: warn about bitwise ANDs that always give zero
[smatch.git] / check_dev_queue_xmit.c
bloba746a7aaadeec4f95cc31c4ce25f3eee65361510
1 /*
2 * sparse/check_dev_queue_xmit.c
4 * Copyright (C) 2010 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * According to an email on lkml you are not allowed to reuse the skb
12 * passed to dev_queue_xmit()
16 #include "smatch.h"
17 #include "smatch_slist.h"
19 static int my_id;
21 STATE(do_not_use);
23 static void ok_to_use(struct sm_state *sm)
25 set_state(my_id, sm->name, sm->sym, &undefined);
28 static int valid_use(void)
30 struct expression *tmp;
31 int i = 0;
32 int dot_ops = 0;
34 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
35 if (!i++)
36 continue;
37 if (tmp->type == EXPR_PREOP && tmp->op == '(')
38 continue;
39 if (tmp->op == '.' && !dot_ops++)
40 continue;
41 // if (tmp->type == EXPR_POSTOP)
42 // return 1;
43 if (tmp->type == EXPR_CALL && sym_name_is("kfree_skb", tmp->fn))
44 return 1;
45 return 0;
46 } END_FOR_EACH_PTR_REVERSE(tmp);
47 return 0;
50 /* match symbol is expensive. only turn it on after we match the xmit function */
51 static int match_symbol_active;
52 static void match_symbol(struct expression *expr)
54 struct sm_state *sm;
55 char *name;
57 sm = get_sm_state_expr(my_id, expr);
58 if (!sm || !slist_has_state(sm->possible, &do_not_use))
59 return;
60 if (valid_use())
61 return;
62 name = get_variable_from_expr(expr, NULL);
63 sm_msg("error: '%s' was already used up by dev_queue_xmit()", name);
64 free_string(name);
67 static void match_kfree_skb(const char *fn, struct expression *expr, void *param)
69 struct expression *arg;
71 arg = get_argument_from_call_expr(expr->args, 0);
72 if (!arg)
73 return;
74 delete_state_expr(my_id, arg);
77 static void match_xmit(const char *fn, struct expression *expr, void *param)
79 struct expression *arg;
81 arg = get_argument_from_call_expr(expr->args, PTR_INT(param));
82 if (!arg)
83 return;
84 set_state_expr(my_id, arg, &do_not_use);
85 if (!match_symbol_active++) {
86 add_hook(&match_symbol, SYM_HOOK);
87 add_function_hook("kfree_skb", &match_kfree_skb, NULL);
91 static void register_funcs_from_file(void)
93 struct token *token;
94 const char *func;
95 int arg;
97 token = get_tokens_file("kernel.dev_queue_xmit");
98 if (!token)
99 return;
100 if (token_type(token) != TOKEN_STREAMBEGIN)
101 return;
102 token = token->next;
103 while (token_type(token) != TOKEN_STREAMEND) {
104 if (token_type(token) != TOKEN_IDENT)
105 return;
106 func = show_ident(token->ident);
107 token = token->next;
108 if (token_type(token) != TOKEN_NUMBER)
109 return;
110 arg = atoi(token->number);
111 add_function_hook(func, &match_xmit, INT_PTR(arg));
112 token = token->next;
114 clear_token_alloc();
117 void check_dev_queue_xmit(int id)
119 if (option_project != PROJ_KERNEL || !option_spammy)
120 return;
121 my_id = id;
122 add_modification_hook(my_id, ok_to_use);
123 register_funcs_from_file();