struct_assignment: move and improve handling smatch_data/*.clears_argument
[smatch.git] / smatch_struct_assignment.c
blobc636aa615dd9fa2fb6507ace6943d3df17aacc5e
1 /*
2 * sparse/smatch_struct_assignment.c
4 * Copyright (C) 2014 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include "scope.h"
11 #include "smatch.h"
12 #include "smatch_slist.h"
13 #include "smatch_extra.h"
15 static struct symbol *get_struct_type(struct expression *expr)
17 struct symbol *type;
19 type = get_type(expr);
20 if (!type)
21 return NULL;
22 if (type->type == SYM_PTR)
23 type = get_real_base_type(type);
24 if (type && type->type == SYM_STRUCT)
25 return type;
26 return NULL;
29 static int known_struct_member_states(struct expression *expr)
31 struct state_list *slist = __get_cur_slist();
32 struct sm_state *sm;
33 char *name;
34 int ret = 0;
35 int cmp;
36 int len;
38 if (expr->type == EXPR_PREOP && expr->op == '&')
39 expr = strip_expr(expr->unop);
41 name = expr_to_var(expr);
42 if (!name)
43 return 0;
44 len = strlen(name);
46 FOR_EACH_PTR(slist, sm) {
47 if (sm->owner != SMATCH_EXTRA)
48 continue;
49 cmp = strncmp(sm->name, name, len);
50 if (cmp < 0)
51 continue;
52 if (cmp == 0) {
53 if (sm->name[len] == '.' ||
54 sm->name[len] == '-' ||
55 sm->name[len] == '.') {
56 ret = 1;
57 goto out;
59 continue;
61 goto out;
62 } END_FOR_EACH_PTR(sm);
64 out:
65 return ret;
68 static struct expression *get_matching_member_expr(struct symbol *left_type, struct expression *right, struct symbol *left_member)
70 struct symbol *struct_type;
71 int op = '.';
73 if (!left_member->ident)
74 return NULL;
76 struct_type = get_struct_type(right);
77 if (!struct_type)
78 return NULL;
79 if (struct_type != left_type)
80 return NULL;
82 if (right->type == EXPR_PREOP && right->op == '&')
83 right = strip_expr(right->unop);
85 if (is_pointer(right)) {
86 right = deref_expression(right);
87 op = '*';
90 return member_expression(right, op, left_member->ident);
93 void __struct_members_copy(int mode, struct expression *left, struct expression *right)
95 struct symbol *struct_type, *tmp, *type;
96 struct expression *left_member, *right_member, *assign;
97 int op = '.';
100 if (__in_fake_assign)
101 return;
103 left = strip_expr(left);
104 right = strip_expr(right);
106 struct_type = get_struct_type(left);
107 if (!struct_type)
108 return;
110 if (is_pointer(left)) {
111 left = deref_expression(left);
112 op = '*';
115 FOR_EACH_PTR(struct_type->symbol_list, tmp) {
116 type = get_real_base_type(tmp);
117 if (type && type->type == SYM_ARRAY)
118 continue;
120 left_member = member_expression(left, op, tmp->ident);
122 switch (mode) {
123 case COPY_NORMAL:
124 case COPY_MEMCPY:
125 right_member = get_matching_member_expr(struct_type, right, tmp);
126 break;
127 case COPY_MEMSET:
128 right_member = right;
129 break;
131 if (!right_member)
132 right_member = unknown_value_expression(left_member);
133 assign = assign_expression(left_member, right_member);
134 __in_fake_assign++;
135 __split_expr(assign);
136 __in_fake_assign--;
137 } END_FOR_EACH_PTR(tmp);
140 void __fake_struct_member_assignments(struct expression *expr)
142 __struct_members_copy(COPY_NORMAL, expr->left, expr->right);
145 static struct expression *remove_addr(struct expression *expr)
147 expr = strip_expr(expr);
149 if (expr->type == EXPR_PREOP && expr->op == '&')
150 return strip_expr(expr->unop);
151 return expr;
154 static void match_memset(const char *fn, struct expression *expr, void *_size_arg)
156 struct expression *buf;
157 struct expression *val;
159 buf = get_argument_from_call_expr(expr->args, 0);
160 val = get_argument_from_call_expr(expr->args, 1);
162 buf = strip_expr(buf);
163 __struct_members_copy(COPY_MEMSET, remove_addr(buf), val);
166 static void match_memcpy(const char *fn, struct expression *expr, void *_arg)
168 struct expression *dest;
169 struct expression *src;
171 dest = get_argument_from_call_expr(expr->args, 0);
172 src = get_argument_from_call_expr(expr->args, 1);
174 __struct_members_copy(COPY_MEMCPY, remove_addr(dest), remove_addr(src));
177 static void match_memcpy_unknown(const char *fn, struct expression *expr, void *_arg)
179 struct expression *dest;
181 dest = get_argument_from_call_expr(expr->args, 0);
182 __struct_members_copy(COPY_MEMCPY, remove_addr(dest), NULL);
185 static void register_clears_param(void)
187 struct token *token;
188 char name[256];
189 const char *function;
190 int param;
192 if (option_project == PROJ_NONE)
193 return;
195 snprintf(name, 256, "%s.clears_argument", option_project_str);
197 token = get_tokens_file(name);
198 if (!token)
199 return;
200 if (token_type(token) != TOKEN_STREAMBEGIN)
201 return;
202 token = token->next;
203 while (token_type(token) != TOKEN_STREAMEND) {
204 if (token_type(token) != TOKEN_IDENT)
205 return;
206 function = show_ident(token->ident);
207 token = token->next;
208 if (token_type(token) != TOKEN_NUMBER)
209 return;
210 param = atoi(token->number);
211 add_function_hook(function, &match_memcpy_unknown, INT_PTR(param));
212 token = token->next;
214 clear_token_alloc();
217 void register_struct_assignment(int id)
219 add_function_hook("memset", &match_memset, NULL);
221 add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
222 add_function_hook("memmove", &match_memcpy, INT_PTR(0));
224 register_clears_param();