2 * Copyright (C) 2020 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 * This is the "strict" version which is more daring and ambitious than
20 * the check_free.c file. The difference is that this looks at split
21 * returns and the other only looks at if every path frees a parameter.
22 * Also this has a bunch of kernel specific things to do with reference
28 #include "smatch_slist.h"
29 #include "smatch_extra.h"
37 static unsigned long silenced
;
39 static void set_ignore(struct sm_state
*sm
, struct expression
*mod_expr
)
41 set_state(my_id
, sm
->name
, sm
->sym
, &undefined
);
44 struct statement
*ignored_stmt
;
45 static void trigger_list_del(struct sm_state
*sm
, struct expression
*mod_expr
)
50 if (__cur_stmt
== ignored_stmt
)
53 snprintf(buf
, sizeof(buf
), "&%s", sm
->name
);
54 p
= strstr(buf
, ".next");
58 set_state(my_id
, buf
, sm
->sym
, &undefined
);
61 static void set_up_next_trigger(struct expression
*expr
)
63 struct symbol
*type
, *member
;
64 struct expression
*next
;
66 type
= get_pointer_type(expr
);
67 if (!type
|| type
->type
!= SYM_STRUCT
)
69 member
= first_ptr_list((struct ptr_list
*)type
->symbol_list
);
70 if (!member
|| !member
->ident
||
71 strcmp(member
->ident
->name
, "next") != 0)
74 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
77 next
= member_expression(expr
, '.', member
->ident
);
78 set_state_expr(next_id
, next
, &trigger
);
79 ignored_stmt
= __cur_stmt
;
82 static void match_add(const char *fn
, struct expression
*expr
, void *param
)
84 struct expression
*arg
;
86 arg
= get_argument_from_call_expr(expr
->args
, 0);
87 set_state_expr(my_id
, arg
, &added
);
88 set_up_next_trigger(arg
);
91 static void match_del(const char *fn
, struct expression
*expr
, void *param
)
93 struct expression
*arg
;
95 arg
= get_argument_from_call_expr(expr
->args
, 0);
96 if (!get_state_expr(my_id
, arg
)) {
100 set_state_expr(my_id
, arg
, &undefined
);
103 static void match_free(const char *fn
, struct expression
*expr
, void *param
)
105 struct expression
*arg
;
113 arg
= get_argument_from_call_expr(expr
->args
, PTR_INT(param
));
116 name
= expr_to_var_sym(arg
, &sym
);
120 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
121 if (sm
->state
== &undefined
)
125 if (strncmp(sm
->name
+ 1, name
, strlen(name
)) != 0)
127 sm_warning("'%s' not removed from list", sm
->name
);
129 } END_FOR_EACH_SM(sm
);
134 void check_list_add(int id
)
138 if (option_project
!= PROJ_KERNEL
)
141 add_function_data(&silenced
);
143 add_function_hook("list_add", &match_add
, NULL
);
144 add_function_hook("list_add_tail", &match_add
, NULL
);
145 add_function_hook("list_del", &match_del
, NULL
);
147 add_modification_hook(my_id
, &set_ignore
);
149 add_function_hook("kfree", &match_free
, 0);
152 void check_list_add_late(int id
)
155 add_modification_hook(next_id
, &trigger_list_del
);