fix size of arrays
[m6w6/ext-psi] / src / context.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27
28 #include "php.h"
29
30 #ifdef HAVE_DIRENT_H
31 # include <dirent.h>
32 # define NAMLEN(dirent) strlen ((dirent)->d_name)
33 #else
34 # define dirent direct
35 # define NAMLEN(dirent) ((dirent)->d_namlen)
36 # ifdef HAVE_SYS_NDIR_H
37 # include <sys/ndir.h>
38 # endif
39 # ifdef HAVE_SYS_DIR_H
40 # include <sys/dir.h>
41 # endif
42 # ifdef HAVE_NDIR_H
43 # include <ndir.h>
44 # endif
45 #endif
46
47 #include <fnmatch.h>
48
49 #include "php_scandir.h"
50 #include "php_psi.h"
51 #include "calc.h"
52 #include "call.h"
53 #include "libjit.h"
54 #include "libffi.h"
55
56 #include "token.h"
57 #include "parser.h"
58
59 #define PSI_PREDEF_TYPES
60 #define PSI_PREDEF_CONSTS
61 #define PSI_PREDEF_COMPOSITES
62 #define PSI_PREDEF_DECLS
63 #include "php_psi_posix.h"
64
65 struct psi_context *psi_context_init(struct psi_context *C, struct psi_context_ops *ops, psi_error_cb error, unsigned flags)
66 {
67 struct psi_data T;
68 struct psi_predef_type *predef_type;
69 struct psi_predef_const *predef_const;
70 struct psi_predef_composite *predef_composite;
71 struct psi_predef_decl *predef_decl;
72
73 if (!C) {
74 C = malloc(sizeof(*C));
75 }
76 memset(C, 0, sizeof(*C));
77
78 psi_data_ctor(PSI_DATA(C), error, flags);
79 C->ops = ops;
80
81 if (ops->init) {
82 ops->init(C);
83 }
84
85 assert(ops->call != NULL);
86 assert(ops->compile != NULL);
87
88 /* build up predefs in a temporary psi_data for validation */
89 memset(&T, 0, sizeof(T));
90 psi_data_ctor_with_dtors(&T, error, flags);
91
92 #if PHP_DEBUG
93 if (psi_check_env("PSI_SKIP"))
94 goto skip_predefs;
95 #endif
96
97 for (predef_type = &psi_predef_types[0]; predef_type->type_tag; ++predef_type) {
98 struct psi_decl_type *type = psi_decl_type_init(predef_type->type_tag, predef_type->type_name);
99 struct psi_decl_var *var = psi_decl_var_init(predef_type->alias, 0, 0); /* FIXME: indirection */
100 struct psi_decl_arg *def = psi_decl_arg_init(type, var);
101
102 T.types = psi_plist_add(T.types, &def);
103 }
104 for (predef_const = &psi_predef_consts[0]; predef_const->type_tag; ++predef_const) {
105 struct psi_const_type *type = psi_const_type_init(predef_const->type_tag, predef_const->type_name);
106 struct psi_impl_def_val *val;
107 struct psi_const *constant;
108
109 switch (type->type) {
110 case PSI_T_INT:
111 val = psi_impl_def_val_init(PSI_T_INT, NULL);
112 val->ival.zend.lval = predef_const->value.zend.lval;
113 break;
114 case PSI_T_STRING:
115 val = psi_impl_def_val_init(PSI_T_STRING, NULL);
116 val->ival.zend.str = zend_string_init(predef_const->value.ptr, strlen(predef_const->value.ptr), 1);
117 break;
118 default:
119 assert(0);
120 break;
121 }
122
123 constant = psi_const_init(type, predef_const->var_name, val);
124 T.consts = psi_plist_add(T.consts, &constant);
125 }
126 for (predef_composite = &psi_predef_composites[0]; predef_composite->type_tag; ++predef_composite) {
127 struct psi_predef_composite *member;
128 struct psi_decl_struct *dstruct;
129 struct psi_decl_union *dunion;
130 struct psi_plist *dargs = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
131
132 switch (predef_composite->type_tag) {
133 case PSI_T_STRUCT:
134 dstruct = psi_decl_struct_init(predef_composite->var_name, dargs);
135 dstruct->size = predef_composite->size;
136 dstruct->align = predef_composite->offset;
137 break;
138 case PSI_T_UNION:
139 dunion = psi_decl_union_init(predef_composite->var_name, dargs);
140 dunion->size = predef_composite->size;
141 dunion->align = predef_composite->offset;
142 break;
143 default:
144 assert(0);
145 }
146 for (member = &predef_composite[1]; member->type_tag; ++member) {
147 struct psi_decl_type *type;
148 struct psi_decl_var *dvar;
149 struct psi_decl_arg *darg;
150
151 type = psi_decl_type_init(member->type_tag, member->type_name);
152 dvar = psi_decl_var_init(member->var_name, member->pointer_level, member->array_size);
153 darg = psi_decl_arg_init(type, dvar);
154 darg->layout = psi_layout_init(member->offset, member->size, NULL);
155
156 switch (predef_composite->type_tag) {
157 case PSI_T_STRUCT:
158 dstruct->args = psi_plist_add(dstruct->args, &darg);
159 break;
160 case PSI_T_UNION:
161 dunion->args = psi_plist_add(dunion->args, &darg);
162 break;
163 default:
164 assert(0);
165 }
166 }
167 switch (predef_composite->type_tag) {
168 case PSI_T_STRUCT:
169 T.structs = psi_plist_add(T.structs, &dstruct);
170 break;
171 case PSI_T_UNION:
172 T.unions = psi_plist_add(T.unions, &dunion);
173 break;
174 default:
175 assert(0);
176 }
177
178 predef_composite = member;
179 }
180 for (predef_decl = &psi_predef_decls[0]; predef_decl->type_tag; ++predef_decl) {
181 struct psi_predef_decl *farg;
182 struct psi_decl_type *dtype, *ftype = psi_decl_type_init(predef_decl->type_tag, predef_decl->type_name);
183 struct psi_decl_var *fname = psi_decl_var_init(predef_decl->var_name, predef_decl->pointer_level, predef_decl->array_size);
184 struct psi_decl_arg *tdef, *func = psi_decl_arg_init(ftype, fname);
185 struct psi_plist *args = psi_plist_init((psi_plist_dtor) psi_decl_arg_free);
186 struct psi_decl *decl = psi_decl_init(func, args);
187
188 for (farg = &predef_decl[1]; farg->type_tag; ++farg) {
189 struct psi_decl_type *arg_type = psi_decl_type_init(farg->type_tag, farg->type_name);
190 struct psi_decl_var *arg_var = psi_decl_var_init(farg->var_name, farg->pointer_level, farg->array_size);
191 struct psi_decl_arg *darg = psi_decl_arg_init(arg_type, arg_var);
192 decl->args = psi_plist_add(decl->args, &darg);
193 }
194
195 switch (predef_decl->kind) {
196 case DECL_KIND_VARARG:
197 decl->varargs = 1;
198 /* no break */
199 case DECL_KIND_STD:
200 T.decls = psi_plist_add(T.decls, &decl);
201 break;
202 case DECL_KIND_FUNCTOR:
203 dtype = psi_decl_type_init(PSI_T_FUNCTION, fname->name);
204 dtype->real.func = decl;
205 tdef = psi_decl_arg_init(dtype, psi_decl_var_copy(fname));
206 T.types = psi_plist_add(T.types, &tdef);
207 break;
208 default:
209 assert(0);
210 }
211
212 predef_decl = farg;
213 }
214
215 #if PHP_DEBUG
216 skip_predefs:
217 #endif
218
219 psi_context_add_data(C, &T);
220
221 return C;
222 }
223
224 static int psi_select_dirent(const struct dirent *entry)
225 {
226 #ifndef FNM_CASEFOLD
227 # define FNM_CASEFOLD 0
228 #endif
229 return 0 == fnmatch("*.psi", entry->d_name, FNM_CASEFOLD);
230 }
231
232 void psi_context_build(struct psi_context *C, const char *paths)
233 {
234 int i, n;
235 char *sep = NULL, *cpy = strdup(paths), *ptr = cpy;
236 struct dirent **entries;
237
238 do {
239 sep = strchr(ptr, ':');
240
241 if (sep) {
242 *sep = 0;
243 }
244
245 entries = NULL;
246 n = php_scandir(ptr, &entries, psi_select_dirent, alphasort);
247
248 if (n > 0) {
249 for (i = 0; i < n; ++i) {
250 char psi[MAXPATHLEN];
251 struct psi_parser P;
252 struct psi_parser_input *I;
253
254 if (MAXPATHLEN <= slprintf(psi, MAXPATHLEN, "%s/%s", ptr, entries[i]->d_name)) {
255 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Path to PSI file too long: %s/%s",
256 ptr, entries[i]->d_name);
257 }
258 if (!psi_parser_init(&P, C->error, C->flags)) {
259 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to init PSI parser (%s): %s",
260 psi, strerror(errno));
261 continue;
262 }
263 if (!(I = psi_parser_open_file(&P, psi, true))) {
264 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to open PSI file (%s): %s",
265 psi, strerror(errno));
266 continue;
267 }
268 psi_parser_parse(&P, I);
269 psi_context_add_data(C, PSI_DATA(&P));
270 psi_parser_dtor(&P);
271 free(I);
272 }
273 }
274
275 if (entries) {
276 for (i = 0; i < n; ++i) {
277 free(entries[i]);
278 }
279 free(entries);
280 }
281
282 ptr = sep + 1;
283 } while (sep);
284
285
286 if (psi_context_compile(C) && SUCCESS != zend_register_functions(NULL, C->closures, NULL, MODULE_PERSISTENT)) {
287 C->error(PSI_DATA(C), NULL, PSI_WARNING, "Failed to register functions!");
288 }
289
290 free(cpy);
291 }
292
293 zend_function_entry *psi_context_compile(struct psi_context *C)
294 {
295 zend_constant zc;
296
297 zc.flags = CONST_PERSISTENT|CONST_CS;
298 zc.module_number = EG(current_module)->module_number;
299
300 if (C->consts) {
301 size_t i = 0;
302 struct psi_const *c;
303
304 while (psi_plist_get(C->consts, i++, &c)) {
305
306 if (zend_get_constant_str(c->name, strlen(c->name))) {
307 continue;
308 }
309
310 zc.name = zend_string_init(c->name, strlen(c->name), 1);
311
312 switch (c->type->type) {
313 case PSI_T_BOOL:
314 ZVAL_BOOL(&zc.value, c->val->ival.zend.bval);
315 break;
316 case PSI_T_INT:
317 ZVAL_LONG(&zc.value, c->val->ival.zend.lval);
318 break;
319 case PSI_T_FLOAT:
320 ZVAL_DOUBLE(&zc.value, c->val->ival.dval);
321 break;
322 case PSI_T_STRING:
323 case PSI_T_QUOTED_STRING:
324 ZVAL_NEW_STR(&zc.value, zend_string_copy(c->val->ival.zend.str));
325 break;
326 default:
327 assert(0);
328 break;
329 }
330
331 zend_register_constant(&zc);
332 }
333 }
334
335 if (C->enums) {
336 size_t i = 0;
337 struct psi_decl_enum *e;
338
339 while (psi_plist_get(C->enums, i++, &e)) {
340 size_t j = 0;
341 struct psi_decl_enum_item *item;
342
343 while (psi_plist_get(e->items, j++, &item)) {
344 zend_string *name;
345
346 if (psi_decl_type_is_anon(e->name, "enum")) {
347 name = strpprintf(0, "psi\\%s", item->name);
348 } else {
349 name = strpprintf(0, "psi\\%s\\%s", e->name, item->name);
350 }
351
352 if (zend_get_constant(name)) {
353 zend_string_release(name);
354 continue;
355 }
356
357 zc.name = zend_string_dup(name, 1);
358 ZVAL_LONG(&zc.value, psi_long_num_exp(item->num, NULL, NULL));
359 zend_register_constant(&zc);
360 zend_string_release(name);
361 }
362 }
363 }
364
365 return C->closures = C->ops->compile(C);
366 }
367
368
369 ZEND_RESULT_CODE psi_context_call(struct psi_context *C, zend_execute_data *execute_data, zval *return_value, struct psi_impl *impl)
370 {
371 struct psi_call_frame *frame;
372
373 frame = psi_call_frame_init(C, impl->decl, impl);
374
375 if (SUCCESS != psi_call_frame_parse_args(frame, execute_data)) {
376 psi_call_frame_free(frame);
377
378 return FAILURE;
379 }
380
381 psi_call_frame_enter(frame);
382
383 if (SUCCESS != psi_call_frame_do_let(frame)) {
384 psi_call_frame_do_return(frame, return_value);
385 psi_call_frame_free(frame);
386
387 return FAILURE;
388 }
389
390 if (SUCCESS != psi_call_frame_do_assert(frame, PSI_ASSERT_PRE)) {
391 psi_call_frame_do_return(frame, return_value);
392 psi_call_frame_free(frame);
393
394 return FAILURE;
395 }
396
397 C->ops->call(frame);
398
399 if (SUCCESS != psi_call_frame_do_assert(frame, PSI_ASSERT_POST)) {
400 psi_call_frame_do_return(frame, return_value);
401 psi_call_frame_free(frame);
402
403 return FAILURE;
404 }
405
406 psi_call_frame_do_return(frame, return_value);
407 psi_call_frame_do_set(frame);
408 psi_call_frame_do_free(frame);
409 psi_call_frame_free(frame);
410
411 return SUCCESS;
412 }
413
414
415 void psi_context_dtor(struct psi_context *C)
416 {
417 size_t i;
418 zend_function_entry *zfe;
419
420 if (C->ops->dtor) {
421 C->ops->dtor(C);
422 }
423
424 psi_data_dtor(PSI_DATA(C));
425
426 if (C->data) {
427 for (i = 0; i < C->count; ++i) {
428 psi_data_dtor(&C->data[i]);
429 }
430 free(C->data);
431 }
432
433 if (C->closures) {
434 for (zfe = C->closures; zfe->fname; ++zfe) {
435 free((void *) zfe->arg_info);
436 }
437 free(C->closures);
438 }
439 }
440
441 void psi_context_free(struct psi_context **C)
442 {
443 if (*C) {
444 psi_context_dtor(*C);
445 free(*C);
446 *C = NULL;
447 }
448 }
449
450 bool psi_context_add_data(struct psi_context *C, struct psi_data *P)
451 {
452 struct psi_data *D;
453
454 C->data = realloc(C->data, (C->count + 1) * sizeof(*C->data));
455 D = psi_data_exchange(&C->data[C->count++], P);
456
457 return psi_data_validate(PSI_DATA(C), D);
458 }
459
460 void psi_context_dump(struct psi_context *C, int fd)
461 {
462
463 dprintf(fd, "// psi.engine=%s\n",
464 (char *) C->ops->query(C, PSI_CONTEXT_QUERY_SELF, NULL));
465
466 psi_data_dump(fd, PSI_DATA(C));
467
468 // size_t i;
469 // dprintf(fd, "/* parsed\n");
470 // for (i = 0; i < C->count; ++i) {
471 // psi_data_dump(fd, &C->data[i]);
472 // }
473 // dprintf(fd, "*/\n");
474
475 }