*new* stored_conditions: make a list of known true/false conditions
[smatch.git] / smatch_struct_assignment.c
blob5bd27ab27bb0c4a0cfe3c70b5c169783bedb6467
1 /*
2 * sparse/smatch_struct_assignment.c
4 * Copyright (C) 2014 Oracle.
6 * Licensed under the Open Software License version 1.1
8 */
11 * This file started out by saying that if you have:
13 * struct foo one, two;
14 * ...
15 * one = two;
17 * That's equivalent to saying:
19 * one.x = two.x;
20 * one.y = two.y;
22 * Turning an assignment like that into a bunch of small fake assignments is
23 * really useful.
25 * The call to memcpy(&one, &two, sizeof(foo)); is the same as "one = two;" so
26 * we can re-use the code. And we may as well use it for memset() too.
27 * Assigning pointers is almost the same:
29 * p1 = p2;
31 * Is the same as:
33 * p1->x = p2->x;
34 * p1->y = p2->y;
36 * The problem is that you can go a bit crazy with pointers to pointers.
38 * p1->x->y->z->one->two->three = p2->x->y->z->one->two->three;
40 * I don't have a proper solution for this problem right now. I just copy one
41 * level and don't nest. It should handle limitted nesting but intelligently.
43 * The other thing is that you end up with a lot of garbage assignments where
44 * we record "x could be anything. x->y could be anything. x->y->z->a->b->c
45 * could *also* be anything!". There should be a better way to filter this
46 * useless information.
50 #include "scope.h"
51 #include "smatch.h"
52 #include "smatch_slist.h"
53 #include "smatch_extra.h"
55 static struct symbol *get_struct_type(struct expression *expr)
57 struct symbol *type;
59 type = get_type(expr);
60 if (!type)
61 return NULL;
62 if (type->type == SYM_PTR)
63 type = get_real_base_type(type);
64 if (type && type->type == SYM_STRUCT)
65 return type;
66 return NULL;
69 static struct expression *get_matching_member_expr(struct symbol *left_type, struct expression *right, struct symbol *left_member)
71 struct symbol *struct_type;
72 int op = '.';
74 if (!left_member->ident)
75 return NULL;
77 struct_type = get_struct_type(right);
78 if (!struct_type)
79 return NULL;
80 if (struct_type != left_type)
81 return NULL;
83 if (right->type == EXPR_PREOP && right->op == '&')
84 right = strip_expr(right->unop);
86 if (is_pointer(right)) {
87 right = deref_expression(right);
88 op = '*';
91 return member_expression(right, op, left_member->ident);
94 void __struct_members_copy(int mode, struct expression *left, struct expression *right)
96 struct symbol *struct_type, *tmp, *type;
97 struct expression *left_member;
98 struct expression *right_member = NULL;
99 struct expression *assign;
100 int op = '.';
103 if (__in_fake_assign)
104 return;
106 left = strip_expr(left);
107 right = strip_expr(right);
109 struct_type = get_struct_type(left);
110 if (!struct_type)
111 return;
113 if (is_pointer(left)) {
114 left = deref_expression(left);
115 op = '*';
118 FOR_EACH_PTR(struct_type->symbol_list, tmp) {
119 type = get_real_base_type(tmp);
120 if (type && type->type == SYM_ARRAY)
121 continue;
123 left_member = member_expression(left, op, tmp->ident);
125 switch (mode) {
126 case COPY_NORMAL:
127 case COPY_MEMCPY:
128 right_member = get_matching_member_expr(struct_type, right, tmp);
129 break;
130 case COPY_MEMSET:
131 right_member = right;
132 break;
134 if (!right_member)
135 right_member = unknown_value_expression(left_member);
136 assign = assign_expression(left_member, right_member);
137 __in_fake_assign++;
138 __split_expr(assign);
139 __in_fake_assign--;
140 } END_FOR_EACH_PTR(tmp);
143 void __fake_struct_member_assignments(struct expression *expr)
145 __struct_members_copy(COPY_NORMAL, expr->left, expr->right);
148 static struct expression *remove_addr(struct expression *expr)
150 expr = strip_expr(expr);
152 if (expr->type == EXPR_PREOP && expr->op == '&')
153 return strip_expr(expr->unop);
154 return expr;
157 static void match_memset(const char *fn, struct expression *expr, void *_size_arg)
159 struct expression *buf;
160 struct expression *val;
162 buf = get_argument_from_call_expr(expr->args, 0);
163 val = get_argument_from_call_expr(expr->args, 1);
165 buf = strip_expr(buf);
166 __struct_members_copy(COPY_MEMSET, remove_addr(buf), val);
169 static void match_memcpy(const char *fn, struct expression *expr, void *_arg)
171 struct expression *dest;
172 struct expression *src;
174 dest = get_argument_from_call_expr(expr->args, 0);
175 src = get_argument_from_call_expr(expr->args, 1);
177 __struct_members_copy(COPY_MEMCPY, remove_addr(dest), remove_addr(src));
180 static void match_memcpy_unknown(const char *fn, struct expression *expr, void *_arg)
182 struct expression *dest;
184 dest = get_argument_from_call_expr(expr->args, 0);
185 __struct_members_copy(COPY_MEMCPY, remove_addr(dest), NULL);
188 static void register_clears_param(void)
190 struct token *token;
191 char name[256];
192 const char *function;
193 int param;
195 if (option_project == PROJ_NONE)
196 return;
198 snprintf(name, 256, "%s.clears_argument", option_project_str);
200 token = get_tokens_file(name);
201 if (!token)
202 return;
203 if (token_type(token) != TOKEN_STREAMBEGIN)
204 return;
205 token = token->next;
206 while (token_type(token) != TOKEN_STREAMEND) {
207 if (token_type(token) != TOKEN_IDENT)
208 return;
209 function = show_ident(token->ident);
210 token = token->next;
211 if (token_type(token) != TOKEN_NUMBER)
212 return;
213 param = atoi(token->number);
214 add_function_hook(function, &match_memcpy_unknown, INT_PTR(param));
215 token = token->next;
217 clear_token_alloc();
220 void register_struct_assignment(int id)
222 add_function_hook("memset", &match_memset, NULL);
224 add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
225 add_function_hook("memmove", &match_memcpy, INT_PTR(0));
227 register_clears_param();