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"
26 static void clear_state(struct sm_state
*sm
, struct expression
*mod_expr
)
28 set_state(my_id
, sm
->name
, sm
->sym
, &undefined
);
31 static void pre_merge_hook(struct sm_state
*cur
, struct sm_state
*other
)
36 sm
= get_sm_state(SMATCH_EXTRA
, cur
->name
, cur
->sym
);
37 if (!sm
|| !estate_rl(sm
->state
))
39 if (type_unsigned(estate_type(sm
->state
)))
41 sval
= estate_min(sm
->state
);
43 set_state(my_id
, cur
->name
, cur
->sym
, &undefined
);
46 static bool is_error_macro(struct expression
*expr
)
53 if (expr
->type
!= EXPR_PREOP
|| expr
->op
!= '-')
56 if (!get_value(expr
, &sval
))
58 if (sval
.value
< -4095 || sval
.value
>= 0)
62 macro
= get_macro_name(expr
->pos
);
63 if (!macro
|| macro
[0] != 'E')
69 static void match_assign(struct expression
*expr
)
74 if (!is_error_macro(expr
->right
))
77 set_state_expr(my_id
, expr
->left
, &error_code
);
80 static void match_condition(struct expression
*expr
)
82 if (expr
->type
!= EXPR_COMPARE
)
84 if (expr
->op
!= '<' && expr
->op
!= SPECIAL_LTE
)
86 if (!expr_is_zero(expr
->right
))
89 set_true_false_states_expr(my_id
, expr
->left
, NULL
, &undefined
);
92 static bool is_empty_state(struct expression
*expr
)
94 struct smatch_state
*state
;
96 state
= get_extra_state(expr
);
104 bool holds_kernel_error_codes(struct expression
*expr
)
106 struct range_list
*rl
;
111 if (is_error_macro(expr
))
114 if (is_empty_state(expr
))
117 if (get_implied_rl(expr
, &rl
)) {
118 if (rl_min(rl
).value
>= 0 &&
119 rl_max(rl
).uvalue
<= INT_MAX
)
122 if (type_positive_bits(rl_type(rl
)) >= 63 &&
123 !sval_is_negative(rl_min(rl
)) &&
124 rl_max(rl
).uvalue
<= UINT_MAX
)
128 return expr_has_possible_state(my_id
, expr
, &error_code
);
131 static void match_return(int return_id
, char *return_ranges
, struct expression
*expr
)
136 if (!holds_kernel_error_codes(expr
))
139 sql_insert_return_states(return_id
, return_ranges
, NEGATIVE_ERROR
,
143 static void set_error_code(struct expression
*expr
, const char *name
, struct symbol
*sym
, void *data
)
145 set_state(my_id
, name
, sym
, &error_code
);
148 void check_returns_negative_error_code(int id
)
152 if (option_project
!= PROJ_KERNEL
)
155 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
156 add_hook(&match_condition
, CONDITION_HOOK
);
157 add_modification_hook(my_id
, &clear_state
);
158 add_pre_merge_hook(my_id
, &pre_merge_hook
);
159 add_split_return_callback(&match_return
);
160 select_return_param_key(NEGATIVE_ERROR
, &set_error_code
);