container_of: export get_param/offset_from_container_of()
[smatch.git] / smatch_constraints_required.c
blob853b1baccb29a585bff28b327e77f4a586fab7fd
1 /*
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
18 #include "smatch.h"
19 #include "smatch_extra.h"
21 static int my_id;
23 static int bytes_per_element(struct expression *expr)
25 struct symbol *type;
27 type = get_type(expr);
28 if (!type)
29 return 0;
31 if (type->type != SYM_PTR && type->type != SYM_ARRAY)
32 return 0;
34 type = get_base_type(type);
35 return type_bytes(type);
38 static void save_constraint_required(struct expression *pointer, int op, struct expression *constraint)
40 char *data, *limit;
42 data = get_constraint_str(pointer);
43 if (!data)
44 return;
46 limit = get_constraint_str(constraint);
47 if (!limit) {
48 // FIXME deal with <= also
49 if (op == '<')
50 set_state_expr(my_id, constraint, alloc_state_expr(pointer));
51 goto free_data;
54 sql_save_constraint_required(data, op, limit);
56 free_string(limit);
57 free_data:
58 free_string(data);
61 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
63 int size_arg = PTR_INT(_size_arg);
64 struct expression *pointer, *call, *arg;
65 sval_t sval;
67 pointer = strip_expr(expr->left);
68 call = strip_expr(expr->right);
69 arg = get_argument_from_call_expr(call->args, size_arg);
70 arg = strip_expr(arg);
72 if (arg->type == EXPR_BINOP && arg->op == '*') {
73 struct expression *left, *right;
75 left = strip_expr(arg->left);
76 right = strip_expr(arg->right);
78 if (get_implied_value(left, &sval) &&
79 sval.value == bytes_per_element(pointer))
80 arg = right;
81 else if (get_implied_value(right, &sval) &&
82 sval.value == bytes_per_element(pointer))
83 arg = left;
84 else
85 return;
88 if (arg->type == EXPR_BINOP && arg->op == '+' &&
89 get_implied_value(expr->right, &sval) &&
90 sval.value == 1)
91 save_constraint_required(pointer, SPECIAL_LTE, arg->left);
92 else
93 save_constraint_required(pointer, '<', arg);
96 static void match_calloc(const char *fn, struct expression *expr, void *_start_arg)
98 struct expression *pointer, *call, *size;
99 struct expression *count = NULL;
100 int start_arg = PTR_INT(_start_arg);
101 sval_t sval;
103 pointer = strip_expr(expr->left);
104 call = strip_expr(expr->right);
106 size = get_argument_from_call_expr(call->args, start_arg);
107 if (get_implied_value(size, &sval) &&
108 sval.value == bytes_per_element(pointer))
109 count = get_argument_from_call_expr(call->args, start_arg + 1);
110 else {
111 size = get_argument_from_call_expr(call->args, start_arg + 1);
112 if (get_implied_value(size, &sval) &&
113 sval.value == bytes_per_element(pointer))
114 count = get_argument_from_call_expr(call->args, start_arg);
117 if (!count)
118 return;
120 save_constraint_required(pointer, '<', count);
123 static void add_allocation_function(const char *func, void *call_back, int param)
125 add_function_assign_hook(func, call_back, INT_PTR(param));
128 static void match_assign_state(struct expression *expr)
130 struct smatch_state *state;
131 char *data, *limit;
133 state = get_state_expr(my_id, expr->right);
134 if (!state || !state->data)
135 return;
137 data = get_constraint_str(state->data);
138 if (!data)
139 return;
141 limit = get_constraint_str(expr->left);
142 if (!limit)
143 goto free_data;
145 sql_save_constraint_required(data, '<', limit);
147 free_string(limit);
148 free_data:
149 free_string(data);
152 static void match_assign_ARRAY_SIZE(struct expression *expr)
154 struct expression *array;
155 char *data, *limit;
156 const char *macro;
158 macro = get_macro_name(expr->right->pos);
159 if (!macro || strcmp(macro, "ARRAY_SIZE") != 0)
160 return;
161 array = strip_expr(expr->right);
162 if (array->type != EXPR_BINOP || array->op != '+')
163 return;
164 array = strip_expr(array->left);
165 if (array->type != EXPR_BINOP || array->op != '/')
166 return;
167 array = strip_expr(array->left);
168 if (array->type != EXPR_SIZEOF)
169 return;
170 array = strip_expr(array->cast_expression);
171 if (array->type != EXPR_PREOP || array->op != '*')
172 return;
173 array = strip_expr(array->unop);
175 data = get_constraint_str(array);
176 limit = get_constraint_str(expr->left);
177 if (!data || !limit)
178 goto free;
180 sql_save_constraint_required(data, '<', limit);
182 free:
183 free_string(data);
184 free_string(limit);
187 void register_constraints_required(int id)
189 my_id = id;
191 add_hook(&match_assign_state, ASSIGNMENT_HOOK);
193 add_hook(&match_assign_ARRAY_SIZE, ASSIGNMENT_HOOK);
194 add_hook(&match_assign_ARRAY_SIZE, GLOBAL_ASSIGNMENT_HOOK);
196 add_allocation_function("malloc", &match_alloc, 0);
197 add_allocation_function("memdup", &match_alloc, 1);
198 add_allocation_function("realloc", &match_alloc, 1);
199 add_allocation_function("realloc", &match_calloc, 0);
200 if (option_project == PROJ_KERNEL) {
201 add_allocation_function("kmalloc", &match_alloc, 0);
202 add_allocation_function("kzalloc", &match_alloc, 0);
203 add_allocation_function("vmalloc", &match_alloc, 0);
204 add_allocation_function("__vmalloc", &match_alloc, 0);
205 add_allocation_function("sock_kmalloc", &match_alloc, 1);
206 add_allocation_function("kmemdup", &match_alloc, 1);
207 add_allocation_function("kmemdup_user", &match_alloc, 1);
208 add_allocation_function("dma_alloc_attrs", &match_alloc, 1);
209 add_allocation_function("pci_alloc_consistent", &match_alloc, 1);
210 add_allocation_function("pci_alloc_coherent", &match_alloc, 1);
211 add_allocation_function("devm_kmalloc", &match_alloc, 1);
212 add_allocation_function("devm_kzalloc", &match_alloc, 1);
213 add_allocation_function("kcalloc", &match_calloc, 0);
214 add_allocation_function("devm_kcalloc", &match_calloc, 1);
215 add_allocation_function("krealloc", &match_alloc, 1);