xref: /illumos-gate/usr/src/tools/smatch/src/smatch_recurse.c (revision 1f5207b7604fb44407eb4342aff613f7c4508508)
1 /*
2  * Copyright (C) 2013 Oracle.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16  */
17 
18 #include "smatch.h"
19 
20 #define RECURSE_LIMIT 10
21 
recurse(struct expression * expr,int (func)(struct expression * expr,void * p),void * param,int nr)22 static int recurse(struct expression *expr,
23 		   int (func)(struct expression *expr, void *p),
24 		   void *param, int nr)
25 {
26 	int ret;
27 
28 	if (!expr)
29 		return 0;
30 
31 	ret = func(expr, param);
32 	if (ret)
33 		return ret;
34 
35 	if (nr > RECURSE_LIMIT)
36 		return -1;
37 	nr++;
38 
39 	switch (expr->type) {
40 	case EXPR_PREOP:
41 		ret = recurse(expr->unop, func, param, nr);
42 		break;
43 	case EXPR_POSTOP:
44 		ret = recurse(expr->unop, func, param, nr);
45 		break;
46 	case EXPR_STATEMENT:
47 		return -1;
48 		break;
49 	case EXPR_LOGICAL:
50 	case EXPR_COMPARE:
51 	case EXPR_BINOP:
52 	case EXPR_COMMA:
53 		ret = recurse(expr->left, func, param, nr);
54 		if (ret)
55 			return ret;
56 		ret = recurse(expr->right, func, param, nr);
57 		break;
58 	case EXPR_ASSIGNMENT:
59 		ret = recurse(expr->right, func, param, nr);
60 		if (ret)
61 			return ret;
62 		ret = recurse(expr->left, func, param, nr);
63 		break;
64 	case EXPR_DEREF:
65 		ret = recurse(expr->deref, func, param, nr);
66 		break;
67 	case EXPR_SLICE:
68 		ret = recurse(expr->base, func, param, nr);
69 		break;
70 	case EXPR_CAST:
71 	case EXPR_FORCE_CAST:
72 		ret = recurse(expr->cast_expression, func, param, nr);
73 		break;
74 	case EXPR_SIZEOF:
75 	case EXPR_OFFSETOF:
76 	case EXPR_ALIGNOF:
77 		break;
78 	case EXPR_CONDITIONAL:
79 	case EXPR_SELECT:
80 		ret = recurse(expr->conditional, func, param, nr);
81 		if (ret)
82 			return ret;
83 		ret = recurse(expr->cond_true, func, param, nr);
84 		if (ret)
85 			return ret;
86 		ret = recurse(expr->cond_false, func, param, nr);
87 		break;
88 	case EXPR_CALL:
89 		return -1;
90 		break;
91 	case EXPR_INITIALIZER:
92 		return -1;
93 		break;
94 	case EXPR_IDENTIFIER:
95 		ret = recurse(expr->ident_expression, func, param, nr);
96 		break;
97 	case EXPR_INDEX:
98 		ret = recurse(expr->idx_expression, func, param, nr);
99 		break;
100 	case EXPR_POS:
101 		ret = recurse(expr->init_expr, func, param, nr);
102 		break;
103 	case EXPR_SYMBOL:
104 	case EXPR_STRING:
105 	case EXPR_VALUE:
106 		break;
107 	default:
108 		return -1;
109 		break;
110 	};
111 	return ret;
112 }
113 
has_symbol_helper(struct expression * expr,void * _sym)114 static int has_symbol_helper(struct expression *expr, void *_sym)
115 {
116 	struct symbol *sym = _sym;
117 
118 	if (!expr || expr->type != EXPR_SYMBOL)
119 		return 0;
120 	if (expr->symbol == sym)
121 		return 1;
122 	return 0;
123 }
124 
has_symbol(struct expression * expr,struct symbol * sym)125 int has_symbol(struct expression *expr, struct symbol *sym)
126 {
127 	return recurse(expr, has_symbol_helper, sym, 0);
128 }
129 
130 struct expr_name_sym {
131 	struct expression *expr;
132 	char *name;
133 	struct symbol *sym;
134 };
135 
has_var_helper(struct expression * expr,void * _var)136 static int has_var_helper(struct expression *expr, void *_var)
137 {
138 	struct expr_name_sym *xns = _var;
139 	char *name;
140 	struct symbol *sym;
141 	int matched = 0;
142 
143 	if (!expr)
144 		return 0;
145 	if (expr->type != xns->expr->type)
146 		return 0;
147 	// I hope this is defined for everything?  It should work, right?
148 	if (expr->op != xns->expr->op)
149 		return 0;
150 
151 	name = expr_to_var_sym(expr, &sym);
152 	if (!name || !sym)
153 		goto free;
154 	if (sym == xns->sym && strcmp(name, xns->name) == 0)
155 		matched = 1;
156 free:
157 	free_string(name);
158 	return matched;
159 }
160 
has_variable(struct expression * expr,struct expression * var)161 int has_variable(struct expression *expr, struct expression *var)
162 {
163 	struct expr_name_sym xns;
164 	int ret = -1;
165 
166 	xns.expr = var;
167 	xns.name = expr_to_var_sym(var, &xns.sym);
168 	if (!xns.name || !xns.sym)
169 		goto free;
170 	ret = recurse(expr, has_var_helper, &xns, 0);
171 free:
172 	free_string(xns.name);
173 	return ret;
174 }
175 
has_inc_dec_helper(struct expression * expr,void * unused)176 static int has_inc_dec_helper(struct expression *expr, void *unused)
177 {
178 	if (!expr)
179 		return 0;
180 	if (expr->type != EXPR_PREOP && expr->type != EXPR_POSTOP)
181 		return 0;
182 	if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
183 		return 1;
184 	return 0;
185 }
186 
has_inc_dec(struct expression * expr)187 int has_inc_dec(struct expression *expr)
188 {
189 	return recurse(expr, has_inc_dec_helper, NULL, 0);
190 }
191 
192