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;
276 case PSI_T_INT32
: tmp
->i32
= intval
; break;
277 case PSI_T_UINT32
: tmp
->u32
= intval
; break;
278 case PSI_T_INT64
: tmp
->i64
= intval
; break;
279 case PSI_T_UINT64
: tmp
->u64
= intval
; break;
281 case PSI_T_INT
: tmp
->ival
= intval
; break;
282 case PSI_T_LONG
: tmp
->lval
= intval
; break;
283 case PSI_T_FLOAT
: tmp
->fval
= intval
; break;
284 case PSI_T_DOUBLE
: tmp
->dval
= intval
; break;
285 #ifdef HAVE_LONG_DOUBLE
286 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= intval
; break;
288 EMPTY_SWITCH_DEFAULT_CASE();
295 * let dvar = intval($ivar)
297 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
)
300 token_t real_type
= spec
? psi_decl_type_get_real(spec
->type
)->type
: PSI_T_LONG
;
302 if (ival
&& impl_type
== PSI_T_INT
) {
303 intval
= ival
->zend
.lval
;
305 intval
= zval_get_long(zvalue
);
308 return psi_val_intval(tmp
, real_type
, intval
);
312 * set $ivar = to_float(dvar)
314 void psi_set_to_float(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
316 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
317 token_t t
= psi_decl_type_get_real(var
->arg
->type
)->type
;
318 impl_val
*v
= deref_impl_val(ret_val
, var
);
321 case PSI_T_FLOAT
: RETVAL_DOUBLE((double) v
->fval
); break;
322 case PSI_T_DOUBLE
: RETVAL_DOUBLE(v
->dval
); break;
323 #ifdef HAVE_LONG_DOUBLE
324 case PSI_T_LONG_DOUBLE
: RETVAL_DOUBLE((double) v
->ldval
); break;
326 case PSI_T_INT8
: RETVAL_DOUBLE((double) v
->i8
); break;
327 case PSI_T_UINT8
: RETVAL_DOUBLE((double) v
->u8
); break;
328 case PSI_T_INT16
: RETVAL_DOUBLE((double) v
->i16
); break;
329 case PSI_T_UINT16
: RETVAL_DOUBLE((double) v
->u16
); break;
330 case PSI_T_INT32
: RETVAL_DOUBLE((double) v
->i32
); break;
331 case PSI_T_UINT32
: RETVAL_DOUBLE((double) v
->u32
); break;
332 case PSI_T_INT64
: RETVAL_DOUBLE((double) v
->i64
); break;
333 case PSI_T_UINT64
: RETVAL_DOUBLE((double) v
->u64
); break;
334 EMPTY_SWITCH_DEFAULT_CASE();
338 static inline impl_val
*psi_val_floatval(impl_val
*tmp
, token_t real_type
, double floatval
) {
340 case PSI_T_INT8
: tmp
->i8
= floatval
; break;
341 case PSI_T_UINT8
: tmp
->u8
= floatval
; break;
342 case PSI_T_INT16
: tmp
->i16
= floatval
; break;
343 case PSI_T_UINT16
: tmp
->u16
= floatval
; break;
344 case PSI_T_INT32
: tmp
->i32
= floatval
; break;
345 case PSI_T_UINT32
: tmp
->u32
= floatval
; break;
346 case PSI_T_INT64
: tmp
->i64
= floatval
; break;
347 case PSI_T_UINT64
: tmp
->u64
= floatval
; break;
348 case PSI_T_FLOAT
: tmp
->fval
= floatval
; break;
349 case PSI_T_DOUBLE
: tmp
->dval
= floatval
; break;
350 #ifdef HAVE_LONG_DOUBLE
351 case PSI_T_LONG_DOUBLE
: tmp
->ldval
= floatval
; break;
353 EMPTY_SWITCH_DEFAULT_CASE();
360 * let dvar = floatval($ivar)
362 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
)
365 token_t real_type
= spec
? psi_decl_type_get_real(spec
->type
)->type
: PSI_T_DOUBLE
;
367 if (ival
&& (impl_type
== PSI_T_FLOAT
|| impl_type
== PSI_T_DOUBLE
)) {
368 floatval
= ival
->dval
;
370 floatval
= zval_get_double(zvalue
);
373 return psi_val_floatval(tmp
, real_type
, floatval
);
377 * set $ivar = to_string(dvar)
379 void psi_set_to_string(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
381 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
382 impl_val
*ptr
= deref_impl_val(ret_val
, var
);
385 if (var
->arg
->var
->array_size
) {
394 RETVAL_EMPTY_STRING();
399 * set $ivar = to_string(dvar, num_exp)
401 void psi_set_to_stringl(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*ret_val
, struct psi_call_frame
*frame
)
403 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
404 char *str
= deref_impl_val(ret_val
, var
)->ptr
;
407 struct psi_set_exp
*sub_exp
;
409 psi_plist_get(set
->inner
, 0, &sub_exp
);
410 RETVAL_STRINGL(str
, psi_long_num_exp(sub_exp
->data
.num
, frame
, NULL
));
412 RETVAL_EMPTY_STRING();
417 * let dvar = strval($ivar)
419 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
)
421 if (ival
&& impl_type
== PSI_T_STRING
) {
422 if (ival
->zend
.str
) {
423 tmp
->ptr
= ival
->zend
.str
->val
;
428 zend_string
*zs
= zval_get_string(zvalue
);
429 tmp
->ptr
= estrdup(zs
->val
);
431 zend_string_release(zs
);
438 * let dvar = pathval($ivar)
440 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
)
442 tmp
= psi_let_strval(tmp
, spec
, impl_type
, ival
, zvalue
, to_free
);
443 if (SUCCESS
!= php_check_open_basedir(tmp
->ptr
)) {
446 return *to_free
= NULL
;
452 * let dvar = strlen($ivar)
454 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
)
456 if (ival
&& impl_type
== PSI_T_STRING
) {
457 if (ival
->zend
.str
) {
458 tmp
->lval
= ival
->zend
.str
->len
;
463 zend_string
*zs
= zval_get_string(zvalue
);
465 zend_string_release(zs
);
472 static impl_val
*iterate(impl_val
*val
, size_t size
, unsigned i
, impl_val
*tmp
)
474 memset(tmp
, 0, sizeof(*tmp
));
475 memcpy(tmp
, ((char *) val
) + size
* i
, size
);
481 * set $ivar = to_array(dvar,
482 * $foo = to_int(d_foo),
483 * $bar = to_string(d_bar),
484 * $baz = to_array(*d_next, ...)
486 void psi_set_to_recursive(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
) {
487 set
->outer
->data
.func
->handler(return_value
, set
, r_val
, frame
);
491 * set $ivar = to_array(dvar, to_string(*dvar));
493 void psi_set_to_array_simple(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
495 struct psi_set_exp
*sub_exp
;
496 struct psi_decl_var
*var
;
501 array_init(return_value
);
503 var
= psi_set_exp_get_decl_var(set
);
504 ret_val
= deref_impl_val(r_val
, var
);
505 if ((intptr_t) ret_val
<= (intptr_t) 0) {
509 psi_plist_get(set
->inner
, 0, &sub_exp
);
511 size
= psi_decl_arg_get_size(var
->arg
);
512 for (ptr
= ret_val
->ptr
; *(void **) ptr
; ptr
+= size
) {
516 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) ptr
, frame
);
517 add_next_index_zval(return_value
, &ele
);
522 * set $ivar = to_array(dvar, num_exp, to_string(*dvar));
524 void psi_set_to_array_counted(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
526 struct psi_set_exp
*sub_exp
;
527 struct psi_decl_var
*var
;
533 array_init(return_value
);
535 var
= psi_set_exp_get_decl_var(set
);
536 ret_val
= deref_impl_val(r_val
, var
);
537 if ((intptr_t) ret_val
<= (intptr_t) 0) {
541 psi_plist_get(set
->inner
, 0, &sub_exp
);
542 count
= psi_long_num_exp(sub_exp
->data
.num
, frame
, NULL
);
543 psi_plist_get(set
->inner
, 1, &sub_exp
);
545 for (ptr
= (char *) ret_val
; 0 < count
--; ptr
+= size
) {
546 size
= psi_decl_var_get_size(psi_set_exp_get_decl_var(sub_exp
));
550 sub_exp
->data
.func
->handler(&ele
, sub_exp
, (void *) &ptr
, frame
);
551 add_next_index_zval(return_value
, &ele
);
558 * set $ivar = to_array(dvar,
559 * $foo = to_int(d_foo),
560 * $bar = to_string(d_bar));
562 void psi_set_to_array(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
564 struct psi_set_exp
*sub_exp
;
565 struct psi_decl_var
*var
;
569 array_init(return_value
);
571 var
= psi_set_exp_get_decl_var(set
);
572 ret_val
= deref_impl_val(r_val
, var
);
573 if ((intptr_t) ret_val
<= (intptr_t) 0) {
577 while (psi_plist_get(set
->inner
, i
++, &sub_exp
)) {
579 struct psi_decl_var
*dvar
= psi_set_exp_get_decl_var(sub_exp
);
580 struct psi_impl_var
*ivar
= psi_set_exp_get_impl_var(sub_exp
);
581 struct psi_call_frame_symbol
*sym
;
583 sym
= psi_call_frame_fetch_symbol(frame
, dvar
);
584 sym
->ptr
= ((char *) ret_val
) + dvar
->arg
->layout
->pos
;
587 psi_set_exp_exec_ex(sub_exp
, &ele
, sym
->ptr
, frame
);
588 add_assoc_zval(return_value
, ivar
->name
+ 1, &ele
);
593 * let dvar = count($ivar)
595 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
)
597 return psi_val_intval(tmp
, psi_decl_type_get_real(spec
->type
)->type
, psi_zval_count(zvalue
));
601 * set $ivar = to_object(dvar)
603 void psi_set_to_object(zval
*return_value
, struct psi_set_exp
*set
, impl_val
*r_val
, struct psi_call_frame
*frame
)
605 struct psi_decl_var
*var
= psi_set_exp_get_decl_var(set
);
606 impl_val
*ret_val
= deref_impl_val(r_val
, var
);
608 if ((intptr_t) ret_val
->ptr
> (intptr_t) 0) {
609 object_init_ex(return_value
, psi_object_get_class_entry());
610 PSI_OBJ(return_value
, NULL
)->data
= ret_val
->ptr
;
617 * let dvar = objval($ivar)
619 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
)
623 if (Z_TYPE_P(zvalue
) != IS_OBJECT
624 || !instanceof_function(Z_OBJCE_P(zvalue
), psi_object_get_class_entry())) {
628 obj
= PSI_OBJ(zvalue
, NULL
);
629 tmp
->ptr
= obj
->data
;