2 * Copyright (C) 2010 Dan Carpenter.
3 * Copyright (C) 2021 Oracle.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
20 #include "smatch_slist.h"
21 #include "smatch_extra.h"
25 #define __GFP_NOFAIL 0x8000u
29 static unsigned long GFP_NOFAIL(void)
31 static unsigned long saved_flags
= -1;
32 struct symbol
*macro_sym
;
34 if (saved_flags
!= -1)
37 macro_sym
= lookup_macro_symbol("___GFP_NOFAIL");
39 macro_sym
= lookup_macro_symbol("__GFP_NOFAIL");
40 if (!macro_sym
|| !macro_sym
->expansion
)
42 if (token_type(macro_sym
->expansion
) != TOKEN_NUMBER
)
45 saved_flags
= strtoul(macro_sym
->expansion
->number
, NULL
, 0);
49 static void is_ok(struct sm_state
*sm
, struct expression
*mod_expr
)
51 set_state(my_id
, sm
->name
, sm
->sym
, &undefined
);
54 static void pre_merge_hook(struct sm_state
*cur
, struct sm_state
*other
)
56 struct smatch_state
*state
;
58 if (is_impossible_path()) {
59 set_state(my_id
, cur
->name
, cur
->sym
, &undefined
);
63 state
= get_state(SMATCH_EXTRA
, cur
->name
, cur
->sym
);
64 if (!state
|| !estate_rl(state
))
66 if (!rl_has_sval(estate_rl(state
), ptr_null
))
67 set_state(my_id
, cur
->name
, cur
->sym
, &undefined
);
70 static bool is_possibly_zero(const char *name
, struct symbol
*sym
)
72 struct sm_state
*sm
, *tmp
;
74 sm
= get_sm_state(SMATCH_EXTRA
, name
, sym
);
77 FOR_EACH_PTR(sm
->possible
, tmp
) {
78 if (!estate_rl(tmp
->state
))
80 if (rl_min(estate_rl(tmp
->state
)).value
== 0 &&
81 rl_max(estate_rl(tmp
->state
)).value
== 0)
83 } END_FOR_EACH_PTR(tmp
);
88 static const char *get_allocation_fn_name(const char *name
, struct symbol
*sym
)
90 struct expression
*expr
;
92 expr
= get_assigned_expr_name_sym(name
, sym
);
95 if (expr
->type
== EXPR_CALL
&&
96 expr
->fn
->type
== EXPR_SYMBOL
&&
97 expr
->fn
->symbol
&& expr
->fn
->symbol
->ident
)
98 return expr
->fn
->symbol
->ident
->name
;
103 static void check_dereference_name_sym(char *name
, struct symbol
*sym
)
108 sm
= get_sm_state(my_id
, name
, sym
);
111 if (is_ignored(my_id
, sm
->name
, sm
->sym
))
113 if (!is_possibly_zero(sm
->name
, sm
->sym
))
115 if (is_impossible_path())
117 if (!slist_has_state(sm
->possible
, &null
))
120 sm_msg("%s: sm='%s'", __func__
, show_sm(sm
));
121 fn_name
= get_allocation_fn_name(name
, sym
);
122 sm_error("potential null dereference '%s'. (%s returns null)",
126 static void check_dereference(struct expression
*expr
)
131 name
= expr_to_var_sym(expr
, &sym
);
134 check_dereference_name_sym(name
, sym
);
138 static void match_dereferences(struct expression
*expr
)
140 if (expr
->type
!= EXPR_PREOP
)
142 check_dereference(expr
->unop
);
145 static void match_pointer_as_array(struct expression
*expr
)
149 check_dereference(get_array_base(expr
));
152 static void set_param_dereferenced(struct expression
*call
, struct expression
*arg
, char *key
, char *unused
)
157 name
= get_variable_from_key(arg
, key
, &sym
);
161 check_dereference_name_sym(name
, sym
);
166 static int called_with_no_fail(struct expression
*call
, int param
)
168 struct expression
*arg
;
173 call
= strip_expr(call
);
174 if (call
->type
!= EXPR_CALL
)
176 arg
= get_argument_from_call_expr(call
->args
, param
);
177 if (get_value(arg
, &sval
) && (sval
.uvalue
& GFP_NOFAIL()))
182 static void match_assign_returns_null(const char *fn
, struct expression
*expr
, void *_gfp
)
184 int gfp_param
= PTR_INT(_gfp
);
186 if (called_with_no_fail(expr
->right
, gfp_param
))
188 set_state_expr(my_id
, expr
->left
, &null
);
191 static void register_allocation_funcs(void)
198 snprintf(filename
, sizeof(filename
), "%s.allocation_funcs_gfp", option_project_str
);
199 token
= get_tokens_file(filename
);
202 if (token_type(token
) != TOKEN_STREAMBEGIN
)
205 while (token_type(token
) != TOKEN_STREAMEND
) {
206 if (token_type(token
) != TOKEN_IDENT
) {
207 printf("error parsing '%s' line %d\n", filename
, token
->pos
.line
);
210 func
= show_ident(token
->ident
);
212 if (token_type(token
) == TOKEN_IDENT
)
214 else if (token_type(token
) == TOKEN_NUMBER
)
215 arg
= atoi(token
->number
);
217 printf("error parsing '%s' line %d\n", filename
, token
->pos
.line
);
220 add_function_assign_hook(func
, &match_assign_returns_null
, INT_PTR(arg
));
226 void check_unchecked_allocation(int id
)
230 add_modification_hook(my_id
, &is_ok
);
231 add_pre_merge_hook(my_id
, &pre_merge_hook
);
232 add_hook(&match_dereferences
, DEREF_HOOK
);
233 add_hook(&match_pointer_as_array
, OP_HOOK
);
234 select_return_implies_hook(DEREFERENCE
, &set_param_dereferenced
);
235 register_allocation_funcs();