1 /*
2  * Copyright (C) 2010 Dan Carpenter.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16  */
17 
18 /*
19  * The kernel has a small stack so putting huge structs and arrays on the
20  * stack is a bug.
21  *
22  */
23 
24 #include "smatch.h"
25 
26 static int my_id;
27 
28 static int total_size;
29 static int max_size;
30 static int max_lineno;
31 static int complained;
32 
33 #define MAX_ALLOWED 1000
34 
scope_end(void * _size)35 static void scope_end(void *_size)
36 {
37 	int size = PTR_INT(_size);
38 	total_size -= size;
39 }
40 
match_declarations(struct symbol * sym)41 static void match_declarations(struct symbol *sym)
42 {
43 	struct symbol *base;
44 	const char *name;
45 
46 	base = get_base_type(sym);
47 	if (sym->ctype.modifiers & MOD_STATIC)
48 		return;
49 	name = sym->ident->name;
50 	total_size += type_bytes(base);
51 	if (total_size > max_size) {
52 		max_size = total_size;
53 		max_lineno = get_lineno();
54 	}
55 	if (type_bytes(base) >= MAX_ALLOWED) {
56 		complained = 1;
57 		sm_warning("'%s' puts %d bytes on stack", name, type_bytes(base));
58 	}
59 	add_scope_hook(&scope_end, INT_PTR(type_bytes(base)));
60 }
61 
match_end_func(struct symbol * sym)62 static void match_end_func(struct symbol *sym)
63 {
64 	if (__inline_fn)
65 		return;
66 
67 	if ((max_size >= MAX_ALLOWED) && !complained) {
68 		sm_printf("%s:%d %s() ", get_filename(), max_lineno, get_function());
69 		sm_printf("warn: function puts %d bytes on stack\n", max_size);
70 	}
71 	total_size = 0;
72 	complained = 0;
73 	max_size = 0;
74 	max_lineno = 0;
75 }
76 
check_stack(int id)77 void check_stack(int id)
78 {
79 	if (option_project != PROJ_KERNEL || !option_spammy)
80 		return;
81 
82 	my_id = id;
83 	add_hook(&match_declarations, DECLARATION_HOOK);
84 	add_hook(&match_end_func, END_FUNC_HOOK);
85 }
86