510bba1ad7280ceb0b262177f77f57c1b289ab5f
[m6w6/ext-psi] / src / validator.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/param.h>
5 #include <dlfcn.h>
6
7 #include <jit/jit.h>
8
9 #include "php.h"
10 #include "php_psi.h"
11 #include "validator.h"
12
13 PSI_Validator *PSI_ValidatorInit(PSI_Validator *V, PSI_Parser *P)
14 {
15 if (!V) {
16 V = malloc(sizeof(*V));
17 }
18 memset(V, 0, sizeof(*V));
19
20 PSI_DataExchange((PSI_Data *) V, (PSI_Data *) P);
21
22 return V;
23 }
24
25 void PSI_ValidatorDtor(PSI_Validator *V)
26 {
27 PSI_DataDtor((PSI_Data *) V);
28 memset(V, 0, sizeof(*V));
29 }
30
31 void PSI_ValidatorFree(PSI_Validator **V)
32 {
33 if (*V) {
34 PSI_ValidatorDtor(*V);
35 free(*V);
36 *V = NULL;
37 }
38 }
39
40 static int validate_lib(PSI_Validator *V) {
41 char lib[MAXPATHLEN];
42 const char *ptr = V->lib;
43 size_t len;
44
45 if (!ptr) {
46 /* FIXME: assume stdlib */
47 return 1;
48 } else if (!strchr(ptr, '/')) {
49 #ifdef DARWIN
50 len = snprintf(lib, MAXPATHLEN, "lib%s.dylib", ptr);
51 #else
52 len = snprintf(lib, MAXPATHLEN, "lib%s.so", ptr);
53 #endif
54 if (MAXPATHLEN == len) {
55 V->error(PSI_WARNING, "Library name too long: '%s'", ptr);
56 }
57 lib[len] = 0;
58 ptr = lib;
59 }
60 if (!(V->dlopened = dlopen(ptr, RTLD_LAZY|RTLD_LOCAL))) {
61 V->error(PSI_WARNING, "Could not open library '%s': %s.", V->lib, dlerror());
62 return 0;
63 }
64 return 1;
65 }
66
67 static inline int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) {
68 size_t i;
69
70 if (type->real) {
71 return 1;
72 }
73 for (i = 0; i < defs->count; ++i) {
74 if (!strcmp(defs->list[i]->alias, type->name)) {
75 type->real = defs->list[i]->type;
76 return 1;
77 }
78 }
79 return 0;
80 }
81 static inline int locate_decl_type_struct(decl_structs *structs, decl_type *type) {
82 size_t i;
83
84 if (type->strct) {
85 return 1;
86 }
87 for (i = 0; i < structs->count; ++i) {
88 if (!strcmp(structs->list[i]->name, type->name)) {
89 type->strct = structs->list[i];
90 return 1;
91 }
92 }
93 return 0;
94 }
95 static inline int validate_decl_type(PSI_Validator *V, decl_type *type) {
96 switch (type->type) {
97 case PSI_T_NAME:
98 if (!V->defs || !locate_decl_type_alias(V->defs, type)) {
99 return 0;
100 }
101 return validate_decl_type(V, type->real);
102 case PSI_T_STRUCT:
103 if (!V->structs || !locate_decl_type_struct(V->structs, type)) {
104 return 0;
105 }
106 break;
107 }
108 return 1;
109 }
110 static inline int validate_typedef(PSI_Validator *V, decl_typedef *def) {
111 /* FIXME: check def->alias */
112 if (def->type->type == PSI_T_NAME) {
113 V->error(PSI_WARNING, "Type '%s' cannot be aliased to '%s'",
114 def->type->name, def->alias);
115 return 0;
116 }
117 return 1;
118 }
119 static inline int validate_typedefs(PSI_Validator *V) {
120 size_t i;
121
122 for (i = 0; i < V->defs->count; ++i) {
123 if (!validate_typedef(V, V->defs->list[i])) {
124 return 0;
125 }
126 }
127
128 return 1;
129 }
130 static const char * const abi_ccs[] = {
131 "default", /* \ */
132 "extern", /* > - all the same */
133 "cdecl", /* / */
134 "stdcall",
135 "fastcall",
136 };
137 static inline int validate_decl_abi(PSI_Validator *V, decl_abi *abi) {
138 size_t i;
139
140 for (i = 0; i < sizeof(abi_ccs)/sizeof(char*); ++i) {
141 if (strcasecmp(abi->convention, abi_ccs[i])) {
142 return 1;
143 }
144 }
145 V->error(PSI_WARNING, "Invalid calling convention: '%s'", abi->convention);
146 return 0;
147 }
148 static inline int validate_decl_arg(PSI_Validator *V, decl_arg *arg) {
149 if (!validate_decl_type(V, arg->type)) {
150 V->error(PSI_WARNING, "Cannot use '%s' as type for '%s'",
151 arg->type->name, arg->var->name);
152 return 0;
153 }
154 return 1;
155 }
156 static inline int validate_decl_args(PSI_Validator *V, decl_args *args) {
157 size_t i;
158
159 for (i = 0; i < args->count; ++i) {
160 if (!validate_decl_arg(V, args->args[i])) {
161 return 0;
162 }
163 }
164 return 1;
165 }
166 static inline int validate_decl_func(PSI_Validator *V, decl *decl, decl_arg *func)
167 {
168 if (!strcmp(func->var->name, "dlsym")) {
169 V->error(PSI_WARNING, "Cannot dlsym dlsym (sic!)");
170 return 0;
171 }
172
173 if (!validate_decl_arg(V, func)) {
174 return 0;
175 }
176 #ifndef RTLD_NEXT
177 # define RTLD_NEXT ((void *) -1l)
178 #endif
179 decl->dlptr = dlsym(V->dlopened ?: RTLD_NEXT, func->var->name);
180 if (!decl->dlptr) {
181 V->error(PSI_WARNING, "Failed to located symbol '%s': %s",
182 func->var->name, dlerror());
183 }
184 return 1;
185 }
186 static inline int validate_decl(PSI_Validator *V, decl *decl) {
187 if (!validate_decl_abi(V, decl->abi)) {
188 return 0;
189 }
190 if (!validate_decl_func(V, decl, decl->func)) {
191 return 0;
192 }
193 if (decl->args && !validate_decl_args(V, decl->args)) {
194 return 0;
195 }
196 return 1;
197 }
198 static inline int validate_decls(PSI_Validator *V) {
199 size_t i;
200
201 for (i = 0; i < V->decls->count; ++i) {
202 if (!validate_decl(V, V->decls->list[i])) {
203 return 0;
204 }
205 }
206 return 1;
207 }
208 static inline int validate_struct(PSI_Validator *V, decl_struct *s) {
209 size_t i;
210
211 if (!validate_decl_args(V, s->args)) {
212 return 0;
213 }
214
215 s->layout = calloc(s->args->count, sizeof(*s->layout));
216 for (i = 0; i < s->args->count; ++i) {
217 decl_arg *darg = s->args->args[i];
218 decl_type *type = real_decl_type(darg->type);
219 token_t t = darg->var->pointer_level ? PSI_T_POINTER : type->type;
220
221 if (i) {
222 decl_struct_layout *l = &s->layout[i-1];
223 s->layout[i].pos = psi_t_align(t, l->pos + l->len);
224 } else {
225 s->layout[i].pos = 0;
226 }
227 s->layout[i].len = psi_t_size(t);
228 }
229 return 1;
230 }
231 static inline int validate_structs(PSI_Validator *V) {
232 size_t i;
233
234 for (i = 0; i < V->structs->count; ++i) {
235 if (!validate_struct(V, V->structs->list[i])) {
236 return 0;
237 }
238 }
239 return 1;
240 }
241
242 static inline int validate_impl_type(PSI_Validator *V, impl *impl, impl_type *type) {
243 /* FIXME */
244 return 1;
245 }
246 static inline int validate_impl_arg(PSI_Validator *V, impl *impl, impl_arg *arg) {
247 return 1;
248 }
249 static inline int validate_impl_args(PSI_Validator *V, impl *impl, impl_args *args) {
250 size_t i;
251
252 for (i = 0; i < args->count; ++i) {
253 if (!validate_impl_arg(V, impl, args->args[i])) {
254 return 0;
255 }
256 }
257 return 1;
258 }
259 static inline int validate_impl_func(PSI_Validator *V, impl *impl, impl_func *func) {
260 /* FIXME: does name need any validation? */
261 if (!validate_impl_type(V, impl, func->return_type)) {
262 return 0;
263 }
264 if (func->args && !validate_impl_args(V, impl, func->args)) {
265 return 0;
266 }
267 return 1;
268 }
269
270 static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) {
271 size_t i;
272
273 for (i = 0; i < decls->count; ++i) {
274 if (!strcmp(decls->list[i]->func->var->name, ret->decl->name)) {
275 ret->decl->arg = decls->list[i]->func;
276 return decls->list[i];
277 }
278 }
279 return NULL;
280 }
281
282 static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *stmts) {
283 /* okay,
284 * - we must have exactly one ret stmt delcaring the native func to call and which type cast to apply
285 * - we can have multiple let stmts; every arg of the ret stmts var (the function to call) must have one
286 * - we can have any count of set stmts; processing out vars
287 * - we can have any count of free stmts; freeing any out vars
288 */
289 size_t i, j, k;
290 return_stmt *ret;
291 decl *decl;
292
293 if (!stmts) {
294 V->error(PSI_WARNING, "Missing body for implementation %s!",
295 impl->func->name);
296 return 0;
297 }
298 if (stmts->ret.count != 1) {
299 if (stmts->ret.count > 1) {
300 V->error(PSI_WARNING, "Too many `ret` statements for implmentation %s;"
301 " found %zu, exactly one is needed",
302 impl->func->name, stmts->ret.count);
303 } else {
304 V->error(PSI_WARNING, "Missing `ret` statement for implementation %s",
305 impl->func->name);
306 }
307 return 0;
308 }
309
310 ret = stmts->ret.list[0];
311 decl = locate_impl_decl(V->decls, ret);
312 if (!decl) {
313 V->error(PSI_WARNING, "Missing declaration for implementation %s",
314 impl->func->name);
315 return 0;
316 }
317
318 /* check that we have a let stmt for every decl arg */
319 if (decl->args) for (i = 0; i < decl->args->count; ++i) {
320 decl_arg *darg = decl->args->args[i];
321 int check = 0;
322
323 for (j = 0; j < stmts->let.count; ++j) {
324 let_stmt *let = stmts->let.list[j];
325
326 if (!strcmp(let->var->name, darg->var->name)) {
327 darg->let = let;
328 check = 1;
329 break;
330 }
331 }
332 if (!check) {
333 V->error(PSI_WARNING, "Missing `let` statement for arg '%s %.*s%s'"
334 " of declaration '%s' for implementation '%s'",
335 darg->type->name, (int) darg->var->pointer_level, "*****",
336 darg->var->name, decl->func->var->name, impl->func->name);
337 return 0;
338 }
339 }
340 /* check that the let_value references a known variable or NULL */
341 for (i = 0; i < stmts->let.count; ++i) {
342 let_stmt *let = stmts->let.list[i];
343 int check = 0;
344
345 if (let->val && let->val->func && let->val->func->alloc) {
346 if (!validate_decl_type(V, let->val->func->alloc->type)) {
347 V->error(PSI_WARNING, "Cannot use '%s' as type for calloc in `let` statement",
348 let->val->func->alloc->type->name);
349 return 0;
350 }
351 }
352 if (let->val && let->val->var) {
353 if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) {
354 impl_arg *iarg = impl->func->args->args[j];
355
356 if (!strcmp(let->val->var->name, iarg->var->name)) {
357 let->arg = iarg;
358 check = 1;
359 break;
360 }
361 }
362 if (!check) {
363 V->error(PSI_WARNING, "Unknown value '$%s' of `let` statement"
364 " for variable '%s' of implementation '%s'",
365 let->val->var->name, let->var->name, impl->func->name);
366 return 0;
367 }
368 }
369 }
370 /* check that set stmts reference known variables */
371 for (i = 0; i < stmts->set.count; ++i) {
372 set_stmt *set = stmts->set.list[i];
373 int check = 0;
374
375 if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) {
376 impl_arg *iarg = impl->func->args->args[j];
377
378 if (!strcmp(set->var->name, iarg->var->name)) {
379 set->arg = iarg;
380 check = 1;
381 break;
382 }
383 }
384 if (!check) {
385 V->error(PSI_WARNING, "Unknown variable '$%s' of `set` statement"
386 " of implementation '%s'",
387 set->var->name, impl->func->name);
388 return 0;
389 }
390
391 for (j = 0; j < set->val->vars->count; ++j) {
392 decl_var *set_var = set->val->vars->vars[j];
393
394 check = 0;
395 if (decl->args) for (k = 0; k < decl->args->count; ++k) {
396 decl_arg *set_arg = decl->args->args[k];
397
398 if (!strcmp(set_var->name, set_arg->var->name)) {
399 check = 1;
400 set_var->arg = set_arg;
401 break;
402 }
403 }
404
405 if (!check) {
406 V->error(PSI_WARNING, "Unknown value '%s' of `set` statement"
407 " for variable '$%s' of implementation '%s'",
408 set_var->name, set->arg->var->name, impl->func->name);
409 return 0;
410 }
411 }
412 }
413 /* check free stmts */
414 for (i = 0; i < stmts->fre.count; ++i) {
415 free_stmt *fre = stmts->fre.list[i];
416
417 for (j = 0; j < fre->vars->count; ++j) {
418 decl_var *free_var = fre->vars->vars[j];
419 int check = 0;
420
421 if (!strcmp(free_var->name, decl->func->var->name)) {
422 continue;
423 }
424 if (decl->args) for (k = 0; k < decl->args->count; ++k) {
425 decl_arg *free_arg = decl->args->args[k];
426
427 if (!strcmp(free_var->name, free_arg->var->name)) {
428 check = 1;
429 free_var->arg = free_arg;
430 break;
431 }
432 }
433
434 if (!check) {
435 V->error(PSI_WARNING, "Unknown variable '%s' of `free` statement"
436 " of implementation '%s'",
437 free_var->name, impl->func->name);
438 return 0;
439 }
440 }
441 }
442
443 impl->decl = decl;
444
445 return 1;
446 }
447
448 static inline int validate_impl(PSI_Validator *V, impl *impl) {
449 if (!validate_impl_func(V, impl, impl->func)) {
450 return 0;
451 }
452 if (!validate_impl_stmts(V, impl, impl->stmts)) {
453 return 0;
454 }
455 return 1;
456 }
457 static inline int validate_impls(PSI_Validator *V) {
458 size_t i;
459
460 for (i = 0; i < V->impls->count; ++i) {
461 if (!validate_impl(V, V->impls->list[i])) {
462 return 0;
463 }
464 }
465 return 1;
466 }
467
468 int PSI_ValidatorValidate(PSI_Validator *V)
469 {
470 if (!validate_lib(V)) {
471 return 0;
472 }
473 if (V->defs && !validate_typedefs(V)) {
474 return 0;
475 }
476 if (V->structs && !validate_structs(V)) {
477 return 0;
478 }
479 if (V->decls && !validate_decls(V)) {
480 return 0;
481 }
482 if (!V->impls || !validate_impls(V)) {
483 return 0;
484 }
485 return 1;
486 }