2 * Copyright (C) 2017 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
19 #include "smatch_extra.h"
29 static struct allocator generic_allocator_table
[] = {
35 static struct allocator kernel_allocator_table
[] = {
44 {"dma_alloc_attrs", 1},
45 {"pci_alloc_consistent", 1},
46 {"pci_alloc_coherent", 1},
52 static struct allocator calloc_table
[] = {
57 static int bytes_per_element(struct expression
*expr
)
61 type
= get_type(expr
);
65 if (type
->type
!= SYM_PTR
&& type
->type
!= SYM_ARRAY
)
68 type
= get_base_type(type
);
69 return type_bytes(type
);
72 static void save_constraint_required(struct expression
*pointer
, int op
, struct expression
*constraint
)
76 data
= get_constraint_str(pointer
);
80 limit
= get_constraint_str(constraint
);
82 // FIXME deal with <= also
84 set_state_expr(my_id
, constraint
, alloc_state_expr(pointer
));
88 sql_save_constraint_required(data
, op
, limit
);
95 static void match_alloc_helper(struct expression
*pointer
, struct expression
*size
)
97 struct expression
*tmp
;
101 pointer
= strip_expr(pointer
);
102 size
= strip_expr(size
);
103 if (!size
|| !pointer
)
106 while ((tmp
= get_assigned_expr(size
))) {
107 size
= strip_expr(tmp
);
112 if (size
->type
== EXPR_BINOP
&& size
->op
== '*') {
113 struct expression
*mult_left
, *mult_right
;
115 mult_left
= strip_expr(size
->left
);
116 mult_right
= strip_expr(size
->right
);
118 if (get_implied_value(mult_left
, &sval
) &&
119 sval
.value
== bytes_per_element(pointer
))
121 else if (get_implied_value(mult_right
, &sval
) &&
122 sval
.value
== bytes_per_element(pointer
))
128 if (size
->type
== EXPR_BINOP
&& size
->op
== '+' &&
129 get_implied_value(size
->right
, &sval
) &&
131 save_constraint_required(pointer
, SPECIAL_LTE
, size
->left
);
133 save_constraint_required(pointer
, '<', size
);
136 static void match_alloc(const char *fn
, struct expression
*expr
, void *_size_arg
)
138 int size_arg
= PTR_INT(_size_arg
);
139 struct expression
*call
, *arg
;
141 call
= strip_expr(expr
->right
);
142 arg
= get_argument_from_call_expr(call
->args
, size_arg
);
144 match_alloc_helper(expr
->left
, arg
);
147 static void match_calloc(const char *fn
, struct expression
*expr
, void *_start_arg
)
149 struct expression
*pointer
, *call
, *size
;
150 struct expression
*count
= NULL
;
151 int start_arg
= PTR_INT(_start_arg
);
154 pointer
= strip_expr(expr
->left
);
155 call
= strip_expr(expr
->right
);
157 size
= get_argument_from_call_expr(call
->args
, start_arg
);
158 if (get_implied_value(size
, &sval
) &&
159 sval
.value
== bytes_per_element(pointer
))
160 count
= get_argument_from_call_expr(call
->args
, start_arg
+ 1);
162 size
= get_argument_from_call_expr(call
->args
, start_arg
+ 1);
163 if (get_implied_value(size
, &sval
) &&
164 sval
.value
== bytes_per_element(pointer
))
165 count
= get_argument_from_call_expr(call
->args
, start_arg
);
171 save_constraint_required(pointer
, '<', count
);
174 static void add_allocation_function(const char *func
, void *call_back
, int param
)
176 add_function_assign_hook(func
, call_back
, INT_PTR(param
));
179 static void match_assign_size(struct expression
*expr
)
181 struct smatch_state
*state
;
184 state
= get_state_expr(my_id
, expr
->right
);
185 if (!state
|| !state
->data
)
188 data
= get_constraint_str(state
->data
);
192 limit
= get_constraint_str(expr
->left
);
196 sql_save_constraint_required(data
, '<', limit
);
203 static void match_assign_data(struct expression
*expr
)
205 struct expression
*right
, *arg
, *tmp
;
213 /* Direct calls are handled else where (for now at least) */
214 tmp
= get_assigned_expr(expr
->right
);
218 right
= strip_expr(tmp
);
219 if (right
->type
!= EXPR_CALL
)
222 if (right
->fn
->type
!= EXPR_SYMBOL
||
223 !right
->fn
->symbol
||
224 !right
->fn
->symbol
->ident
)
227 for (i
= 0; i
< ARRAY_SIZE(generic_allocator_table
); i
++) {
228 if (strcmp(right
->fn
->symbol
->ident
->name
,
229 generic_allocator_table
[i
].func
) == 0) {
230 size_arg
= generic_allocator_table
[i
].param
;
235 if (option_project
!= PROJ_KERNEL
)
238 for (i
= 0; i
< ARRAY_SIZE(kernel_allocator_table
); i
++) {
239 if (strcmp(right
->fn
->symbol
->ident
->name
,
240 kernel_allocator_table
[i
].func
) == 0) {
241 size_arg
= kernel_allocator_table
[i
].param
;
246 for (i
= 0; i
< ARRAY_SIZE(calloc_table
); i
++) {
247 if (strcmp(right
->fn
->symbol
->ident
->name
,
248 calloc_table
[i
].func
) == 0) {
249 size_arg
= calloc_table
[i
].param
;
250 size_arg2
= calloc_table
[i
].param2
;
258 arg
= get_argument_from_call_expr(right
->args
, size_arg
);
259 match_alloc_helper(expr
->left
, arg
);
262 arg
= get_argument_from_call_expr(right
->args
, size_arg2
);
263 match_alloc_helper(expr
->left
, arg
);
266 static void match_assign_ARRAY_SIZE(struct expression
*expr
)
268 struct expression
*array
;
272 macro
= get_macro_name(expr
->right
->pos
);
273 if (!macro
|| strcmp(macro
, "ARRAY_SIZE") != 0)
275 array
= strip_expr(expr
->right
);
276 if (array
->type
!= EXPR_BINOP
|| array
->op
!= '+')
278 array
= strip_expr(array
->left
);
279 if (array
->type
!= EXPR_BINOP
|| array
->op
!= '/')
281 array
= strip_expr(array
->left
);
282 if (array
->type
!= EXPR_SIZEOF
)
284 array
= strip_expr(array
->cast_expression
);
285 if (array
->type
!= EXPR_PREOP
|| array
->op
!= '*')
287 array
= strip_expr(array
->unop
);
289 data
= get_constraint_str(array
);
290 limit
= get_constraint_str(expr
->left
);
294 sql_save_constraint_required(data
, '<', limit
);
301 void register_constraints_required(int id
)
305 add_hook(&match_assign_size
, ASSIGNMENT_HOOK
);
306 add_hook(&match_assign_data
, ASSIGNMENT_HOOK
);
308 add_hook(&match_assign_ARRAY_SIZE
, ASSIGNMENT_HOOK
);
309 add_hook(&match_assign_ARRAY_SIZE
, GLOBAL_ASSIGNMENT_HOOK
);
311 add_allocation_function("malloc", &match_alloc
, 0);
312 add_allocation_function("memdup", &match_alloc
, 1);
313 add_allocation_function("realloc", &match_alloc
, 1);
314 add_allocation_function("realloc", &match_calloc
, 0);
315 if (option_project
== PROJ_KERNEL
) {
316 add_allocation_function("kmalloc", &match_alloc
, 0);
317 add_allocation_function("kzalloc", &match_alloc
, 0);
318 add_allocation_function("vmalloc", &match_alloc
, 0);
319 add_allocation_function("__vmalloc", &match_alloc
, 0);
320 add_allocation_function("vzalloc", &match_alloc
, 0);
321 add_allocation_function("sock_kmalloc", &match_alloc
, 1);
322 add_allocation_function("kmemdup", &match_alloc
, 1);
323 add_allocation_function("kmemdup_user", &match_alloc
, 1);
324 add_allocation_function("dma_alloc_attrs", &match_alloc
, 1);
325 add_allocation_function("pci_alloc_consistent", &match_alloc
, 1);
326 add_allocation_function("pci_alloc_coherent", &match_alloc
, 1);
327 add_allocation_function("devm_kmalloc", &match_alloc
, 1);
328 add_allocation_function("devm_kzalloc", &match_alloc
, 1);
329 add_allocation_function("kcalloc", &match_calloc
, 0);
330 add_allocation_function("devm_kcalloc", &match_calloc
, 1);
331 add_allocation_function("krealloc", &match_alloc
, 1);