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
[] = {
55 {"kmalloc_array", 0, 1},
56 {"devm_kcalloc", 1, 2},
59 static int bytes_per_element(struct expression
*expr
)
63 type
= get_type(expr
);
67 if (type
->type
!= SYM_PTR
&& type
->type
!= SYM_ARRAY
)
70 type
= get_base_type(type
);
71 return type_bytes(type
);
74 static void save_constraint_required(struct expression
*pointer
, int op
, struct expression
*constraint
)
78 data
= get_constraint_str(pointer
);
82 limit
= get_constraint_str(constraint
);
84 // FIXME deal with <= also
86 set_state_expr(my_id
, constraint
, alloc_state_expr(pointer
));
90 sql_save_constraint_required(data
, op
, limit
);
97 static int handle_zero_size_arrays(struct expression
*pointer
, struct expression
*size
)
99 struct expression
*left
, *right
;
100 struct symbol
*type
, *array
, *array_type
;
105 if (size
->type
!= EXPR_BINOP
|| size
->op
!= '+')
108 type
= get_type(pointer
);
109 if (!type
|| type
->type
!= SYM_PTR
)
111 type
= get_real_base_type(type
);
112 if (!type
|| !type
->ident
|| type
->type
!= SYM_STRUCT
)
114 if (!last_member_is_resizable(type
))
116 array
= last_ptr_list((struct ptr_list
*)type
->symbol_list
);
117 if (!array
|| !array
->ident
)
119 array_type
= get_real_base_type(array
);
120 if (!array_type
|| array_type
->type
!= SYM_ARRAY
)
122 array_type
= get_real_base_type(array_type
);
124 left
= strip_expr(size
->left
);
125 right
= strip_expr(size
->right
);
127 if (!get_implied_value(left
, &struct_size
))
129 if (struct_size
.value
!= type_bytes(type
))
132 if (right
->type
== EXPR_BINOP
&& right
->op
== '*') {
133 struct expression
*mult_left
, *mult_right
;
136 mult_left
= strip_expr(right
->left
);
137 mult_right
= strip_expr(right
->right
);
139 if (get_implied_value(mult_left
, &sval
) &&
140 sval
.value
== type_bytes(array_type
))
142 else if (get_implied_value(mult_right
, &sval
) &&
143 sval
.value
== type_bytes(array_type
))
149 snprintf(data
, sizeof(data
), "(struct %s)->%s", type
->ident
->name
, array
->ident
->name
);
150 limit
= get_constraint_str(size
);
152 set_state_expr(my_id
, size
, alloc_state_expr(
153 member_expression(deref_expression(pointer
), '*', array
->ident
)));
157 sql_save_constraint_required(data
, '<', limit
);
163 static void match_alloc_helper(struct expression
*pointer
, struct expression
*size
)
165 struct expression
*tmp
;
169 pointer
= strip_expr(pointer
);
170 size
= strip_expr(size
);
171 if (!size
|| !pointer
)
174 while ((tmp
= get_assigned_expr(size
))) {
175 size
= strip_expr(tmp
);
180 if (handle_zero_size_arrays(pointer
, size
))
183 if (size
->type
== EXPR_BINOP
&& size
->op
== '*') {
184 struct expression
*mult_left
, *mult_right
;
186 mult_left
= strip_expr(size
->left
);
187 mult_right
= strip_expr(size
->right
);
189 if (get_implied_value(mult_left
, &sval
) &&
190 sval
.value
== bytes_per_element(pointer
))
192 else if (get_implied_value(mult_right
, &sval
) &&
193 sval
.value
== bytes_per_element(pointer
))
199 if (size
->type
== EXPR_BINOP
&& size
->op
== '+' &&
200 get_implied_value(size
->right
, &sval
) &&
202 save_constraint_required(pointer
, SPECIAL_LTE
, size
->left
);
204 save_constraint_required(pointer
, '<', size
);
207 static void match_alloc(const char *fn
, struct expression
*expr
, void *_size_arg
)
209 int size_arg
= PTR_INT(_size_arg
);
210 struct expression
*call
, *arg
;
212 call
= strip_expr(expr
->right
);
213 arg
= get_argument_from_call_expr(call
->args
, size_arg
);
215 match_alloc_helper(expr
->left
, arg
);
218 static void match_calloc(const char *fn
, struct expression
*expr
, void *_start_arg
)
220 struct expression
*pointer
, *call
, *size
;
221 struct expression
*count
= NULL
;
222 int start_arg
= PTR_INT(_start_arg
);
225 pointer
= strip_expr(expr
->left
);
226 call
= strip_expr(expr
->right
);
228 size
= get_argument_from_call_expr(call
->args
, start_arg
);
229 if (get_implied_value(size
, &sval
) &&
230 sval
.value
== bytes_per_element(pointer
))
231 count
= get_argument_from_call_expr(call
->args
, start_arg
+ 1);
233 size
= get_argument_from_call_expr(call
->args
, start_arg
+ 1);
234 if (get_implied_value(size
, &sval
) &&
235 sval
.value
== bytes_per_element(pointer
))
236 count
= get_argument_from_call_expr(call
->args
, start_arg
);
242 save_constraint_required(pointer
, '<', count
);
245 static void add_allocation_function(const char *func
, void *call_back
, int param
)
247 add_function_assign_hook(func
, call_back
, INT_PTR(param
));
250 static void match_assign_size(struct expression
*expr
)
252 struct smatch_state
*state
;
255 state
= get_state_expr(my_id
, expr
->right
);
256 if (!state
|| !state
->data
)
259 data
= get_constraint_str(state
->data
);
263 limit
= get_constraint_str(expr
->left
);
267 sql_save_constraint_required(data
, '<', limit
);
274 static void match_assign_has_buf_comparison(struct expression
*expr
)
276 struct expression
*size
;
280 if (expr
->right
->type
== EXPR_CALL
)
282 size
= get_size_variable(expr
->right
);
285 match_alloc_helper(expr
->left
, size
);
288 static void match_assign_data(struct expression
*expr
)
290 struct expression
*right
, *arg
, *tmp
;
298 /* Direct calls are handled else where (for now at least) */
299 tmp
= get_assigned_expr(expr
->right
);
303 right
= strip_expr(tmp
);
304 if (right
->type
!= EXPR_CALL
)
307 if (right
->fn
->type
!= EXPR_SYMBOL
||
308 !right
->fn
->symbol
||
309 !right
->fn
->symbol
->ident
)
312 for (i
= 0; i
< ARRAY_SIZE(generic_allocator_table
); i
++) {
313 if (strcmp(right
->fn
->symbol
->ident
->name
,
314 generic_allocator_table
[i
].func
) == 0) {
315 size_arg
= generic_allocator_table
[i
].param
;
320 if (option_project
!= PROJ_KERNEL
)
323 for (i
= 0; i
< ARRAY_SIZE(kernel_allocator_table
); i
++) {
324 if (strcmp(right
->fn
->symbol
->ident
->name
,
325 kernel_allocator_table
[i
].func
) == 0) {
326 size_arg
= kernel_allocator_table
[i
].param
;
331 for (i
= 0; i
< ARRAY_SIZE(calloc_table
); i
++) {
332 if (strcmp(right
->fn
->symbol
->ident
->name
,
333 calloc_table
[i
].func
) == 0) {
334 size_arg
= calloc_table
[i
].param
;
335 size_arg2
= calloc_table
[i
].param2
;
343 arg
= get_argument_from_call_expr(right
->args
, size_arg
);
344 match_alloc_helper(expr
->left
, arg
);
347 arg
= get_argument_from_call_expr(right
->args
, size_arg2
);
348 match_alloc_helper(expr
->left
, arg
);
351 static void match_assign_ARRAY_SIZE(struct expression
*expr
)
353 struct expression
*array
;
357 macro
= get_macro_name(expr
->right
->pos
);
358 if (!macro
|| strcmp(macro
, "ARRAY_SIZE") != 0)
360 array
= strip_expr(expr
->right
);
361 if (array
->type
!= EXPR_BINOP
|| array
->op
!= '+')
363 array
= strip_expr(array
->left
);
364 if (array
->type
!= EXPR_BINOP
|| array
->op
!= '/')
366 array
= strip_expr(array
->left
);
367 if (array
->type
!= EXPR_SIZEOF
)
369 array
= strip_expr(array
->cast_expression
);
370 if (array
->type
!= EXPR_PREOP
|| array
->op
!= '*')
372 array
= strip_expr(array
->unop
);
374 data
= get_constraint_str(array
);
375 limit
= get_constraint_str(expr
->left
);
379 sql_save_constraint_required(data
, '<', limit
);
386 static void match_assign_buf_comparison(struct expression
*expr
)
388 struct expression
*pointer
;
392 pointer
= get_array_variable(expr
->right
);
396 match_alloc_helper(pointer
, expr
->right
);
399 static int constraint_found(void *_found
, int argc
, char **argv
, char **azColName
)
407 static int has_constraint(struct expression
*expr
, const char *constraint
)
411 if (get_state_expr(my_id
, expr
))
414 run_sql(constraint_found
, &found
,
415 "select data from constraints_required where bound = '%s' limit 1",
421 static void match_assign_constraint(struct expression
*expr
)
429 type
= get_type(expr
->left
);
430 if (!type
|| type
->type
!= SYM_BASETYPE
)
433 left
= get_constraint_str(expr
->left
);
436 right
= get_constraint_str(expr
->right
);
439 if (!has_constraint(expr
->right
, right
))
441 sql_copy_constraint_required(left
, right
);
447 void register_constraints_required(int id
)
451 add_hook(&match_assign_size
, ASSIGNMENT_HOOK
);
452 add_hook(&match_assign_data
, ASSIGNMENT_HOOK
);
453 add_hook(&match_assign_has_buf_comparison
, ASSIGNMENT_HOOK
);
455 add_hook(&match_assign_ARRAY_SIZE
, ASSIGNMENT_HOOK
);
456 add_hook(&match_assign_ARRAY_SIZE
, GLOBAL_ASSIGNMENT_HOOK
);
457 add_hook(&match_assign_buf_comparison
, ASSIGNMENT_HOOK
);
458 add_hook(&match_assign_constraint
, ASSIGNMENT_HOOK
);
460 add_allocation_function("malloc", &match_alloc
, 0);
461 add_allocation_function("memdup", &match_alloc
, 1);
462 add_allocation_function("realloc", &match_alloc
, 1);
463 add_allocation_function("realloc", &match_calloc
, 0);
464 if (option_project
== PROJ_KERNEL
) {
465 add_allocation_function("kmalloc", &match_alloc
, 0);
466 add_allocation_function("kzalloc", &match_alloc
, 0);
467 add_allocation_function("vmalloc", &match_alloc
, 0);
468 add_allocation_function("__vmalloc", &match_alloc
, 0);
469 add_allocation_function("vzalloc", &match_alloc
, 0);
470 add_allocation_function("sock_kmalloc", &match_alloc
, 1);
471 add_allocation_function("kmemdup", &match_alloc
, 1);
472 add_allocation_function("kmemdup_user", &match_alloc
, 1);
473 add_allocation_function("dma_alloc_attrs", &match_alloc
, 1);
474 add_allocation_function("pci_alloc_consistent", &match_alloc
, 1);
475 add_allocation_function("pci_alloc_coherent", &match_alloc
, 1);
476 add_allocation_function("devm_kmalloc", &match_alloc
, 1);
477 add_allocation_function("devm_kzalloc", &match_alloc
, 1);
478 add_allocation_function("kcalloc", &match_calloc
, 0);
479 add_allocation_function("kmalloc_array", &match_calloc
, 0);
480 add_allocation_function("devm_kcalloc", &match_calloc
, 1);
481 add_allocation_function("krealloc", &match_alloc
, 1);