xref: /illumos-gate/usr/src/tools/smatch/src/smatch_expressions.c (revision 6523a3aa7f325d64841382707603be7a86e68147)
1  #include "smatch.h"
2  #include "smatch_extra.h"
3  
4  DECLARE_ALLOCATOR(sname);
5  __ALLOCATOR(struct expression, "temporary expr", tmp_expression);
6  
get_cur_pos(void)7  static struct position get_cur_pos(void)
8  {
9  	static struct position pos;
10  	static struct position none;
11  	struct expression *expr;
12  	struct statement *stmt;
13  
14  	expr = last_ptr_list((struct ptr_list *)big_expression_stack);
15  	stmt = last_ptr_list((struct ptr_list *)big_statement_stack);
16  	if (expr)
17  		pos = expr->pos;
18  	else if (stmt)
19  		pos = stmt->pos;
20  	else
21  		pos = none;
22  	return pos;
23  }
24  
alloc_tmp_expression(struct position pos,int type)25  struct expression *alloc_tmp_expression(struct position pos, int type)
26  {
27  	struct expression *expr;
28  
29  	expr = __alloc_tmp_expression(0);
30  	expr->smatch_flags |= Tmp;
31  	expr->type = type;
32  	expr->pos = pos;
33  	return expr;
34  }
35  
free_tmp_expressions(void)36  void free_tmp_expressions(void)
37  {
38  	clear_tmp_expression_alloc();
39  }
40  
zero_expr(void)41  struct expression *zero_expr(void)
42  {
43  	struct expression *zero;
44  
45  	zero = alloc_tmp_expression(get_cur_pos(), EXPR_VALUE);
46  	zero->value = 0;
47  	zero->ctype = &int_ctype;
48  	return zero;
49  }
50  
value_expr(long long val)51  struct expression *value_expr(long long val)
52  {
53  	struct expression *expr;
54  
55  	if (!val)
56  		return zero_expr();
57  
58  	expr = alloc_tmp_expression(get_cur_pos(), EXPR_VALUE);
59  	expr->value = val;
60  	expr->ctype = &llong_ctype;
61  	return expr;
62  }
63  
member_expression(struct expression * deref,int op,struct ident * member)64  struct expression *member_expression(struct expression *deref, int op, struct ident *member)
65  {
66  	struct expression *expr;
67  
68  	expr = alloc_tmp_expression(deref->pos, EXPR_DEREF);
69  	expr->op = op;
70  	expr->deref = deref;
71  	expr->member = member;
72  	expr->member_offset = -1;
73  	return expr;
74  }
75  
preop_expression(struct expression * expr,int op)76  struct expression *preop_expression(struct expression *expr, int op)
77  {
78  	struct expression *preop;
79  
80  	preop = alloc_tmp_expression(expr->pos, EXPR_PREOP);
81  	preop->unop = expr;
82  	preop->op = op;
83  	return preop;
84  }
85  
deref_expression(struct expression * expr)86  struct expression *deref_expression(struct expression *expr)
87  {
88  	if (expr->type == EXPR_BINOP)
89  		expr = preop_expression(expr, '(');
90  	return preop_expression(expr, '*');
91  }
92  
assign_expression(struct expression * left,int op,struct expression * right)93  struct expression *assign_expression(struct expression *left, int op, struct expression *right)
94  {
95  	struct expression *expr;
96  
97  	if (!right)
98  		return NULL;
99  
100  	/* FIXME: make this a tmp expression. */
101  	expr = alloc_expression(right->pos, EXPR_ASSIGNMENT);
102  	expr->op = op;
103  	expr->left = left;
104  	expr->right = right;
105  	return expr;
106  }
107  
binop_expression(struct expression * left,int op,struct expression * right)108  struct expression *binop_expression(struct expression *left, int op, struct expression *right)
109  {
110  	struct expression *expr;
111  
112  	expr = alloc_tmp_expression(right->pos, EXPR_BINOP);
113  	expr->op = op;
114  	expr->left = left;
115  	expr->right = right;
116  	return expr;
117  }
118  
array_element_expression(struct expression * array,struct expression * offset)119  struct expression *array_element_expression(struct expression *array, struct expression *offset)
120  {
121  	struct expression *expr;
122  
123  	expr = binop_expression(array, '+', offset);
124  	return deref_expression(expr);
125  }
126  
symbol_expression(struct symbol * sym)127  struct expression *symbol_expression(struct symbol *sym)
128  {
129  	struct expression *expr;
130  
131  	expr = alloc_tmp_expression(sym->pos, EXPR_SYMBOL);
132  	expr->symbol = sym;
133  	expr->symbol_name = sym->ident;
134  	return expr;
135  }
136  
compare_expression(struct expression * left,int op,struct expression * right)137  struct expression *compare_expression(struct expression *left, int op, struct expression *right)
138  {
139  	struct expression *expr;
140  
141  	expr = alloc_tmp_expression(get_cur_pos(), EXPR_COMPARE);
142  	expr->op = op;
143  	expr->left = left;
144  	expr->right = right;
145  	return expr;
146  }
147  
string_expression(char * str)148  struct expression *string_expression(char *str)
149  {
150  	struct expression *ret;
151  	struct string *string;
152  	int len;
153  
154  	len = strlen(str) + 1;
155  	string = (void *)__alloc_sname(4 + len);
156  	string->length = len;
157  	string->immutable = 0;
158  	memcpy(string->data, str, len);
159  
160  	ret = alloc_tmp_expression(get_cur_pos(), EXPR_STRING);
161  	ret->wide = 0;
162  	ret->string = string;
163  
164  	return ret;
165  }
166  
call_expression(struct expression * fn,struct expression_list * args)167  struct expression *call_expression(struct expression *fn, struct expression_list *args)
168  {
169  	struct expression *expr;
170  
171  	expr = alloc_tmp_expression(fn->pos, EXPR_CALL);
172  	expr->fn = fn;
173  	expr->args = args;
174  
175  	return expr;
176  }
177  
get_expression_from_base_and_str(struct expression * base,const char * addition)178  static struct expression *get_expression_from_base_and_str(struct expression *base, const char *addition)
179  {
180  	struct expression *ret = NULL;
181  	struct token *token, *prev, *end;
182  	char *alloc;
183  
184  	if (addition[0] == '\0')
185  		return base;
186  
187  	alloc = alloc_string_newline(addition);
188  
189  	token = tokenize_buffer(alloc, strlen(alloc), &end);
190  	if (!token)
191  		goto free;
192  	if (token_type(token) != TOKEN_STREAMBEGIN)
193  		goto free;
194  	token = token->next;
195  
196  	ret = base;
197  	while (token_type(token) == TOKEN_SPECIAL &&
198  	       (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
199  		prev = token;
200  		token = token->next;
201  		if (token_type(token) != TOKEN_IDENT)
202  			goto free;
203  		switch (prev->special) {
204  		case SPECIAL_DEREFERENCE:
205  			ret = deref_expression(ret);
206  			ret = member_expression(ret, '*', token->ident);
207  			break;
208  		case '.':
209  			ret = member_expression(ret, '.', token->ident);
210  			break;
211  		default:
212  			goto free;
213  		}
214  		token = token->next;
215  	}
216  
217  	if (token_type(token) != TOKEN_STREAMEND)
218  		goto free;
219  
220  free:
221  	free_string(alloc);
222  
223  	return ret;
224  }
225  
gen_expression_from_name_sym(const char * name,struct symbol * sym)226  struct expression *gen_expression_from_name_sym(const char *name, struct symbol *sym)
227  {
228  	struct expression *base;
229  	int skip = 0;
230  	struct expression *ret;
231  
232  	if (!name || !sym)
233  		return NULL;
234  
235  	base = symbol_expression(sym);
236  	while (name[skip] != '\0' && name[skip] != '.' && name[skip] != '-')
237  		skip++;
238  
239  	ret = get_expression_from_base_and_str(base, name + skip);
240  	if (ret) {
241  		char *new = expr_to_str(ret);
242  
243  		/*
244  		 * FIXME: this sometimes changes "foo->bar.a.b->c" into
245  		 * "foo->bar.a.b.c".  I don't know why...  :(
246  		 *
247  		 */
248  		if (!new || strcmp(name, new) != 0)
249  			return NULL;
250  	}
251  	return ret;
252  }
253  
gen_expression_from_key(struct expression * arg,const char * key)254  struct expression *gen_expression_from_key(struct expression *arg, const char *key)
255  {
256  	struct expression *ret;
257  	struct token *token, *prev, *end;
258  	const char *p = key;
259  	char buf[4095];
260  	char *alloc;
261  	size_t len;
262  
263  	/* The idea is that we can parse either $0->foo or $->foo */
264  	if (key[0] != '$')
265  		return NULL;
266  	p++;
267  	while (*p >= '0' && *p <= '9')
268  		p++;
269  	len = snprintf(buf, sizeof(buf), "%s\n", p);
270  	alloc = alloc_string(buf);
271  
272  	token = tokenize_buffer(alloc, len, &end);
273  	if (!token)
274  		return NULL;
275  	if (token_type(token) != TOKEN_STREAMBEGIN)
276  		return NULL;
277  	token = token->next;
278  
279  	ret = arg;
280  	while (token_type(token) == TOKEN_SPECIAL &&
281  	       (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
282  		prev = token;
283  		token = token->next;
284  		if (token_type(token) != TOKEN_IDENT)
285  			return NULL;
286  		ret = deref_expression(ret);
287  		ret = member_expression(ret,
288  				        (prev->special == SPECIAL_DEREFERENCE) ? '*' : '.',
289  					token->ident);
290  		token = token->next;
291  	}
292  
293  	if (token_type(token) != TOKEN_STREAMEND)
294  		return NULL;
295  
296  	return ret;
297  }
298  
expr_set_parent_expr(struct expression * expr,struct expression * parent)299  void expr_set_parent_expr(struct expression *expr, struct expression *parent)
300  {
301  	if (!expr)
302  		return;
303  	if (parent && parent->smatch_flags & Tmp)
304  		return;
305  
306  	expr->parent = (unsigned long)parent | 0x1UL;
307  }
308  
expr_set_parent_stmt(struct expression * expr,struct statement * parent)309  void expr_set_parent_stmt(struct expression *expr, struct statement *parent)
310  {
311  	if (!expr)
312  		return;
313  	expr->parent = (unsigned long)parent;
314  }
315  
expr_get_parent_expr(struct expression * expr)316  struct expression *expr_get_parent_expr(struct expression *expr)
317  {
318  	if (!expr)
319  		return NULL;
320  	if (!(expr->parent & 0x1UL))
321  		return NULL;
322  	return (struct expression *)(expr->parent & ~0x1UL);
323  }
324  
expr_get_parent_stmt(struct expression * expr)325  struct statement *expr_get_parent_stmt(struct expression *expr)
326  {
327  	if (!expr)
328  		return NULL;
329  	if (expr->parent & 0x1UL)
330  		return NULL;
331  	return (struct statement *)expr->parent;
332  }
333  
334