fix size of arrays
[m6w6/ext-psi] / src / call.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 #include "context.h"
28 #include "data.h"
29 #include "call.h"
30
31 #include "php.h"
32 #include "zend_exceptions.h"
33 #include "ext/spl/spl_exceptions.h"
34
35 struct psi_call_frame_argument *psi_call_frame_argument_init(struct psi_impl_arg *spec,
36 impl_val *ival, zval *zptr, int is_vararg) {
37 struct psi_call_frame_argument *frame_arg = ecalloc(1, sizeof(*frame_arg));
38
39
40 if ((frame_arg->zval_ptr = zptr)) {
41 ZVAL_DEREF(frame_arg->zval_ptr);
42
43 /* use userland type if the declared type of the vararg is mixed */
44 if (is_vararg) {
45 if (spec->type->type == PSI_T_MIXED) {
46 switch (Z_TYPE_P(zptr)) {
47 case IS_TRUE:
48 frame_arg->va_type = PSI_T_BOOL;
49 ival->zend.bval = 1;
50 break;
51 case IS_FALSE:
52 frame_arg->va_type = PSI_T_BOOL;
53 ival->zend.bval = 0;
54 break;
55 case IS_LONG:
56 frame_arg->va_type = PSI_T_INT;
57 ival->zend.lval = Z_LVAL_P(zptr);
58 break;
59 case IS_DOUBLE:
60 frame_arg->va_type = PSI_T_FLOAT;
61 ival->dval = Z_DVAL_P(zptr);
62 break;
63 default:
64 frame_arg->va_type = PSI_T_STRING;
65 ival->zend.str = zval_get_string(zptr);
66 break;
67 }
68 } else {
69 frame_arg->va_type = spec->type->type;
70 }
71 }
72 }
73
74 frame_arg->ival = *ival;
75 frame_arg->ival_ptr = &frame_arg->ival;
76 frame_arg->spec = spec;
77
78 return frame_arg;
79 }
80
81 void psi_call_frame_argument_free(struct psi_call_frame_argument *arg) {
82 switch (arg->spec->type->type) {
83 case PSI_T_STRING:
84 if (arg->ival.zend.str) {
85 zend_string_release(arg->ival.zend.str);
86 }
87 break;
88 case PSI_T_CALLABLE:
89 if (arg->ival.zend.cb) {
90 if (arg->ival.zend.cb->fci.size) {
91 zend_fcall_info_args_clear(&arg->ival.zend.cb->fci, 1);
92 }
93 efree(arg->ival.zend.cb);
94 }
95 break;
96 default:
97 break;
98 }
99 if (arg->ival_ptr && arg->ival_ptr != &arg->temp_val && arg->ival_ptr != &arg->ival) {
100 efree(arg->ival_ptr);
101 }
102 efree(arg);
103 }
104
105 struct psi_call_frame_symbol *psi_call_frame_symbol_init(struct psi_decl_var *dvar) {
106 struct psi_call_frame_symbol *frame_sym;
107 size_t size = psi_decl_type_get_size(dvar->arg->type, NULL);
108
109 frame_sym = ecalloc(1, sizeof(*frame_sym) + size);
110 frame_sym->ptr = frame_sym->ival_ptr = &frame_sym->temp_val;
111
112 return frame_sym;
113 }
114
115 void psi_call_frame_symbol_free(struct psi_call_frame_symbol *sym) {
116 efree(sym);
117 }
118
119 static void psi_call_frame_free_argument(zval *zptr) {
120 psi_call_frame_argument_free(Z_PTR_P(zptr));
121 }
122
123 static void psi_call_frame_free_symbol(zval *zptr) {
124 psi_call_frame_symbol_free(Z_PTR_P(zptr));
125 }
126
127 struct psi_call_frame_auto_free {
128 void *data;
129 void (*dtor)(void *);
130 };
131
132 static void psi_call_frame_free_temp(void *ptr) {
133 struct psi_call_frame_auto_free *f = ptr;
134
135 if (f->data) {
136 if (f->dtor) {
137 f->dtor(&f->data);
138 } else {
139 efree(f->data);
140 }
141 }
142 }
143
144 struct psi_call_frame *psi_call_frame_init(struct psi_context *C, struct psi_decl *decl, struct psi_impl *impl) {
145 struct psi_call_frame *frame = ecalloc(1, sizeof(*frame));
146
147 frame->context = C;
148 frame->decl = decl;
149 frame->impl = impl;
150
151 zend_hash_init(&frame->arguments, 8, NULL, psi_call_frame_free_argument, 0);
152 zend_hash_init(&frame->symbols, 8, NULL, psi_call_frame_free_symbol, 0);
153 zend_llist_init(&frame->temp, sizeof(struct psi_call_frame_auto_free), psi_call_frame_free_temp, 0);
154
155 return frame;
156 }
157
158 struct psi_call_frame_symbol *psi_call_frame_fetch_symbol(
159 struct psi_call_frame *frame, struct psi_decl_var *dvar) {
160 struct psi_call_frame_symbol *frame_sym;
161
162 frame_sym = zend_hash_str_find_ptr(&frame->symbols, dvar->fqn, strlen(dvar->fqn));
163 if (!frame_sym) {
164 frame_sym = zend_hash_str_add_ptr(&frame->symbols, dvar->fqn, strlen(dvar->fqn),
165 psi_call_frame_symbol_init(dvar));
166 }
167 return frame_sym;
168 }
169
170 zval *psi_call_frame_new_argument(struct psi_call_frame *frame,
171 struct psi_call_frame_argument *frame_arg) {
172 if (frame_arg->va_type) {
173 /* varargs are just appended with numeric indices */
174 return zend_hash_next_index_insert_ptr(&frame->arguments, frame_arg);
175 } else {
176 return zend_hash_str_add_ptr(&frame->arguments,
177 frame_arg->spec->var->name, strlen(frame_arg->spec->var->name),
178 frame_arg);
179 }
180 }
181
182 zval *psi_call_frame_sub_argument(struct psi_call_frame *frame,
183 struct psi_impl_var *inner_var, zval *outer_zval, const char *name) {
184 struct psi_call_frame_argument *iarg;
185 zval *inner_zval = zend_symtable_str_find(Z_ARRVAL_P(outer_zval),
186 &inner_var->name[1], strlen(&inner_var->name[1]));
187
188 if (!inner_zval) {
189 zval empty_zval;
190
191 SEPARATE_ZVAL(outer_zval);
192 ZVAL_NULL(&empty_zval);
193 inner_zval = zend_symtable_str_update(Z_ARRVAL_P(outer_zval),
194 &inner_var->name[1], strlen(&inner_var->name[1]),
195 &empty_zval);
196 }
197
198 iarg = psi_call_frame_get_argument(frame, name);
199
200 if (!iarg) {
201 struct psi_call_frame_argument *frame_arg;
202 impl_val empty_val = {0};
203 struct psi_impl_arg *carg_spec = psi_impl_arg_init(
204 psi_impl_type_init(PSI_T_MIXED, "mixed"),
205 psi_impl_var_copy(inner_var), NULL);
206
207 psi_call_frame_push_auto_ex(frame, carg_spec, (void(*)(void*)) psi_impl_arg_free);
208 frame_arg = psi_call_frame_argument_init(carg_spec, &empty_val, inner_zval, 0);
209 zend_hash_str_add_ptr(&frame->arguments, name, strlen(name), frame_arg);
210 }
211
212 return inner_zval;
213 }
214
215 struct psi_call_frame_argument *psi_call_frame_get_argument(
216 struct psi_call_frame *frame, const char *name) {
217 return zend_hash_str_find_ptr(&frame->arguments, name, strlen(name));
218 }
219
220 size_t psi_call_frame_num_var_args(struct psi_call_frame *frame) {
221 return zend_hash_next_free_element(&frame->arguments);
222 }
223
224 size_t psi_call_frame_num_fixed_args(struct psi_call_frame *frame) {
225 return psi_plist_count(frame->decl->args);
226 }
227
228 struct psi_call_frame_argument *psi_call_frame_get_var_argument(
229 struct psi_call_frame *frame, zend_long index) {
230 return zend_hash_index_find_ptr(&frame->arguments, index);
231 }
232
233 void **psi_call_frame_get_arg_pointers(struct psi_call_frame *frame) {
234 return frame->pointers;
235 }
236
237 void *psi_call_frame_get_rpointer(struct psi_call_frame *frame) {
238 return frame->rpointer;
239 }
240
241 struct psi_decl *psi_call_frame_get_decl(struct psi_call_frame *frame) {
242 return frame->decl;
243 }
244
245 struct psi_impl *psi_call_frame_get_impl(struct psi_call_frame *frame) {
246 return frame->impl;
247 }
248
249 struct psi_context *psi_call_frame_get_context(struct psi_call_frame *frame) {
250 return frame->context;
251 }
252
253 #if PHP_VERSION_ID < 70300
254 # define PARAM_PROLOGUE(separate) Z_PARAM_PROLOGUE(separate)
255 #else
256 # define PARAM_PROLOGUE(separate) Z_PARAM_PROLOGUE(1, separate)
257 #endif
258 ZEND_RESULT_CODE psi_call_frame_parse_args(struct psi_call_frame *frame,
259 zend_execute_data *execute_data) {
260 size_t i, argc = psi_plist_count(frame->impl->func->args);
261 zend_error_handling zeh;
262
263 zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
264
265 if (!argc) {
266 ZEND_RESULT_CODE rv;
267
268 rv = zend_parse_parameters_none();
269 zend_restore_error_handling(&zeh);
270 return rv;
271 }
272
273 ZEND_PARSE_PARAMETERS_START(
274 psi_impl_num_min_args(frame->impl),
275 frame->impl->func->vararg ? -1 : argc
276 )
277 nextarg: {
278
279 struct psi_impl_arg *iarg;
280 impl_val ival = {0};
281
282 if (frame->impl->func->vararg && _i >= argc) {
283 iarg = frame->impl->func->vararg;
284 Z_PARAM_OPTIONAL;
285 } else {
286 psi_plist_get(frame->impl->func->args, _i, &iarg);
287 if (iarg->def) {
288 Z_PARAM_OPTIONAL;
289 }
290 }
291
292 if (PSI_T_BOOL == iarg->type->type) {
293 Z_PARAM_BOOL(ival.zend.bval);
294 } else if (PSI_T_INT == iarg->type->type) {
295 Z_PARAM_LONG(ival.zend.lval);
296 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
297 Z_PARAM_DOUBLE(ival.dval);
298 } else if (PSI_T_STRING == iarg->type->type) {
299 Z_PARAM_STR_EX(ival.zend.str, 1, iarg->var->reference);
300 if (ival.zend.str) {
301 zend_string_addref(ival.zend.str);
302 }
303 } else if (PSI_T_ARRAY == iarg->type->type) {
304 zval *tmp;
305 Z_PARAM_ARRAY_EX(tmp, _optional || iarg->var->reference,
306 iarg->var->reference);
307 } else if (PSI_T_OBJECT == iarg->type->type) {
308 PARAM_PROLOGUE(iarg->var->reference);
309 } else if (PSI_T_MIXED == iarg->type->type) {
310 PARAM_PROLOGUE(iarg->var->reference);
311 } else if (PSI_T_CALLABLE == iarg->type->type) {
312 zend_fcall_info fci;
313 zend_fcall_info_cache fcc;
314
315 Z_PARAM_FUNC_EX(fci, fcc, 1, 0);
316
317 if (fci.size) {
318 ival.zend.cb = ecalloc(1, sizeof(zend_fcall));
319 ival.zend.cb->fci = fci;
320 ival.zend.cb->fcc = fcc;
321 }
322 } else {
323 error_code = ZPP_ERROR_FAILURE;
324 break;
325 }
326
327 psi_call_frame_new_argument(frame,
328 psi_call_frame_argument_init(iarg, &ival, _arg, _i > argc));
329
330 if (_i < _num_args) {
331 goto nextarg;
332 }
333 }
334 ZEND_PARSE_PARAMETERS_END_EX(
335 zend_restore_error_handling(&zeh);
336 return FAILURE;
337 );
338
339 /* set up defaults */
340 for (i = EX_NUM_ARGS(); i < argc; ++i) {
341 struct psi_impl_arg *iarg;
342
343 psi_plist_get(frame->impl->func->args, i, &iarg);
344
345 assert(iarg->def);
346 psi_call_frame_new_argument(frame, psi_call_frame_argument_init(iarg,
347 &iarg->def->ival, NULL, 0));
348 }
349
350 zend_restore_error_handling(&zeh);
351 return SUCCESS;
352 }
353
354 void psi_call_frame_enter(struct psi_call_frame *frame) {
355 size_t argc = psi_call_frame_num_fixed_args(frame);
356 size_t va_count = psi_call_frame_num_var_args(frame);
357 size_t rsize = psi_decl_arg_get_size(frame->decl->func);
358 struct psi_call_frame_symbol *rv_sym;
359
360 /* initialize ffi argument array */
361 frame->pointers = ecalloc(argc + va_count + 1, sizeof(void *));
362
363 /* initialize return value symbol */
364 rv_sym = psi_call_frame_fetch_symbol(frame, frame->decl->func->var);
365 if (rsize > sizeof(impl_val)) {
366 rv_sym->ival_ptr = ecalloc(1, rsize);
367 } else {
368 rv_sym->ival_ptr = &rv_sym->temp_val;
369 }
370 frame->rpointer = rv_sym->ptr = rv_sym->ival_ptr;
371 }
372
373 ZEND_RESULT_CODE psi_call_frame_do_let(struct psi_call_frame *frame) {
374 size_t i;
375 struct psi_let_stmt *let;
376 struct psi_decl_arg *arg;
377 size_t argc = psi_call_frame_num_fixed_args(frame);
378 size_t va_count = psi_call_frame_num_var_args(frame);
379
380 for (i = 0; psi_plist_get(frame->impl->stmts.let, i, &let); ++i) {
381 psi_let_stmt_exec(let, frame);
382 }
383 for (i = 0; psi_plist_get(frame->decl->args, i, &arg); ++i) {
384 struct psi_let_stmt *let;
385 struct psi_call_frame_symbol *frame_sym;
386
387 let = psi_impl_get_let(frame->impl, arg->var);
388 frame_sym = psi_call_frame_fetch_symbol(frame, let->exp->var);
389 frame->pointers[i] = frame_sym->ptr;
390 }
391 /* varargs */
392 if (va_count) {
393 for (i = 0; i < va_count; ++i) {
394 struct psi_call_frame_argument *frame_arg;
395 psi_marshal_let let_fn;
396 void *temp = NULL;
397
398 frame_arg = psi_call_frame_get_var_argument(frame, i);
399 switch (frame_arg->va_type) {
400 case PSI_T_BOOL: let_fn = psi_let_boolval; break;
401 case PSI_T_INT: let_fn = psi_let_intval; break;
402 case PSI_T_FLOAT:
403 case PSI_T_DOUBLE: let_fn = psi_let_floatval; break;
404 case PSI_T_STRING: let_fn = psi_let_strval; break;
405 default:
406 assert(0);
407 }
408
409 frame_arg->ival_ptr = let_fn(&frame_arg->temp_val, NULL, frame_arg->va_type,
410 &frame_arg->ival, frame_arg->zval_ptr, &temp);
411 if (temp) {
412 psi_call_frame_push_auto(frame, temp);
413 }
414
415 frame->pointers[argc + i] = frame_arg->ival_ptr;
416 }
417 }
418
419 return SUCCESS;
420 }
421
422 ZEND_RESULT_CODE psi_call_frame_do_assert(struct psi_call_frame *frame, enum psi_assert_kind kind) {
423 size_t i = 0;
424 struct psi_assert_stmt *ass;
425
426 while (psi_plist_get(frame->impl->stmts.ass, i++, &ass)) {
427 if (ass->kind == kind) {
428 if (!psi_assert_stmt_exec(ass, frame)) {
429 char *message = psi_assert_stmt_message(ass);
430 zend_throw_exception(kind == PSI_ASSERT_PRE
431 ? spl_ce_InvalidArgumentException
432 : spl_ce_UnexpectedValueException, message, 0);
433 free(message);
434 return FAILURE;
435 }
436 }
437 }
438
439 return SUCCESS;
440 }
441
442 void psi_call_frame_do_call(struct psi_call_frame *frame) {
443 frame->context->ops->call(frame);
444 }
445
446 void psi_call_frame_do_callback(struct psi_call_frame *frame, struct psi_call_frame_callback *cbdata)
447 {
448 size_t i;
449 void *retptr;
450 ZEND_RESULT_CODE rc;
451 struct psi_let_callback *cb = cbdata->cb->data.callback;
452 zval return_value, *zargv = ecalloc(cbdata->argc, sizeof(*zargv));
453 struct psi_call_frame_argument *frame_arg;
454
455 assert(cbdata->argc == psi_plist_count(cb->decl->args));
456
457 /* prepare args for the userland call */
458 for (i = 0; i < cbdata->argc; ++i) {
459 struct psi_set_exp *set_exp;
460 struct psi_decl_var *set_var;
461 struct psi_call_frame_symbol *set_sym;
462
463 psi_plist_get(cb->args, i, &set_exp);
464 set_var = psi_set_exp_get_decl_var(set_exp);
465 set_sym = psi_call_frame_fetch_symbol(frame, set_var);
466
467 set_sym->ptr = cbdata->argv[i];
468 psi_set_exp_exec_ex(set_exp, &zargv[i], set_sym->ptr, frame);
469 }
470
471 frame_arg = psi_call_frame_get_argument(frame, cb->func->var->fqn);
472
473 /* callback into userland */
474 ZVAL_UNDEF(&return_value);
475 zend_fcall_info_argp(&frame_arg->ival_ptr->zend.cb->fci, cbdata->argc, zargv);
476 rc = zend_fcall_info_call(&frame_arg->ival_ptr->zend.cb->fci,
477 &frame_arg->ival_ptr->zend.cb->fcc, &return_value, NULL);
478 assert(rc == SUCCESS);
479
480 /* marshal return value of the userland call */
481 frame_arg->zval_ptr = &return_value;
482 retptr = psi_let_func_exec(cbdata->cb, cb->func, cb->decl->func, frame);
483 memcpy(cbdata->rval, retptr, psi_decl_arg_get_size(cb->decl->func));
484
485 /* cleanup */
486 zend_fcall_info_args_clear(&frame_arg->ival_ptr->zend.cb->fci, 0);
487 for (i = 0; i < cbdata->argc; ++i) {
488 zval_ptr_dtor(&zargv[i]);
489 }
490 efree(zargv);
491 }
492
493 void psi_call_frame_do_return(struct psi_call_frame *frame, zval *return_value) {
494 struct psi_return_stmt *ret;
495
496 psi_plist_get(frame->impl->stmts.ret, 0, &ret);
497 psi_return_stmt_exec(ret, return_value, frame);
498 }
499
500 void psi_call_frame_do_set(struct psi_call_frame *frame) {
501 size_t i = 0;
502 struct psi_set_stmt *set;
503
504 while (psi_plist_get(frame->impl->stmts.set, i++, &set)) {
505 psi_set_stmt_exec(set, frame);
506 }
507 }
508
509 void psi_call_frame_do_free(struct psi_call_frame *frame) {
510 size_t i = 0;
511 struct psi_free_stmt *fre;
512
513 while (psi_plist_get(frame->impl->stmts.fre, i++, &fre)) {
514 psi_free_stmt_exec(fre, frame);
515 }
516 }
517
518 void **psi_call_frame_push_auto_ex(struct psi_call_frame *frame, void *auto_free, void (*dtor)(void*)) {
519 struct psi_call_frame_auto_free f;
520
521 f.data = auto_free;
522 f.dtor = dtor;
523
524 zend_llist_add_element(&frame->temp, &f);
525 return &((struct psi_call_frame_auto_free *) zend_llist_get_last(&frame->temp))->data;
526 }
527
528 void **psi_call_frame_push_auto(struct psi_call_frame *frame, void *auto_free) {
529 return psi_call_frame_push_auto_ex(frame, auto_free, NULL);
530 }
531
532 static void psi_call_frame_local_auto_dtor(void *auto_list)
533 {
534 zend_llist_destroy(auto_list);
535 efree(auto_list);
536 }
537
538 #include "php_psi.h"
539
540 void psi_call_frame_free(struct psi_call_frame *frame) {
541 zend_hash_destroy(&frame->arguments);
542 zend_hash_destroy(&frame->symbols);
543 if (frame->impl && frame->impl->func->static_memory) {
544 zend_llist *temp = emalloc(sizeof(*temp));
545 zval zlocal;
546
547 memcpy(temp, &frame->temp, sizeof(*temp));
548 ZVAL_OBJ(&zlocal, psi_object_init_ex(NULL, temp, psi_call_frame_local_auto_dtor));
549 zend_set_local_var_str(frame->impl->func->name,
550 strlen(frame->impl->func->name), &zlocal, /* force */ 1);
551 } else {
552 zend_llist_destroy(&frame->temp);
553 }
554 efree(frame->pointers);
555 efree(frame);
556 }
557
558
559