allocations: add some more allocation functions
[smatch.git] / smatch_allocations.c
blob09858399d04bca6c4d0073b81e34e71dc1cc9b02
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 {"comedi_alloc_spriv", "$1", .zeroed=true},
51 {"devm_kmalloc", "$1"},
52 {"devm_kzalloc", "$1", .zeroed=true},
53 {"devm_kmalloc_array", "$1 * $2"},
54 {"devm_kcalloc", "$1 * $2", .zeroed=true},
56 {"dma_alloc_attrs", "$1", .zeroed=true},
57 {"dma_alloc_coherent", "$1", .zeroed=true},
58 {"dma_alloc_contiguous", "$1"},
60 {"krealloc", "$1"},
62 {"kmalloc", "$0"},
63 {"kmalloc_node", "$0"},
64 {"kmalloc_noprof", "$0"},
65 {"kzalloc", "$0", .zeroed=true},
66 {"kzalloc_node", "$0", .zeroed=true},
67 {"kzalloc_noprof", "$0", .zeroed=true},
69 {"kmalloc_array", "$0 * $1"},
70 {"kcalloc", "$0 * $1", .zeroed=true},
72 {"vmalloc", "$0"},
73 {"__vmalloc", "$0"},
74 {"vzalloc", "$0", .zeroed=true},
76 {"kvmalloc", "$0"},
77 {"kvmalloc_array", "$0 * $1"},
78 {"kvmalloc_node", "$0"},
79 {"kvzalloc", "$0", .zeroed=true},
80 {"kvcalloc", "$0 * $1", .zeroed=true},
81 {"kvzalloc_node", "$0", .zeroed=true},
82 {"kvrealloc", "$2"},
84 {"kmemdup", "$1"},
85 {"devm_kmemdup", "$2"},
86 {"memdup_user", "$1"},
88 {"sk_alloc", ""},
89 {"sk_prot_alloc", ""},
90 {"sock_kmalloc", "$1"},
92 #if 0
93 {"get_zeroed_page", {"PAGE_SIZE", zeroed=true}},
94 {"alloc_page", {"PAGE_SIZE"}},
95 {"alloc_pages", {"(1 < $0) * PAGE_SIZE"}},
96 {"alloc_pages_current", {"(1 < $0) * PAGE_SIZE"}},
97 {"__get_free_pages", {"(1 < $0) * PAGE_SIZE"}},
98 #endif
99 { },
102 void add_allocation_hook(alloc_hook *hook)
104 add_ptr_list(&hook_funcs, hook);
107 void add_allocation_hook_early(alloc_hook *hook)
109 add_ptr_list(&hook_funcs_early, hook);
112 static void load_size_data(struct allocation_info *data, struct expression *expr, const char *size_str)
114 struct expression *call, *arg1, *arg2;
115 const char *p;
116 int op;
117 int param;
119 if (!size_str)
120 return;
122 p = size_str;
123 if (*p != '$')
124 return;
125 p++;
126 if (!isdigit(*p))
127 return;
128 param = atoi(p);
130 call = get_assigned_call(expr);
131 if (!call)
132 return;
133 arg1 = get_argument_from_call_expr(call->args, param);
134 if (!arg1)
135 return;
137 p++;
138 if (*p == '\0') {
139 data->total_size = arg1;
140 return;
142 while (*p == ' ')
143 p++;
144 op = *p;
145 if (op != '*' && op != '+')
146 return;
147 p++;
148 while (p[0] == ' ')
149 p++;
150 if (p[0] != '$' || !isdigit(p[1]))
151 return;
152 p++;
153 param = atoi(p);
154 arg2 = get_argument_from_call_expr(call->args, param);
155 if (!arg2)
156 return;
158 if (op == '*') {
159 data->nr_elems = arg1;
160 data->elem_size = arg2;
164 static void match_alloc_helper(struct alloc_hook_list *hooks, struct expression *expr, const char *name, struct symbol *sym, void *_info)
166 struct alloc_fn_info *info = _info;
167 struct allocation_info data = { };
168 alloc_hook *fn;
170 data.fn_name = info->name;
171 data.size_str = info->size;
172 data.zeroed = info->zeroed;
173 load_size_data(&data, expr, info->size);
175 FOR_EACH_PTR(hooks, fn) {
176 fn(expr, name, sym, &data);
177 } END_FOR_EACH_PTR(fn);
180 static void match_alloc_early(struct expression *expr, const char *name, struct symbol *sym, void *_info)
182 match_alloc_helper(hook_funcs_early, expr, name, sym, _info);
185 static void match_alloc(struct expression *expr, const char *name, struct symbol *sym, void *_info)
187 match_alloc_helper(hook_funcs, expr, name, sym, _info);
190 void register_allocations(int id)
192 struct alloc_fn_info *info;
194 my_id = id;
196 if (option_project == PROJ_KERNEL)
197 info = kernel_alloc_funcs;
198 else
199 info = alloc_fns;
201 while (info->name) {
202 add_function_param_key_hook_early(info->name, &match_alloc_early, -1, "$", info);
203 add_function_param_key_hook(info->name, &match_alloc, -1, "$", info);
204 info++;