flush
[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 token_t t;
219
220 if (!validate_decl_arg(V, darg)) {
221 return 0;
222 }
223
224 t = darg->var->pointer_level
225 ? PSI_T_POINTER
226 : real_decl_type(darg->type)->type;
227
228 if (i) {
229 decl_struct_layout *l = &s->layout[i-1];
230 s->layout[i].pos = psi_t_align(t, l->pos + l->len);
231 } else {
232 s->layout[i].pos = 0;
233 }
234 s->layout[i].len = psi_t_size(t);
235 }
236 return 1;
237 }
238 static inline int validate_structs(PSI_Validator *V) {
239 size_t i;
240
241 for (i = 0; i < V->structs->count; ++i) {
242 if (!validate_struct(V, V->structs->list[i])) {
243 return 0;
244 }
245 }
246 return 1;
247 }
248
249 static inline int validate_impl_type(PSI_Validator *V, impl *impl, impl_type *type) {
250 /* FIXME */
251 return 1;
252 }
253 static inline int validate_impl_arg(PSI_Validator *V, impl *impl, impl_arg *arg) {
254 return 1;
255 }
256 static inline int validate_impl_args(PSI_Validator *V, impl *impl, impl_args *args) {
257 size_t i;
258
259 for (i = 0; i < args->count; ++i) {
260 if (!validate_impl_arg(V, impl, args->args[i])) {
261 return 0;
262 }
263 }
264 return 1;
265 }
266 static inline int validate_impl_func(PSI_Validator *V, impl *impl, impl_func *func) {
267 /* FIXME: does name need any validation? */
268 if (!validate_impl_type(V, impl, func->return_type)) {
269 return 0;
270 }
271 if (func->args && !validate_impl_args(V, impl, func->args)) {
272 return 0;
273 }
274 return 1;
275 }
276
277 static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) {
278 size_t i;
279
280 for (i = 0; i < decls->count; ++i) {
281 if (!strcmp(decls->list[i]->func->var->name, ret->decl->name)) {
282 ret->decl->arg = decls->list[i]->func;
283 return decls->list[i];
284 }
285 }
286 return NULL;
287 }
288 static inline int validate_impl_ret_stmt(PSI_Validator *V, impl *impl) {
289 /* we must have exactly one ret stmt delcaring the native func to call */
290 /* and which type cast to apply */
291 if (impl->stmts->ret.count != 1) {
292 if (impl->stmts->ret.count > 1) {
293 V->error(PSI_WARNING, "Too many `return` statements for implmentation %s;"
294 " found %zu, exactly one is needed",
295 impl->func->name, impl->stmts->ret.count);
296 } else {
297 V->error(PSI_WARNING, "Missing `return` statement for implementation %s",
298 impl->func->name);
299 }
300 return 0;
301 }
302 if (!(impl->decl = locate_impl_decl(V->decls, impl->stmts->ret.list[0]))) {
303 V->error(PSI_WARNING, "Missing declaration for implementation %s",
304 impl->func->name);
305 return 0;
306 }
307
308 return 1;
309 }
310 static inline int validate_impl_let_stmts(PSI_Validator *V, impl *impl) {
311 size_t i, j;
312 /* we can have multiple let stmts */
313 /* check that we have a let stmt for every decl arg */
314 if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
315 decl_arg *darg = impl->decl->args->args[i];
316 int check = 0;
317
318 for (j = 0; j < impl->stmts->let.count; ++j) {
319 let_stmt *let = impl->stmts->let.list[j];
320
321 if (!strcmp(let->var->name, darg->var->name)) {
322 darg->let = let;
323 check = 1;
324 break;
325 }
326 }
327 if (!check) {
328 V->error(PSI_WARNING, "Missing `let` statement for arg '%s %.*s%s'"
329 " of declaration '%s' for implementation '%s'",
330 darg->type->name, (int) darg->var->pointer_level, "*****",
331 darg->var->name, impl->decl->func->var->name, impl->func->name);
332 return 0;
333 }
334 }
335 /* check that the let_value references a known variable or NULL */
336 for (i = 0; i < impl->stmts->let.count; ++i) {
337 let_stmt *let = impl->stmts->let.list[i];
338 int check = 0;
339
340 if (let->val && let->val->func && let->val->func->alloc) {
341 if (!validate_decl_type(V, let->val->func->alloc->type)) {
342 V->error(PSI_WARNING, "Cannot use '%s' as type for calloc in `let` statement",
343 let->val->func->alloc->type->name);
344 return 0;
345 }
346 }
347 if (let->val && let->val->var) {
348 if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) {
349 impl_arg *iarg = impl->func->args->args[j];
350
351 if (!strcmp(let->val->var->name, iarg->var->name)) {
352 let->arg = iarg;
353 check = 1;
354 break;
355 }
356 }
357 if (!check) {
358 V->error(PSI_WARNING, "Unknown value '$%s' of `let` statement"
359 " for variable '%s' of implementation '%s'",
360 let->val->var->name, let->var->name, impl->func->name);
361 return 0;
362 }
363 }
364 }
365 return 1;
366 }
367 static inline int validate_impl_set_stmts(PSI_Validator *V, impl *impl) {
368 size_t i, j, k;
369 /* we can have any count of set stmts; processing out vars */
370 /* check that set stmts reference known variables */
371 for (i = 0; i < impl->stmts->set.count; ++i) {
372 set_stmt *set = impl->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 (impl->decl->args) for (k = 0; k < impl->decl->args->count; ++k) {
396 decl_arg *set_arg = impl->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 return 1;
414 }
415 static inline int validate_impl_free_stmts(PSI_Validator *V, impl *impl) {
416 size_t i, j, k;
417 /* we can have any count of free stmts; freeing any out vars */
418 for (i = 0; i < impl->stmts->fre.count; ++i) {
419 free_stmt *fre = impl->stmts->fre.list[i];
420
421 for (j = 0; j < fre->vars->count; ++j) {
422 decl_var *free_var = fre->vars->vars[j];
423 int check = 0;
424
425 if (!strcmp(free_var->name, impl->decl->func->var->name)) {
426 continue;
427 }
428 if (impl->decl->args) for (k = 0; k < impl->decl->args->count; ++k) {
429 decl_arg *free_arg = impl->decl->args->args[k];
430
431 if (!strcmp(free_var->name, free_arg->var->name)) {
432 check = 1;
433 free_var->arg = free_arg;
434 break;
435 }
436 }
437
438 if (!check) {
439 V->error(PSI_WARNING, "Unknown variable '%s' of `free` statement"
440 " of implementation '%s'",
441 free_var->name, impl->func->name);
442 return 0;
443 }
444 }
445 }
446 return 1;
447 }
448 static inline int validate_impl_stmts(PSI_Validator *V, impl *impl) {
449 if (!impl->stmts) {
450 V->error(PSI_WARNING, "Missing body for implementation %s!",
451 impl->func->name);
452 return 0;
453 }
454
455 if (!validate_impl_ret_stmt(V, impl)) {
456 return 0;
457 }
458
459 if (!validate_impl_let_stmts(V, impl)) {
460 return 0;
461 }
462 if (!validate_impl_set_stmts(V, impl)) {
463 return 0;
464 }
465 if (!validate_impl_free_stmts(V, impl)) {
466 return 0;
467 }
468
469 return 1;
470 }
471
472 static inline int validate_impl(PSI_Validator *V, impl *impl) {
473 if (!validate_impl_func(V, impl, impl->func)) {
474 return 0;
475 }
476 if (!validate_impl_stmts(V, impl)) {
477 return 0;
478 }
479 return 1;
480 }
481 static inline int validate_impls(PSI_Validator *V) {
482 size_t i;
483
484 for (i = 0; i < V->impls->count; ++i) {
485 if (!validate_impl(V, V->impls->list[i])) {
486 return 0;
487 }
488 }
489 return 1;
490 }
491
492 int PSI_ValidatorValidate(PSI_Validator *V)
493 {
494 if (!validate_lib(V)) {
495 return 0;
496 }
497 if (V->defs && !validate_typedefs(V)) {
498 return 0;
499 }
500 if (V->structs && !validate_structs(V)) {
501 return 0;
502 }
503 if (V->decls && !validate_decls(V)) {
504 return 0;
505 }
506 if (!V->impls || !validate_impls(V)) {
507 return 0;
508 }
509 return 1;
510 }