db/fixup_kernel.sh: fix clear_user() handling
[smatch.git] / smatch_kernel_err_ptr.c
bloba3f75e180ebda1ea3d6e1155a020648e586c725a
1 /*
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
18 #include "smatch.h"
19 #include "smatch_extra.h"
20 #include "smatch_slist.h"
22 static int my_id;
24 STATE(err_ptr);
26 bool possible_err_ptr(struct expression *expr)
28 struct smatch_state *state;
29 struct range_list *rl;
31 state = get_state_expr(SMATCH_EXTRA, expr);
32 if (state && estate_is_empty(state))
33 return false;
35 get_absolute_rl(expr, &rl);
36 if (!rl_intersection(rl, alloc_rl(ptr_err_min, ptr_err_max)))
37 return false;
38 if (!expr_has_possible_state(my_id, expr, &err_ptr))
39 return false;
40 return true;
43 static void match_return_info(int return_id, char *return_ranges,
44 struct expression *returned_expr,
45 int param,
46 const char *printed_name,
47 struct sm_state *sm)
49 struct smatch_state *state;
51 if (param != -1 || strcmp(printed_name, "$") != 0)
52 return;
53 if (!slist_has_state(sm->possible, &err_ptr))
54 return;
56 state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
57 if (!state)
58 return;
59 if (!rl_intersection(estate_rl(state), alloc_rl(ptr_err_min, ptr_err_max)))
60 return;
62 sql_insert_return_states(return_id, return_ranges, ERR_PTR, param, printed_name, "");
65 static void match_assign(struct expression *expr)
68 * I felt like I had to implement this function for completeness but
69 * also that it isn't required and might lead to false positives.
71 if (expr->op != '=' || !is_pointer(expr->left))
72 return;
73 if (!has_states(__get_cur_stree(), my_id))
74 return;
75 if (possible_err_ptr(expr->right))
76 set_state_expr(my_id, expr->left, &err_ptr);
79 static void match_err_ptr(const char *fn, struct expression *expr, void *unused)
81 set_state_expr(my_id, expr->left, &err_ptr);
84 static void set_error_code(struct expression *expr, const char *name, struct symbol *sym, void *data)
86 char *macro;
88 macro = get_macro_name(expr->pos);
89 if (macro) {
90 if (strcmp(macro, "for_each_gpio_desc") == 0 ||
91 strcmp(macro, "for_each_gpio_desc_with_flag") == 0)
92 return;
95 set_state(my_id, name, sym, &err_ptr);
98 static void match_is_err_true(struct expression *expr, const char *name, struct symbol *sym, void *data)
100 set_state(my_id, name, sym, &err_ptr);
103 static void match_is_err_false(struct expression *expr, const char *name, struct symbol *sym, void *data)
105 set_state(my_id, name, sym, &undefined);
108 void register_kernel_err_ptr(int id)
110 my_id = id;
112 if (option_project != PROJ_KERNEL)
113 return;
115 add_modification_hook(my_id, &set_undefined);
116 add_hook(&match_assign, ASSIGNMENT_HOOK);
118 add_return_info_callback(my_id, &match_return_info);
120 add_function_assign_hook("ERR_PTR", &match_err_ptr, NULL);
121 add_function_assign_hook("ERR_CAST", &match_err_ptr, NULL);
122 return_implies_param_key_exact("IS_ERR", int_one, int_one,
123 match_is_err_true, 0, "$", NULL);
124 return_implies_param_key_exact("IS_ERR", int_zero, int_zero,
125 match_is_err_false, 0, "$", NULL);
126 return_implies_param_key_exact("PTR_ERR_OR_ZERO", ptr_err_min, ptr_err_max,
127 match_is_err_true, 0, "$", NULL);
128 return_implies_param_key_exact("PTR_ERR_OR_ZERO", int_zero, int_zero,
129 match_is_err_false, 0, "$", NULL);
130 return_implies_param_key_exact("IS_ERR_OR_NULL", int_zero, int_zero,
131 match_is_err_false, 0, "$", NULL);
132 select_return_param_key(ERR_PTR, &set_error_code);