strlen: add a comment and rename some things
[smatch.git] / smatch_strlen.c
blob65249f02702ad9e9b803a6f62d5cc405f1548862
1 /*
2 * smatch/smatch_strlen.c
4 * Copyright (C) 2013 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdlib.h>
11 #include <errno.h>
12 #include "parse.h"
13 #include "smatch.h"
14 #include "smatch_slist.h"
15 #include "smatch_extra.h"
18 * The trick with the my_equiv_id is that if we have:
19 * foo = strlen(bar);
20 * We don't know at that point what the strlen() is but we know it's equivalent
21 * to "foo" so maybe we can find the value of "foo" later.
23 static int my_equiv_id;
25 static void set_strlen_equiv_undefined(struct sm_state *sm, struct expression *mod_expr)
27 set_state(sm->owner, sm->name, sm->sym, &undefined);
30 static void match_strlen(const char *fn, struct expression *expr, void *unused)
32 struct expression *right;
33 struct expression *str;
34 struct expression *len_expr;
35 char *len_name;
36 struct smatch_state *state;
38 right = strip_expr(expr->right);
39 str = get_argument_from_call_expr(right->args, 0);
40 len_expr = strip_expr(expr->left);
42 len_name = expr_to_var(len_expr);
43 if (!len_name)
44 return;
46 state = __alloc_smatch_state(0);
47 state->name = len_name;
48 state->data = len_expr;
50 set_state_expr(my_equiv_id, str, state);
53 static int get_strlen_from_string(struct expression *expr, struct range_list **rl)
55 sval_t sval;
56 int len;
58 len = expr->string->length;
59 sval = sval_type_val(&int_ctype, len - 1);
60 *rl = alloc_rl(sval, sval);
61 return 1;
64 int get_implied_strlen(struct expression *expr, struct range_list **rl)
66 struct smatch_state *state;
68 *rl = NULL;
70 switch (expr->type) {
71 case EXPR_STRING:
72 return get_strlen_from_string(expr, rl);
75 state = get_state_expr(my_equiv_id, expr);
76 if (!state || !state->data)
77 return 0;
78 if (!get_implied_rl((struct expression *)state->data, rl))
79 return 0;
80 return 1;
83 int get_size_from_strlen(struct expression *expr)
85 struct range_list *rl;
86 sval_t max;
88 if (!get_implied_strlen(expr, &rl))
89 return 0;
90 max = rl_max(rl);
91 if (sval_is_negative(max) || sval_is_max(max))
92 return 0;
94 return max.value + 1; /* add one because strlen doesn't include the NULL */
97 void register_strlen(int id)
99 my_equiv_id = id;
100 add_function_assign_hook("strlen", &match_strlen, NULL);
101 add_modification_hook(my_equiv_id, &set_strlen_equiv_undefined);