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 check looks for code like:
30 * And the bug is that some error paths forgot to set "ret" to an error code.
35 #include "smatch_slist.h"
36 #include "smatch_extra.h"
41 * Instead of having a bunch of different states declared here,
42 * what this does is it has "goto == &yup" and "cleanup == &yup"
47 static bool set_label
;
49 static void match_goto(struct statement
*stmt
)
51 if (stmt
->type
!= STMT_GOTO
)
53 set_state(my_id
, "goto", NULL
, &yup
);
56 static void match_label(struct statement
*stmt
)
60 if (stmt
->type
!= STMT_LABEL
)
62 if (get_state(my_id
, "cleanup", NULL
) == &yup
) {
63 /* The second label in a cleanup block is still cleanup. */
69 * If the cleanup block isn't preceded by a "return 0;" then it could
73 if (__get_cur_stree())
75 if (!__prev_stmt
|| __prev_stmt
->type
!= STMT_RETURN
)
77 if (!get_implied_value(__prev_stmt
->ret_value
, &sval
) || sval
.value
!= 0)
79 /* We can't set the state until after we've merged the gotos. */
83 static void match_label_after(struct statement
*stmt
)
85 if (stmt
->type
!= STMT_LABEL
)
88 set_state(my_id
, "cleanup", NULL
, &yup
);
93 static bool find_pool(struct sm_state
*extra_sm
, struct stree
*pool
)
95 if (!extra_sm
|| !pool
)
98 if (extra_sm
->pool
== pool
)
100 if (find_pool(extra_sm
->left
, pool
))
102 if (find_pool(extra_sm
->right
, pool
))
108 static int check_pool(struct sm_state
*goto_sm
, struct sm_state
*extra_sm
)
110 struct sm_state
*old
;
118 orig
= __swap_cur_stree(goto_sm
->pool
);
120 old
= get_sm_state(SMATCH_EXTRA
, extra_sm
->name
, extra_sm
->sym
);
123 if (goto_sm
->line
< old
->line
)
124 goto swap
; // hopefully this is impossible
125 if (goto_sm
->line
< old
->line
+ 3)
126 goto swap
; // the ret value is deliberately set to zero
127 if (!estate_get_single_value(old
->state
, &sval
) || sval
.value
!= 0)
128 goto swap
; // the ret variable is not zero
129 if (!find_pool(extra_sm
, old
->pool
))
130 goto swap
; // the ret variable was modified after the goto
132 line
= goto_sm
->line
;
134 __swap_cur_stree(orig
);
138 static int recursive_search_for_zero(struct sm_state
*goto_sm
, struct sm_state
*extra_sm
)
145 line
= check_pool(goto_sm
, extra_sm
);
149 line
= recursive_search_for_zero(goto_sm
->left
, extra_sm
);
152 line
= recursive_search_for_zero(goto_sm
->right
, extra_sm
);
159 static void match_return(struct statement
*stmt
)
161 struct sm_state
*goto_sm
, *extra_sm
;
165 if (stmt
->type
!= STMT_RETURN
)
167 if (!stmt
->ret_value
|| stmt
->ret_value
->type
!= EXPR_SYMBOL
)
169 if (cur_func_return_type() != &int_ctype
)
171 if (get_state(my_id
, "cleanup", NULL
) != &yup
)
173 goto_sm
= get_sm_state(my_id
, "goto", NULL
);
174 if (!goto_sm
|| goto_sm
->state
!= &yup
)
176 extra_sm
= get_extra_sm_state(stmt
->ret_value
);
179 if (!estate_rl(extra_sm
->state
) ||
180 !sval_is_negative(rl_min(estate_rl(extra_sm
->state
))))
182 line
= recursive_search_for_zero(goto_sm
, extra_sm
);
186 name
= expr_to_str(stmt
->ret_value
);
187 sm_printf("%s:%d %s() warn: missing error code '%s'\n",
188 get_filename(), line
, get_function(), name
);
192 void check_missing_error_code(int id
)
194 if (option_project
!= PROJ_KERNEL
)
199 add_hook(&match_goto
, STMT_HOOK
);
200 add_hook(&match_label
, STMT_HOOK
);
201 add_hook(&match_label_after
, STMT_HOOK_AFTER
);
202 add_hook(&match_return
, STMT_HOOK
);