2 * smatch/smatch_strlen.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
14 #include "smatch_slist.h"
15 #include "smatch_extra.h"
17 #define UNKNOWN_SIZE (-1)
19 static int my_strlen_id
;
21 * The trick with the my_equiv_id is that if we have:
23 * We don't know at that point what the strlen() is but we know it's equivalent
24 * to "foo" so maybe we can find the value of "foo" later.
26 static int my_equiv_id
;
28 static struct smatch_state
*size_to_estate(int size
)
32 sval
.type
= &int_ctype
;
35 return alloc_estate_sval(sval
);
38 static struct smatch_state
*unmatched_strlen_state(struct sm_state
*sm
)
40 return size_to_estate(UNKNOWN_SIZE
);
43 static void set_strlen_undefined(struct sm_state
*sm
, struct expression
*mod_expr
)
45 set_state(sm
->owner
, sm
->name
, sm
->sym
, size_to_estate(UNKNOWN_SIZE
));
48 static void set_strlen_equiv_undefined(struct sm_state
*sm
, struct expression
*mod_expr
)
50 set_state(sm
->owner
, sm
->name
, sm
->sym
, &undefined
);
53 static void match_string_assignment(struct expression
*expr
)
55 struct range_list
*rl
;
59 if (!get_implied_strlen(expr
->right
, &rl
))
61 set_state_expr(my_strlen_id
, expr
->left
, alloc_estate_rl(clone_rl(rl
)));
64 static void match_strlen(const char *fn
, struct expression
*expr
, void *unused
)
66 struct expression
*right
;
67 struct expression
*str
;
68 struct expression
*len_expr
;
70 struct smatch_state
*state
;
72 right
= strip_expr(expr
->right
);
73 str
= get_argument_from_call_expr(right
->args
, 0);
74 len_expr
= strip_expr(expr
->left
);
76 len_name
= expr_to_var(len_expr
);
80 state
= __alloc_smatch_state(0);
81 state
->name
= len_name
;
82 state
->data
= len_expr
;
84 set_state_expr(my_equiv_id
, str
, state
);
87 static int get_strlen_from_string(struct expression
*expr
, struct range_list
**rl
)
92 len
= expr
->string
->length
;
93 sval
= sval_type_val(&int_ctype
, len
- 1);
94 *rl
= alloc_rl(sval
, sval
);
99 static int get_strlen_from_state(struct expression
*expr
, struct range_list
**rl
)
101 struct smatch_state
*state
;
103 state
= get_state_expr(my_strlen_id
, expr
);
106 *rl
= estate_rl(state
);
110 static int get_strlen_from_equiv(struct expression
*expr
, struct range_list
**rl
)
112 struct smatch_state
*state
;
114 state
= get_state_expr(my_equiv_id
, expr
);
115 if (!state
|| !state
->data
)
117 if (!get_implied_rl((struct expression
*)state
->data
, rl
))
122 int get_implied_strlen(struct expression
*expr
, struct range_list
**rl
)
127 switch (expr
->type
) {
129 return get_strlen_from_string(expr
, rl
);
132 if (get_strlen_from_state(expr
, rl
))
134 if (get_strlen_from_equiv(expr
, rl
))
139 int get_size_from_strlen(struct expression
*expr
)
141 struct range_list
*rl
;
144 if (!get_implied_strlen(expr
, &rl
))
147 if (sval_is_negative(max
) || sval_is_max(max
))
150 return max
.value
+ 1; /* add one because strlen doesn't include the NULL */
153 void set_param_strlen(const char *name
, struct symbol
*sym
, char *key
, char *value
)
155 struct range_list
*rl
= NULL
;
156 struct smatch_state
*state
;
159 if (strncmp(key
, "$$", 2) != 0)
162 snprintf(fullname
, 256, "%s%s", name
, key
+ 2);
164 str_to_rl(&int_ctype
, value
, &rl
);
165 if (!rl
|| is_whole_rl(rl
))
167 state
= alloc_estate_rl(rl
);
168 set_state(my_strlen_id
, fullname
, sym
, state
);
171 static void match_call(struct expression
*expr
)
173 struct expression
*arg
;
174 struct range_list
*rl
;
178 FOR_EACH_PTR(expr
->args
, arg
) {
179 if (!get_implied_strlen(arg
, &rl
))
181 if (!is_whole_rl(rl
))
182 sql_insert_caller_info(expr
, STR_LEN
, i
, "$$", show_rl(rl
));
184 } END_FOR_EACH_PTR(arg
);
187 static void struct_member_callback(struct expression
*call
, int param
, char *printed_name
, struct smatch_state
*state
)
189 if (state
== &merged
)
191 sql_insert_caller_info(call
, STR_LEN
, param
, printed_name
, state
->name
);
194 void register_strlen(int id
)
198 add_unmatched_state_hook(my_strlen_id
, &unmatched_strlen_state
);
200 select_caller_info_hook(set_param_strlen
, STR_LEN
);
201 add_hook(&match_string_assignment
, ASSIGNMENT_HOOK
);
203 add_modification_hook(my_strlen_id
, &set_strlen_undefined
);
204 add_merge_hook(my_strlen_id
, &merge_estates
);
205 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
206 add_member_info_callback(my_strlen_id
, struct_member_callback
);
209 void register_strlen_equiv(int id
)
212 add_function_assign_hook("strlen", &match_strlen
, NULL
);
213 add_modification_hook(my_equiv_id
, &set_strlen_equiv_undefined
);