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(struct expression
*expr
)
74 struct sm_state
*sm
, *tmp
;
78 if (expr
->type
== EXPR_STRING
)
80 sm
= get_sm_state_expr(my_id
, expr
);
83 if (sm
->state
== &terminated
|| sm
->state
== &unterminated
)
86 FOR_EACH_PTR(sm
->possible
, tmp
) {
87 if (tmp
->state
== &unterminated
)
89 } END_FOR_EACH_PTR(tmp
);
94 static void match_string_assign(struct expression
*expr
)
96 struct smatch_state
*state
;
100 state
= get_terminated_state(expr
->right
);
103 set_terminated(expr
->left
, state
);
106 static int sm_to_term(struct sm_state
*sm
)
108 struct sm_state
*tmp
;
112 if (sm
->state
== &terminated
)
115 FOR_EACH_PTR(sm
->possible
, tmp
) {
116 if (tmp
->state
== &unterminated
)
118 } END_FOR_EACH_PTR(tmp
);
123 static void struct_member_callback(struct expression
*call
, int param
, char *printed_name
, struct sm_state
*sm
)
127 term
= sm_to_term(sm
);
131 sql_insert_caller_info(call
, TERMINATED
, param
, printed_name
, term
? "1" : "0");
134 static void match_call_info(struct expression
*expr
)
136 struct smatch_state
*state
;
137 struct expression
*arg
;
141 FOR_EACH_PTR(expr
->args
, arg
) {
144 state
= get_terminated_state(arg
);
147 sql_insert_caller_info(expr
, TERMINATED
, i
, "$",
148 (state
== &terminated
) ? "1" : "0");
149 } END_FOR_EACH_PTR(arg
);
152 static void caller_info_terminated(const char *name
, struct symbol
*sym
, char *key
, char *value
)
156 if (strcmp(key
, "*$") == 0)
157 snprintf(fullname
, sizeof(fullname
), "*%s", name
);
158 else if (strncmp(key
, "$", 1) == 0)
159 snprintf(fullname
, 256, "%s%s", name
, key
+ 1);
163 set_state(my_id
, fullname
, sym
, (*value
== '1') ? &terminated
: &unterminated
);
166 static void split_return_info(int return_id
, char *return_ranges
, struct expression
*expr
)
168 struct symbol
*returned_sym
;
169 struct sm_state
*tmp
, *sm
;
170 const char *param_name
;
174 FOR_EACH_MY_SM(param_set_id
, __get_cur_stree(), tmp
) {
175 sm
= get_sm_state(my_id
, tmp
->name
, tmp
->sym
);
178 term
= sm_to_term(sm
);
181 param
= get_param_num_from_sym(tmp
->sym
);
185 param_name
= get_param_name(sm
);
188 if (strcmp(param_name
, "$") == 0)
191 sql_insert_return_states(return_id
, return_ranges
, TERMINATED
,
192 param
, param_name
, term
? "1" : "0");
193 } END_FOR_EACH_SM(tmp
);
195 returned_sym
= expr_to_sym(expr
);
199 FOR_EACH_MY_SM(my_id
, __get_cur_stree(), sm
) {
200 if (sm
->sym
!= returned_sym
)
202 term
= sm_to_term(sm
);
205 param_name
= get_param_name(sm
);
208 sql_insert_return_states(return_id
, return_ranges
, TERMINATED
,
209 -1, param_name
, term
? "1" : "0");
210 } END_FOR_EACH_SM(sm
);
213 static void return_info_terminated(struct expression
*expr
, int param
, char *key
, char *value
)
215 struct expression
*arg
;
222 struct expression
*call
= expr
;
224 while (call
->type
== EXPR_ASSIGNMENT
)
225 call
= strip_expr(call
->right
);
226 if (call
->type
!= EXPR_CALL
)
229 arg
= get_argument_from_call_expr(call
->args
, param
);
234 name
= get_variable_from_key(arg
, key
, &sym
);
238 set_terminated_var_sym(name
, sym
, (*value
== '1') ? &terminated
: &unterminated
);
243 bool is_nul_terminated(struct expression
*expr
)
245 if (get_terminated_state(expr
) == &terminated
)
250 void register_nul_terminator(int id
)
254 add_hook(&match_nul_assign
, ASSIGNMENT_HOOK
);
255 add_hook(&match_string_assign
, ASSIGNMENT_HOOK
);
257 add_hook(&match_call_info
, FUNCTION_CALL_HOOK
);
258 add_member_info_callback(my_id
, struct_member_callback
);
259 add_split_return_callback(&split_return_info
);
261 select_caller_info_hook(caller_info_terminated
, TERMINATED
);
262 select_return_states_hook(TERMINATED
, return_info_terminated
);
265 void register_nul_terminator_param_set(int id
)