2 * Copyright (C) 2019 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 * There are a bunch of allocation functions where we allocate some memory,
20 * set up some struct members and then return the allocated memory. One
21 * nice thing about this is that we just one pointer to the allocated memory
22 * so what we can do is we can generate a mtag alias for it in the caller.
26 #include "smatch_extra.h"
27 #include "smatch_slist.h"
33 struct alloc_info
*alloc_funcs
;
35 struct alloc_info kernel_allocation_funcs
[] = {
44 {"kmalloc_array", 0, 1},
48 {"dma_alloc_attrs", 1},
49 {"dma_alloc_coherent", 1},
53 {"__alloc_bootmem", 0},
55 {"dma_alloc_contiguous", 1},
56 {"dma_alloc_coherent", 1},
60 struct alloc_info general_allocation_funcs
[] = {
68 static void pre_merge_hook(struct sm_state
*cur
, struct sm_state
*other
)
70 struct smatch_state
*state
;
73 state
= get_state(SMATCH_EXTRA
, cur
->name
, cur
->sym
);
74 if (estate_get_single_value(state
, &sval
) && sval
.value
== 0)
75 set_state(my_id
, cur
->name
, cur
->sym
, &undefined
);
78 static int fresh_callback(void *fresh
, int argc
, char **argv
, char **azColName
)
84 static int fresh_from_db(struct expression
*call
)
86 static struct expression
*prev_call
;
90 if (is_fake_call(call
))
93 if (call
== prev_call
)
97 /* for function pointers assume everything is used */
98 if (call
->fn
->type
!= EXPR_SYMBOL
) {
103 run_sql(&fresh_callback
, &fresh
,
104 "select * from return_states where %s and type = %d and parameter = -1 and key = '$' limit 1;",
105 get_static_filter(call
->fn
->symbol
), FRESH_ALLOC
);
111 bool is_fresh_alloc_var_sym(const char *var
, struct symbol
*sym
)
113 return get_state(my_id
, var
, sym
) == &fresh
;
116 bool is_fresh_alloc(struct expression
*expr
)
124 if (get_implied_value_fast(expr
, &sval
) && sval
.value
== 0)
127 if (get_state_expr(my_id
, expr
) == &fresh
)
130 if (expr
->type
!= EXPR_CALL
)
132 if (fresh_from_db(expr
))
135 while (alloc_funcs
[++i
].fn
) {
136 if (sym_name_is(kernel_allocation_funcs
[i
].fn
, expr
->fn
))
142 static void record_alloc_func(int return_id
, char *return_ranges
, struct expression
*expr
)
144 if (!is_fresh_alloc(expr
))
146 sql_insert_return_states(return_id
, return_ranges
, FRESH_ALLOC
, -1, "$", "");
149 static void set_unfresh(struct expression
*expr
)
153 sm
= get_sm_state_expr(my_id
, expr
);
156 if (!slist_has_state(sm
->possible
, &fresh
))
158 // TODO call unfresh hooks
159 set_state_expr(my_id
, expr
, &undefined
);
162 static void match_assign(struct expression
*expr
)
164 set_unfresh(expr
->right
);
167 static void match_call(struct expression
*expr
)
169 struct expression
*arg
;
171 FOR_EACH_PTR(expr
->args
, arg
) {
173 } END_FOR_EACH_PTR(arg
);
176 static struct expression
*handled
;
177 static void set_fresh(struct expression
*expr
)
179 struct range_list
*rl
;
181 expr
= strip_expr(expr
);
182 if (expr
->type
!= EXPR_SYMBOL
)
187 get_absolute_rl(expr
, &rl
);
188 rl
= rl_intersection(rl
, valid_ptr_rl
);
191 set_state_expr(my_id
, expr
, &fresh
);
195 static void returns_fresh_alloc(struct expression
*expr
, int param
, char *key
, char *value
)
197 if (param
!= -1 || !key
|| strcmp(key
, "$") != 0)
199 if (expr
->type
!= EXPR_ASSIGNMENT
)
202 set_fresh(expr
->left
);
205 static void match_alloc(const char *fn
, struct expression
*expr
, void *_size_arg
)
207 set_fresh(expr
->left
);
210 void register_fresh_alloc(int id
)
216 if (option_project
== PROJ_KERNEL
)
217 alloc_funcs
= kernel_allocation_funcs
;
219 alloc_funcs
= general_allocation_funcs
;
222 while (alloc_funcs
[++i
].fn
)
223 add_function_assign_hook(alloc_funcs
[i
].fn
, &match_alloc
, 0);
225 add_split_return_callback(&record_alloc_func
);
226 select_return_states_hook(FRESH_ALLOC
, &returns_fresh_alloc
);
227 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
228 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
230 add_pre_merge_hook(my_id
, &pre_merge_hook
);