buf_size: fix handling of unknown flexible array sizes
[smatch.git] / check_implicit_dependencies.c
blob7d776fc2ed90eea4e71afbfcac2cb3e7948cd4ec
1 #include "smatch.h"
2 #include "smatch_slist.h"
4 static int my_id;
6 /* If set, we ignore struct type symbols as implicit dependencies */
7 static int ignore_structs;
9 static struct symbol *cur_syscall;
10 /* note: cannot track return type and remove from implicit dependencies,
11 * because every syscall returns a long, and we don't have a good way to know
12 * whether or not this is a resource. The only example I can think of is open
13 * returning a filedescriptor, so in the implicit dep parsing, we will just
14 * blacklist struct fd --> file
16 static struct symbol *cur_return_type;
17 static char *syscall_name;
19 static struct tracker_list *read_list; // what fields does syscall branch on?
20 static struct tracker_list *write_list; // what fields does syscall modify?
21 static struct tracker_list *arg_list; // what struct arguments does the syscall take?
22 static struct tracker_list *parsed_syscalls; // syscalls we have already checked
24 static inline void prefix(void)
26 printf("%s:%d %s() ", get_filename(), get_lineno(), get_function());
29 static void match_syscall_definition(struct symbol *sym)
31 struct symbol *arg;
32 struct tracker *tracker;
33 char *macro;
34 char *name;
35 int is_syscall = 0;
37 macro = get_macro_name(sym->pos);
38 if (macro &&
39 (strncmp("SYSCALL_DEFINE", macro, strlen("SYSCALL_DEFINE")) == 0 ||
40 strncmp("COMPAT_SYSCALL_DEFINE", macro, strlen("COMPAT_SYSCALL_DEFINE")) == 0))
41 is_syscall = 1;
43 name = get_function();
45 if (name && strncmp(name, "sys_", 4) == 0)
46 is_syscall = 1;
48 if (name && strncmp(name, "compat_sys_", 11) == 0)
49 is_syscall = 1;
51 if (!is_syscall)
52 return;
54 FOR_EACH_PTR(parsed_syscalls, tracker) {
55 if (tracker->sym == sym) // don't re-parse
56 return;
57 } END_FOR_EACH_PTR(tracker);
59 syscall_name = name;
60 cur_syscall = sym;
62 cur_return_type = cur_func_return_type();
63 if (cur_return_type && cur_return_type->ident)
64 sm_msg("return type: %s\n", cur_return_type->ident->name);
67 FOR_EACH_PTR(sym->ctype.base_type->arguments, arg) {
68 // set_state(my_id, arg->ident->name, arg, &user_data_set);
69 sm_msg("=======check_impl: arguments for call %s=========\n", syscall_name);
70 if (arg->type == SYM_STRUCT)
71 arg = get_real_base_type(arg);
72 if (cur_return_type && cur_return_type->ident)
73 sm_msg("arg type: %s\n", cur_return_type->ident->name);
74 // add_tracker(&arg_list, my_id, member, arg);
75 sm_msg("=================================\n");
76 } END_FOR_EACH_PTR(arg);
79 static void print_read_list(void)
81 struct tracker *tracker;
82 int i = 0;
84 FOR_EACH_PTR(read_list, tracker) {
85 if (i == 0)
86 sm_printf("%s read_list: [", syscall_name);
87 sm_printf("%s, ", tracker->name);
88 i++;
89 } END_FOR_EACH_PTR(tracker);
91 if (i > 0)
92 sm_printf("]\n");
95 static void print_write_list(void)
97 struct tracker *tracker;
98 int i = 0;
100 FOR_EACH_PTR(write_list, tracker) {
101 if (i == 0)
102 sm_printf("%s write_list: [", syscall_name);
103 sm_printf("%s, ", tracker->name);
104 i++;
105 } END_FOR_EACH_PTR(tracker);
107 if (i > 0)
108 sm_printf("]\n");
111 static void print_arg_list(void)
113 struct tracker *tracker;
114 int i = 0;
116 FOR_EACH_PTR(write_list, tracker) {
117 if (i == 0)
118 sm_printf("%s arg_list: [", syscall_name);
119 sm_printf("%s, ", tracker->name);
120 i++;
121 } END_FOR_EACH_PTR(tracker);
123 if (i > 0)
124 sm_printf("]\n");
127 static void match_after_syscall(struct symbol *sym)
129 if (!cur_syscall || sym != cur_syscall)
130 return;
131 // printf("\n"); prefix();
132 // printf("exiting scope of syscall %s\n", get_function());
133 // printf("-------------------------\n");
134 print_read_list();
135 print_write_list();
136 print_arg_list();
137 free_trackers_and_list(&read_list);
138 free_trackers_and_list(&write_list);
139 free_trackers_and_list(&arg_list);
140 add_tracker(&parsed_syscalls, my_id, syscall_name, sym);
141 cur_syscall = NULL;
142 cur_return_type = NULL;
143 syscall_name = NULL;
146 static void print_read_member_type(struct expression *expr)
148 char *member;
149 struct symbol *sym;
150 struct symbol *member_sym;
152 member = get_member_name(expr);
153 if (!member)
154 return;
156 sym = get_type(expr->deref);
157 member_sym = get_type(expr);
159 if (member_sym->type == SYM_PTR)
160 member_sym = get_real_base_type(member_sym);
163 if (member_sym->type == SYM_STRUCT)
164 printf("found struct type %s\n", member);
165 else
166 printf("found non-struct type %s with enum value%d\n", member, member_sym->type);
169 if (ignore_structs && member_sym->type == SYM_STRUCT) {
170 // printf("ignoring %s\n", member);
171 return;
174 add_tracker(&read_list, my_id, member, sym);
175 // sm_msg("info: uses %s", member);
176 // prefix();
177 // printf("info: uses %s\n", member);
178 free_string(member);
181 static void print_write_member_type(struct expression *expr)
183 char *member;
184 struct symbol *sym;
185 struct symbol *member_sym;
187 member = get_member_name(expr);
188 if (!member)
189 return;
191 sym = get_type(expr->deref);
192 member_sym = get_type(expr);
194 if (member_sym->type == SYM_PTR)
195 member_sym = get_real_base_type(member_sym);
198 if (member_sym->type == SYM_STRUCT)
199 printf("found struct type %s\n", member);
200 else
201 printf("found non-struct type %s with enum value%d\n", member, member_sym->type);
204 if (ignore_structs && member_sym->type == SYM_STRUCT) {
205 // printf("ignoring %s\n", member);
206 return;
209 add_tracker(&write_list, my_id, member, sym);
210 free_string(member);
213 static void match_condition(struct expression *expr)
215 struct expression *arg;
217 if (!cur_syscall)
218 return;
220 // prefix(); printf("-- condition found\n");
222 if (expr->type == EXPR_COMPARE ||
223 expr->type == EXPR_BINOP ||
224 expr->type == EXPR_LOGICAL ||
225 expr->type == EXPR_ASSIGNMENT ||
226 expr->type == EXPR_COMMA) {
227 match_condition(expr->left);
228 match_condition(expr->right);
229 return;
232 if (expr->type == EXPR_CALL) {
233 FOR_EACH_PTR(expr->args, arg) {
234 // if we find deref in conditional call,
235 // mark it as a read dependency
236 print_read_member_type(arg);
237 } END_FOR_EACH_PTR(arg);
238 return;
241 print_read_member_type(expr);
245 /* when we are parsing an inline function and can no longer nest,
246 * assume that all struct fields passed to nested inline functions
247 * are read dependencies
249 static void match_call_info(struct expression *expr)
251 struct expression *arg;
252 int i;
254 if (!__inline_fn || !cur_syscall)
255 return;
257 // prefix(); printf("fn: %s\n", expr->fn->symbol->ident->name);
259 i = 0;
260 FOR_EACH_PTR(expr->args, arg) {
262 if (arg->type == EXPR_DEREF)
263 printf("arg %d is deref\n", i);
265 print_read_member_type(arg);
266 i++;
267 } END_FOR_EACH_PTR(arg);
270 static void match_assign_value(struct expression *expr)
272 if (!cur_syscall)
273 return;
274 print_write_member_type(expr->left);
277 static void unop_expr(struct expression *expr)
279 if (!cur_syscall)
280 return;
282 if (expr->op == SPECIAL_ADD_ASSIGN || expr->op == SPECIAL_INCREMENT ||
283 expr->op == SPECIAL_SUB_ASSIGN || expr->op == SPECIAL_DECREMENT ||
284 expr->op == SPECIAL_MUL_ASSIGN || expr->op == SPECIAL_DIV_ASSIGN ||
285 expr->op == SPECIAL_MOD_ASSIGN || expr->op == SPECIAL_AND_ASSIGN ||
286 expr->op == SPECIAL_OR_ASSIGN || expr->op == SPECIAL_XOR_ASSIGN ||
287 expr->op == SPECIAL_SHL_ASSIGN || expr->op == SPECIAL_SHR_ASSIGN)
288 print_write_member_type(strip_expr(expr->unop));
291 void check_implicit_dependencies(int id)
293 my_id = id;
294 ignore_structs = 0;
296 if (option_project != PROJ_KERNEL)
297 return;
298 if (!option_info)
299 return;
301 add_hook(&match_syscall_definition, AFTER_DEF_HOOK);
302 add_hook(&match_after_syscall, AFTER_FUNC_HOOK);
303 add_hook(&match_condition, CONDITION_HOOK);
304 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
306 /* hooks to track written fields */
307 add_hook(&match_assign_value, ASSIGNMENT_HOOK_AFTER);
308 add_hook(&unop_expr, OP_HOOK);