zend_string'ify
[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_find_ptr(&frame->symbols, dvar->fqn);
163 if (!frame_sym) {
164 frame_sym = zend_hash_add_ptr(&frame->symbols, 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_add_ptr(&frame->arguments,
177 frame_arg->spec->var->name, frame_arg);
178 }
179 }
180
181 zval *psi_call_frame_sub_argument(struct psi_call_frame *frame,
182 struct psi_impl_var *inner_var, zval *outer_zval, zend_string *name) {
183 struct psi_call_frame_argument *iarg;
184 zval *inner_zval = zend_symtable_str_find(Z_ARRVAL_P(outer_zval),
185 &inner_var->name->val[1], inner_var->name->len - 1);
186
187 if (!inner_zval) {
188 zval empty_zval;
189
190 SEPARATE_ZVAL(outer_zval);
191 ZVAL_NULL(&empty_zval);
192 inner_zval = zend_symtable_str_update(Z_ARRVAL_P(outer_zval),
193 &inner_var->name->val[1], inner_var->name->len - 1,
194 &empty_zval);
195 }
196
197 iarg = psi_call_frame_get_argument(frame, name);
198
199 if (!iarg) {
200 struct psi_call_frame_argument *frame_arg;
201 impl_val empty_val = {0};
202 struct psi_impl_arg *carg_spec = psi_impl_arg_init(
203 psi_impl_type_init(PSI_T_MIXED, zend_string_init(ZEND_STRL("mixed"), 1)),
204 psi_impl_var_copy(inner_var), NULL);
205
206 psi_call_frame_push_auto_ex(frame, carg_spec, (void(*)(void*)) psi_impl_arg_free);
207 frame_arg = psi_call_frame_argument_init(carg_spec, &empty_val, inner_zval, 0);
208 zend_hash_add_ptr(&frame->arguments, name, frame_arg);
209 }
210
211 return inner_zval;
212 }
213
214 struct psi_call_frame_argument *psi_call_frame_get_argument(
215 struct psi_call_frame *frame, zend_string *name) {
216 return zend_hash_find_ptr(&frame->arguments, name);
217 }
218
219 size_t psi_call_frame_num_var_args(struct psi_call_frame *frame) {
220 return zend_hash_next_free_element(&frame->arguments);
221 }
222
223 size_t psi_call_frame_num_fixed_args(struct psi_call_frame *frame) {
224 return psi_plist_count(frame->decl->args);
225 }
226
227 struct psi_call_frame_argument *psi_call_frame_get_var_argument(
228 struct psi_call_frame *frame, zend_long index) {
229 return zend_hash_index_find_ptr(&frame->arguments, index);
230 }
231
232 void **psi_call_frame_get_arg_pointers(struct psi_call_frame *frame) {
233 return frame->pointers;
234 }
235
236 void *psi_call_frame_get_rpointer(struct psi_call_frame *frame) {
237 return frame->rpointer;
238 }
239
240 struct psi_decl *psi_call_frame_get_decl(struct psi_call_frame *frame) {
241 return frame->decl;
242 }
243
244 struct psi_impl *psi_call_frame_get_impl(struct psi_call_frame *frame) {
245 return frame->impl;
246 }
247
248 struct psi_context *psi_call_frame_get_context(struct psi_call_frame *frame) {
249 return frame->context;
250 }
251
252 #if PHP_VERSION_ID < 70300
253 # define PARAM_PROLOGUE(separate) Z_PARAM_PROLOGUE(separate)
254 #else
255 # define PARAM_PROLOGUE(separate) Z_PARAM_PROLOGUE(1, separate)
256 #endif
257 ZEND_RESULT_CODE psi_call_frame_parse_args(struct psi_call_frame *frame,
258 zend_execute_data *execute_data) {
259 size_t i, argc = psi_plist_count(frame->impl->func->args);
260 zend_error_handling zeh;
261
262 zend_replace_error_handling(EH_THROW, zend_exception_get_default(), &zeh);
263
264 if (!argc) {
265 ZEND_RESULT_CODE rv;
266
267 rv = zend_parse_parameters_none();
268 zend_restore_error_handling(&zeh);
269 return rv;
270 }
271
272 ZEND_PARSE_PARAMETERS_START(
273 psi_impl_num_min_args(frame->impl),
274 frame->impl->func->vararg ? -1 : argc
275 )
276 nextarg: {
277
278 struct psi_impl_arg *iarg;
279 impl_val ival = {0};
280
281 if (frame->impl->func->vararg && _i >= argc) {
282 iarg = frame->impl->func->vararg;
283 Z_PARAM_OPTIONAL;
284 } else {
285 psi_plist_get(frame->impl->func->args, _i, &iarg);
286 if (iarg->def) {
287 Z_PARAM_OPTIONAL;
288 }
289 }
290
291 if (PSI_T_BOOL == iarg->type->type) {
292 Z_PARAM_BOOL(ival.zend.bval);
293 } else if (PSI_T_INT == iarg->type->type) {
294 Z_PARAM_LONG(ival.zend.lval);
295 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
296 Z_PARAM_DOUBLE(ival.dval);
297 } else if (PSI_T_STRING == iarg->type->type) {
298 Z_PARAM_STR_EX(ival.zend.str, 1, iarg->var->reference);
299 if (ival.zend.str) {
300 zend_string_addref(ival.zend.str);
301 }
302 } else if (PSI_T_ARRAY == iarg->type->type) {
303 zval *tmp;
304 Z_PARAM_ARRAY_EX(tmp, _optional || iarg->var->reference,
305 iarg->var->reference);
306 } else if (PSI_T_OBJECT == iarg->type->type) {
307 PARAM_PROLOGUE(iarg->var->reference);
308 } else if (PSI_T_MIXED == iarg->type->type) {
309 PARAM_PROLOGUE(iarg->var->reference);
310 } else if (PSI_T_CALLABLE == iarg->type->type) {
311 zend_fcall_info fci;
312 zend_fcall_info_cache fcc;
313
314 Z_PARAM_FUNC_EX(fci, fcc, 1, 0);
315
316 if (fci.size) {
317 ival.zend.cb = ecalloc(1, sizeof(zend_fcall));
318 ival.zend.cb->fci = fci;
319 ival.zend.cb->fcc = fcc;
320 }
321 } else {
322 error_code = ZPP_ERROR_FAILURE;
323 break;
324 }
325
326 psi_call_frame_new_argument(frame,
327 psi_call_frame_argument_init(iarg, &ival, _arg, _i > argc));
328
329 if (_i < _num_args) {
330 goto nextarg;
331 }
332 }
333 ZEND_PARSE_PARAMETERS_END_EX(
334 zend_restore_error_handling(&zeh);
335 return FAILURE;
336 );
337
338 /* set up defaults */
339 for (i = EX_NUM_ARGS(); i < argc; ++i) {
340 struct psi_impl_arg *iarg;
341
342 psi_plist_get(frame->impl->func->args, i, &iarg);
343
344 assert(iarg->def);
345 psi_call_frame_new_argument(frame, psi_call_frame_argument_init(iarg,
346 &iarg->def->ival, NULL, 0));
347 }
348
349 zend_restore_error_handling(&zeh);
350 return SUCCESS;
351 }
352
353 void psi_call_frame_enter(struct psi_call_frame *frame) {
354 size_t argc = psi_call_frame_num_fixed_args(frame);
355 size_t va_count = psi_call_frame_num_var_args(frame);
356 size_t rsize = psi_decl_arg_get_size(frame->decl->func);
357 struct psi_call_frame_symbol *rv_sym;
358
359 /* initialize ffi argument array */
360 frame->pointers = ecalloc(argc + va_count + 1, sizeof(void *));
361
362 /* initialize return value symbol */
363 rv_sym = psi_call_frame_fetch_symbol(frame, frame->decl->func->var);
364 if (rsize > sizeof(impl_val)) {
365 rv_sym->ival_ptr = ecalloc(1, rsize);
366 } else {
367 rv_sym->ival_ptr = &rv_sym->temp_val;
368 }
369 frame->rpointer = rv_sym->ptr = rv_sym->ival_ptr;
370 }
371
372 ZEND_RESULT_CODE psi_call_frame_do_let(struct psi_call_frame *frame) {
373 size_t i;
374 struct psi_let_stmt *let;
375 struct psi_decl_arg *arg;
376 size_t argc = psi_call_frame_num_fixed_args(frame);
377 size_t va_count = psi_call_frame_num_var_args(frame);
378
379 for (i = 0; psi_plist_get(frame->impl->stmts.let, i, &let); ++i) {
380 psi_let_stmt_exec(let, frame);
381 }
382 for (i = 0; psi_plist_get(frame->decl->args, i, &arg); ++i) {
383 struct psi_let_stmt *let;
384 struct psi_call_frame_symbol *frame_sym;
385
386 let = psi_impl_get_let(frame->impl, arg->var);
387 frame_sym = psi_call_frame_fetch_symbol(frame, let->exp->var);
388 frame->pointers[i] = frame_sym->ptr;
389 }
390 /* varargs */
391 if (va_count) {
392 for (i = 0; i < va_count; ++i) {
393 struct psi_call_frame_argument *frame_arg;
394 psi_marshal_let let_fn;
395 void *temp = NULL;
396
397 frame_arg = psi_call_frame_get_var_argument(frame, i);
398 switch (frame_arg->va_type) {
399 case PSI_T_BOOL: let_fn = psi_let_boolval; break;
400 case PSI_T_INT: let_fn = psi_let_intval; break;
401 case PSI_T_FLOAT:
402 case PSI_T_DOUBLE: let_fn = psi_let_floatval; break;
403 case PSI_T_STRING: let_fn = psi_let_strval; break;
404 default:
405 assert(0);
406 }
407
408 frame_arg->ival_ptr = let_fn(&frame_arg->temp_val, NULL, frame_arg->va_type,
409 &frame_arg->ival, frame_arg->zval_ptr, &temp);
410 if (temp) {
411 psi_call_frame_push_auto(frame, temp);
412 }
413
414 frame->pointers[argc + i] = frame_arg->ival_ptr;
415 }
416 }
417
418 return SUCCESS;
419 }
420
421 ZEND_RESULT_CODE psi_call_frame_do_assert(struct psi_call_frame *frame, enum psi_assert_kind kind) {
422 size_t i = 0;
423 struct psi_assert_stmt *ass;
424
425 while (psi_plist_get(frame->impl->stmts.ass, i++, &ass)) {
426 if (ass->kind == kind) {
427 if (!psi_assert_stmt_exec(ass, frame)) {
428 char *message = psi_assert_stmt_message(ass);
429 zend_throw_exception(kind == PSI_ASSERT_PRE
430 ? spl_ce_InvalidArgumentException
431 : spl_ce_UnexpectedValueException, message, 0);
432 free(message);
433 return FAILURE;
434 }
435 }
436 }
437
438 return SUCCESS;
439 }
440
441 void psi_call_frame_do_call(struct psi_call_frame *frame) {
442 frame->context->ops->call(frame);
443 }
444
445 void psi_call_frame_do_callback(struct psi_call_frame *frame, struct psi_call_frame_callback *cbdata)
446 {
447 size_t i;
448 void *retptr;
449 ZEND_RESULT_CODE rc;
450 struct psi_let_callback *cb = cbdata->cb->data.callback;
451 zval return_value, *zargv = ecalloc(cbdata->argc, sizeof(*zargv));
452 struct psi_call_frame_argument *frame_arg;
453
454 assert(cbdata->argc == psi_plist_count(cb->decl->args));
455
456 /* prepare args for the userland call */
457 for (i = 0; i < cbdata->argc; ++i) {
458 struct psi_set_exp *set_exp;
459 struct psi_decl_var *set_var;
460 struct psi_call_frame_symbol *set_sym;
461
462 psi_plist_get(cb->args, i, &set_exp);
463 set_var = psi_set_exp_get_decl_var(set_exp);
464 set_sym = psi_call_frame_fetch_symbol(frame, set_var);
465
466 set_sym->ptr = cbdata->argv[i];
467 psi_set_exp_exec_ex(set_exp, &zargv[i], set_sym->ptr, frame);
468 }
469
470 frame_arg = psi_call_frame_get_argument(frame, cb->func->var->fqn);
471
472 /* callback into userland */
473 ZVAL_UNDEF(&return_value);
474 zend_fcall_info_argp(&frame_arg->ival_ptr->zend.cb->fci, cbdata->argc, zargv);
475 rc = zend_fcall_info_call(&frame_arg->ival_ptr->zend.cb->fci,
476 &frame_arg->ival_ptr->zend.cb->fcc, &return_value, NULL);
477 assert(rc == SUCCESS);
478
479 /* marshal return value of the userland call */
480 frame_arg->zval_ptr = &return_value;
481 retptr = psi_let_func_exec(cbdata->cb, cb->func, cb->decl->func, frame);
482 memcpy(cbdata->rval, retptr, psi_decl_arg_get_size(cb->decl->func));
483
484 /* cleanup */
485 zend_fcall_info_args_clear(&frame_arg->ival_ptr->zend.cb->fci, 0);
486 for (i = 0; i < cbdata->argc; ++i) {
487 zval_ptr_dtor(&zargv[i]);
488 }
489 efree(zargv);
490 }
491
492 void psi_call_frame_do_return(struct psi_call_frame *frame, zval *return_value) {
493 struct psi_return_stmt *ret;
494
495 psi_plist_get(frame->impl->stmts.ret, 0, &ret);
496 psi_return_stmt_exec(ret, return_value, frame);
497 }
498
499 void psi_call_frame_do_set(struct psi_call_frame *frame) {
500 size_t i = 0;
501 struct psi_set_stmt *set;
502
503 while (psi_plist_get(frame->impl->stmts.set, i++, &set)) {
504 psi_set_stmt_exec(set, frame);
505 }
506 }
507
508 void psi_call_frame_do_free(struct psi_call_frame *frame) {
509 size_t i = 0;
510 struct psi_free_stmt *fre;
511
512 while (psi_plist_get(frame->impl->stmts.fre, i++, &fre)) {
513 psi_free_stmt_exec(fre, frame);
514 }
515 }
516
517 void **psi_call_frame_push_auto_ex(struct psi_call_frame *frame, void *auto_free, void (*dtor)(void*)) {
518 struct psi_call_frame_auto_free f;
519
520 f.data = auto_free;
521 f.dtor = dtor;
522
523 zend_llist_add_element(&frame->temp, &f);
524 return &((struct psi_call_frame_auto_free *) zend_llist_get_last(&frame->temp))->data;
525 }
526
527 void **psi_call_frame_push_auto(struct psi_call_frame *frame, void *auto_free) {
528 return psi_call_frame_push_auto_ex(frame, auto_free, NULL);
529 }
530
531 static void psi_call_frame_local_auto_dtor(void *auto_list)
532 {
533 zend_llist_destroy(auto_list);
534 efree(auto_list);
535 }
536
537 #include "php_psi.h"
538
539 void psi_call_frame_free(struct psi_call_frame *frame) {
540 zend_hash_destroy(&frame->arguments);
541 zend_hash_destroy(&frame->symbols);
542 if (frame->impl && frame->impl->func->static_memory) {
543 zend_llist *temp = emalloc(sizeof(*temp));
544 zval zlocal;
545
546 memcpy(temp, &frame->temp, sizeof(*temp));
547 ZVAL_OBJ(&zlocal, psi_object_init_ex(NULL, temp, psi_call_frame_local_auto_dtor));
548 zend_set_local_var(frame->impl->func->name, &zlocal, /* force */ 1);
549 } else {
550 zend_llist_destroy(&frame->temp);
551 }
552 efree(frame->pointers);
553 efree(frame);
554 }
555
556
557