1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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.
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 *******************************************************************************/
26 #include "php_psi_stdinc.h"
33 #include "Zend/zend_interfaces.h"
34 #include "ext/spl/spl_iterators.h"
36 zend_long
psi_zval_count(zval
*zvalue
)
38 /* mimic PHP count() */
42 switch (Z_TYPE_P(zvalue
)) {
50 count
= zend_array_count(Z_ARRVAL_P(zvalue
));
54 if (Z_OBJ_HT_P(zvalue
)->count_elements
) {
55 if (SUCCESS
== Z_OBJ_HT_P(zvalue
)->count_elements(zvalue
, &count
)) {
60 if (instanceof_function(Z_OBJCE_P(zvalue
), spl_ce_Countable
)) {
61 zend_call_method_with_0_params(zvalue
, NULL
, NULL
, "count", &retval
);
62 if (Z_TYPE(retval
) != IS_UNDEF
) {
63 count
= zval_get_long(&retval
);
64 zval_ptr_dtor(&retval
);
73 int psi_internal_type(struct psi_impl_type
*type
)
92 zend_internal_arg_info
*psi_internal_arginfo(struct psi_impl
*impl
)
94 size_t i
= 0, argc
= psi_plist_count(impl
->func
->args
);
95 zend_internal_arg_info
*aip
;
96 zend_internal_function_info
*fi
;
97 struct psi_impl_arg
*iarg
;
99 aip
= calloc(argc
+ 1 + !!impl
->func
->vararg
, sizeof(*aip
));
101 fi
= (zend_internal_function_info
*) &aip
[0];
102 #ifdef ZEND_TYPE_ENCODE
103 fi
->type
= ZEND_TYPE_ENCODE(psi_internal_type(impl
->func
->return_type
), 1);
106 fi
->type_hint
= psi_internal_type(impl
->func
->return_type
);
108 fi
->required_num_args
= psi_impl_num_min_args(impl
);
109 fi
->return_reference
= impl
->func
->return_reference
;
111 if (impl
->func
->vararg
) {
112 struct psi_impl_arg
*vararg
= impl
->func
->vararg
;
113 zend_internal_arg_info
*ai
= &aip
[argc
];
115 ai
->name
= vararg
->var
->name
;
116 #ifdef ZEND_TYPE_ENCODE
117 ai
->type
= ZEND_TYPE_ENCODE(psi_internal_type(vararg
->type
), 1);
120 ai
->type_hint
= psi_internal_type(vararg
->type
);
122 if (vararg
->var
->reference
) {
123 ai
->pass_by_reference
= 1;
128 while (psi_plist_get(impl
->func
->args
, i
++, &iarg
)) {
129 zend_internal_arg_info
*ai
= &aip
[i
];
131 ai
->name
= iarg
->var
->name
;
132 #ifdef ZEND_TYPE_ENCODE
133 ai
->type
= ZEND_TYPE_ENCODE(psi_internal_type(iarg
->type
), 1);
136 ai
->type_hint
= psi_internal_type(iarg
->type
);
138 if (iarg
->var
->reference
) {
139 ai
->pass_by_reference
= 1;
149 void psi_set_void(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
157 impl_val
*psi_let_void(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
163 * set $ivar = zval(dvar)
165 void psi_set_zval(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
) {
166 RETVAL_ZVAL(ret_val
->ptr
, 1, 0);
170 * let dvar = zval($ivar)
172 impl_val
*psi_let_zval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
174 *to_free
= tmp
->ptr
= emalloc(sizeof(zval
));
175 ZVAL_COPY_VALUE(tmp
->ptr
, zvalue
);
180 * return to_bool(dvar)
182 void psi_set_to_bool(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
184 psi_set_to_int(return_value
, set
, ret_val
, frame
);
185 convert_to_boolean(return_value
);
188 static inline impl_val
*psi_val_boolval(impl_val
*tmp
, token_t real_type
, zend_bool boolval
) {
190 case PSI_T_INT8
: tmp
->i8
= boolval
; break;
191 case PSI_T_UINT8
: tmp
->u8
= boolval
; break;
192 case PSI_T_INT16
: tmp
->i16
= boolval
; break;
193 case PSI_T_UINT16
: tmp
->u16
= boolval
; break;
194 case PSI_T_INT32
: tmp
->i32
= boolval
; break;
195 case PSI_T_UINT32
: tmp
->u32
= boolval
; break;
196 case PSI_T_INT64
: tmp
->i64
= boolval
; break;
197 case PSI_T_UINT64
: tmp
->u64
= boolval
; break;
198 case PSI_T_FLOAT
: tmp
->fval
= boolval
; break;
199 case PSI_T_DOUBLE
: tmp
->dval
= boolval
; break;
200 #ifdef HAVE_LONG_DOUBLE
201 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= boolval
; break;
203 EMPTY_SWITCH_DEFAULT_CASE();
209 * let dvar = boolval($ivar)
211 impl_val
*psi_let_boolval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
214 token_t real_type
= spec
? psi_decl_type_get_real(spec
->type
)->type
: PSI_T_UINT8
;
216 if (ival
&& impl_type
== PSI_T_BOOL
) {
217 boolval
= ival
->zend
.bval
;
219 boolval
= zend_is_true(zvalue
);
222 return psi_val_boolval(tmp
, real_type
, boolval
);
225 # define RETVAL_LONG_U64(V) \
226 if (V > ZEND_LONG_MAX) { \
228 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], V)); \
234 * set $ivar = to_int(*dvar)
236 void psi_set_to_int(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
238 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
239 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
240 impl_val
*v
= deref_impl_val(ret_val
, var
);
243 case PSI_T_INT8
: RETVAL_LONG(v
->i8
); break;
244 case PSI_T_UINT8
: RETVAL_LONG(v
->u8
); break;
245 case PSI_T_INT16
: RETVAL_LONG(v
->i16
); break;
246 case PSI_T_UINT16
: RETVAL_LONG(v
->u16
); break;
247 case PSI_T_INT32
: RETVAL_LONG(v
->i32
); break;
248 case PSI_T_UINT32
: RETVAL_LONG(v
->u32
); break;
249 case PSI_T_INT64
: RETVAL_LONG(v
->i64
); break;
250 case PSI_T_UINT64
: RETVAL_LONG_U64(v
->u64
); break;
252 RETVAL_DOUBLE((double) v
->fval
);
253 convert_to_long(return_value
);
256 RETVAL_DOUBLE(v
->dval
);
257 convert_to_long(return_value
);
259 #ifdef HAVE_LONG_DOUBLE
260 case PSI_T_LONG_DOUBLE
:
261 RETVAL_DOUBLE((double) v
->ldval
);
262 convert_to_long(return_value
);
265 EMPTY_SWITCH_DEFAULT_CASE();
269 static inline impl_val
*psi_val_intval(impl_val
*tmp
, token_t real_type
, zend_long intval
) {
271 case PSI_T_INT8
: tmp
->i8
= intval
; break;
272 case PSI_T_UINT8
: tmp
->u8
= intval
; break;
273 case PSI_T_INT16
: tmp
->i16
= intval
; break;
274 case PSI_T_UINT16
: tmp
->u16
= intval
; break;
275 case PSI_T_INT32
: tmp
->i32
= intval
; break;
276 case PSI_T_UINT32
: tmp
->u32
= intval
; break;
277 case PSI_T_INT64
: tmp
->i64
= intval
; break;
278 case PSI_T_UINT64
: tmp
->u64
= intval
; break;
279 case PSI_T_INT
: tmp
->ival
= intval
; break;
280 case PSI_T_LONG
: tmp
->lval
= intval
; break;
281 case PSI_T_FLOAT
: tmp
->fval
= intval
; break;
282 case PSI_T_DOUBLE
: tmp
->dval
= intval
; break;
283 #ifdef HAVE_LONG_DOUBLE
284 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= intval
; break;
286 EMPTY_SWITCH_DEFAULT_CASE();
293 * let dvar = intval($ivar)
295 impl_val
*psi_let_intval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
298 token_t real_type
= spec
? psi_decl_type_get_real(spec
->type
)->type
: PSI_T_LONG
;
300 if (ival
&& impl_type
== PSI_T_INT
) {
301 intval
= ival
->zend
.lval
;
303 intval
= zval_get_long(zvalue
);
306 return psi_val_intval(tmp
, real_type
, intval
);
310 * set $ivar = to_float(dvar)
312 void psi_set_to_float(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
314 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
315 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
316 impl_val
*v
= deref_impl_val(ret_val
, var
);
319 case PSI_T_FLOAT
: RETVAL_DOUBLE((double) v
->fval
); break;
320 case PSI_T_DOUBLE
: RETVAL_DOUBLE(v
->dval
); break;
321 #ifdef HAVE_LONG_DOUBLE
322 case PSI_T_LONG_DOUBLE
: RETVAL_DOUBLE((double) v
->ldval
); break;
324 case PSI_T_INT8
: RETVAL_DOUBLE((double) v
->i8
); break;
325 case PSI_T_UINT8
: RETVAL_DOUBLE((double) v
->u8
); break;
326 case PSI_T_INT16
: RETVAL_DOUBLE((double) v
->i16
); break;
327 case PSI_T_UINT16
: RETVAL_DOUBLE((double) v
->u16
); break;
328 case PSI_T_INT32
: RETVAL_DOUBLE((double) v
->i32
); break;
329 case PSI_T_UINT32
: RETVAL_DOUBLE((double) v
->u32
); break;
330 case PSI_T_INT64
: RETVAL_DOUBLE((double) v
->i64
); break;
331 case PSI_T_UINT64
: RETVAL_DOUBLE((double) v
->u64
); break;
332 EMPTY_SWITCH_DEFAULT_CASE();
336 static inline impl_val
*psi_val_floatval(impl_val
*tmp
, token_t real_type
, double floatval
) {
338 case PSI_T_INT8
: tmp
->i8
= floatval
; break;
339 case PSI_T_UINT8
: tmp
->u8
= floatval
; break;
340 case PSI_T_INT16
: tmp
->i16
= floatval
; break;
341 case PSI_T_UINT16
: tmp
->u16
= floatval
; break;
342 case PSI_T_INT32
: tmp
->i32
= floatval
; break;
343 case PSI_T_UINT32
: tmp
->u32
= floatval
; break;
344 case PSI_T_INT64
: tmp
->i64
= floatval
; break;
345 case PSI_T_UINT64
: tmp
->u64
= floatval
; break;
346 case PSI_T_FLOAT
: tmp
->fval
= floatval
; break;
347 case PSI_T_DOUBLE
: tmp
->dval
= floatval
; break;
348 #ifdef HAVE_LONG_DOUBLE
349 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= floatval
; break;
351 EMPTY_SWITCH_DEFAULT_CASE();
358 * let dvar = floatval($ivar)
360 impl_val
*psi_let_floatval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
363 token_t real_type
= spec
? psi_decl_type_get_real(spec
->type
)->type
: PSI_T_DOUBLE
;
365 if (ival
&& (impl_type
== PSI_T_FLOAT
|| impl_type
== PSI_T_DOUBLE
)) {
366 floatval
= ival
->dval
;
368 floatval
= zval_get_double(zvalue
);
371 return psi_val_floatval(tmp
, real_type
, floatval
);
375 * set $ivar = to_string(dvar)
377 void psi_set_to_string(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
379 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
380 impl_val
*ptr
= deref_impl_val(ret_val
, var
);
383 if (var
->arg
->var
->array_size
) {
392 RETVAL_EMPTY_STRING();
397 * set $ivar = to_string(dvar, num_exp)
399 void psi_set_to_stringl(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
401 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
402 char *str
= deref_impl_val(ret_val
, var
)->ptr
;
405 struct psi_set_exp
*sub_exp
;
407 psi_plist_get(set
->inner
, 0, &sub_exp
);
408 RETVAL_STRINGL(str
, psi_long_num_exp(sub_exp
->data
.num
, frame
, NULL
));
410 RETVAL_EMPTY_STRING();
415 * let dvar = strval($ivar)
417 impl_val
*psi_let_strval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
419 if (ival
&& impl_type
== PSI_T_STRING
) {
420 if (ival
->zend
.str
) {
421 tmp
->ptr
= ival
->zend
.str
->val
;
426 zend_string
*zs
= zval_get_string(zvalue
);
427 tmp
->ptr
= estrdup(zs
->val
);
429 zend_string_release(zs
);
436 * let dvar = pathval($ivar)
438 impl_val
*psi_let_pathval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
440 tmp
= psi_let_strval(tmp
, spec
, impl_type
, ival
, zvalue
, to_free
);
441 if (SUCCESS
!= php_check_open_basedir(tmp
->ptr
)) {
444 return *to_free
= NULL
;
450 * let dvar = strlen($ivar)
452 impl_val
*psi_let_strlen(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
454 if (ival
&& impl_type
== PSI_T_STRING
) {
455 if (ival
->zend
.str
) {
456 tmp
->lval
= ival
->zend
.str
->len
;
461 zend_string
*zs
= zval_get_string(zvalue
);
463 zend_string_release(zs
);
470 static impl_val
*iterate(impl_val
*val
, size_t size
, unsigned i
, impl_val
*tmp
)
472 memset(tmp
, 0, sizeof(*tmp
));
473 memcpy(tmp
, ((char *) val
) + size
* i
, size
);
479 * set $ivar = to_array(dvar,
480 * $foo = to_int(d_foo),
481 * $bar = to_string(d_bar),
482 * $baz = to_array(*d_next, ...)
484 void psi_set_to_recursive(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
) {
485 set
->outer
->data
.func
->handler(return_value
, set
, r_val
, frame
);
489 * set $ivar = to_array(dvar, to_string(*dvar));
491 void psi_set_to_array_simple(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
493 struct psi_set_exp
*sub_exp
;
494 struct psi_decl_var
*var
;
499 array_init(return_value
);
501 var
= psi_set_exp_get_decl_var(set
);
502 ret_val
= deref_impl_val(r_val
, var
);
503 if ((intptr_t) ret_val
<= (intptr_t) 0) {
507 psi_plist_get(set
->inner
, 0, &sub_exp
);
509 size
= psi_decl_arg_get_size(var
->arg
);
510 for (ptr
= ret_val
->ptr
; *(void **) ptr
; ptr
+= size
) {
514 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) ptr
, frame
);
515 add_next_index_zval(return_value
, &ele
);
520 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
522 void psi_set_to_array_counted(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
524 struct psi_set_exp
*sub_exp
;
525 struct psi_decl_var
*var
;
531 array_init(return_value
);
533 var
= psi_set_exp_get_decl_var(set
);
534 ret_val
= deref_impl_val(r_val
, var
);
535 if ((intptr_t) ret_val
<= (intptr_t) 0) {
539 psi_plist_get(set
->inner
, 0, &sub_exp
);
540 count
= psi_long_num_exp(sub_exp
->data
.num
, frame
, NULL
);
541 psi_plist_get(set
->inner
, 1, &sub_exp
);
543 for (ptr
= (char *) ret_val
; 0 < count
--; ptr
+= size
) {
544 size
= psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp
));
548 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) &ptr
, frame
);
549 add_next_index_zval(return_value
, &ele
);
556 * set $ivar = to_array(dvar,
557 * $foo = to_int(d_foo),
558 * $bar = to_string(d_bar));
560 void psi_set_to_array(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
562 struct psi_set_exp
*sub_exp
;
563 struct psi_decl_var
*var
;
567 array_init(return_value
);
569 var
= psi_set_exp_get_decl_var(set
);
570 ret_val
= deref_impl_val(r_val
, var
);
571 if ((intptr_t) ret_val
<= (intptr_t) 0) {
575 while (psi_plist_get(set
->inner
, i
++, &sub_exp
)) {
577 struct psi_decl_var
*dvar
= psi_set_exp_get_decl_var(sub_exp
);
578 struct psi_impl_var
*ivar
= psi_set_exp_get_impl_var(sub_exp
);
579 struct psi_call_frame_symbol
*sym
;
581 sym
= psi_call_frame_fetch_symbol(frame
, dvar
);
582 sym
->ptr
= ((char *) ret_val
) + dvar
->arg
->layout
->pos
;
585 psi_set_exp_exec_ex(sub_exp
, &ele
, sym
->ptr
, frame
);
586 add_assoc_zval(return_value
, ivar
->name
+ 1, &ele
);
591 * let dvar = count($ivar)
593 impl_val
*psi_let_count(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
595 return psi_val_intval(tmp
, psi_decl_type_get_real(spec
->type
)->type
, psi_zval_count(zvalue
));
599 * set $ivar = to_object(dvar)
601 void psi_set_to_object(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
603 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
604 impl_val
*ret_val
= deref_impl_val(r_val
, var
);
606 if ((intptr_t) ret_val
->ptr
> (intptr_t) 0) {
607 object_init_ex(return_value
, psi_object_get_class_entry());
608 PSI_OBJ(return_value
, NULL
)->data
= ret_val
->ptr
;
615 * let dvar = objval($ivar)
617 impl_val
*psi_let_objval(impl_val
*tmp
, struct psi_decl_arg
*spec
, token_t impl_type
, impl_val
*ival
, zval
*zvalue
, void **to_free
)
621 if (Z_TYPE_P(zvalue
) != IS_OBJECT
622 || !instanceof_function(Z_OBJCE_P(zvalue
), psi_object_get_class_entry())) {
626 obj
= PSI_OBJ(zvalue
, NULL
);
627 tmp
->ptr
= obj
->data
;