fix leaks
[m6w6/ext-psi] / src / module.c
1
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5
6 #include "php.h"
7 #include "php_ini.h"
8 #include "ext/standard/info.h"
9 #include "zend_exceptions.h"
10 #include "zend_constants.h"
11 #include "zend_operators.h"
12
13 #include "php_psi.h"
14
15 #if HAVE_LIBJIT
16 # include "libjit.h"
17 # ifndef HAVE_LIBFFI
18 # define PSI_ENGINE "jit"
19 # endif
20 #endif
21 #if HAVE_LIBFFI
22 # include "libffi.h"
23 # define PSI_ENGINE "ffi"
24 #endif
25
26 ZEND_DECLARE_MODULE_GLOBALS(psi);
27
28 PHP_INI_BEGIN()
29 STD_PHP_INI_ENTRY("psi.engine", PSI_ENGINE, PHP_INI_SYSTEM, OnUpdateString, engine, zend_psi_globals, psi_globals)
30 STD_PHP_INI_ENTRY("psi.directory", "psi.d", PHP_INI_SYSTEM, OnUpdateString, directory, zend_psi_globals, psi_globals)
31 PHP_INI_END();
32
33 static zend_object_handlers psi_object_handlers;
34 static zend_class_entry *psi_class_entry;
35
36 void psi_error(int type, const char *msg, ...)
37 {
38 char buf[0x1000];
39 va_list argv;
40
41 va_start(argv, msg);
42 vslprintf(buf, 0x1000, msg, argv);
43 va_end(argv);
44
45 php_error(type, buf);
46 }
47
48 size_t psi_t_alignment(token_t t)
49 {
50 #define PSI_ALIGNOF(T) case PSI_T_## T: return ALIGNOF_## T ##_T;
51 switch (t) {
52 PSI_ALIGNOF(INT8);
53 PSI_ALIGNOF(UINT8);
54 PSI_ALIGNOF(INT16);
55 PSI_ALIGNOF(UINT16);
56 PSI_ALIGNOF(INT32);
57 PSI_ALIGNOF(UINT32);
58 PSI_ALIGNOF(INT64);
59 PSI_ALIGNOF(UINT64);
60 case PSI_T_FLOAT:
61 return ALIGNOF_FLOAT;
62 case PSI_T_DOUBLE:
63 return ALIGNOF_DOUBLE;
64 case PSI_T_POINTER:
65 return ALIGNOF_VOID_P;
66 EMPTY_SWITCH_DEFAULT_CASE();
67 }
68 return 0;
69 }
70
71 size_t psi_t_size(token_t t)
72 {
73 #define PSI_SIZEOF(T) case PSI_T_## T : return SIZEOF_## T ##_T;
74 switch (t) {
75 PSI_SIZEOF(INT8);
76 PSI_SIZEOF(UINT8);
77 PSI_SIZEOF(INT16);
78 PSI_SIZEOF(UINT16);
79 PSI_SIZEOF(INT32);
80 PSI_SIZEOF(UINT32);
81 PSI_SIZEOF(INT64);
82 PSI_SIZEOF(UINT64);
83 case PSI_T_FLOAT:
84 return SIZEOF_FLOAT;
85 case PSI_T_DOUBLE:
86 return SIZEOF_DOUBLE;
87 case PSI_T_POINTER:
88 return SIZEOF_VOID_P;
89 EMPTY_SWITCH_DEFAULT_CASE();
90 }
91 return 0;
92 }
93
94 size_t psi_t_align(token_t t, size_t s)
95 {
96 size_t a = psi_t_alignment(t);
97 return ((s - 1) | (a - 1)) + 1;
98 }
99
100 int psi_internal_type(impl_type *type)
101 {
102 switch (type->type) {
103 case PSI_T_BOOL:
104 return _IS_BOOL;
105 case PSI_T_INT:
106 return IS_LONG;
107 case PSI_T_FLOAT:
108 case PSI_T_DOUBLE:
109 return IS_DOUBLE;
110 case PSI_T_STRING:
111 return IS_STRING;
112 case PSI_T_ARRAY:
113 return IS_ARRAY;
114 default:
115 return 0;
116 }
117 }
118
119 zend_internal_arg_info *psi_internal_arginfo(impl *impl)
120 {
121 size_t i;
122 zend_internal_arg_info *aip;
123 zend_internal_function_info *fi;
124
125 aip = calloc(impl->func->args->count + 1 + !!impl->func->args->vararg.name, sizeof(*aip));
126
127 fi = (zend_internal_function_info *) &aip[0];
128 fi->allow_null = 1;
129 fi->required_num_args = psi_num_min_args(impl);
130 fi->return_reference = impl->func->return_reference;
131 fi->type_hint = psi_internal_type(impl->func->return_type);
132
133 if (impl->func->args->vararg.name) {
134 impl_arg *vararg = impl->func->args->vararg.name;
135 zend_internal_arg_info *ai = &aip[impl->func->args->count];
136
137 ai->name = vararg->var->name;
138 ai->type_hint = psi_internal_type(vararg->type);
139 if (vararg->var->reference) {
140 ai->pass_by_reference = 1;
141 }
142 ai->is_variadic = 1;
143 }
144
145 for (i = 0; i < impl->func->args->count; ++i) {
146 impl_arg *iarg = impl->func->args->args[i];
147 zend_internal_arg_info *ai = &aip[i+1];
148
149 ai->name = iarg->var->name;
150 ai->type_hint = psi_internal_type(iarg->type);
151 if (iarg->var->reference) {
152 ai->pass_by_reference = 1;
153 }
154 if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
155 ai->allow_null = 1;
156 }
157 }
158
159 return aip;
160 }
161
162 size_t psi_num_min_args(impl *impl)
163 {
164 size_t i, n = impl->func->args->count;
165
166 for (i = 0; i < impl->func->args->count; ++i) {
167 if (impl->func->args->args[i]->def) {
168 --n;
169 }
170 }
171 return n;
172 }
173
174 void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val)
175 {
176 RETVAL_NULL();
177 }
178
179 void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val)
180 {
181 psi_to_int(return_value, set, ret_val);
182 convert_to_boolean(return_value);
183 }
184
185 void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val)
186 {
187 decl_var *var = set->vars->vars[0];
188 token_t t = real_decl_type(var->arg->type)->type;
189 impl_val *v = deref_impl_val(ret_val, var);
190
191 switch (t) {
192 case PSI_T_FLOAT:
193 RETVAL_DOUBLE((double) v->fval);
194 convert_to_long(return_value);
195 break;
196 case PSI_T_DOUBLE:
197 RETVAL_DOUBLE(v->dval);
198 convert_to_long(return_value);
199 break;
200 case PSI_T_INT8:
201 RETVAL_LONG(v->i8);
202 break;
203 case PSI_T_UINT8:
204 RETVAL_LONG(v->u8);
205 break;
206 case PSI_T_INT16:
207 RETVAL_LONG(v->i16);
208 break;
209 case PSI_T_UINT16:
210 RETVAL_LONG(v->u16);
211 break;
212 case PSI_T_INT32:
213 RETVAL_LONG(v->i32);
214 break;
215 case PSI_T_UINT32:
216 #if UINT32_MAX >= ZEND_LONG_MAX
217 if (v->u32 > ZEND_LONG_MAX) {
218 char d[12] = {0};
219
220 RETVAL_STRING(zend_print_ulong_to_buf(&d[10], v->u32));
221 } else {
222 #endif
223 RETVAL_LONG(v->u32);
224 #if UINT32_MAX >= ZEND_LONG_MAX
225 }
226 #endif
227 break;
228 case PSI_T_INT64:
229 RETVAL_LONG(v->i64);
230 break;
231 case PSI_T_UINT64:
232 if (v->u64 > ZEND_LONG_MAX) {
233 char d[24] = {0};
234
235 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], v->u64));
236 } else {
237 RETVAL_LONG(v->u64);
238 }
239 break;
240 EMPTY_SWITCH_DEFAULT_CASE();
241 }
242 }
243
244 void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val)
245 {
246 decl_var *var = set->vars->vars[0];
247 token_t t = real_decl_type(var->arg->type)->type;
248 impl_val *v = deref_impl_val(ret_val, var);
249
250 switch (t) {
251 case PSI_T_FLOAT:
252 RETVAL_DOUBLE((double) v->fval);
253 break;
254 case PSI_T_DOUBLE:
255 RETVAL_DOUBLE(v->dval);
256 break;
257 case PSI_T_INT8:
258 RETVAL_DOUBLE((double) v->i8);
259 break;
260 case PSI_T_UINT8:
261 RETVAL_DOUBLE((double) v->u8);
262 break;
263 case PSI_T_INT16:
264 RETVAL_DOUBLE((double) v->i16);
265 break;
266 case PSI_T_UINT16:
267 RETVAL_DOUBLE((double) v->u16);
268 break;
269 case PSI_T_INT32:
270 RETVAL_DOUBLE((double) v->i32);
271 break;
272 case PSI_T_UINT32:
273 RETVAL_DOUBLE((double) v->u32);
274 break;
275 case PSI_T_INT64:
276 RETVAL_DOUBLE((double) v->i64);
277 break;
278 case PSI_T_UINT64:
279 RETVAL_DOUBLE((double) v->u64);
280 break;
281 EMPTY_SWITCH_DEFAULT_CASE();
282 }
283 }
284
285 void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val)
286 {
287 decl_var *var = set->vars->vars[0];
288 token_t t = real_decl_type(var->arg->type)->type;
289
290 switch (t) {
291 case PSI_T_VOID:
292 case PSI_T_INT8:
293 case PSI_T_UINT8:
294 if (!var->arg->var->pointer_level) {
295 RETVAL_STRINGL(&ret_val->cval, 1);
296 } else {
297 ret_val = deref_impl_val(ret_val, var);
298 if (ret_val && ret_val->ptr) {
299 if (set->num) {
300 RETVAL_STRINGL(ret_val->ptr, psi_long_num_exp(set->num, set->outer.val));
301 } else {
302 RETVAL_STRING(ret_val->ptr);
303 }
304 } else {
305 RETVAL_EMPTY_STRING();
306 }
307 }
308 return;
309 case PSI_T_FLOAT:
310 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval);
311 break;
312 case PSI_T_DOUBLE:
313 RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval);
314 break;
315 default:
316 psi_to_int(return_value, set, ret_val);
317 break;
318 }
319 convert_to_string(return_value);
320 }
321
322
323 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
324 {
325 memset(tmp, 0, sizeof(*tmp));
326 memcpy(tmp, ((void*) val->ptr) + size * i, size);
327 return tmp;
328 }
329
330 void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
331 {
332 decl_type *type = real_decl_type(spec->type);
333
334 switch (type->type) {
335 case PSI_T_FLOAT:
336 mem->fval = (float) zval_get_double(zv);
337 break;
338 case PSI_T_DOUBLE:
339 mem->dval = zval_get_double(zv);
340 break;
341 case PSI_T_INT8:
342 case PSI_T_UINT8:
343 if (spec->var->pointer_level) {
344 zend_string *zs = zval_get_string(zv);
345 *tmp = mem->ptr = estrndup(zs->val, zs->len);
346 zend_string_release(zs);
347 break;
348 }
349 /* no break */
350 default:
351 mem->zend.lval = zval_get_long(zv);
352 break;
353 }
354 }
355
356 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
357 {
358 size_t i, j = 0;
359 char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
360
361 if (arr) for (i = 0; i < s->args->count; ++i) {
362 decl_arg *darg = s->args->args[i];
363 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
364
365 if (entry) {
366 impl_val val;
367 void *tmp = NULL;
368
369 memset(&tmp, 0, sizeof(tmp));
370 psi_from_zval(&val, darg, entry, &tmp);
371 memcpy(mem + darg->layout->pos, &val, darg->layout->len);
372 if (tmp) {
373 ((void **)(mem + s->size))[j++] = tmp;
374 }
375 }
376 }
377 return mem;
378 }
379
380 void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
381 {
382 size_t i;
383 decl_var *var = set->vars->vars[0];
384 token_t t = real_decl_type(var->arg->type)->type;
385 impl_val tmp, *ret_val = deref_impl_val(r_val, var);
386
387 if ((intptr_t) ret_val->ptr <= (intptr_t) 0) {
388 RETURN_NULL();
389 }
390
391 array_init(return_value);
392
393 if (t == PSI_T_STRUCT) {
394 // decl_struct *s = real_decl_type(var->arg->type)->strct;
395
396 if (set->count) {
397 /* explicit member casts */
398 for (i = 0; i < set->count; ++i) {
399 set_value *sub_set = set->inner[i];
400 decl_var *sub_var = sub_set->vars->vars[0];
401
402 sub_set->outer.val = r_val;
403
404 if (sub_var->arg) {
405 impl_val *tmp = NULL, *val;
406 zval ztmp;
407
408 val = deref_impl_val(struct_member_ref(sub_var->arg, ret_val, &tmp), sub_var);
409 sub_set->func->handler(&ztmp, sub_set, val);
410 add_assoc_zval(return_value, sub_var->name, &ztmp);
411
412 if (tmp) {
413 free(tmp);
414 }
415 }
416 }
417 }
418 return;
419 }
420
421 if (var->arg->var->array_size) {
422 /* to_array(foo[NUMBER]) */
423 for (i = 0; i < var->arg->var->array_size; ++i) {
424 size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t);
425 impl_val *ptr = iterate(ret_val, size, i, &tmp);
426 zval ele;
427
428 switch (t) {
429 case PSI_T_FLOAT:
430 ZVAL_DOUBLE(&ele, (double) ptr->fval);
431 break;
432 case PSI_T_DOUBLE:
433 ZVAL_DOUBLE(&ele, ptr->dval);
434 break;
435 default:
436 ZVAL_LONG(&ele, ptr->lval);
437 break;
438 }
439
440 add_next_index_zval(return_value, &ele);
441 }
442 return;
443 } else if (set->num) {
444 /* to_array(arr_var, num_expr, to_int(*arr_var))
445 */
446 zval ele;
447 zend_long i, n = psi_long_num_exp(set->num, set->outer.val);
448
449 for (i = 0; i < n; ++i) {
450 size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
451 impl_val *ptr = iterate(ret_val, size, i, &tmp);
452
453 set->inner[0]->func->handler(&ele, set->inner[0], ptr);
454 add_next_index_zval(return_value, &ele);
455 }
456 } else {
457 ZEND_ASSERT(0);
458 }
459 }
460
461 void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
462 {
463 decl_var *var = set->vars->vars[0];
464 impl_val *ret_val = deref_impl_val(r_val, var);
465 psi_object *obj;
466
467 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
468 object_init_ex(return_value, psi_class_entry);
469 obj = PSI_OBJ(return_value, NULL);
470 obj->data = ret_val->ptr;
471 } else {
472 RETVAL_NULL();
473 }
474 }
475
476 static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
477 {
478 size_t i;
479 zval *zarg = ZEND_CALL_ARG(execute_data, 0);
480 impl_arg *iarg;
481 zend_error_handling zeh;
482
483 zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
484
485 if (!impl->func->args->count) {
486 ZEND_RESULT_CODE rv;
487
488 rv = zend_parse_parameters_none();
489 zend_restore_error_handling(&zeh);
490 return rv;
491 }
492
493 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->vararg.name ? -1 : impl->func->args->count)
494 nextarg:
495 if (impl->func->args->vararg.name && _i >= impl->func->args->count) {
496 impl_arg *varg = impl->func->args->vararg.name;
497 iarg = init_impl_arg(
498 init_impl_type(varg->type->type, varg->type->name),
499 init_impl_var(varg->var->name, varg->var->reference),
500 NULL);
501
502 Z_PARAM_OPTIONAL;
503 if (_i == impl->func->args->count) {
504 impl->func->args->vararg.args = init_impl_args(iarg);
505 } else {
506 add_impl_arg(impl->func->args->vararg.args, iarg);
507 }
508 } else {
509 iarg = impl->func->args->args[_i];
510 if (iarg->def) {
511 Z_PARAM_OPTIONAL;
512 }
513 }
514 if (PSI_T_BOOL == iarg->type->type) {
515 Z_PARAM_BOOL(iarg->val.zend.bval);
516 } else if (PSI_T_INT == iarg->type->type) {
517 Z_PARAM_LONG(iarg->val.zend.lval);
518 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
519 Z_PARAM_DOUBLE(iarg->val.dval);
520 } else if (PSI_T_STRING == iarg->type->type) {
521 Z_PARAM_STR_EX(iarg->val.zend.str, 1, iarg->var->reference);
522 if (iarg->val.zend.str) {
523 zend_string_addref(iarg->val.zend.str);
524 }
525 } else if (PSI_T_ARRAY == iarg->type->type) {
526 Z_PARAM_PROLOGUE(0);
527 } else if (PSI_T_OBJECT == iarg->type->type) {
528 Z_PARAM_PROLOGUE(0);
529 } else if (PSI_T_MIXED == iarg->type->type) {
530 Z_PARAM_PROLOGUE(0);
531 } else {
532 error_code = ZPP_ERROR_FAILURE;
533 break;
534 }
535 iarg->_zv = _arg;
536 ZVAL_DEREF(iarg->_zv);
537 if (_i < _num_args) {
538 goto nextarg;
539 }
540 ZEND_PARSE_PARAMETERS_END_EX(
541 zend_restore_error_handling(&zeh);
542 return FAILURE
543 );
544
545 /* set up defaults */
546 for (i = 0; i < impl->func->args->count; ++i) {
547 iarg = impl->func->args->args[i];
548
549 if (i < EX_NUM_ARGS()) {
550 } else if (iarg->def) {
551 switch (iarg->type->type) {
552 case PSI_T_BOOL:
553 iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
554 break;
555 case PSI_T_INT:
556 iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
557 break;
558 case PSI_T_FLOAT:
559 case PSI_T_DOUBLE:
560 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
561 break;
562 case PSI_T_STRING:
563 /* FIXME */
564 iarg->val.zend.str = zend_string_init(&iarg->def->text[1], strlen(iarg->def->text) - 2, 0);
565 break;
566 }
567 }
568 }
569
570 zend_restore_error_handling(&zeh);
571 return SUCCESS;
572 }
573
574 static inline void *psi_do_calloc(let_calloc *alloc)
575 {
576 zend_long n = psi_long_num_exp(alloc->nmemb, NULL), s = psi_long_num_exp(alloc->size, NULL);
577 void *mem = safe_emalloc(n, s, sizeof(void *));
578 memset(mem, 0, n * s + sizeof(void *));
579 return mem;
580 }
581
582 static inline ZEND_RESULT_CODE psi_let_val(token_t let_func, impl_arg *iarg, impl_val *arg_val, decl_struct *strct, void **to_free)
583 {
584 switch (let_func) {
585 case PSI_T_BOOLVAL:
586 if (iarg->type->type == PSI_T_BOOL) {
587 arg_val->cval = iarg->val.zend.bval;
588 } else {
589 arg_val->cval = zend_is_true(iarg->_zv);
590 }
591 break;
592 case PSI_T_INTVAL:
593 if (iarg->type->type == PSI_T_INT) {
594 arg_val->lval = iarg->val.zend.lval;
595 } else {
596 arg_val->lval = zval_get_long(iarg->_zv);
597 }
598 break;
599 case PSI_T_FLOATVAL:
600 if (iarg->type->type == PSI_T_FLOAT || iarg->type->type == PSI_T_DOUBLE) {
601 arg_val->dval = iarg->val.dval;
602 } else {
603 arg_val->dval = zval_get_double(iarg->_zv);
604 }
605 break;
606 case PSI_T_PATHVAL:
607 case PSI_T_STRVAL:
608 if (iarg->type->type == PSI_T_STRING) {
609 if (iarg->val.zend.str) {
610 arg_val->ptr = estrdup(iarg->val.zend.str->val);
611 *to_free = arg_val->ptr;
612 } else {
613 arg_val->ptr = "";
614 }
615 } else {
616 zend_string *zs = zval_get_string(iarg->_zv);
617 arg_val->ptr = estrdup(zs->val);
618 *to_free = arg_val->ptr;
619 zend_string_release(zs);
620 }
621 if (PSI_T_PATHVAL == let_func) {
622 if (SUCCESS != php_check_open_basedir(arg_val->ptr)) {
623 efree(arg_val->ptr);
624 return FAILURE;
625 }
626 }
627 break;
628 case PSI_T_STRLEN:
629 if (iarg->type->type == PSI_T_STRING) {
630 if (iarg->val.zend.str) {
631 arg_val->lval = iarg->val.zend.str->len;
632 } else {
633 arg_val->lval = 0;
634 }
635 } else {
636 zend_string *zs = zval_get_string(iarg->_zv);
637 arg_val->lval = zs->len;
638 zend_string_release(zs);
639 }
640 break;
641 case PSI_T_ARRVAL:
642 if (iarg->type->type == PSI_T_ARRAY) {
643 arg_val->ptr = psi_array_to_struct(strct, HASH_OF(iarg->_zv));
644 *to_free = arg_val->ptr;
645 }
646 break;
647 case PSI_T_OBJVAL:
648 if (iarg->type->type == PSI_T_OBJECT) {
649 psi_object *obj;
650
651 if (!instanceof_function(Z_OBJCE_P(iarg->_zv), psi_class_entry)) {
652 return FAILURE;
653 }
654
655 obj = PSI_OBJ(iarg->_zv, NULL);
656 arg_val->ptr = obj->data;
657 }
658 break;
659 EMPTY_SWITCH_DEFAULT_CASE();
660 }
661 return SUCCESS;
662 }
663
664 static inline void *psi_do_let(let_stmt *let)
665 {
666 decl_arg *darg = let->var->arg;
667 impl_val *arg_val = darg->ptr;
668 impl_arg *iarg;
669
670 switch (let->val ? let->val->kind : PSI_LET_NULL) {
671 case PSI_LET_TMP:
672 arg_val->ptr = deref_impl_val(let->val->data.var->arg->val.ptr, let->var);
673 break;
674 case PSI_LET_NULL:
675 if (darg->var->array_size) {
676 arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val));
677 darg->mem = arg_val->ptr;
678 } else {
679 memset(arg_val, 0, sizeof(*arg_val));
680 }
681 break;
682 case PSI_LET_CALLOC:
683 arg_val->ptr = psi_do_calloc(let->val->data.alloc);
684 darg->mem = arg_val->ptr;
685 break;
686 case PSI_LET_NUMEXP:
687 arg_val->zend.lval = psi_long_num_exp(let->val->data.num, NULL);
688 break;
689 case PSI_LET_FUNC:
690 iarg = let->val->data.func->arg;
691
692 if (SUCCESS != psi_let_val(let->val->data.func->type, iarg, darg->ptr, real_decl_type(darg->type)->strct, &darg->mem)) {
693 return NULL;
694 }
695 }
696
697 if (let->val && let->val->flags.one.is_reference) {
698 return let->ptr = &darg->ptr;
699 } else {
700 return let->ptr = darg->ptr;
701 }
702 }
703
704 static inline void psi_do_set(zval *return_value, set_value *set)
705 {
706 zval_dtor(return_value);
707 set->func->handler(return_value, set, set->vars->vars[0]->arg->ptr);
708 }
709
710 static inline void psi_do_return(zval *return_value, return_stmt *ret)
711 {
712 ret->set->func->handler(return_value, ret->set, ret->set->vars->vars[0]->arg->ptr);
713 }
714
715 static inline void psi_do_free(free_stmt *fre)
716 {
717 size_t i, j;
718
719 for (i = 0; i < fre->calls->count; ++i) {
720 free_call *f = fre->calls->list[i];
721
722 for (j = 0; j < f->vars->count; ++j) {
723 decl_var *dvar = f->vars->vars[j];
724 decl_arg *darg = dvar->arg;
725
726 f->decl->call.args[j] = &darg->val;
727 }
728
729 /* FIXME: check in validate_* that free functions return scalar */
730 PSI_ContextCall(&PSI_G(context), &f->decl->call, NULL);
731 }
732 }
733
734 static inline void psi_do_clean(impl *impl)
735 {
736 size_t i;
737
738 for (i = 0; i < impl->func->args->count; ++i ) {
739 impl_arg *iarg = impl->func->args->args[i];
740
741 switch (iarg->type->type) {
742 case PSI_T_STRING:
743 if (iarg->val.zend.str) {
744 zend_string_release(iarg->val.zend.str);
745 }
746 break;
747 }
748 }
749
750 if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
751 decl_arg *darg = impl->decl->args->args[i];
752
753 if (darg->mem) {
754 decl_type *type = real_decl_type(darg->type);
755
756 if (type->type == PSI_T_STRUCT) {
757 void **ptr = (void **) ((char *) darg->mem + type->strct->size);
758
759 while (*ptr) {
760 efree(*ptr++);
761 }
762 }
763 efree(darg->mem);
764 darg->mem = NULL;
765 }
766 }
767
768 if (impl->func->args->vararg.args) {
769 free_impl_args(impl->func->args->vararg.args);
770 impl->func->args->vararg.args = NULL;
771 }
772 if (impl->func->args->vararg.types) {
773 efree(impl->func->args->vararg.types);
774 impl->func->args->vararg.types = NULL;
775 }
776 if (impl->func->args->vararg.values) {
777 efree(impl->func->args->vararg.values);
778 impl->func->args->vararg.values = NULL;
779 }
780 if (impl->func->args->vararg.free_list) {
781 void **list = impl->func->args->vararg.free_list;
782
783 while (*list) {
784 efree(*list++);
785 }
786
787 efree(impl->func->args->vararg.free_list);
788 impl->func->args->vararg.free_list = NULL;
789 }
790 }
791
792 static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *strct, impl_val *res) {
793 impl_val *ref, *tmp = NULL;
794
795 switch (exp->t) {
796 case PSI_T_NUMBER:
797 switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) res, (double *) res, 0)) {
798 case IS_LONG:
799 return PSI_T_INT64;
800 case IS_DOUBLE:
801 return PSI_T_DOUBLE;
802 }
803 break;
804
805 case PSI_T_NSNAME:
806 switch (exp->u.cnst->type->type) {
807 case PSI_T_INT:
808 res->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval;
809 return PSI_T_INT64;
810 case PSI_T_FLOAT:
811 res->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval;
812 return PSI_T_DOUBLE;
813 default:
814 return 0;
815 }
816 break;
817
818 case PSI_T_NAME:
819 if (strct) {
820 ref = struct_member_ref(exp->u.dvar->arg, strct, &tmp);
821 } else {
822 ref = exp->u.dvar->arg->ptr;
823 }
824 switch (real_decl_type(exp->u.dvar->arg->type)->type) {
825 case PSI_T_INT8:
826 case PSI_T_UINT8:
827 case PSI_T_INT16:
828 case PSI_T_UINT16:
829 case PSI_T_INT32:
830 case PSI_T_UINT32:
831 case PSI_T_INT64:
832 case PSI_T_UINT64:
833 memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
834 if (tmp) {
835 free(tmp);
836 }
837 return real_decl_type(exp->u.dvar->arg->type)->type;
838
839 case PSI_T_FLOAT:
840 case PSI_T_DOUBLE:
841 memcpy(res, deref_impl_val(ref, exp->u.dvar), sizeof(*res));
842 if (tmp) {
843 free(tmp);
844 }
845 return real_decl_type(exp->u.dvar->arg->type)->type;
846
847 EMPTY_SWITCH_DEFAULT_CASE();
848 }
849 break;
850
851 EMPTY_SWITCH_DEFAULT_CASE();
852 }
853 return 0;
854 }
855
856 int psi_calc_num_exp(num_exp *exp, impl_val *strct, impl_val *res) {
857 impl_val num = {0};
858 int num_type = psi_calc_num_exp_value(exp, strct, &num);
859
860 if (exp->operand) {
861 impl_val tmp = {0};
862 int tmp_type = psi_calc_num_exp(exp->operand, strct, &tmp);
863
864 return exp->calculator(num_type, &num, tmp_type, &tmp, res);
865 }
866
867 memcpy(res, &num, sizeof(*res));
868 return num_type;
869 }
870
871 #define PRIfval "f"
872 #define PRIdval "lf"
873
874 #define PSI_CALC_OP(var) do { \
875 const char *fmt = "calc %" PRI##var ", %" PRI##var ": %" PRI##var "\n"; \
876 res->var = PSI_CALC(v1->var, v2->var); \
877 if (!res->var) fprintf(stderr, fmt, v1->var, v2->var, res->var); \
878 } while (0)
879 #define PSI_CALC_OP2(vres, var1, var2) do { \
880 const char *fmt = "calc %" PRI##var1 ", %" PRI##var2 ": %" PRI##vres "\n"; \
881 res->vres = PSI_CALC(v1->var1, v2->var2); \
882 if (!res->vres) fprintf(stderr, fmt, v1->var1, v2->var2, res->vres); \
883 } while(0)
884 #define PSI_CALC_FN(op) int psi_calc_##op(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res) \
885 { \
886 if (t1 == t2) { \
887 switch (t1) { \
888 case PSI_T_FLOAT: PSI_CALC_OP(fval); break; \
889 case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; \
890 case PSI_T_INT8: PSI_CALC_OP(i8); break; \
891 case PSI_T_UINT8: PSI_CALC_OP(u8); break; \
892 case PSI_T_INT16: PSI_CALC_OP(i16); break; \
893 case PSI_T_UINT16: PSI_CALC_OP(u16); break; \
894 case PSI_T_INT32: PSI_CALC_OP(i32); break; \
895 case PSI_T_UINT32: PSI_CALC_OP(u32); break; \
896 case PSI_T_INT64: PSI_CALC_OP(i64); break; \
897 case PSI_T_UINT64: PSI_CALC_OP(u64); break; \
898 EMPTY_SWITCH_DEFAULT_CASE(); \
899 } \
900 return t1; \
901 } else if (t1 == PSI_T_DOUBLE) { \
902 switch (t2) { \
903 case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; \
904 case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; \
905 case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; \
906 case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; \
907 case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; \
908 case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; \
909 case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; \
910 case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; \
911 case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; \
912 EMPTY_SWITCH_DEFAULT_CASE(); \
913 } \
914 return t1; \
915 } else if (t2 == PSI_T_DOUBLE) { \
916 switch (t1) { \
917 case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; \
918 case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; \
919 case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; \
920 case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; \
921 case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; \
922 case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; \
923 case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; \
924 case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; \
925 case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; \
926 EMPTY_SWITCH_DEFAULT_CASE(); \
927 } \
928 return t2; \
929 } else if (t1 == PSI_T_FLOAT) { \
930 switch (t2) { \
931 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; \
932 case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; \
933 case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; \
934 case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; \
935 case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; \
936 case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; \
937 case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; \
938 case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; \
939 case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; \
940 EMPTY_SWITCH_DEFAULT_CASE(); \
941 } \
942 return t1; \
943 } else if (t2 == PSI_T_FLOAT) { \
944 switch (t1) { \
945 case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; \
946 case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; \
947 case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; \
948 case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; \
949 case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; \
950 case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; \
951 case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; \
952 case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; \
953 case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; \
954 EMPTY_SWITCH_DEFAULT_CASE(); \
955 } \
956 return t2; \
957 } else { \
958 int64_t sval1 = v1->i64, sval2 = v2->i64; \
959 uint64_t uval1 = v1->u64, uval2 = v2->u64; \
960 switch (t1) { \
961 case PSI_T_INT8: sval1 >>= 8; \
962 case PSI_T_INT16: sval1 >>= 8; \
963 case PSI_T_INT32: sval1 >>= 8; \
964 case PSI_T_INT64: \
965 switch (t2) { \
966 case PSI_T_INT8: sval2 >>= 8; \
967 case PSI_T_INT16: sval2 >>= 8; \
968 case PSI_T_INT32: sval2 >>= 8; \
969 case PSI_T_INT64: \
970 res->i64 = PSI_CALC(sval1 , sval2); \
971 return PSI_T_INT64; \
972 case PSI_T_UINT8: uval2 >>= 8; \
973 case PSI_T_UINT16: uval2 >>= 8; \
974 case PSI_T_UINT32: uval2 >>= 8; \
975 case PSI_T_UINT64: \
976 res->i64 = PSI_CALC(sval1, uval2); \
977 return PSI_T_INT64; \
978 } \
979 break; \
980 case PSI_T_UINT8: uval1 >>= 8; \
981 case PSI_T_UINT16: uval1 >>= 8; \
982 case PSI_T_UINT32: uval1 >>= 8; \
983 case PSI_T_UINT64: \
984 switch (t2) { \
985 case PSI_T_INT8: sval2 >>= 8; \
986 case PSI_T_INT16: sval2 >>= 8; \
987 case PSI_T_INT32: sval2 >>= 8; \
988 case PSI_T_INT64: \
989 res->i64 = PSI_CALC(uval1, sval2); \
990 return PSI_T_INT64; \
991 case PSI_T_UINT8: uval2 >>= 8; \
992 case PSI_T_UINT16: uval2 >>= 8; \
993 case PSI_T_UINT32: uval2 >>= 8; \
994 case PSI_T_UINT64: \
995 res->u64 = PSI_CALC(uval1, uval2); \
996 return PSI_T_UINT64; \
997 } \
998 break; \
999 } \
1000 } \
1001 ZEND_ASSERT(0); \
1002 return 0; \
1003 }
1004
1005 #undef PSI_CALC
1006 #define PSI_CALC(var1, var2) (var1) + (var2)
1007 PSI_CALC_FN(add)
1008 #undef PSI_CALC
1009 #define PSI_CALC(var1, var2) (var1) * (var2)
1010 PSI_CALC_FN(mul)
1011 #undef PSI_CALC
1012 #define PSI_CALC(var1, var2) (var1) - (var2)
1013 PSI_CALC_FN(sub)
1014 #undef PSI_CALC
1015 #define PSI_CALC(var1, var2) (var1) / (var2)
1016 PSI_CALC_FN(div)
1017
1018 static inline void psi_do_args(impl *impl) {
1019 size_t i;
1020
1021 for (i = 0; i < impl->decl->args->count; ++i) {
1022 impl->decl->call.args[i] = impl->decl->args->args[i]->let->ptr;
1023 }
1024 }
1025
1026 static inline impl_vararg *psi_do_varargs(impl *impl) {
1027 size_t i, j;
1028 impl_vararg *va = &impl->func->args->vararg;
1029 size_t vacount = va->args->count;
1030
1031
1032 if (!vacount) {
1033 return NULL;
1034 }
1035
1036 va->types = ecalloc(vacount, sizeof(*va->types));
1037 va->values = ecalloc(vacount, sizeof(*va->values));
1038
1039 for (i = 0, j = 0; i < vacount; ++i) {
1040 impl_arg *vaarg = va->args->args[i];
1041 void *to_free = NULL;
1042 token_t let_fn, vatype = va->name->type->type;
1043
1044 if (vatype == PSI_T_MIXED) {
1045 switch (Z_TYPE_P(vaarg->_zv)) {
1046 case IS_TRUE:
1047 case IS_FALSE: vatype = PSI_T_BOOL; break;
1048 case IS_LONG: vatype = PSI_T_INT; break;
1049 case IS_DOUBLE: vatype = PSI_T_FLOAT; break;
1050 default: vatype = PSI_T_STRING; break;
1051 }
1052 }
1053
1054
1055 switch (vatype) {
1056 case PSI_T_BOOL: let_fn = PSI_T_BOOLVAL; break;
1057 case PSI_T_INT: let_fn = PSI_T_INTVAL; break;
1058 case PSI_T_FLOAT:
1059 case PSI_T_DOUBLE: let_fn = PSI_T_FLOATVAL;break;
1060 case PSI_T_STRING: let_fn = PSI_T_STRVAL; break;
1061 EMPTY_SWITCH_DEFAULT_CASE();
1062 }
1063
1064 va->types[i] = vatype;
1065 psi_let_val(let_fn, vaarg, &va->values[i], NULL, &to_free);
1066
1067 if (to_free) {
1068 if (!va->free_list) {
1069 va->free_list = ecalloc(vacount - i + 1, sizeof(*va->free_list));
1070 }
1071 va->free_list[j++] = to_free;
1072 }
1073 }
1074
1075 return va;
1076 }
1077
1078 void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
1079 {
1080 size_t i;
1081 impl_vararg *va = NULL;
1082
1083 memset(impl->decl->func->ptr, 0, sizeof(impl_val));
1084
1085 if (SUCCESS != psi_parse_args(execute_data, impl)) {
1086 return;
1087 }
1088
1089 for (i = 0; i < impl->stmts->let.count; ++i) {
1090 let_stmt *let = impl->stmts->let.list[i];
1091
1092 if (!psi_do_let(let)) {
1093 psi_do_return(return_value, impl->stmts->ret.list[0]);
1094 psi_do_clean(impl);
1095 return;
1096 }
1097 }
1098
1099 if (impl->decl->args) {
1100 psi_do_args(impl);
1101
1102 if (impl->func->args->vararg.args) {
1103 va = psi_do_varargs(impl);
1104 }
1105 }
1106
1107 PSI_ContextCall(&PSI_G(context), &impl->decl->call, va);
1108 psi_do_return(return_value, impl->stmts->ret.list[0]);
1109
1110 for (i = 0; i < impl->stmts->set.count; ++i) {
1111 set_stmt *set = impl->stmts->set.list[i];
1112
1113 if (set->arg->_zv) {
1114 psi_do_set(set->arg->_zv, set->val);
1115 }
1116 }
1117
1118 for (i = 0; i < impl->stmts->fre.count; ++i) {
1119 free_stmt *fre = impl->stmts->fre.list[i];
1120
1121 psi_do_free(fre);
1122 }
1123 psi_do_clean(impl);
1124 }
1125
1126 static void psi_object_free(zend_object *o)
1127 {
1128 psi_object *obj = PSI_OBJ(NULL, o);
1129
1130 if (obj->data) {
1131 // free(obj->data);
1132 obj->data = NULL;
1133 }
1134 zend_object_std_dtor(o);
1135 }
1136
1137 static zend_object *psi_object_init(zend_class_entry *ce)
1138 {
1139 psi_object *o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
1140
1141 zend_object_std_init(&o->std, ce);
1142 object_properties_init(&o->std, ce);
1143 o->std.handlers = &psi_object_handlers;
1144 return &o->std;
1145 }
1146
1147 PHP_MINIT_FUNCTION(psi)
1148 {
1149 PSI_ContextOps *ops = NULL;
1150 zend_class_entry ce = {0};
1151
1152 REGISTER_INI_ENTRIES();
1153
1154 INIT_NS_CLASS_ENTRY(ce, "psi", "object", NULL);
1155 psi_class_entry = zend_register_internal_class_ex(&ce, NULL);
1156 psi_class_entry->create_object = psi_object_init;
1157
1158 memcpy(&psi_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1159 psi_object_handlers.offset = XtOffsetOf(psi_object, std);
1160 psi_object_handlers.free_obj = psi_object_free;
1161 psi_object_handlers.clone_obj = NULL;
1162
1163 #ifdef HAVE_LIBJIT
1164 if (!strcasecmp(PSI_G(engine), "jit")) {
1165 ops = PSI_Libjit();
1166 } else
1167 #endif
1168 #ifdef HAVE_LIBFFI
1169 ops = PSI_Libffi();
1170 #endif
1171
1172 if (!ops) {
1173 php_error(E_WARNING, "No PSI engine found");
1174 return FAILURE;
1175 }
1176
1177 PSI_ContextInit(&PSI_G(context), ops, psi_error);
1178 PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
1179
1180 if (psi_check_env("PSI_DUMP")) {
1181 PSI_ContextDump(&PSI_G(context), STDOUT_FILENO);
1182 }
1183
1184 return SUCCESS;
1185 }
1186
1187 PHP_MSHUTDOWN_FUNCTION(psi)
1188 {
1189 PSI_ContextDtor(&PSI_G(context));
1190
1191 UNREGISTER_INI_ENTRIES();
1192
1193 return SUCCESS;
1194 }
1195
1196 #if defined(COMPILE_DL_PSI) && defined(ZTS)
1197 PHP_RINIT_FUNCTION(psi)
1198 {
1199 ZEND_TSRMLS_CACHE_UPDATE();
1200 return SUCCESS;
1201 }
1202 #endif
1203
1204 PHP_MINFO_FUNCTION(psi)
1205 {
1206 php_info_print_table_start();
1207 php_info_print_table_header(2, "psi support", "enabled");
1208 php_info_print_table_end();
1209
1210 DISPLAY_INI_ENTRIES();
1211 }
1212 const zend_function_entry psi_functions[] = {
1213 PHP_FE_END
1214 };
1215
1216 zend_module_entry psi_module_entry = {
1217 STANDARD_MODULE_HEADER,
1218 "psi",
1219 psi_functions,
1220 PHP_MINIT(psi),
1221 PHP_MSHUTDOWN(psi),
1222 #if defined(COMPILE_DL_PSI) && defined(ZTS)
1223 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
1224 #else
1225 NULL,
1226 #endif
1227 NULL,
1228 PHP_MINFO(psi),
1229 PHP_PSI_VERSION,
1230 STANDARD_MODULE_PROPERTIES
1231 };
1232
1233 #ifdef COMPILE_DL_PSI
1234 #ifdef ZTS
1235 ZEND_TSRMLS_CACHE_DEFINE();
1236 #endif
1237 ZEND_GET_MODULE(psi)
1238 #endif
1239
1240 /*
1241 * Local variables:
1242 * tab-width: 4
1243 * c-basic-offset: 4
1244 * End:
1245 * vim600: noet sw=4 ts=4 fdm=marker
1246 * vim<600: noet sw=4 ts=4
1247 */