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;
248 case PSI_T_INT32
: RETVAL_LONG(v
->i32
); break;
249 case PSI_T_UINT32
: RETVAL_LONG(v
->u32
); break;
250 case PSI_T_INT64
: RETVAL_LONG(v
->i64
); break;
251 case PSI_T_UINT64
: RETVAL_LONG_U64(v
->u64
); break;
253 RETVAL_DOUBLE((double) v
->fval
);
254 convert_to_long(return_value
);
257 RETVAL_DOUBLE(v
->dval
);
258 convert_to_long(return_value
);
260 #ifdef HAVE_LONG_DOUBLE
261 case PSI_T_LONG_DOUBLE
:
262 RETVAL_DOUBLE((double) v
->ldval
);
263 convert_to_long(return_value
);
266 EMPTY_SWITCH_DEFAULT_CASE();
270 static inline impl_val
*psi_val_intval(impl_val
*tmp
, token_t real_type
, zend_long intval
) {
272 case PSI_T_INT8
: tmp
->i8
= intval
; break;
273 case PSI_T_UINT8
: tmp
->u8
= intval
; break;
274 case PSI_T_INT16
: tmp
->i16
= intval
; break;
275 case PSI_T_UINT16
: tmp
->u16
= intval
; break;
277 case PSI_T_INT32
: tmp
->i32
= intval
; break;
278 case PSI_T_UINT32
: tmp
->u32
= intval
; break;
279 case PSI_T_INT64
: tmp
->i64
= intval
; break;
280 case PSI_T_UINT64
: tmp
->u64
= 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
->u64
= ival
->zend
.str
->len
;
461 zend_string
*zs
= zval_get_string(zvalue
);
463 zend_string_release(zs
);
467 psi_calc_cast(PSI_T_UINT64
, tmp
, psi_decl_type_get_real(spec
->type
)->type
, tmp
);
473 static impl_val
*iterate(impl_val
*val
, size_t size
, unsigned i
, impl_val
*tmp
)
475 memset(tmp
, 0, sizeof(*tmp
));
476 memcpy(tmp
, ((char *) val
) + size
* i
, size
);
482 * set $ivar = to_array(dvar,
483 * $foo = to_int(d_foo),
484 * $bar = to_string(d_bar),
485 * $baz = to_array(*d_next, ...)
487 void psi_set_to_recursive(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
) {
488 set
->outer
->data
.func
->handler(return_value
, set
, r_val
, frame
);
492 * set $ivar = to_array(dvar, to_string(*dvar));
494 void psi_set_to_array_simple(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
496 struct psi_set_exp
*sub_exp
;
497 struct psi_decl_var
*var
;
502 array_init(return_value
);
504 var
= psi_set_exp_get_decl_var(set
);
505 ret_val
= deref_impl_val(r_val
, var
);
506 if ((intptr_t) ret_val
<= (intptr_t) 0) {
510 psi_plist_get(set
->inner
, 0, &sub_exp
);
512 size
= psi_decl_arg_get_size(var
->arg
);
513 for (ptr
= ret_val
->ptr
; *(void **) ptr
; ptr
+= size
) {
517 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) ptr
, frame
);
518 add_next_index_zval(return_value
, &ele
);
523 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
525 void psi_set_to_array_counted(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
527 struct psi_set_exp
*sub_exp
;
528 struct psi_decl_var
*var
;
534 array_init(return_value
);
536 var
= psi_set_exp_get_decl_var(set
);
537 ret_val
= deref_impl_val(r_val
, var
);
538 if ((intptr_t) ret_val
<= (intptr_t) 0) {
542 psi_plist_get(set
->inner
, 0, &sub_exp
);
543 count
= psi_long_num_exp(sub_exp
->data
.num
, frame
, NULL
);
544 psi_plist_get(set
->inner
, 1, &sub_exp
);
546 for (ptr
= (char *) ret_val
; 0 < count
--; ptr
+= size
) {
547 size
= psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp
));
551 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) &ptr
, frame
);
552 add_next_index_zval(return_value
, &ele
);
559 * set $ivar = to_array(dvar,
560 * $foo = to_int(d_foo),
561 * $bar = to_string(d_bar));
563 void psi_set_to_array(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
565 struct psi_set_exp
*sub_exp
;
566 struct psi_decl_var
*var
;
570 array_init(return_value
);
572 var
= psi_set_exp_get_decl_var(set
);
573 ret_val
= deref_impl_val(r_val
, var
);
574 if ((intptr_t) ret_val
<= (intptr_t) 0) {
578 while (psi_plist_get(set
->inner
, i
++, &sub_exp
)) {
580 struct psi_decl_var
*dvar
= psi_set_exp_get_decl_var(sub_exp
);
581 struct psi_impl_var
*ivar
= psi_set_exp_get_impl_var(sub_exp
);
582 struct psi_call_frame_symbol
*sym
;
584 sym
= psi_call_frame_fetch_symbol(frame
, dvar
);
585 sym
->ptr
= ((char *) ret_val
) + dvar
->arg
->layout
->pos
;
588 psi_set_exp_exec_ex(sub_exp
, &ele
, sym
->ptr
, frame
);
589 add_assoc_zval(return_value
, ivar
->name
+ 1, &ele
);
594 * let dvar = count($ivar)
596 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
)
598 return psi_val_intval(tmp
, psi_decl_type_get_real(spec
->type
)->type
, psi_zval_count(zvalue
));
602 * set $ivar = to_object(dvar)
604 void psi_set_to_object(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
606 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
607 impl_val
*ret_val
= deref_impl_val(r_val
, var
);
609 if ((intptr_t) ret_val
->ptr
> (intptr_t) 0) {
610 object_init_ex(return_value
, psi_object_get_class_entry());
611 PSI_OBJ(return_value
, NULL
)->data
= ret_val
->ptr
;
618 * let dvar = objval($ivar)
620 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
)
624 if (Z_TYPE_P(zvalue
) != IS_OBJECT
625 || !instanceof_function(Z_OBJCE_P(zvalue
), psi_object_get_class_entry())) {
629 obj
= PSI_OBJ(zvalue
, NULL
);
630 tmp
->ptr
= obj
->data
;