2 * Copyright (C) 2022 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"
20 #include "smatch_slist.h"
24 static struct statement
*goto_stmt
, *next_goto
;
25 static struct expression
*return_expr
;
27 static unsigned long set_label
;
28 static unsigned long label_cnt
;
30 static void reset(void)
37 static bool is_do_nothing_goto(struct statement
*goto_stmt
)
40 struct statement
*stmt
;
42 fn
= get_base_type(cur_func_sym
);
47 stmt
= fn
->inline_stmt
;
48 if (!stmt
|| stmt
->type
!= STMT_COMPOUND
)
50 stmt
= last_ptr_list((struct ptr_list
*)stmt
->stmts
);
53 if (stmt
->type
!= STMT_LABEL
)
56 if (!stmt
->label_identifier
||
57 stmt
->label_identifier
->type
!= SYM_LABEL
||
58 !stmt
->label_identifier
->ident
)
61 if (strcmp(stmt
->label_identifier
->ident
->name
,
62 goto_stmt
->goto_label
->ident
->name
) == 0)
68 static bool is_printk_stmt(struct statement
*stmt
)
75 str
= pos_ident(stmt
->pos
);
79 if (strcmp(str
, "dev_err") == 0 ||
80 strcmp(str
, "dev_info") == 0 ||
81 strcmp(str
, "dev_warn") == 0 ||
82 strcmp(str
, "dev_notice") == 0 ||
83 strcmp(str
, "dev_dbg") == 0)
86 if (strcmp(str
, "pr_err") == 0 ||
87 strcmp(str
, "pr_info") == 0 ||
88 strcmp(str
, "pr_warn") == 0 ||
89 strcmp(str
, "pr_notice") == 0 ||
90 strcmp(str
, "pr_debug") == 0)
93 if (strstr(str
, "_dev_err") ||
94 strstr(str
, "_dev_warn") ||
95 strstr(str
, "_dev_dbg"))
101 static bool label_name_matches(struct statement
*goto_stmt
,
102 struct statement
*stmt
)
107 if (stmt
->type
!= STMT_LABEL
)
110 if (!stmt
->label_identifier
||
111 stmt
->label_identifier
->type
!= SYM_LABEL
||
112 !stmt
->label_identifier
->ident
)
115 if (strcmp(stmt
->label_identifier
->ident
->name
,
116 goto_stmt
->goto_label
->ident
->name
) == 0)
122 static bool is_printk_goto(struct statement
*goto_stmt
)
125 struct statement
*stmt
, *tmp
;
127 fn
= get_base_type(cur_func_sym
);
132 stmt
= fn
->inline_stmt
;
133 if (!stmt
|| stmt
->type
!= STMT_COMPOUND
)
136 FOR_EACH_PTR_REVERSE(stmt
->stmts
, tmp
) {
137 if (tmp
->type
== STMT_RETURN
)
139 if (tmp
->type
== STMT_LABEL
&&
140 !is_printk_stmt(tmp
->label_statement
))
142 if (is_printk_stmt(tmp
))
144 if (label_name_matches(goto_stmt
, tmp
))
147 } END_FOR_EACH_PTR_REVERSE(tmp
);
152 static void match_goto(struct statement
*stmt
)
154 /* Find the first goto */
159 if (stmt
->type
!= STMT_GOTO
||
161 stmt
->goto_label
->type
!= SYM_LABEL
||
162 !stmt
->goto_label
->ident
)
165 if (is_do_nothing_goto(stmt
))
168 if (is_printk_goto(stmt
))
174 static void match_return(struct expression
*expr
)
176 struct range_list
*rl
;
184 !get_implied_rl(expr
, &rl
) ||
185 success_fail_return(rl
) != RET_FAIL
) {
193 static void match_next_goto(struct statement
*stmt
)
198 if (stmt
->type
!= STMT_GOTO
||
200 stmt
->goto_label
->type
!= SYM_LABEL
||
201 !stmt
->goto_label
->ident
)
204 if (!goto_stmt
|| !return_expr
) {
212 static void add_label_cnt(struct statement
*stmt
)
220 !stmt
->label_identifier
||
221 stmt
->label_identifier
->type
!= SYM_LABEL
||
222 !stmt
->label_identifier
->ident
)
225 if (strcmp(stmt
->label_identifier
->ident
->name
,
226 goto_stmt
->goto_label
->ident
->name
) == 0)
229 if (strcmp(stmt
->label_identifier
->ident
->name
,
230 next_goto
->goto_label
->ident
->name
) == 0)
234 static void match_label(struct statement
*stmt
)
238 if (stmt
->type
!= STMT_LABEL
)
241 if (get_state(my_id
, "cleanup", NULL
) == &true_state
) {
242 /* The second label in a cleanup block is still cleanup. */
249 * If the cleanup block isn't preceded by a "return 0;" then it could
253 if (__get_cur_stree())
255 if (!__prev_stmt
|| __prev_stmt
->type
!= STMT_RETURN
)
257 if (!get_implied_value(__prev_stmt
->ret_value
, &sval
) || sval
.value
!= 0)
259 /* We can't set the state until after we've merged the gotos. */
264 static void match_label_after(struct statement
*stmt
)
266 if (stmt
->type
!= STMT_LABEL
)
269 set_state(my_id
, "cleanup", NULL
, &true_state
);
274 static void match_final_return(struct expression
*expr
)
276 struct range_list
*rl
;
285 if (get_state(my_id
, "cleanup", NULL
) != &true_state
)
288 if (!get_implied_rl(expr
, &rl
))
290 if (success_fail_return(rl
) != RET_FAIL
)
293 sm_warning_line(return_expr
->pos
.line
, "missing unwind goto?");
296 void check_direct_return_instead_of_goto(int id
)
300 if (option_project
!= PROJ_KERNEL
)
303 add_function_data(&set_label
);
304 add_function_data(&label_cnt
);
306 add_function_data((unsigned long *)&goto_stmt
);
307 add_function_data((unsigned long *)&return_expr
);
308 add_function_data((unsigned long *)&next_goto
);
310 // check them in reverse order
311 add_hook(&match_next_goto
, STMT_HOOK
);
312 add_hook(&match_return
, RETURN_HOOK
);
313 add_hook(&match_goto
, STMT_HOOK
);
314 add_hook(&match_final_return
, RETURN_HOOK
);
317 add_hook(&match_label
, STMT_HOOK
);
318 add_hook(&match_label_after
, STMT_HOOK_AFTER
);