db: move free_slist() inside the loop and fix a memory leak
[smatch.git] / smatch_db.c
blob4a0f79ebb3daf080c83006431d7f5f149ea4ed32
1 /*
2 * smatch/smatch_db.c
4 * Copyright (C) 2010 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <string.h>
11 #include <errno.h>
12 #include <sqlite3.h>
13 #include "smatch.h"
14 #include "smatch_slist.h"
15 #include "smatch_extra.h"
17 static sqlite3 *db;
19 struct def_callback {
20 int hook_type;
21 void (*callback)(const char *name, struct symbol *sym, char *key, char *value);
23 ALLOCATOR(def_callback, "definition db hook callbacks");
24 DECLARE_PTR_LIST(callback_list, struct def_callback);
25 static struct callback_list *callbacks;
27 struct member_info_callback {
28 int owner;
29 void (*callback)(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state);
31 ALLOCATOR(member_info_callback, "caller_info callbacks");
32 DECLARE_PTR_LIST(member_info_cb_list, struct member_info_callback);
33 static struct member_info_cb_list *member_callbacks;
35 struct returned_member_callback {
36 int owner;
37 void (*callback)(char *return_ranges, char *printed_name, struct smatch_state *state);
39 ALLOCATOR(returned_member_callback, "returned member callbacks");
40 DECLARE_PTR_LIST(returned_member_cb_list, struct returned_member_callback);
41 static struct returned_member_cb_list *returned_member_callbacks;
43 struct call_implies_callback {
44 int type;
45 void (*callback)(struct expression *arg, char *value);
47 ALLOCATOR(call_implies_callback, "call_implies callbacks");
48 DECLARE_PTR_LIST(call_implies_cb_list, struct call_implies_callback);
49 static struct call_implies_cb_list *call_implies_cb_list;
51 static int return_id;
52 int get_return_id(void)
54 return return_id;
57 void sql_exec(int (*callback)(void*, int, char**, char**), const char *sql)
59 char *err = NULL;
60 int rc;
62 if (option_no_db || !db)
63 return;
65 rc = sqlite3_exec(db, sql, callback, 0, &err);
66 if (rc != SQLITE_OK) {
67 fprintf(stderr, "SQL error #2: %s\n", err);
68 fprintf(stderr, "SQL: '%s'\n", sql);
72 void add_definition_db_callback(void (*callback)(const char *name, struct symbol *sym, char *key, char *value), int type)
74 struct def_callback *def_callback = __alloc_def_callback(0);
76 def_callback->hook_type = type;
77 def_callback->callback = callback;
78 add_ptr_list(&callbacks, def_callback);
82 * These call backs are used when the --info option is turned on to print struct
83 * member information. For example foo->bar could have a state in
84 * smatch_extra.c and also check_user.c.
86 void add_member_info_callback(int owner, void (*callback)(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state))
88 struct member_info_callback *member_callback = __alloc_member_info_callback(0);
90 member_callback->owner = owner;
91 member_callback->callback = callback;
92 add_ptr_list(&member_callbacks, member_callback);
95 void add_returned_member_callback(int owner, void (*callback)(char *return_ranges, char *printed_name, struct smatch_state *state))
97 struct returned_member_callback *member_callback = __alloc_returned_member_callback(0);
99 member_callback->owner = owner;
100 member_callback->callback = callback;
101 add_ptr_list(&returned_member_callbacks, member_callback);
104 void add_db_fn_call_callback(int type, void (*callback)(struct expression *arg, char *value))
106 struct call_implies_callback *cb = __alloc_call_implies_callback(0);
108 cb->type = type;
109 cb->callback = callback;
110 add_ptr_list(&call_implies_cb_list, cb);
113 static struct symbol *return_type;
114 static struct range_list *return_range_list;
115 static int db_return_callback(void *unused, int argc, char **argv, char **azColName)
117 if (argc != 1)
118 return 0;
119 if (option_debug)
120 sm_msg("return type %d", type_positive_bits(return_type));
121 parse_value_ranges_type(return_type, argv[0], &return_range_list);
122 return 0;
125 struct range_list *db_return_vals(struct expression *expr)
127 struct symbol *sym;
128 static char sql_filter[1024];
130 if (expr->type != EXPR_CALL)
131 return NULL;
132 if (expr->fn->type != EXPR_SYMBOL)
133 return NULL;
134 return_type = get_type(expr);
135 if (!return_type)
136 return NULL;
137 sym = expr->fn->symbol;
138 if (!sym)
139 return NULL;
141 if (sym->ctype.modifiers & MOD_STATIC) {
142 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
143 get_filename(), sym->ident->name);
144 } else {
145 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
146 sym->ident->name);
149 return_range_list = NULL;
150 run_sql(db_return_callback, "select return from return_values where %s",
151 sql_filter);
152 return return_range_list;
155 static void match_call_hack(struct expression *expr)
157 char *name;
160 * we just want to record something in the database so that if we have
161 * two calls like: frob(4); frob(some_unkown); then on the receiving
162 * side we know that sometimes frob is called with unknown parameters.
165 name = get_fnptr_name(expr->fn);
166 if (!name)
167 return;
168 sm_msg("info: call_marker '%s' %s", name, is_static(expr->fn) ? "static" : "global");
169 free_string(name);
172 static void print_struct_members(char *fn, char *global_static, struct expression *expr, int param, struct state_list *slist,
173 void (*callback)(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state))
175 struct sm_state *sm;
176 char *name;
177 struct symbol *sym;
178 int len;
179 char printed_name[256];
180 int is_address = 0;
182 expr = strip_expr(expr);
183 if (expr->type == EXPR_PREOP && expr->op == '&') {
184 expr = strip_expr(expr->unop);
185 is_address = 1;
188 name = get_variable_from_expr(expr, &sym);
189 if (!name || !sym)
190 goto free;
192 len = strlen(name);
193 FOR_EACH_PTR(slist, sm) {
194 if (sm->sym != sym)
195 continue;
196 if (strncmp(name, sm->name, len) || sm->name[len] == '\0')
197 continue;
198 if (is_address)
199 snprintf(printed_name, sizeof(printed_name), "$$->%s", sm->name + len + 1);
200 else
201 snprintf(printed_name, sizeof(printed_name), "$$%s", sm->name + len);
202 callback(fn, global_static, param, printed_name, sm->state);
203 } END_FOR_EACH_PTR(sm);
204 free:
205 free_string(name);
208 static void match_call_info(struct expression *expr)
210 struct member_info_callback *cb;
211 struct expression *arg;
212 struct state_list *slist;
213 char *name;
214 int i;
215 char *gs;
217 name = get_fnptr_name(expr->fn);
218 if (!name)
219 return;
221 if (is_static(expr->fn))
222 gs = (char *)"static";
223 else
224 gs = (char *)"global";
226 FOR_EACH_PTR(member_callbacks, cb) {
227 slist = get_all_states(cb->owner);
228 i = 0;
229 FOR_EACH_PTR(expr->args, arg) {
230 print_struct_members(name, gs, arg, i, slist, cb->callback);
231 i++;
232 } END_FOR_EACH_PTR(arg);
233 free_slist(&slist);
234 } END_FOR_EACH_PTR(cb);
236 free_string(name);
239 static int get_param(int param, char **name, struct symbol **sym)
241 struct symbol *arg;
242 int i;
244 i = 0;
245 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
247 * this is a temporary hack to work around a bug (I think in sparse?)
248 * 2.6.37-rc1:fs/reiserfs/journal.o
249 * If there is a function definition without parameter name found
250 * after a function implementation then it causes a crash.
251 * int foo() {}
252 * int bar(char *);
254 if (arg->ident->name < (char *)100)
255 continue;
256 if (i == param && arg->ident->name) {
257 *name = arg->ident->name;
258 *sym = arg;
259 return TRUE;
261 i++;
262 } END_FOR_EACH_PTR(arg);
264 return FALSE;
267 static struct state_list *final_states;
268 static int prev_func_id = -1;
269 static int db_callback(void *unused, int argc, char **argv, char **azColName)
271 int func_id;
272 long type;
273 long param;
274 char *name = NULL;
275 struct symbol *sym = NULL;
276 struct def_callback *def_callback;
278 if (argc != 5)
279 return 0;
281 func_id = atoi(argv[0]);
282 errno = 0;
283 type = strtol(argv[1], NULL, 10);
284 param = strtol(argv[2], NULL, 10);
285 if (errno)
286 return 0;
288 if (prev_func_id == -1)
289 prev_func_id = func_id;
290 if (func_id != prev_func_id) {
291 merge_slist(&final_states, __pop_fake_cur_slist());
292 __push_fake_cur_slist();
293 __unnullify_path();
294 prev_func_id = func_id;
297 if (type == INTERNAL)
298 return 0;
299 if (param >= 0 && !get_param(param, &name, &sym))
300 return 0;
302 FOR_EACH_PTR(callbacks, def_callback) {
303 if (def_callback->hook_type == type)
304 def_callback->callback(name, sym, argv[3], argv[4]);
305 } END_FOR_EACH_PTR(def_callback);
307 return 0;
310 static void get_direct_callers(struct symbol *sym)
312 char sql_filter[1024];
314 if (sym->ctype.modifiers & MOD_STATIC) {
315 snprintf(sql_filter, 1024,
316 "file = '%s' and function = '%s' order by function_id;",
317 get_filename(), sym->ident->name);
318 } else {
319 snprintf(sql_filter, 1024,
320 "function = '%s' and static = 0 order by function_id;",
321 sym->ident->name);
324 run_sql(db_callback, "select function_id, type, parameter, key, value from caller_info"
325 " where %s", sql_filter);
328 static char *ptr_name;
329 static int get_ptr_name(void *unused, int argc, char **argv, char **azColName)
331 if (!ptr_name)
332 ptr_name = alloc_string(argv[0]);
333 return 0;
336 static void get_function_pointer_callers(struct symbol *sym)
338 ptr_name = NULL;
339 run_sql(get_ptr_name, "select ptr from function_ptr where function = '%s'",
340 sym->ident->name);
341 if (!ptr_name)
342 return;
344 run_sql(db_callback, "select function_id, type, parameter, key, value from caller_info"
345 " where function = '%s' order by function_id", ptr_name);
348 static void match_data_from_db(struct symbol *sym)
350 struct sm_state *sm;
352 if (!sym || !sym->ident || !sym->ident->name)
353 return;
355 __push_fake_cur_slist();
356 __unnullify_path();
357 prev_func_id = -1;
359 get_direct_callers(sym);
360 get_function_pointer_callers(sym);
362 merge_slist(&final_states, __pop_fake_cur_slist());
364 FOR_EACH_PTR(final_states, sm) {
365 __set_sm(sm);
366 } END_FOR_EACH_PTR(sm);
368 free_slist(&final_states);
371 static void match_function_assign(struct expression *expr)
373 struct expression *right = expr->right;
374 struct symbol *sym;
375 char *fn_name;
376 char *ptr_name;
378 if (right->type == EXPR_PREOP && right->op == '&')
379 right = right->unop;
380 if (right->type != EXPR_SYMBOL)
381 return;
382 sym = get_type(right);
383 if (!sym || sym->type != SYM_FN)
384 return;
386 fn_name = get_variable_from_expr(right, NULL);
387 ptr_name = get_fnptr_name(expr->left);
388 if (!fn_name || !ptr_name)
389 goto free;
391 sm_msg("info: sets_fn_ptr '%s' '%s'", ptr_name, fn_name);
393 free:
394 free_string(fn_name);
395 free_string(ptr_name);
398 static struct expression *call_implies_call_expr;
399 static int call_implies_callbacks(void *unused, int argc, char **argv, char **azColName)
401 struct call_implies_callback *cb;
402 struct expression *arg = NULL;
403 int type;
404 int param;
406 if (argc != 4)
407 return 0;
409 type = atoi(argv[1]);
410 param = atoi(argv[2]);
412 FOR_EACH_PTR(call_implies_cb_list, cb) {
413 if (cb->type != type)
414 continue;
415 if (param != -1) {
416 arg = get_argument_from_call_expr(call_implies_call_expr->args, param);
417 if (!arg)
418 continue;
420 cb->callback(arg, argv[3]);
421 } END_FOR_EACH_PTR(cb);
423 return 0;
426 static void match_call_implies(struct expression *expr)
428 struct symbol *sym;
429 static char sql_filter[1024];
431 if (expr->fn->type != EXPR_SYMBOL)
432 return;
433 sym = expr->fn->symbol;
434 if (!sym)
435 return;
437 if (sym->ctype.modifiers & MOD_STATIC) {
438 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
439 get_filename(), sym->ident->name);
440 } else {
441 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
442 sym->ident->name);
445 call_implies_call_expr = expr;
446 run_sql(call_implies_callbacks,
447 "select function, type, parameter, value from call_implies where %s",
448 sql_filter);
449 return;
452 static void print_initializer_list(struct expression_list *expr_list,
453 struct symbol *struct_type)
455 struct expression *expr;
456 struct symbol *base_type;
458 FOR_EACH_PTR(expr_list, expr) {
459 if (expr->type == EXPR_INDEX && expr->idx_expression && expr->idx_expression->type == EXPR_INITIALIZER) {
460 print_initializer_list(expr->idx_expression->expr_list, struct_type);
461 continue;
463 if (expr->type != EXPR_IDENTIFIER)
464 continue;
465 if (!expr->expr_ident)
466 continue;
467 if (!expr->ident_expression || !expr->ident_expression->symbol_name)
468 continue;
469 base_type = get_type(expr->ident_expression);
470 if (!base_type || base_type->type != SYM_FN)
471 continue;
472 sm_msg("info: sets_fn_ptr '(struct %s)->%s' '%s'", struct_type->ident->name,
473 expr->expr_ident->name,
474 expr->ident_expression->symbol_name->name);
475 } END_FOR_EACH_PTR(expr);
478 static void global_variable(struct symbol *sym)
480 struct symbol *struct_type;
482 if (!sym->ident)
483 return;
484 if (!sym->initializer || sym->initializer->type != EXPR_INITIALIZER)
485 return;
486 struct_type = get_base_type(sym);
487 if (!struct_type)
488 return;
489 if (struct_type->type == SYM_ARRAY) {
490 struct_type = get_base_type(struct_type);
491 if (!struct_type)
492 return;
494 if (struct_type->type != SYM_STRUCT || !struct_type->ident)
495 return;
496 print_initializer_list(sym->initializer->expr_list, struct_type);
499 static void match_return_info(struct expression *ret_value)
501 struct range_list *rl;
503 get_implied_range_list(ret_value, &rl);
504 rl = cast_rl(cur_func_return_type(), rl);
505 sm_msg("info: return_marker %d '%s' %s",
506 get_return_id(), show_ranges(rl), global_static());
509 static void print_returned_struct_members(struct expression *expr)
511 struct returned_member_callback *cb;
512 struct state_list *slist;
513 struct sm_state *sm;
514 struct symbol *type;
515 struct range_list *rl;
516 char *return_ranges;
517 char *name;
518 char member_name[256];
519 int len;
521 type = get_type(expr);
522 if (!type || type->type != SYM_PTR)
523 return;
524 type = get_real_base_type(type);
525 if (!type || type->type != SYM_STRUCT)
526 return;
527 name = get_variable_from_expr(expr, NULL);
528 if (!name)
529 return;
531 if (!get_implied_range_list(expr, &rl))
532 return;
533 return_ranges = show_ranges(rl);
535 member_name[sizeof(member_name) - 1] = '\0';
536 strcpy(member_name, "$$");
538 len = strlen(name);
539 FOR_EACH_PTR(returned_member_callbacks, cb) {
540 slist = get_all_states(cb->owner);
541 FOR_EACH_PTR(slist, sm) {
542 if (strncmp(sm->name, name, len) != 0)
543 continue;
544 if (strncmp(sm->name + len, "->", 2) != 0)
545 continue;
546 strncpy(member_name + 2, sm->name + len, sizeof(member_name) - 2);
547 cb->callback(return_ranges, member_name, sm->state);
548 } END_FOR_EACH_PTR(sm);
549 free_slist(&slist);
550 } END_FOR_EACH_PTR(cb);
552 free_string(name);
555 static void match_end_func_info(struct symbol *sym)
557 if (__path_is_null())
558 return;
559 sm_msg("info: return_marker %d '' %s", get_return_id(), global_static());
562 static void match_function_def(struct symbol *sym)
564 return_id = 0;
567 static void match_return(struct expression *ret_value)
569 return_id++;
572 static void match_end_func(struct symbol *sym)
574 return_id++;
577 void open_smatch_db(void)
579 #ifdef SQLITE_OPEN_READONLY
580 int rc;
582 if (option_no_db)
583 return;
585 rc = sqlite3_open_v2("smatch_db.sqlite", &db, SQLITE_OPEN_READONLY, NULL);
586 if (rc != SQLITE_OK) {
587 option_no_db = 1;
588 return;
590 return;
591 #else
592 option_no_db = 1;
593 return;
594 #endif
597 void register_definition_db_callbacks(int id)
599 add_hook(&match_function_def, FUNC_DEF_HOOK);
600 add_hook(&match_return, RETURN_HOOK);
601 add_hook(&match_end_func, END_FUNC_HOOK);
603 if (option_info) {
604 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
605 add_hook(&match_call_hack, FUNCTION_CALL_HOOK);
606 add_hook(&match_function_assign, ASSIGNMENT_HOOK);
607 add_hook(&global_variable, BASE_HOOK);
608 add_hook(&global_variable, DECLARATION_HOOK);
609 add_hook(&match_return_info, RETURN_HOOK);
610 add_hook(&print_returned_struct_members, RETURN_HOOK);
611 add_hook(&match_end_func_info, END_FUNC_HOOK);
614 if (option_no_db)
615 return;
617 add_hook(&match_data_from_db, FUNC_DEF_HOOK);
618 add_hook(&match_call_implies, FUNCTION_CALL_HOOK);