struct_assignment: use the ->zeroed flag from allocations
[smatch.git] / smatch_allocations.c
blob757e93b089ef797cca6c4510e2e90fa9b79a2b63
1 /*
2 * Copyright (C) 2021 Oracle.
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.
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.
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
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <ctype.h>
21 #include "parse.h"
22 #include "smatch.h"
23 #include "smatch_extra.h"
24 #include "smatch_slist.h"
26 static int my_id;
28 DECLARE_PTR_LIST(alloc_hook_list, alloc_hook);
29 static struct alloc_hook_list *hook_funcs_early;
30 static struct alloc_hook_list *hook_funcs;
32 struct alloc_fn_info {
33 const char *name;
34 const char *size;
35 bool zeroed;
38 static struct alloc_fn_info alloc_fns[] = {
39 {"malloc", "$0"},
40 {"calloc", "$0 * $1", .zeroed=true},
41 {"memdup", "$1"},
42 {"realloc", "$1"},
43 { },
46 static struct alloc_fn_info kernel_alloc_funcs[] = {
47 {"__alloc_skb", "$0"},
49 {"devm_kmalloc", "$1"},
50 {"devm_kzalloc", "$1", .zeroed=true},
51 {"devm_kmalloc_array", "$1 * $2"},
52 {"devm_kcalloc", "$1 * $2", .zeroed=true},
54 {"dma_alloc_attrs", "$1", .zeroed=true},
55 {"dma_alloc_coherent", "$1", .zeroed=true},
56 {"dma_alloc_contiguous", "$1"},
58 {"krealloc", "$1"},
60 {"kmalloc", "$0"},
61 {"kmalloc_node", "$0"},
62 {"kzalloc", "$0", .zeroed=true},
63 {"kzalloc_node", "$0", .zeroed=true},
65 {"kmalloc_array", "$0 * $1"},
66 {"kcalloc", "$0 * $1", .zeroed=true},
68 {"vmalloc", "$0"},
69 {"__vmalloc", "$0"},
70 {"vzalloc", "$0", .zeroed=true},
72 {"kvmalloc", "$0"},
73 {"kvmalloc_array", "$0 * $1"},
74 {"kvmalloc_node", "$0"},
75 {"kvzalloc", "$0", .zeroed=true},
76 {"kvcalloc", "$0 * $1", .zeroed=true},
77 {"kvzalloc_node", "$0", .zeroed=true},
78 {"kvrealloc", "$2"},
80 {"kmemdup", "$1"},
81 {"devm_kmemdup", "$2"},
82 {"memdup_user", "$1"},
84 {"sock_kmalloc", "$1"},
86 #if 0
87 {"get_zeroed_page", {"PAGE_SIZE", zeroed=true}},
88 {"alloc_page", {"PAGE_SIZE"}},
89 {"alloc_pages", {"(1 < $0) * PAGE_SIZE"}},
90 {"alloc_pages_current", {"(1 < $0) * PAGE_SIZE"}},
91 {"__get_free_pages", {"(1 < $0) * PAGE_SIZE"}},
92 #endif
93 { },
96 void add_allocation_hook(alloc_hook *hook)
98 add_ptr_list(&hook_funcs, hook);
101 void add_allocation_hook_early(alloc_hook *hook)
103 add_ptr_list(&hook_funcs_early, hook);
106 static void load_size_data(struct allocation_info *data, struct expression *expr, const char *size_str)
108 struct expression *call, *arg1, *arg2;
109 const char *p;
110 int op;
111 int param;
113 if (!size_str)
114 return;
116 p = size_str;
117 if (*p != '$')
118 return;
119 p++;
120 if (!isdigit(*p))
121 return;
122 param = atoi(p);
124 call = get_assigned_call(expr);
125 if (!call)
126 return;
127 arg1 = get_argument_from_call_expr(call->args, param);
128 if (!arg1)
129 return;
131 p++;
132 if (*p == '\0') {
133 data->total_size = arg1;
134 return;
136 while (*p == ' ')
137 p++;
138 op = *p;
139 if (op != '*' && op != '+')
140 return;
141 p++;
142 while (p[0] == ' ')
143 p++;
144 if (p[0] != '$' || !isdigit(p[1]))
145 return;
146 p++;
147 param = atoi(p);
148 arg2 = get_argument_from_call_expr(call->args, param);
149 if (!arg2)
150 return;
152 if (op == '*') {
153 data->nr_elems = arg1;
154 data->elem_size = arg2;
158 static void match_alloc_helper(struct alloc_hook_list *hooks, struct expression *expr, const char *name, struct symbol *sym, void *_info)
160 struct alloc_fn_info *info = _info;
161 struct allocation_info data = { };
162 alloc_hook *fn;
164 data.fn_name = info->name;
165 data.size_str = info->size;
166 data.zeroed = info->zeroed;
167 load_size_data(&data, expr, info->size);
169 FOR_EACH_PTR(hooks, fn) {
170 fn(expr, name, sym, &data);
171 } END_FOR_EACH_PTR(fn);
174 static void match_alloc_early(struct expression *expr, const char *name, struct symbol *sym, void *_info)
176 match_alloc_helper(hook_funcs_early, expr, name, sym, _info);
179 static void match_alloc(struct expression *expr, const char *name, struct symbol *sym, void *_info)
181 match_alloc_helper(hook_funcs, expr, name, sym, _info);
184 void register_allocations(int id)
186 struct alloc_fn_info *info;
188 my_id = id;
190 if (option_project == PROJ_KERNEL)
191 info = kernel_alloc_funcs;
192 else
193 info = alloc_fns;
195 while (info->name) {
196 add_function_param_key_hook_early(info->name, &match_alloc_early, -1, "$", info);
197 add_function_param_key_hook(info->name, &match_alloc, -1, "$", info);
198 info++;