2 * Copyright (C) 2018 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_slist.h"
22 static int param_set_id
;
28 static void set_terminated_var_sym(const char *name
, struct symbol
*sym
, struct smatch_state
*state
)
30 if (get_param_num_from_sym(sym
) >= 0)
31 set_state(param_set_id
, name
, sym
, &set
);
32 set_state(my_id
, name
, sym
, state
);
35 static void set_terminated(struct expression
*expr
, struct smatch_state
*state
)
40 name
= expr_to_var_sym(expr
, &sym
);
43 set_terminated_var_sym(name
, sym
, state
);
47 static void match_nul_assign(struct expression
*expr
)
49 struct expression
*array
;
56 if (!get_value(expr
->right
, &sval
) || sval
.value
!= 0)
59 array
= get_array_base(expr
->left
);
63 type
= get_type(array
);
66 type
= get_real_base_type(type
);
67 if (type
!= &char_ctype
)
69 set_terminated(array
, &terminated
);
72 static struct smatch_state
*get_terminated_state_var_sym(const char *name
, struct symbol
*sym
)
74 struct sm_state
*sm
, *tmp
;
76 sm
= get_sm_state(my_id
, name
, sym
);
79 if (sm
->state
== &terminated
|| sm
->state
== &unterminated
)
82 FOR_EACH_PTR(sm
->possible
, tmp
) {
83 if (tmp
->state
== &unterminated
)
85 } END_FOR_EACH_PTR(tmp
);
90 static struct smatch_state
*get_terminated_state(struct expression
*expr
)
92 struct sm_state
*sm
, *tmp
;
96 if (expr
->type
== EXPR_STRING
)
98 sm
= get_sm_state_expr(my_id
, expr
);
101 if (sm
->state
== &terminated
|| sm
->state
== &unterminated
)
104 FOR_EACH_PTR(sm
->possible
, tmp
) {
105 if (tmp
->state
== &unterminated
)
106 return &unterminated
;
107 } END_FOR_EACH_PTR(tmp
);
112 static void match_string_assign(struct expression
*expr
)
114 struct smatch_state
*state
;
118 state
= get_terminated_state(expr
->right
);
121 set_terminated(expr
->left
, state
);
124 static int sm_to_term(struct sm_state
*sm
)
126 struct sm_state
*tmp
;
130 if (sm
->state
== &terminated
)
133 FOR_EACH_PTR(sm
->possible
, tmp
) {
134 if (tmp
->state
== &unterminated
)
136 } END_FOR_EACH_PTR(tmp
);
141 static void struct_member_callback(struct expression
*call
, int param
, char *printed_name
, struct sm_state
*sm
)
145 term
= sm_to_term(sm
);
149 sql_insert_caller_info(call
, TERMINATED
, param
, printed_name
, term
? "1" : "0");
152 static void match_call_info(struct expression
*expr
)
154 struct smatch_state
*state
;
155 struct expression
*arg
;
159 FOR_EACH_PTR(expr
->args
, arg
) {
162 state
= get_terminated_state(arg
);
165 sql_insert_caller_info(expr
, TERMINATED
, i
, "$",
166 (state
== &terminated
) ? "1" : "0");
167 } END_FOR_EACH_PTR(arg
);
170 static void caller_info_terminated(const char *name
, struct symbol
*sym
, char *key
, char *value
)
174 if (strcmp(key
, "*$") == 0)
175 snprintf(fullname
, sizeof(fullname
), "*%s", name
);
176 else if (strncmp(key
, "$", 1) == 0)
177 snprintf(fullname
, 256, "%s%s", name
, key
+ 1);
181 set_state(my_id
, fullname
, sym
, (*value
== '1') ? &terminated
: &unterminated
);
184 static void split_return_info(int return_id
, char *return_ranges
, struct expression
*expr
)
186 struct symbol
*returned_sym
;
187 struct sm_state
*tmp
, *sm
;
188 const char *param_name
;
192 FOR_EACH_MY_SM(param_set_id
, __get_cur_stree(), tmp
) {
193 sm
= get_sm_state(my_id
, tmp
->name
, tmp
->sym
);
196 term
= sm_to_term(sm
);
199 param
= get_param_num_from_sym(tmp
->sym
);
203 param_name
= get_param_name(sm
);
206 if (strcmp(param_name
, "$") == 0)
209 sql_insert_return_states(return_id
, return_ranges
, TERMINATED
,
210 param
, param_name
, term
? "1" : "0");
211 } END_FOR_EACH_SM(tmp
);
213 returned_sym
= expr_to_sym(expr
);
217 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
218 if (sm
->sym
!= returned_sym
)
220 term
= sm_to_term(sm
);
223 param_name
= get_param_name(sm
);
226 sql_insert_return_states(return_id
, return_ranges
, TERMINATED
,
227 -1, param_name
, term
? "1" : "0");
228 } END_FOR_EACH_SM(sm
);
231 static void return_info_terminated(struct expression
*expr
, int param
, char *key
, char *value
)
233 struct expression
*arg
;
240 struct expression
*call
= expr
;
242 while (call
->type
== EXPR_ASSIGNMENT
)
243 call
= strip_expr(call
->right
);
244 if (call
->type
!= EXPR_CALL
)
247 arg
= get_argument_from_call_expr(call
->args
, param
);
252 name
= get_variable_from_key(arg
, key
, &sym
);
256 set_terminated_var_sym(name
, sym
, (*value
== '1') ? &terminated
: &unterminated
);
261 bool is_nul_terminated_var_sym(const char *name
, struct symbol
*sym
)
263 if (get_terminated_state_var_sym(name
, sym
) == &terminated
)
268 bool is_nul_terminated(struct expression
*expr
)
270 if (get_terminated_state(expr
) == &terminated
)
275 static void match_strnlen_test(struct expression
*expr
)
277 struct expression
*left
, *tmp
, *arg
;
280 if (expr
->type
!= EXPR_COMPARE
)
282 if (expr
->op
!= SPECIAL_EQUAL
&& expr
->op
!= SPECIAL_NOTEQUAL
)
285 left
= strip_expr(expr
->left
);
287 while ((tmp
= get_assigned_expr(left
))) {
293 if (left
->type
!= EXPR_CALL
)
295 if (!sym_name_is("strnlen", left
->fn
))
297 arg
= get_argument_from_call_expr(left
->args
, 0);
298 set_true_false_states_expr(my_id
, arg
,
299 (expr
->op
== SPECIAL_EQUAL
) ? &terminated
: NULL
,
300 (expr
->op
== SPECIAL_NOTEQUAL
) ? &terminated
: NULL
);
301 if (get_param_num(arg
) >= 0)
302 set_true_false_states_expr(param_set_id
, arg
,
303 (expr
->op
== SPECIAL_EQUAL
) ? &terminated
: NULL
,
304 (expr
->op
== SPECIAL_NOTEQUAL
) ? &terminated
: NULL
);
307 void register_nul_terminator(int id
)
311 add_hook(&match_nul_assign
, ASSIGNMENT_HOOK
);
312 add_hook(&match_string_assign
, ASSIGNMENT_HOOK
);
314 add_hook(&match_call_info
, FUNCTION_CALL_HOOK
);
315 add_member_info_callback(my_id
, struct_member_callback
);
316 add_split_return_callback(&split_return_info
);
318 select_caller_info_hook(caller_info_terminated
, TERMINATED
);
319 select_return_states_hook(TERMINATED
, return_info_terminated
);
321 add_hook(&match_strnlen_test
, CONDITION_HOOK
);
324 void register_nul_terminator_param_set(int id
)