unwind: ignore path states in pre-merge hook
[smatch.git] / smatch_allocations.c
blobfe40144e93e3d4776d3833e8f0d236ec50e73bf9
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;
31 struct alloc_fn_info {
32 const char *name;
33 const char *size;
34 bool zeroed;
37 static struct alloc_fn_info alloc_fns[] = {
38 {"malloc", "$0"},
39 {"calloc", "$0 * $1", .zeroed=true},
40 {"memdup", "$1"},
41 {"realloc", "$1"},
42 { },
45 static struct alloc_fn_info kernel_alloc_funcs[] = {
46 {"__alloc_skb", "$0"},
48 {"devm_kmalloc", "$1"},
49 {"devm_kzalloc", "$1", .zeroed=true},
50 {"devm_kmalloc_array", "$1 * $2"},
51 {"devm_kcalloc", "$1 * $2", .zeroed=true},
53 {"dma_alloc_attrs", "$1", .zeroed=true},
54 {"dma_alloc_coherent", "$1", .zeroed=true},
55 {"dma_alloc_contiguous", "$1"},
57 {"krealloc", "$1"},
59 {"kmalloc", "$0"},
60 {"kmalloc_node", "$0"},
61 {"kzalloc", "$0", .zeroed=true},
62 {"kzalloc_node", "$0", .zeroed=true},
64 {"kmalloc_array", "$0 * $1"},
65 {"kcalloc", "$0 * $1", .zeroed=true},
67 {"vmalloc", "$0"},
68 {"__vmalloc", "$0"},
69 {"vzalloc", "$0", .zeroed=true},
71 {"kvmalloc", "$0"},
72 {"kvmalloc_array", "$0 * $1"},
73 {"kvmalloc_node", "$0"},
74 {"kvzalloc", "$0", .zeroed=true},
75 {"kvcalloc", "$0 * $1", .zeroed=true},
76 {"kvzalloc_node", "$0", .zeroed=true},
77 {"kvrealloc", "$2"},
79 {"kmemdup", "$1"},
80 {"devm_kmemdup", "$2"},
81 {"memdup_user", "$1"},
83 {"sock_kmalloc", "$1"},
85 #if 0
86 {"get_zeroed_page", {"PAGE_SIZE", zeroed=true}},
87 {"alloc_page", {"PAGE_SIZE"}},
88 {"alloc_pages", {"(1 < $0) * PAGE_SIZE"}},
89 {"alloc_pages_current", {"(1 < $0) * PAGE_SIZE"}},
90 {"__get_free_pages", {"(1 < $0) * PAGE_SIZE"}},
91 #endif
92 { },
95 void add_allocation_hook(alloc_hook *hook)
97 add_ptr_list(&hook_funcs, hook);
100 static void load_size_data(struct allocation_info *data, struct expression *expr, const char *size_str)
102 struct expression *call, *arg1, *arg2;
103 const char *p;
104 int op;
105 int param;
107 if (!size_str)
108 return;
110 p = size_str;
111 if (*p != '$')
112 return;
113 p++;
114 if (!isdigit(*p))
115 return;
116 param = atoi(p);
118 call = get_assigned_call(expr);
119 if (!call)
120 return;
121 arg1 = get_argument_from_call_expr(call->args, param);
122 if (!arg1)
123 return;
125 p++;
126 if (*p == '\0') {
127 data->total_size = arg1;
128 return;
130 while (*p == ' ')
131 p++;
132 op = *p;
133 if (op != '*' && op != '+')
134 return;
135 p++;
136 while (p[0] == ' ')
137 p++;
138 if (p[0] != '$' || !isdigit(p[1]))
139 return;
140 p++;
141 param = atoi(p);
142 arg2 = get_argument_from_call_expr(call->args, param);
143 if (!arg2)
144 return;
146 if (op == '*') {
147 data->nr_elems = arg1;
148 data->elem_size = arg2;
152 static void match_alloc(struct expression *expr, const char *name, struct symbol *sym, void *_info)
154 struct alloc_fn_info *info = _info;
155 struct allocation_info data = { };
156 alloc_hook *fn;
158 data.fn_name = info->name;
159 data.size_str = info->size;
160 data.zeroed = info->zeroed;
161 load_size_data(&data, expr, info->size);
163 FOR_EACH_PTR(hook_funcs, fn) {
164 fn(expr, name, sym, &data);
165 } END_FOR_EACH_PTR(fn);
168 void register_allocations(int id)
170 struct alloc_fn_info *info;
172 my_id = id;
174 if (option_project == PROJ_KERNEL)
175 info = kernel_alloc_funcs;
176 else
177 info = alloc_fns;
179 while (info->name) {
180 add_function_param_key_hook(info->name, &match_alloc, -1, "$", info);
181 info++;