php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
ffi.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Dmitry Stogov <dmitry@zend.com> |
14 +----------------------------------------------------------------------+
15*/
16
17#ifdef HAVE_CONFIG_H
18# include "config.h"
19#endif
20
21#include "php.h"
22#include "php_ffi.h"
23#include "ext/standard/info.h"
24#include "php_scandir.h"
25#include "zend_exceptions.h"
26#include "zend_closures.h"
27#include "zend_weakrefs.h"
28#include "main/SAPI.h"
29#include "zend_observer.h"
30
31#include <ffi.h>
32
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <fcntl.h>
36
37#ifdef HAVE_LIBDL
38#ifdef PHP_WIN32
39#include "win32/param.h"
40#include "win32/winutil.h"
41#define GET_DL_ERROR() php_win_err()
42#else
43#include <sys/param.h>
44#define GET_DL_ERROR() DL_ERROR()
45#endif
46#endif
47
48#ifdef HAVE_GLOB
49#ifdef PHP_WIN32
50#include "win32/glob.h"
51#else
52#include <glob.h>
53#endif
54#endif
55
56#ifndef __BIGGEST_ALIGNMENT__
57/* XXX need something better, perhaps with regard to SIMD, etc. */
58# define __BIGGEST_ALIGNMENT__ sizeof(size_t)
59#endif
60
62
68
69static const char *zend_ffi_tag_kind_name[3] = {"enum", "struct", "union"};
70
71
76
100
101#include "ffi_arginfo.h"
102
108
111 size_t size;
112 uint32_t align;
113 uint32_t attr;
114 union {
115 struct {
119 struct {
123 struct {
126 struct {
130 struct {
133 ffi_abi abi;
135 };
136};
137
138typedef struct _zend_ffi_field {
139 size_t offset;
141 bool is_nested; /* part of nested anonymous struct */
142 uint8_t first_bit;
143 uint8_t bits;
146
153
163
168
176
177#define ZEND_FFI_TYPE_OWNED (1<<0)
178
179#define ZEND_FFI_TYPE(t) \
180 ((zend_ffi_type*)(((uintptr_t)(t)) & ~ZEND_FFI_TYPE_OWNED))
181
182#define ZEND_FFI_TYPE_IS_OWNED(t) \
183 (((uintptr_t)(t)) & ZEND_FFI_TYPE_OWNED)
184
185#define ZEND_FFI_TYPE_MAKE_OWNED(t) \
186 ((zend_ffi_type*)(((uintptr_t)(t)) | ZEND_FFI_TYPE_OWNED))
187
188#define ZEND_FFI_SIZEOF_ARG \
189 MAX(FFI_SIZEOF_ARG, sizeof(double))
190
198
203
204static zend_class_entry *zend_ffi_exception_ce;
205static zend_class_entry *zend_ffi_parser_exception_ce;
206static zend_class_entry *zend_ffi_ce;
207static zend_class_entry *zend_ffi_cdata_ce;
208static zend_class_entry *zend_ffi_ctype_ce;
209
210static zend_object_handlers zend_ffi_handlers;
211static zend_object_handlers zend_ffi_cdata_handlers;
212static zend_object_handlers zend_ffi_cdata_value_handlers;
213static zend_object_handlers zend_ffi_cdata_free_handlers;
214static zend_object_handlers zend_ffi_ctype_handlers;
215
216static zend_internal_function zend_ffi_new_fn;
217static zend_internal_function zend_ffi_cast_fn;
218static zend_internal_function zend_ffi_type_fn;
219
220/* forward declarations */
221static void _zend_ffi_type_dtor(zend_ffi_type *type);
222static void zend_ffi_finalize_type(zend_ffi_dcl *dcl);
223static bool zend_ffi_is_same_type(zend_ffi_type *type1, zend_ffi_type *type2);
224static zend_ffi_type *zend_ffi_remember_type(zend_ffi_type *type);
225static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, bool preload);
226static ZEND_FUNCTION(ffi_trampoline);
227static ZEND_COLD void zend_ffi_return_unsupported(zend_ffi_type *type);
228static ZEND_COLD void zend_ffi_pass_unsupported(zend_ffi_type *type);
229static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *type);
230static bool zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type);
231
232#if FFI_CLOSURES
233static void *zend_ffi_create_callback(zend_ffi_type *type, zval *value);
234#endif
235
236static zend_always_inline void zend_ffi_type_dtor(zend_ffi_type *type) /* {{{ */
237{
239 _zend_ffi_type_dtor(type);
240 return;
241 }
242}
243/* }}} */
244
245static zend_always_inline void zend_ffi_object_init(zend_object *object, zend_class_entry *ce) /* {{{ */
246{
247 GC_SET_REFCOUNT(object, 1);
249 object->extra_flags = 0;
250 object->ce = ce;
251 object->handlers = ce->default_object_handlers;
252 object->properties = NULL;
254}
255/* }}} */
256
257static zend_object *zend_ffi_cdata_new(zend_class_entry *class_type) /* {{{ */
258{
260
261 cdata = emalloc(sizeof(zend_ffi_cdata));
262
263 zend_ffi_object_init(&cdata->std, class_type);
264
265 cdata->type = NULL;
266 cdata->ptr = NULL;
267 cdata->flags = 0;
268
269 return &cdata->std;
270}
271/* }}} */
272
273static bool zend_ffi_func_ptr_are_compatible(zend_ffi_type *dst_type, zend_ffi_type *src_type) /* {{{ */
274{
275 uint32_t dst_argc, src_argc, i;
276 zend_ffi_type *dst_arg, *src_arg;
277
278 ZEND_ASSERT(dst_type->kind == ZEND_FFI_TYPE_FUNC);
279 ZEND_ASSERT(src_type->kind == ZEND_FFI_TYPE_FUNC);
280
281 /* Ensure calling convention matches */
282 if (dst_type->func.abi != src_type->func.abi) {
283 return 0;
284 }
285
286 /* Ensure variadic attr matches */
287 if ((dst_type->attr & ZEND_FFI_ATTR_VARIADIC) != (src_type->attr & ZEND_FFI_ATTR_VARIADIC)) {
288 return 0;
289 }
290
291 /* Ensure same arg count */
292 dst_argc = dst_type->func.args ? zend_hash_num_elements(dst_type->func.args) : 0;
293 src_argc = src_type->func.args ? zend_hash_num_elements(src_type->func.args) : 0;
294 if (dst_argc != src_argc) {
295 return 0;
296 }
297
298 /* Ensure compatible ret_type */
299 if (!zend_ffi_is_compatible_type(dst_type->func.ret_type, src_type->func.ret_type)) {
300 return 0;
301 }
302
303 /* Ensure compatible args */
304 for (i = 0; i < dst_argc; i++) {
305 dst_arg = zend_hash_index_find_ptr(dst_type->func.args, i);
306 src_arg = zend_hash_index_find_ptr(src_type->func.args, i);
307 if (!zend_ffi_is_compatible_type(ZEND_FFI_TYPE(dst_arg), ZEND_FFI_TYPE(src_arg))) {
308 return 0;
309 }
310 }
311
312 return 1;
313}
314/* }}} */
315
316static bool zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type) /* {{{ */
317{
318 while (1) {
319 if (dst_type == src_type) {
320 return 1;
321 } else if (dst_type->kind == src_type->kind) {
322 if (dst_type->kind < ZEND_FFI_TYPE_POINTER) {
323 return 1;
324 } else if (dst_type->kind == ZEND_FFI_TYPE_POINTER) {
325 dst_type = ZEND_FFI_TYPE(dst_type->pointer.type);
326 src_type = ZEND_FFI_TYPE(src_type->pointer.type);
327 if (dst_type->kind == ZEND_FFI_TYPE_VOID ||
328 src_type->kind == ZEND_FFI_TYPE_VOID) {
329 return 1;
330 } else if (dst_type->kind == ZEND_FFI_TYPE_FUNC &&
331 src_type->kind == ZEND_FFI_TYPE_FUNC) {
332 return zend_ffi_func_ptr_are_compatible(dst_type, src_type);
333 }
334 } else if (dst_type->kind == ZEND_FFI_TYPE_ARRAY &&
335 (dst_type->array.length == src_type->array.length ||
336 dst_type->array.length == 0)) {
337 dst_type = ZEND_FFI_TYPE(dst_type->array.type);
338 src_type = ZEND_FFI_TYPE(src_type->array.type);
339 } else {
340 break;
341 }
342 } else if (dst_type->kind == ZEND_FFI_TYPE_POINTER &&
343 src_type->kind == ZEND_FFI_TYPE_ARRAY) {
344 dst_type = ZEND_FFI_TYPE(dst_type->pointer.type);
345 src_type = ZEND_FFI_TYPE(src_type->array.type);
346 if (dst_type->kind == ZEND_FFI_TYPE_VOID) {
347 return 1;
348 }
349 } else {
350 break;
351 }
352 }
353 return 0;
354}
355/* }}} */
356
357static ffi_type* zend_ffi_face_struct_add_fields(ffi_type* t, zend_ffi_type *type, int *i, size_t size)
358{
359 zend_ffi_field *field;
360
361 ZEND_HASH_MAP_FOREACH_PTR(&type->record.fields, field) {
362 switch (ZEND_FFI_TYPE(field->type)->kind) {
364 t->elements[(*i)++] = &ffi_type_float;
365 break;
367 t->elements[(*i)++] = &ffi_type_double;
368 break;
369#ifdef HAVE_LONG_DOUBLE
370 case ZEND_FFI_TYPE_LONGDOUBLE:
371 t->elements[(*i)++] = &ffi_type_longdouble;
372 break;
373#endif
378 t->elements[(*i)++] = &ffi_type_uint8;
379 break;
382 t->elements[(*i)++] = &ffi_type_uint16;
383 break;
386 t->elements[(*i)++] = &ffi_type_uint32;
387 break;
390 t->elements[(*i)++] = &ffi_type_uint64;
391 break;
393 t->elements[(*i)++] = &ffi_type_pointer;
394 break;
396 zend_ffi_type *field_type = ZEND_FFI_TYPE(field->type);
397 /* for unions we use only the first field */
398 uint32_t num_fields = !(field_type->attr & ZEND_FFI_ATTR_UNION) ?
399 zend_hash_num_elements(&field_type->record.fields) : 1;
400
401 if (num_fields > 1) {
402 size += sizeof(ffi_type*) * (num_fields - 1);
403 t = erealloc(t, size);
404 t->elements = (ffi_type**)(t + 1);
405 }
406 t = zend_ffi_face_struct_add_fields(t, field_type, i, size);
407 break;
408 }
409 default:
410 t->elements[(*i)++] = &ffi_type_void;
411 break;
412 }
413 if (type->attr & ZEND_FFI_ATTR_UNION) {
414 /* for unions we use only the first field */
415 break;
416 }
418 return t;
419}
420
421static ffi_type *zend_ffi_make_fake_struct_type(zend_ffi_type *type) /* {{{ */
422{
423 /* for unions we use only the first field */
424 uint32_t num_fields = !(type->attr & ZEND_FFI_ATTR_UNION) ?
425 zend_hash_num_elements(&type->record.fields) : 1;
426 size_t size = sizeof(ffi_type) + sizeof(ffi_type*) * (num_fields + 1);
427 ffi_type *t = emalloc(size);
428 int i;
429
430 t->size = type->size;
431 t->alignment = type->align;
432 t->type = FFI_TYPE_STRUCT;
433 t->elements = (ffi_type**)(t + 1);
434 i = 0;
435 t = zend_ffi_face_struct_add_fields(t, type, &i, size);
436 t->elements[i] = NULL;
437 return t;
438}
439/* }}} */
440
441static ffi_type *zend_ffi_get_type(zend_ffi_type *type) /* {{{ */
442{
444
445again:
446 switch (kind) {
448 return &ffi_type_float;
450 return &ffi_type_double;
451#ifdef HAVE_LONG_DOUBLE
452 case ZEND_FFI_TYPE_LONGDOUBLE:
453 return &ffi_type_longdouble;
454#endif
456 return &ffi_type_uint8;
458 return &ffi_type_sint8;
460 return &ffi_type_uint16;
462 return &ffi_type_sint16;
464 return &ffi_type_uint32;
466 return &ffi_type_sint32;
468 return &ffi_type_uint64;
470 return &ffi_type_sint64;
472 return &ffi_type_pointer;
474 return &ffi_type_void;
476 return &ffi_type_uint8;
478 return &ffi_type_sint8;
480 kind = type->enumeration.kind;
481 goto again;
483 return zend_ffi_make_fake_struct_type(type);
484 default:
485 break;
486 }
487 return NULL;
488}
489/* }}} */
490
491static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow(void *ptr, zend_ffi_type *type, zend_ffi_flags flags) /* {{{ */
492{
494
495 zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
496 cdata->std.handlers =
497 (type->kind < ZEND_FFI_TYPE_POINTER) ?
498 &zend_ffi_cdata_value_handlers :
499 &zend_ffi_cdata_handlers;
500 cdata->type = type;
501 cdata->flags = flags;
502 cdata->ptr = ptr;
503 return cdata;
504}
505/* }}} */
506
507static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow_ptr(void *ptr, zend_ffi_type *type, zend_ffi_flags flags) /* {{{ */
508{
510
511 zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
512 cdata->type = type;
513 cdata->flags = flags;
514 cdata->ptr = (void*)&cdata->ptr_holder;
515 *(void**)cdata->ptr = *(void**)ptr;
516 return cdata;
517}
518/* }}} */
519
520static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow_ret(void *ptr, zend_ffi_type *type, zend_ffi_flags flags) /* {{{ */
521{
523
524 zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
525 cdata->std.handlers =
526 (type->kind < ZEND_FFI_TYPE_POINTER) ?
527 &zend_ffi_cdata_value_handlers :
528 &zend_ffi_cdata_handlers;
529 cdata->type = type;
530 cdata->flags = flags;
531 if (type->kind == ZEND_FFI_TYPE_POINTER) {
532 cdata->ptr = (void*)&cdata->ptr_holder;
533 *(void**)cdata->ptr = *(void**)ptr;
534 } else if (type->kind == ZEND_FFI_TYPE_STRUCT) {
535 cdata->ptr = emalloc(type->size);
536 cdata->flags |= ZEND_FFI_FLAG_OWNED;
537 memcpy(cdata->ptr, ptr, type->size);
538 } else {
539 cdata->ptr = ptr;
540 }
541 return cdata;
542}
543/* }}} */
544
545static zend_always_inline void zend_ffi_cdata_to_zval(zend_ffi_cdata *cdata, void *ptr, zend_ffi_type *type, int read_type, zval *rv, zend_ffi_flags flags, bool is_ret, bool debug_union) /* {{{ */
546{
547 if (read_type == BP_VAR_R) {
549
550again:
551 switch (kind) {
553 ZVAL_DOUBLE(rv, *(float*)ptr);
554 return;
556 ZVAL_DOUBLE(rv, *(double*)ptr);
557 return;
558#ifdef HAVE_LONG_DOUBLE
559 case ZEND_FFI_TYPE_LONGDOUBLE:
560 ZVAL_DOUBLE(rv, *(long double*)ptr);
561 return;
562#endif
564 ZVAL_LONG(rv, *(uint8_t*)ptr);
565 return;
567 ZVAL_LONG(rv, *(int8_t*)ptr);
568 return;
570 ZVAL_LONG(rv, *(uint16_t*)ptr);
571 return;
573 ZVAL_LONG(rv, *(int16_t*)ptr);
574 return;
576 ZVAL_LONG(rv, *(uint32_t*)ptr);
577 return;
579 ZVAL_LONG(rv, *(int32_t*)ptr);
580 return;
582 ZVAL_LONG(rv, *(uint64_t*)ptr);
583 return;
585 ZVAL_LONG(rv, *(int64_t*)ptr);
586 return;
588 ZVAL_BOOL(rv, *(uint8_t*)ptr);
589 return;
591 ZVAL_CHAR(rv, *(char*)ptr);
592 return;
594 kind = type->enumeration.kind;
595 goto again;
597 if (*(void**)ptr == NULL) {
598 ZVAL_NULL(rv);
599 return;
600 } else if (debug_union) {
601 ZVAL_STR(rv, zend_strpprintf(0, "%p", *(void**)ptr));
602 return;
603 } else if ((type->attr & ZEND_FFI_ATTR_CONST) && ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
604 ZVAL_STRING(rv, *(char**)ptr);
605 return;
606 }
607 if (!cdata) {
608 if (is_ret) {
609 cdata = zend_ffi_cdata_to_zval_slow_ret(ptr, type, flags);
610 } else {
611 cdata = zend_ffi_cdata_to_zval_slow_ptr(ptr, type, flags);
612 }
613 } else {
614 GC_ADDREF(&cdata->std);
615 }
616 ZVAL_OBJ(rv, &cdata->std);
617 return;
618 default:
619 break;
620 }
621 }
622
623 if (!cdata) {
624 if (is_ret) {
625 cdata = zend_ffi_cdata_to_zval_slow_ret(ptr, type, flags);
626 } else {
627 cdata = zend_ffi_cdata_to_zval_slow(ptr, type, flags);
628 }
629 } else {
630 GC_ADDREF(&cdata->std);
631 }
632 ZVAL_OBJ(rv, &cdata->std);
633}
634/* }}} */
635
636static uint64_t zend_ffi_bit_field_read(void *ptr, zend_ffi_field *field) /* {{{ */
637{
638 size_t bit = field->first_bit;
639 size_t last_bit = bit + field->bits - 1;
640 uint8_t *p = (uint8_t *) ptr + bit / 8;
641 uint8_t *last_p = (uint8_t *) ptr + last_bit / 8;
642 size_t pos = bit % 8;
643 size_t insert_pos = 0;
644 uint8_t mask;
645 uint64_t val = 0;
646
647 /* Bitfield fits into a single byte */
648 if (p == last_p) {
649 mask = (1U << field->bits) - 1U;
650 return (*p >> pos) & mask;
651 }
652
653 /* Read partial prefix byte */
654 if (pos != 0) {
655 size_t num_bits = 8 - pos;
656 mask = (1U << num_bits) - 1U;
657 val = (*p++ >> pos) & mask;
658 insert_pos += num_bits;
659 }
660
661 /* Read full bytes */
662 while (p < last_p) {
663 val |= (uint64_t) *p++ << insert_pos;
664 insert_pos += 8;
665 }
666
667 /* Read partial suffix byte */
668 if (p == last_p) {
669 size_t num_bits = last_bit % 8 + 1;
670 mask = (1U << num_bits) - 1U;
671 val |= (uint64_t) (*p & mask) << insert_pos;
672 }
673
674 return val;
675}
676/* }}} */
677
678static void zend_ffi_bit_field_to_zval(void *ptr, zend_ffi_field *field, zval *rv) /* {{{ */
679{
680 uint64_t val = zend_ffi_bit_field_read(ptr, field);
681 if (ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_CHAR
682 || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT8
683 || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT16
684 || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT32
685 || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT64) {
686 /* Sign extend */
687 uint64_t shift = 64 - (field->bits % 64);
688 if (shift != 0) {
689 val = (int64_t)(val << shift) >> shift;
690 }
691 }
692 ZVAL_LONG(rv, val);
693}
694/* }}} */
695
696static void zend_ffi_zval_to_bit_field(void *ptr, zend_ffi_field *field, zval *value) /* {{{ */
697{
698 uint64_t val = zval_get_long(value);
699 size_t bit = field->first_bit;
700 size_t last_bit = bit + field->bits - 1;
701 uint8_t *p = (uint8_t *) ptr + bit / 8;
702 uint8_t *last_p = (uint8_t *) ptr + last_bit / 8;
703 size_t pos = bit % 8;
704 uint8_t mask;
705
706 /* Bitfield fits into a single byte */
707 if (p == last_p) {
708 mask = ((1U << field->bits) - 1U) << pos;
709 *p = (*p & ~mask) | ((val << pos) & mask);
710 return;
711 }
712
713 /* Write partial prefix byte */
714 if (pos != 0) {
715 size_t num_bits = 8 - pos;
716 mask = ((1U << num_bits) - 1U) << pos;
717 *p = (*p & ~mask) | ((val << pos) & mask);
718 p++;
719 val >>= num_bits;
720 }
721
722 /* Write full bytes */
723 while (p < last_p) {
724 *p++ = val;
725 val >>= 8;
726 }
727
728 /* Write partial suffix byte */
729 if (p == last_p) {
730 size_t num_bits = last_bit % 8 + 1;
731 mask = (1U << num_bits) - 1U;
732 *p = (*p & ~mask) | (val & mask);
733 }
734}
735/* }}} */
736
737static zend_always_inline zend_result zend_ffi_zval_to_cdata(void *ptr, zend_ffi_type *type, zval *value) /* {{{ */
738{
739 zend_long lval;
740 double dval;
741 zend_string *tmp_str;
742 zend_string *str;
744
745 /* Pointer type has special handling of CData */
746 if (kind != ZEND_FFI_TYPE_POINTER && Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == zend_ffi_cdata_ce) {
748 if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type)) &&
749 type->size == ZEND_FFI_TYPE(cdata->type)->size) {
750 memcpy(ptr, cdata->ptr, type->size);
751 return SUCCESS;
752 }
753 }
754
755again:
756 switch (kind) {
758 dval = zval_get_double(value);
759 *(float*)ptr = dval;
760 break;
762 dval = zval_get_double(value);
763 *(double*)ptr = dval;
764 break;
765#ifdef HAVE_LONG_DOUBLE
766 case ZEND_FFI_TYPE_LONGDOUBLE:
767 dval = zval_get_double(value);
768 *(long double*)ptr = dval;
769 break;
770#endif
772 lval = zval_get_long(value);
773 *(uint8_t*)ptr = lval;
774 break;
776 lval = zval_get_long(value);
777 *(int8_t*)ptr = lval;
778 break;
780 lval = zval_get_long(value);
781 *(uint16_t*)ptr = lval;
782 break;
784 lval = zval_get_long(value);
785 *(int16_t*)ptr = lval;
786 break;
788 lval = zval_get_long(value);
789 *(uint32_t*)ptr = lval;
790 break;
792 lval = zval_get_long(value);
793 *(int32_t*)ptr = lval;
794 break;
796 lval = zval_get_long(value);
797 *(uint64_t*)ptr = lval;
798 break;
800 lval = zval_get_long(value);
801 *(int64_t*)ptr = lval;
802 break;
804 *(uint8_t*)ptr = zend_is_true(value);
805 break;
807 str = zval_get_tmp_string(value, &tmp_str);
808 if (ZSTR_LEN(str) == 1) {
809 *(char*)ptr = ZSTR_VAL(str)[0];
810 } else {
811 zend_tmp_string_release(tmp_str);
812 zend_ffi_assign_incompatible(value, type);
813 return FAILURE;
814 }
815 zend_tmp_string_release(tmp_str);
816 break;
818 kind = type->enumeration.kind;
819 goto again;
821 if (Z_TYPE_P(value) == IS_NULL) {
822 *(void**)ptr = NULL;
823 break;
824 } else if (Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == zend_ffi_cdata_ce) {
826
827 if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
828 if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
829 *(void**)ptr = *(void**)cdata->ptr;
830 } else {
831 if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
832 zend_throw_error(zend_ffi_exception_ce, "Attempt to perform assign of owned C pointer");
833 return FAILURE;
834 }
835 *(void**)ptr = cdata->ptr;
836 }
837 return SUCCESS;
838 /* Allow transparent assignment of not-owned CData to compatible pointers */
839 } else if (ZEND_FFI_TYPE(cdata->type)->kind != ZEND_FFI_TYPE_POINTER
840 && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(type->pointer.type), ZEND_FFI_TYPE(cdata->type))) {
841 if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
842 zend_throw_error(zend_ffi_exception_ce, "Attempt to perform assign pointer to owned C data");
843 return FAILURE;
844 }
845 *(void**)ptr = cdata->ptr;
846 return SUCCESS;
847 }
848#if FFI_CLOSURES
849 } else if (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_FUNC) {
850 void *callback = zend_ffi_create_callback(ZEND_FFI_TYPE(type->pointer.type), value);
851
852 if (callback) {
853 *(void**)ptr = callback;
854 break;
855 } else {
856 return FAILURE;
857 }
858#endif
859 }
860 zend_ffi_assign_incompatible(value, type);
861 return FAILURE;
864 default:
865 /* Incompatible types, because otherwise the CData check at the entry point would've succeeded. */
866 zend_ffi_assign_incompatible(value, type);
867 return FAILURE;
868 }
869 return SUCCESS;
870}
871/* }}} */
872
873#if defined(ZEND_WIN32) && (defined(HAVE_FFI_FASTCALL) || defined(HAVE_FFI_STDCALL) || defined(HAVE_FFI_VECTORCALL_PARTIAL))
874static size_t zend_ffi_arg_size(zend_ffi_type *type) /* {{{ */
875{
876 zend_ffi_type *arg_type;
877 size_t arg_size = 0;
878
879 ZEND_HASH_PACKED_FOREACH_PTR(type->func.args, arg_type) {
880 arg_size += MAX(ZEND_FFI_TYPE(arg_type)->size, sizeof(size_t));
882 return arg_size;
883}
884/* }}} */
885#endif
886
887static zend_always_inline zend_string *zend_ffi_mangled_func_name(zend_string *name, zend_ffi_type *type) /* {{{ */
888{
889#ifdef ZEND_WIN32
890 switch (type->func.abi) {
891# ifdef HAVE_FFI_FASTCALL
892 case FFI_FASTCALL:
893 return strpprintf(0, "@%s@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
894# endif
895# ifdef HAVE_FFI_STDCALL
896 case FFI_STDCALL:
897 return strpprintf(0, "_%s@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
898# endif
899# ifdef HAVE_FFI_VECTORCALL_PARTIAL
900 case FFI_VECTORCALL_PARTIAL:
901 return strpprintf(0, "%s@@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
902# endif
903 }
904#endif
905 return zend_string_copy(name);
906}
907/* }}} */
908
909#if FFI_CLOSURES
910typedef struct _zend_ffi_callback_data {
913 void *code;
914 void *callback;
915 ffi_cif cif;
916 uint32_t arg_count;
917 ffi_type *ret_type;
918 ffi_type *arg_types[] ZEND_ELEMENT_COUNT(arg_count);
919} zend_ffi_callback_data;
920
921static void zend_ffi_callback_hash_dtor(zval *zv) /* {{{ */
922{
923 zend_ffi_callback_data *callback_data = Z_PTR_P(zv);
924
925 ffi_closure_free(callback_data->callback);
926 if (callback_data->fcc.function_handler->common.fn_flags & ZEND_ACC_CLOSURE) {
927 OBJ_RELEASE(ZEND_CLOSURE_OBJECT(callback_data->fcc.function_handler));
928 }
929 for (int i = 0; i < callback_data->arg_count; ++i) {
930 if (callback_data->arg_types[i]->type == FFI_TYPE_STRUCT) {
931 efree(callback_data->arg_types[i]);
932 }
933 }
934 if (callback_data->ret_type->type == FFI_TYPE_STRUCT) {
935 efree(callback_data->ret_type);
936 }
937 efree(callback_data);
938}
939/* }}} */
940
941static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, void* data) /* {{{ */
942{
943 zend_ffi_callback_data *callback_data = (zend_ffi_callback_data*)data;
944 zend_fcall_info fci;
945 zend_ffi_type *ret_type;
946 zval retval;
947 ALLOCA_FLAG(use_heap)
948
949 fci.size = sizeof(zend_fcall_info);
951 fci.retval = &retval;
952 fci.params = do_alloca(sizeof(zval) *callback_data->arg_count, use_heap);
953 fci.object = NULL;
954 fci.param_count = callback_data->arg_count;
955 fci.named_params = NULL;
956
957 if (callback_data->type->func.args) {
958 int n = 0;
959 zend_ffi_type *arg_type;
960
961 ZEND_HASH_PACKED_FOREACH_PTR(callback_data->type->func.args, arg_type) {
962 arg_type = ZEND_FFI_TYPE(arg_type);
963 zend_ffi_cdata_to_zval(NULL, args[n], arg_type, BP_VAR_R, &fci.params[n], (zend_ffi_flags)(arg_type->attr & ZEND_FFI_ATTR_CONST), 0, 0);
964 n++;
966 }
967
969 if (zend_call_function(&fci, &callback_data->fcc) != SUCCESS) {
970 zend_throw_error(zend_ffi_exception_ce, "Cannot call callback");
971 }
972
973 if (callback_data->arg_count) {
974 int n = 0;
975
976 for (n = 0; n < callback_data->arg_count; n++) {
977 zval_ptr_dtor(&fci.params[n]);
978 }
979 }
980 free_alloca(fci.params, use_heap);
981
982 if (EG(exception)) {
983 zend_error_noreturn(E_ERROR, "Throwing from FFI callbacks is not allowed");
984 }
985
986 ret_type = ZEND_FFI_TYPE(callback_data->type->func.ret_type);
987 if (ret_type->kind != ZEND_FFI_TYPE_VOID) {
988 zend_ffi_zval_to_cdata(ret, ret_type, &retval);
989
990#ifdef WORDS_BIGENDIAN
991 if (ret_type->size < sizeof(ffi_arg)
992 && ret_type->kind >= ZEND_FFI_TYPE_UINT8
993 && ret_type->kind < ZEND_FFI_TYPE_POINTER) {
994 /* We need to widen the value (zero extend) */
995 switch (ret_type->size) {
996 case 1:
997 *(ffi_arg*)ret = *(uint8_t*)ret;
998 break;
999 case 2:
1000 *(ffi_arg*)ret = *(uint16_t*)ret;
1001 break;
1002 case 4:
1003 *(ffi_arg*)ret = *(uint32_t*)ret;
1004 break;
1005 default:
1006 break;
1007 }
1008 }
1009#endif
1010 }
1011
1013}
1014/* }}} */
1015
1016static void *zend_ffi_create_callback(zend_ffi_type *type, zval *value) /* {{{ */
1017{
1019 char *error = NULL;
1020 uint32_t arg_count;
1021 void *code;
1022 void *callback;
1023 zend_ffi_callback_data *callback_data;
1024
1025 if (type->attr & ZEND_FFI_ATTR_VARIADIC) {
1026 zend_throw_error(zend_ffi_exception_ce, "Variadic function closures are not supported");
1027 return NULL;
1028 }
1029
1030 if (!zend_is_callable_ex(value, NULL, 0, NULL, &fcc, &error)) {
1031 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign an invalid callback, %s", error);
1032 return NULL;
1033 }
1034
1035 arg_count = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
1036 if (arg_count < fcc.function_handler->common.required_num_args) {
1037 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign an invalid callback, insufficient number of arguments");
1038 return NULL;
1039 }
1040
1041 callback = ffi_closure_alloc(sizeof(ffi_closure), &code);
1042 if (!callback) {
1043 zend_throw_error(zend_ffi_exception_ce, "Cannot allocate callback");
1044 return NULL;
1045 }
1046
1047 callback_data = emalloc(sizeof(zend_ffi_callback_data) + sizeof(ffi_type*) * arg_count);
1048 memcpy(&callback_data->fcc, &fcc, sizeof(zend_fcall_info_cache));
1049 callback_data->type = type;
1050 callback_data->callback = callback;
1051 callback_data->code = code;
1052 callback_data->arg_count = arg_count;
1053
1054 if (type->func.args) {
1055 int n = 0;
1056 zend_ffi_type *arg_type;
1057
1058 ZEND_HASH_PACKED_FOREACH_PTR(type->func.args, arg_type) {
1059 arg_type = ZEND_FFI_TYPE(arg_type);
1060 callback_data->arg_types[n] = zend_ffi_get_type(arg_type);
1061 if (!callback_data->arg_types[n]) {
1062 zend_ffi_pass_unsupported(arg_type);
1063 for (int i = 0; i < n; ++i) {
1064 if (callback_data->arg_types[i]->type == FFI_TYPE_STRUCT) {
1065 efree(callback_data->arg_types[i]);
1066 }
1067 }
1068 efree(callback_data);
1069 ffi_closure_free(callback);
1070 return NULL;
1071 }
1072 n++;
1074 }
1075 callback_data->ret_type = zend_ffi_get_type(ZEND_FFI_TYPE(type->func.ret_type));
1076 if (!callback_data->ret_type) {
1077 zend_ffi_return_unsupported(type->func.ret_type);
1078 for (int i = 0; i < callback_data->arg_count; ++i) {
1079 if (callback_data->arg_types[i]->type == FFI_TYPE_STRUCT) {
1080 efree(callback_data->arg_types[i]);
1081 }
1082 }
1083 efree(callback_data);
1084 ffi_closure_free(callback);
1085 return NULL;
1086 }
1087
1088 if (ffi_prep_cif(&callback_data->cif, type->func.abi, callback_data->arg_count, callback_data->ret_type, callback_data->arg_types) != FFI_OK) {
1089 zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback CIF");
1090 goto free_on_failure;
1091 }
1092
1093 if (ffi_prep_closure_loc(callback, &callback_data->cif, zend_ffi_callback_trampoline, callback_data, code) != FFI_OK) {
1094 zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback");
1095free_on_failure: ;
1096 for (int i = 0; i < callback_data->arg_count; ++i) {
1097 if (callback_data->arg_types[i]->type == FFI_TYPE_STRUCT) {
1098 efree(callback_data->arg_types[i]);
1099 }
1100 }
1101 if (callback_data->ret_type->type == FFI_TYPE_STRUCT) {
1102 efree(callback_data->ret_type);
1103 }
1104 efree(callback_data);
1105 ffi_closure_free(callback);
1106 return NULL;
1107 }
1108
1109 if (!FFI_G(callbacks)) {
1110 FFI_G(callbacks) = emalloc(sizeof(HashTable));
1111 zend_hash_init(FFI_G(callbacks), 0, NULL, zend_ffi_callback_hash_dtor, 0);
1112 }
1113 zend_hash_next_index_insert_ptr(FFI_G(callbacks), callback_data);
1114
1117 }
1118
1119 return code;
1120}
1121/* }}} */
1122#endif
1123
1124static zval *zend_ffi_cdata_get(zend_object *obj, zend_string *member, int read_type, void **cache_slot, zval *rv) /* {{{ */
1125{
1128
1129#if 0
1130 if (UNEXPECTED(!cdata->ptr)) {
1131 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1132 return &EG(uninitialized_zval);
1133 }
1134#endif
1135
1136 if (UNEXPECTED(!zend_string_equals_literal(member, "cdata"))) {
1137 zend_throw_error(zend_ffi_exception_ce, "Only 'cdata' property may be read");
1138 return &EG(uninitialized_zval);
1139 }
1140
1141 zend_ffi_cdata_to_zval(cdata, cdata->ptr, type, BP_VAR_R, rv, 0, 0, 0);
1142 return rv;
1143}
1144/* }}} */
1145
1146static zval *zend_ffi_cdata_set(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
1147{
1150
1151#if 0
1152 if (UNEXPECTED(!cdata->ptr)) {
1153 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1154 return &EG(uninitialized_zval);
1155 }
1156#endif
1157
1158 if (UNEXPECTED(!zend_string_equals_literal(member, "cdata"))) {
1159 zend_throw_error(zend_ffi_exception_ce, "Only 'cdata' property may be set");
1160 return &EG(uninitialized_zval);
1161 }
1162
1163 zend_ffi_zval_to_cdata(cdata->ptr, type, value);
1164
1165 return value;
1166}
1167/* }}} */
1168
1169static zend_result zend_ffi_cdata_cast_object(zend_object *readobj, zval *writeobj, int type) /* {{{ */
1170{
1171 if (type == IS_STRING) {
1172 zend_ffi_cdata *cdata = (zend_ffi_cdata*)readobj;
1174 void *ptr = cdata->ptr;
1176
1177again:
1178 switch (kind) {
1180 ZVAL_DOUBLE(writeobj, *(float*)ptr);
1181 break;
1183 ZVAL_DOUBLE(writeobj, *(double*)ptr);
1184 break;
1185#ifdef HAVE_LONG_DOUBLE
1186 case ZEND_FFI_TYPE_LONGDOUBLE:
1187 ZVAL_DOUBLE(writeobj, *(long double*)ptr);
1188 break;
1189#endif
1191 ZVAL_LONG(writeobj, *(uint8_t*)ptr);
1192 break;
1194 ZVAL_LONG(writeobj, *(int8_t*)ptr);
1195 break;
1197 ZVAL_LONG(writeobj, *(uint16_t*)ptr);
1198 break;
1200 ZVAL_LONG(writeobj, *(int16_t*)ptr);
1201 break;
1203 ZVAL_LONG(writeobj, *(uint32_t*)ptr);
1204 break;
1206 ZVAL_LONG(writeobj, *(int32_t*)ptr);
1207 break;
1209 ZVAL_LONG(writeobj, *(uint64_t*)ptr);
1210 break;
1212 ZVAL_LONG(writeobj, *(int64_t*)ptr);
1213 break;
1214 case ZEND_FFI_TYPE_BOOL:
1215 ZVAL_BOOL(writeobj, *(uint8_t*)ptr);
1216 break;
1217 case ZEND_FFI_TYPE_CHAR:
1218 ZVAL_CHAR(writeobj, *(char*)ptr);
1219 return SUCCESS;
1220 case ZEND_FFI_TYPE_ENUM:
1221 kind = ctype->enumeration.kind;
1222 goto again;
1224 if (*(void**)ptr == NULL) {
1225 ZVAL_NULL(writeobj);
1226 break;
1227 } else if ((ctype->attr & ZEND_FFI_ATTR_CONST) && ZEND_FFI_TYPE(ctype->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
1228 ZVAL_STRING(writeobj, *(char**)ptr);
1229 return SUCCESS;
1230 }
1231 return FAILURE;
1232 default:
1233 return FAILURE;
1234 }
1235 convert_to_string(writeobj);
1236 return SUCCESS;
1237 } else if (type == _IS_BOOL) {
1238 ZVAL_TRUE(writeobj);
1239 return SUCCESS;
1240 }
1241
1242 return FAILURE;
1243}
1244/* }}} */
1245
1246static zval *zend_ffi_cdata_read_field(zend_object *obj, zend_string *field_name, int read_type, void **cache_slot, zval *rv) /* {{{ */
1247{
1250 void *ptr = cdata->ptr;
1251 zend_ffi_field *field;
1252
1253 if (cache_slot && *cache_slot == type) {
1254 field = *(cache_slot + 1);
1255 } else {
1256 if (type->kind == ZEND_FFI_TYPE_POINTER) {
1257 type = ZEND_FFI_TYPE(type->pointer.type);
1258 }
1259 if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1260 if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1261 zend_throw_error(zend_ffi_exception_ce, "Attempt to read field '%s' of non C struct/union", ZSTR_VAL(field_name));
1262 return &EG(uninitialized_zval);
1263 }
1264 }
1265
1266 field = zend_hash_find_ptr(&type->record.fields, field_name);
1267 if (UNEXPECTED(!field)) {
1268 zend_throw_error(zend_ffi_exception_ce, "Attempt to read undefined field '%s' of C struct/union", ZSTR_VAL(field_name));
1269 return &EG(uninitialized_zval);
1270 }
1271
1272 if (cache_slot) {
1273 *cache_slot = type;
1274 *(cache_slot + 1) = field;
1275 }
1276 }
1277
1278 if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
1279 /* transparently dereference the pointer */
1280 if (UNEXPECTED(!ptr)) {
1281 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1282 return &EG(uninitialized_zval);
1283 }
1284 ptr = (void*)(*(char**)ptr);
1285 if (UNEXPECTED(!ptr)) {
1286 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1287 return &EG(uninitialized_zval);
1288 }
1289 type = ZEND_FFI_TYPE(type->pointer.type);
1290 }
1291
1292#if 0
1293 if (UNEXPECTED(!ptr)) {
1294 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1295 return &EG(uninitialized_zval);
1296 }
1297#endif
1298
1299 if (EXPECTED(!field->bits)) {
1300 zend_ffi_type *field_type = field->type;
1301
1302 if (ZEND_FFI_TYPE_IS_OWNED(field_type)) {
1303 field_type = ZEND_FFI_TYPE(field_type);
1304 if (!(field_type->attr & ZEND_FFI_ATTR_STORED)
1305 && field_type->kind == ZEND_FFI_TYPE_POINTER) {
1306 field->type = field_type = zend_ffi_remember_type(field_type);
1307 }
1308 }
1309 ptr = (void*)(((char*)ptr) + field->offset);
1310 zend_ffi_cdata_to_zval(NULL, ptr, field_type, read_type, rv, (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)field->is_const, 0, 0);
1311 } else {
1312 zend_ffi_bit_field_to_zval(ptr, field, rv);
1313 }
1314
1315 return rv;
1316}
1317/* }}} */
1318
1319static zval *zend_ffi_cdata_write_field(zend_object *obj, zend_string *field_name, zval *value, void **cache_slot) /* {{{ */
1320{
1323 void *ptr = cdata->ptr;
1324 zend_ffi_field *field;
1325
1326 if (cache_slot && *cache_slot == type) {
1327 field = *(cache_slot + 1);
1328 } else {
1329 if (UNEXPECTED(type == NULL)) {
1330 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign field '%s' to uninitialized FFI\\CData object", ZSTR_VAL(field_name));
1331 return value;
1332 }
1333 if (type->kind == ZEND_FFI_TYPE_POINTER) {
1334 type = ZEND_FFI_TYPE(type->pointer.type);
1335 }
1336 if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1337 if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1338 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign field '%s' of non C struct/union", ZSTR_VAL(field_name));
1339 return value;
1340 }
1341 }
1342
1343 field = zend_hash_find_ptr(&type->record.fields, field_name);
1344 if (UNEXPECTED(!field)) {
1345 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign undefined field '%s' of C struct/union", ZSTR_VAL(field_name));
1346 return value;
1347 }
1348
1349 if (cache_slot) {
1350 *cache_slot = type;
1351 *(cache_slot + 1) = field;
1352 }
1353 }
1354
1355 if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
1356 /* transparently dereference the pointer */
1357 if (UNEXPECTED(!ptr)) {
1358 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1359 return value;
1360 }
1361 ptr = (void*)(*(char**)ptr);
1362 if (UNEXPECTED(!ptr)) {
1363 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1364 return value;
1365 }
1366 }
1367
1368#if 0
1369 if (UNEXPECTED(!ptr)) {
1370 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1371 return value;
1372 }
1373#endif
1374
1375 if (UNEXPECTED(cdata->flags & ZEND_FFI_FLAG_CONST)) {
1376 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only location");
1377 return value;
1378 } else if (UNEXPECTED(field->is_const)) {
1379 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only field '%s'", ZSTR_VAL(field_name));
1380 return value;
1381 }
1382
1383 if (EXPECTED(!field->bits)) {
1384 ptr = (void*)(((char*)ptr) + field->offset);
1385 zend_ffi_zval_to_cdata(ptr, ZEND_FFI_TYPE(field->type), value);
1386 } else {
1387 zend_ffi_zval_to_bit_field(ptr, field, value);
1388 }
1389 return value;
1390}
1391/* }}} */
1392
1393static zval *zend_ffi_cdata_read_dim(zend_object *obj, zval *offset, int read_type, zval *rv) /* {{{ */
1394{
1397 zend_long dim = zval_get_long(offset);
1398 zend_ffi_type *dim_type;
1399 void *ptr;
1401
1402 if (EXPECTED(type->kind == ZEND_FFI_TYPE_ARRAY)) {
1403 if (UNEXPECTED((zend_ulong)(dim) >= (zend_ulong)type->array.length)
1404 && (UNEXPECTED(dim < 0) || UNEXPECTED(type->array.length != 0))) {
1405 zend_throw_error(zend_ffi_exception_ce, "C array index out of bounds");
1406 return &EG(uninitialized_zval);
1407 }
1408
1410
1411 dim_type = type->array.type;
1412 if (ZEND_FFI_TYPE_IS_OWNED(dim_type)) {
1413 dim_type = ZEND_FFI_TYPE(dim_type);
1414 if (!(dim_type->attr & ZEND_FFI_ATTR_STORED)
1415 && dim_type->kind == ZEND_FFI_TYPE_POINTER) {
1416 type->array.type = dim_type = zend_ffi_remember_type(dim_type);
1417 }
1418 }
1419#if 0
1420 if (UNEXPECTED(!cdata->ptr)) {
1421 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1422 return &EG(uninitialized_zval);
1423 }
1424#endif
1425 ptr = (void*)(((char*)cdata->ptr) + dim_type->size * dim);
1426 } else if (EXPECTED(type->kind == ZEND_FFI_TYPE_POINTER)) {
1428 dim_type = type->pointer.type;
1429 if (ZEND_FFI_TYPE_IS_OWNED(dim_type)) {
1430 dim_type = ZEND_FFI_TYPE(dim_type);
1431 if (!(dim_type->attr & ZEND_FFI_ATTR_STORED)
1432 && dim_type->kind == ZEND_FFI_TYPE_POINTER) {
1433 type->pointer.type = dim_type = zend_ffi_remember_type(dim_type);
1434 }
1435 }
1436 if (UNEXPECTED(!cdata->ptr)) {
1437 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1438 return &EG(uninitialized_zval);
1439 }
1440 ptr = (void*)((*(char**)cdata->ptr) + dim_type->size * dim);
1441 } else {
1442 zend_throw_error(zend_ffi_exception_ce, "Attempt to read element of non C array");
1443 return &EG(uninitialized_zval);
1444 }
1445
1446 zend_ffi_cdata_to_zval(NULL, ptr, dim_type, read_type, rv, is_const, 0, 0);
1447 return rv;
1448}
1449/* }}} */
1450
1451static void zend_ffi_cdata_write_dim(zend_object *obj, zval *offset, zval *value) /* {{{ */
1452{
1455 zend_long dim;
1456 void *ptr;
1458
1459 if (offset == NULL) {
1460 zend_throw_error(zend_ffi_exception_ce, "Cannot add next element to object of type FFI\\CData");
1461 return;
1462 }
1463
1464 dim = zval_get_long(offset);
1465 if (EXPECTED(type->kind == ZEND_FFI_TYPE_ARRAY)) {
1466 if (UNEXPECTED((zend_ulong)(dim) >= (zend_ulong)type->array.length)
1467 && (UNEXPECTED(dim < 0) || UNEXPECTED(type->array.length != 0))) {
1468 zend_throw_error(zend_ffi_exception_ce, "C array index out of bounds");
1469 return;
1470 }
1471
1473 type = ZEND_FFI_TYPE(type->array.type);
1474#if 0
1475 if (UNEXPECTED(!cdata->ptr)) {
1476 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1477 return;
1478 }
1479#endif
1480 ptr = (void*)(((char*)cdata->ptr) + type->size * dim);
1481 } else if (EXPECTED(type->kind == ZEND_FFI_TYPE_POINTER)) {
1483 type = ZEND_FFI_TYPE(type->pointer.type);
1484 if (UNEXPECTED(!cdata->ptr)) {
1485 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1486 return;
1487 }
1488 ptr = (void*)((*(char**)cdata->ptr) + type->size * dim);
1489 } else {
1490 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign element of non C array");
1491 return;
1492 }
1493
1494 if (UNEXPECTED(is_const)) {
1495 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only location");
1496 return;
1497 }
1498
1499 zend_ffi_zval_to_cdata(ptr, type, value);
1500}
1501/* }}} */
1502
1503#define MAX_TYPE_NAME_LEN 256
1504
1510
1511static bool zend_ffi_ctype_name_prepend(zend_ffi_ctype_name_buf *buf, const char *str, size_t len) /* {{{ */
1512{
1513 buf->start -= len;
1514 if (buf->start < buf->buf) {
1515 return 0;
1516 }
1517 memcpy(buf->start, str, len);
1518 return 1;
1519}
1520/* }}} */
1521
1522static bool zend_ffi_ctype_name_append(zend_ffi_ctype_name_buf *buf, const char *str, size_t len) /* {{{ */
1523{
1524 if (buf->end + len > buf->buf + MAX_TYPE_NAME_LEN) {
1525 return 0;
1526 }
1527 buf->end = zend_mempcpy(buf->end, str, len);
1528 return 1;
1529}
1530/* }}} */
1531
1532static bool zend_ffi_ctype_name(zend_ffi_ctype_name_buf *buf, const zend_ffi_type *type) /* {{{ */
1533{
1534 const char *name = NULL;
1535 bool is_ptr = 0;
1536
1537 while (1) {
1538 switch (type->kind) {
1539 case ZEND_FFI_TYPE_VOID:
1540 name = "void";
1541 break;
1543 name = "float";
1544 break;
1546 name = "double";
1547 break;
1548#ifdef HAVE_LONG_DOUBLE
1549 case ZEND_FFI_TYPE_LONGDOUBLE:
1550 name = "long double";
1551 break;
1552#endif
1554 name = "uint8_t";
1555 break;
1557 name = "int8_t";
1558 break;
1560 name = "uint16_t";
1561 break;
1563 name = "int16_t";
1564 break;
1566 name = "uint32_t";
1567 break;
1569 name = "int32_t";
1570 break;
1572 name = "uint64_t";
1573 break;
1575 name = "int64_t";
1576 break;
1577 case ZEND_FFI_TYPE_ENUM:
1578 if (type->enumeration.tag_name) {
1579 zend_ffi_ctype_name_prepend(buf, ZSTR_VAL(type->enumeration.tag_name), ZSTR_LEN(type->enumeration.tag_name));
1580 } else {
1581 zend_ffi_ctype_name_prepend(buf, "<anonymous>", sizeof("<anonymous>")-1);
1582 }
1583 name = "enum ";
1584 break;
1585 case ZEND_FFI_TYPE_BOOL:
1586 name = "bool";
1587 break;
1588 case ZEND_FFI_TYPE_CHAR:
1589 name = "char";
1590 break;
1592 if (!zend_ffi_ctype_name_prepend(buf, "*", 1)) {
1593 return 0;
1594 }
1595 is_ptr = 1;
1596 type = ZEND_FFI_TYPE(type->pointer.type);
1597 break;
1598 case ZEND_FFI_TYPE_FUNC:
1599 if (is_ptr) {
1600 is_ptr = 0;
1601 if (!zend_ffi_ctype_name_prepend(buf, "(", 1)
1602 || !zend_ffi_ctype_name_append(buf, ")", 1)) {
1603 return 0;
1604 }
1605 }
1606 if (!zend_ffi_ctype_name_append(buf, "(", 1)
1607 || !zend_ffi_ctype_name_append(buf, ")", 1)) {
1608 return 0;
1609 }
1610 type = ZEND_FFI_TYPE(type->func.ret_type);
1611 break;
1613 if (is_ptr) {
1614 is_ptr = 0;
1615 if (!zend_ffi_ctype_name_prepend(buf, "(", 1)
1616 || !zend_ffi_ctype_name_append(buf, ")", 1)) {
1617 return 0;
1618 }
1619 }
1620 if (!zend_ffi_ctype_name_append(buf, "[", 1)) {
1621 return 0;
1622 }
1623 if (type->attr & ZEND_FFI_ATTR_VLA) {
1624 if (!zend_ffi_ctype_name_append(buf, "*", 1)) {
1625 return 0;
1626 }
1627 } else if (!(type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
1628 char str[MAX_LENGTH_OF_LONG + 1];
1629 char *s = zend_print_long_to_buf(str + sizeof(str) - 1, type->array.length);
1630
1631 if (!zend_ffi_ctype_name_append(buf, s, strlen(s))) {
1632 return 0;
1633 }
1634 }
1635 if (!zend_ffi_ctype_name_append(buf, "]", 1)) {
1636 return 0;
1637 }
1638 type = ZEND_FFI_TYPE(type->array.type);
1639 break;
1641 if (type->attr & ZEND_FFI_ATTR_UNION) {
1642 if (type->record.tag_name) {
1643 zend_ffi_ctype_name_prepend(buf, ZSTR_VAL(type->record.tag_name), ZSTR_LEN(type->record.tag_name));
1644 } else {
1645 zend_ffi_ctype_name_prepend(buf, "<anonymous>", sizeof("<anonymous>")-1);
1646 }
1647 name = "union ";
1648 } else {
1649 if (type->record.tag_name) {
1650 zend_ffi_ctype_name_prepend(buf, ZSTR_VAL(type->record.tag_name), ZSTR_LEN(type->record.tag_name));
1651 } else {
1652 zend_ffi_ctype_name_prepend(buf, "<anonymous>", sizeof("<anonymous>")-1);
1653 }
1654 name = "struct ";
1655 }
1656 break;
1657 default:
1659 }
1660 if (name) {
1661 break;
1662 }
1663 }
1664
1665// if (buf->start != buf->end && *buf->start != '[') {
1666// if (!zend_ffi_ctype_name_prepend(buf, " ", 1)) {
1667// return 0;
1668// }
1669// }
1670 return zend_ffi_ctype_name_prepend(buf, name, strlen(name));
1671}
1672/* }}} */
1673
1674static ZEND_COLD void zend_ffi_return_unsupported(zend_ffi_type *type) /* {{{ */
1675{
1677 if (type->kind == ZEND_FFI_TYPE_STRUCT) {
1678 zend_throw_error(zend_ffi_exception_ce, "FFI return struct/union is not implemented");
1679 } else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
1680 zend_throw_error(zend_ffi_exception_ce, "FFI return array is not implemented");
1681 } else {
1682 zend_throw_error(zend_ffi_exception_ce, "FFI internal error. Unsupported return type");
1683 }
1684}
1685/* }}} */
1686
1687static ZEND_COLD void zend_ffi_pass_unsupported(zend_ffi_type *type) /* {{{ */
1688{
1690 if (type->kind == ZEND_FFI_TYPE_STRUCT) {
1691 zend_throw_error(zend_ffi_exception_ce, "FFI passing struct/union is not implemented");
1692 } else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
1693 zend_throw_error(zend_ffi_exception_ce, "FFI passing array is not implemented");
1694 } else {
1695 zend_throw_error(zend_ffi_exception_ce, "FFI internal error. Unsupported parameter type");
1696 }
1697}
1698/* }}} */
1699
1700static ZEND_COLD void zend_ffi_pass_incompatible(zval *arg, zend_ffi_type *type, uint32_t n, zend_execute_data *execute_data) /* {{{ */
1701{
1702 zend_ffi_ctype_name_buf buf1, buf2;
1703
1704 buf1.start = buf1.end = buf1.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
1705 if (!zend_ffi_ctype_name(&buf1, type)) {
1706 zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name));
1707 } else {
1708 *buf1.end = 0;
1709 if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
1711
1712 type = ZEND_FFI_TYPE(cdata->type);
1713 buf2.start = buf2.end = buf2.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
1714 if (!zend_ffi_ctype_name(&buf2, type)) {
1715 zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start);
1716 } else {
1717 *buf2.end = 0;
1718 zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s', found '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start, buf2.start);
1719 }
1720 } else {
1721 zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s', found PHP '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start, zend_zval_value_name(arg));
1722 }
1723 }
1724}
1725/* }}} */
1726
1727static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *type) /* {{{ */
1728{
1729 zend_ffi_ctype_name_buf buf1, buf2;
1730
1731 buf1.start = buf1.end = buf1.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
1732 if (!zend_ffi_ctype_name(&buf1, type)) {
1733 zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning");
1734 } else {
1735 *buf1.end = 0;
1736 if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
1738
1739 type = ZEND_FFI_TYPE(cdata->type);
1740 buf2.start = buf2.end = buf2.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
1741 if (!zend_ffi_ctype_name(&buf2, type)) {
1742 zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s'", buf1.start);
1743 } else {
1744 *buf2.end = 0;
1745 zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s' from type '%s'", buf1.start, buf2.start);
1746 }
1747 } else {
1748 zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s' from PHP '%s'", buf1.start, zend_zval_value_name(arg));
1749 }
1750 }
1751}
1752/* }}} */
1753
1754static zend_string *zend_ffi_get_class_name(zend_string *prefix, const zend_ffi_type *type) /* {{{ */
1755{
1757
1758 buf.start = buf.end = buf.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
1759 if (!zend_ffi_ctype_name(&buf, type)) {
1760 return zend_string_copy(prefix);
1761 } else {
1762 return zend_string_concat3(
1763 ZSTR_VAL(prefix), ZSTR_LEN(prefix), ":", 1, buf.start, buf.end - buf.start);
1764 }
1765}
1766/* }}} */
1767
1768static zend_string *zend_ffi_cdata_get_class_name(const zend_object *zobj) /* {{{ */
1769{
1771
1772 return zend_ffi_get_class_name(zobj->ce->name, ZEND_FFI_TYPE(cdata->type));
1773}
1774/* }}} */
1775
1776static int zend_ffi_cdata_compare_objects(zval *o1, zval *o2) /* {{{ */
1777{
1778 if (Z_TYPE_P(o1) == IS_OBJECT && Z_OBJCE_P(o1) == zend_ffi_cdata_ce &&
1779 Z_TYPE_P(o2) == IS_OBJECT && Z_OBJCE_P(o2) == zend_ffi_cdata_ce) {
1784
1785 if (type1->kind == ZEND_FFI_TYPE_POINTER && type2->kind == ZEND_FFI_TYPE_POINTER) {
1786 void *ptr1 = *(void**)cdata1->ptr;
1787 void *ptr2 = *(void**)cdata2->ptr;
1788
1789 if (!ptr1 || !ptr2) {
1790 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1791 return 0;
1792 }
1793 return ptr1 == ptr2 ? 0 : (ptr1 < ptr2 ? -1 : 1);
1794 }
1795 }
1796 zend_throw_error(zend_ffi_exception_ce, "Comparison of incompatible C types");
1797 return 0;
1798}
1799/* }}} */
1800
1801static zend_result zend_ffi_cdata_count_elements(zend_object *obj, zend_long *count) /* {{{ */
1802{
1805
1806 if (type->kind != ZEND_FFI_TYPE_ARRAY) {
1807 zend_throw_error(zend_ffi_exception_ce, "Attempt to count() on non C array");
1808 return FAILURE;
1809 } else {
1810 *count = type->array.length;
1811 return SUCCESS;
1812 }
1813}
1814/* }}} */
1815
1816static zend_object* zend_ffi_add(zend_ffi_cdata *base_cdata, zend_ffi_type *base_type, zend_long offset) /* {{{ */
1817{
1818 char *ptr;
1819 zend_ffi_type *ptr_type;
1821 (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
1822
1823 if (base_type->kind == ZEND_FFI_TYPE_POINTER) {
1824 if (ZEND_FFI_TYPE_IS_OWNED(base_cdata->type)) {
1825 if (!(base_type->attr & ZEND_FFI_ATTR_STORED)) {
1826 if (GC_REFCOUNT(&base_cdata->std) == 1) {
1827 /* transfer type ownership */
1828 base_cdata->type = base_type;
1829 base_type = ZEND_FFI_TYPE_MAKE_OWNED(base_type);
1830 } else {
1831 base_cdata->type = base_type = zend_ffi_remember_type(base_type);
1832 }
1833 }
1834 }
1835 cdata->type = base_type;
1836 ptr = (char*)(*(void**)base_cdata->ptr);
1837 ptr_type = ZEND_FFI_TYPE(base_type)->pointer.type;
1838 } else {
1840
1842 new_type->attr = 0;
1843 new_type->size = sizeof(void*);
1844 new_type->align = _Alignof(void*);
1845
1846 ptr_type = base_type->array.type;
1847 if (ZEND_FFI_TYPE_IS_OWNED(ptr_type)) {
1848 ptr_type = ZEND_FFI_TYPE(ptr_type);
1849 if (!(ptr_type->attr & ZEND_FFI_ATTR_STORED)) {
1850 if (GC_REFCOUNT(&base_cdata->std) == 1) {
1851 /* transfer type ownership */
1852 base_type->array.type = ptr_type;
1853 ptr_type = ZEND_FFI_TYPE_MAKE_OWNED(ptr_type);
1854 } else {
1855 base_type->array.type = ptr_type = zend_ffi_remember_type(ptr_type);
1856 }
1857 }
1858 }
1859 new_type->pointer.type = ptr_type;
1860
1862 ptr = (char*)base_cdata->ptr;
1863 }
1864 cdata->ptr = &cdata->ptr_holder;
1865 cdata->ptr_holder = ptr +
1866 (ptrdiff_t) (offset * ZEND_FFI_TYPE(ptr_type)->size);
1867 cdata->flags = base_cdata->flags & ZEND_FFI_FLAG_CONST;
1868 return &cdata->std;
1869}
1870/* }}} */
1871
1872static zend_result zend_ffi_cdata_do_operation(uint8_t opcode, zval *result, zval *op1, zval *op2) /* {{{ */
1873{
1875
1876 ZVAL_DEREF(op1);
1877 ZVAL_DEREF(op2);
1878 if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJCE_P(op1) == zend_ffi_cdata_ce) {
1881
1882 if (type1->kind == ZEND_FFI_TYPE_POINTER || type1->kind == ZEND_FFI_TYPE_ARRAY) {
1883 if (opcode == ZEND_ADD) {
1884 offset = zval_get_long(op2);
1885 ZVAL_OBJ(result, zend_ffi_add(cdata1, type1, offset));
1886 if (result == op1) {
1887 OBJ_RELEASE(&cdata1->std);
1888 }
1889 return SUCCESS;
1890 } else if (opcode == ZEND_SUB) {
1891 if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJCE_P(op2) == zend_ffi_cdata_ce) {
1894
1895 if (type2->kind == ZEND_FFI_TYPE_POINTER || type2->kind == ZEND_FFI_TYPE_ARRAY) {
1896 zend_ffi_type *t1, *t2;
1897 char *p1, *p2;
1898
1899 if (type1->kind == ZEND_FFI_TYPE_POINTER) {
1900 t1 = ZEND_FFI_TYPE(type1->pointer.type);
1901 p1 = (char*)(*(void**)cdata1->ptr);
1902 } else {
1903 t1 = ZEND_FFI_TYPE(type1->array.type);
1904 p1 = cdata1->ptr;
1905 }
1906 if (type2->kind == ZEND_FFI_TYPE_POINTER) {
1907 t2 = ZEND_FFI_TYPE(type2->pointer.type);
1908 p2 = (char*)(*(void**)cdata2->ptr);
1909 } else {
1910 t2 = ZEND_FFI_TYPE(type2->array.type);
1911 p2 = cdata2->ptr;
1912 }
1913 if (zend_ffi_is_same_type(t1, t2)) {
1915 (zend_long)(p1 - p2) / (zend_long)t1->size);
1916 return SUCCESS;
1917 }
1918 }
1919 }
1920 offset = zval_get_long(op2);
1921 ZVAL_OBJ(result, zend_ffi_add(cdata1, type1, -offset));
1922 if (result == op1) {
1923 OBJ_RELEASE(&cdata1->std);
1924 }
1925 return SUCCESS;
1926 }
1927 }
1928 } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJCE_P(op2) == zend_ffi_cdata_ce) {
1931
1932 if (type2->kind == ZEND_FFI_TYPE_POINTER || type2->kind == ZEND_FFI_TYPE_ARRAY) {
1933 if (opcode == ZEND_ADD) {
1934 offset = zval_get_long(op1);
1935 ZVAL_OBJ(result, zend_ffi_add(cdata2, type2, offset));
1936 return SUCCESS;
1937 }
1938 }
1939 }
1940
1941 return FAILURE;
1942}
1943/* }}} */
1944
1951
1952static void zend_ffi_cdata_it_dtor(zend_object_iterator *iter) /* {{{ */
1953{
1955 zval_ptr_dtor(&iter->data);
1956}
1957/* }}} */
1958
1959static zend_result zend_ffi_cdata_it_valid(zend_object_iterator *it) /* {{{ */
1960{
1964
1965 return (iter->key >= 0 && iter->key < type->array.length) ? SUCCESS : FAILURE;
1966}
1967/* }}} */
1968
1969static zval *zend_ffi_cdata_it_get_current_data(zend_object_iterator *it) /* {{{ */
1970{
1974 zend_ffi_type *dim_type;
1975 void *ptr;
1976
1977 if (!cdata->ptr) {
1978 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1979 return &EG(uninitialized_zval);
1980 }
1981 dim_type = type->array.type;
1982 if (ZEND_FFI_TYPE_IS_OWNED(dim_type)) {
1983 dim_type = ZEND_FFI_TYPE(dim_type);
1984 if (!(dim_type->attr & ZEND_FFI_ATTR_STORED)
1985 && dim_type->kind == ZEND_FFI_TYPE_POINTER) {
1986 type->array.type = dim_type = zend_ffi_remember_type(dim_type);
1987 }
1988 }
1989 ptr = (void*)((char*)cdata->ptr + dim_type->size * iter->it.index);
1990
1991 zval_ptr_dtor(&iter->value);
1992 zend_ffi_cdata_to_zval(NULL, ptr, dim_type, iter->by_ref ? BP_VAR_RW : BP_VAR_R, &iter->value, (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST), 0, 0);
1993 return &iter->value;
1994}
1995/* }}} */
1996
1997static void zend_ffi_cdata_it_get_current_key(zend_object_iterator *it, zval *key) /* {{{ */
1998{
2000 ZVAL_LONG(key, iter->key);
2001}
2002/* }}} */
2003
2004static void zend_ffi_cdata_it_move_forward(zend_object_iterator *it) /* {{{ */
2005{
2007 iter->key++;
2008}
2009/* }}} */
2010
2011static void zend_ffi_cdata_it_rewind(zend_object_iterator *it) /* {{{ */
2012{
2014 iter->key = 0;
2015}
2016/* }}} */
2017
2018static const zend_object_iterator_funcs zend_ffi_cdata_it_funcs = {
2019 zend_ffi_cdata_it_dtor,
2020 zend_ffi_cdata_it_valid,
2021 zend_ffi_cdata_it_get_current_data,
2022 zend_ffi_cdata_it_get_current_key,
2023 zend_ffi_cdata_it_move_forward,
2024 zend_ffi_cdata_it_rewind,
2025 NULL,
2026 NULL, /* get_gc */
2027};
2028
2029static zend_object_iterator *zend_ffi_cdata_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
2030{
2034
2035 if (type->kind != ZEND_FFI_TYPE_ARRAY) {
2036 zend_throw_error(zend_ffi_exception_ce, "Attempt to iterate on non C array");
2037 return NULL;
2038 }
2039
2040 iter = emalloc(sizeof(zend_ffi_cdata_iterator));
2041
2042 zend_iterator_init(&iter->it);
2043
2044 Z_ADDREF_P(object);
2045 ZVAL_OBJ(&iter->it.data, Z_OBJ_P(object));
2046 iter->it.funcs = &zend_ffi_cdata_it_funcs;
2047 iter->key = 0;
2048 iter->by_ref = by_ref;
2049 ZVAL_UNDEF(&iter->value);
2050
2051 return &iter->it;
2052}
2053/* }}} */
2054
2055static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
2056{
2059 void *ptr = cdata->ptr;
2060 HashTable *ht = NULL;
2062 zend_ffi_field *f;
2063 zend_long n;
2064 zval tmp;
2065
2066 if (!cdata->ptr) {
2067 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
2068 return NULL;
2069 }
2070
2071 switch (type->kind) {
2072 case ZEND_FFI_TYPE_VOID:
2073 return NULL;
2074 case ZEND_FFI_TYPE_BOOL:
2075 case ZEND_FFI_TYPE_CHAR:
2076 case ZEND_FFI_TYPE_ENUM:
2079#ifdef HAVE_LONG_DOUBLE
2080 case ZEND_FFI_TYPE_LONGDOUBLE:
2081#endif
2090 zend_ffi_cdata_to_zval(cdata, ptr, type, BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
2091 ht = zend_new_array(1);
2092 zend_hash_str_add(ht, "cdata", sizeof("cdata")-1, &tmp);
2093 *is_temp = 1;
2094 return ht;
2095 break;
2097 if (*(void**)ptr == NULL) {
2098 ZVAL_NULL(&tmp);
2099 ht = zend_new_array(1);
2100 zend_hash_index_add_new(ht, 0, &tmp);
2101 *is_temp = 1;
2102 return ht;
2103 } else if (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_VOID) {
2104 ZVAL_LONG(&tmp, (uintptr_t)*(void**)ptr);
2105 ht = zend_new_array(1);
2106 zend_hash_index_add_new(ht, 0, &tmp);
2107 *is_temp = 1;
2108 return ht;
2109 } else {
2110 zend_ffi_cdata_to_zval(NULL, *(void**)ptr, ZEND_FFI_TYPE(type->pointer.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
2111 ht = zend_new_array(1);
2112 zend_hash_index_add_new(ht, 0, &tmp);
2113 *is_temp = 1;
2114 return ht;
2115 }
2116 break;
2118 ht = zend_new_array(zend_hash_num_elements(&type->record.fields));
2119 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&type->record.fields, key, f) {
2120 if (key) {
2121 if (!f->bits) {
2122 void *f_ptr = (void*)(((char*)ptr) + f->offset);
2123 zend_ffi_cdata_to_zval(NULL, f_ptr, ZEND_FFI_TYPE(f->type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, type->attr & ZEND_FFI_ATTR_UNION);
2124 zend_hash_add(ht, key, &tmp);
2125 } else {
2126 zend_ffi_bit_field_to_zval(ptr, f, &tmp);
2127 zend_hash_add(ht, key, &tmp);
2128 }
2129 }
2131 *is_temp = 1;
2132 return ht;
2134 ht = zend_new_array(type->array.length);
2135 for (n = 0; n < type->array.length; n++) {
2136 zend_ffi_cdata_to_zval(NULL, ptr, ZEND_FFI_TYPE(type->array.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
2137 zend_hash_index_add(ht, n, &tmp);
2138 ptr = (void*)(((char*)ptr) + ZEND_FFI_TYPE(type->array.type)->size);
2139 }
2140 *is_temp = 1;
2141 return ht;
2142 case ZEND_FFI_TYPE_FUNC:
2143 ht = zend_new_array(0);
2144 // TODO: function name ???
2145 *is_temp = 1;
2146 return ht;
2147 break;
2148 default:
2150 break;
2151 }
2152 return NULL;
2153}
2154/* }}} */
2155
2156static zend_result zend_ffi_cdata_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only) /* {{{ */
2157{
2161
2162 if (type->kind != ZEND_FFI_TYPE_POINTER) {
2163 if (!check_only) {
2164 zend_throw_error(zend_ffi_exception_ce, "Attempt to call non C function pointer");
2165 }
2166 return FAILURE;
2167 }
2168 type = ZEND_FFI_TYPE(type->pointer.type);
2169 if (type->kind != ZEND_FFI_TYPE_FUNC) {
2170 if (!check_only) {
2171 zend_throw_error(zend_ffi_exception_ce, "Attempt to call non C function pointer");
2172 }
2173 return FAILURE;
2174 }
2175 if (!cdata->ptr) {
2176 if (!check_only) {
2177 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
2178 }
2179 return FAILURE;
2180 }
2181
2182 if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
2183 func = &EG(trampoline);
2184 } else {
2185 func = ecalloc(1, sizeof(zend_internal_function));
2186 }
2188 func->common.arg_flags[0] = 0;
2189 func->common.arg_flags[1] = 0;
2190 func->common.arg_flags[2] = 0;
2191 func->common.fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE;
2192 func->common.function_name = ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE);
2193 /* set to 0 to avoid arg_info[] allocation, because all values are passed by value anyway */
2194 func->common.num_args = 0;
2195 func->common.required_num_args = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
2196 func->common.scope = NULL;
2197 func->common.prototype = NULL;
2198 func->common.arg_info = NULL;
2199 func->internal_function.handler = ZEND_FN(ffi_trampoline);
2200 func->internal_function.module = NULL;
2201 func->internal_function.doc_comment = NULL;
2202
2203 func->internal_function.reserved[0] = type;
2204 func->internal_function.reserved[1] = *(void**)cdata->ptr;
2205
2206 *ce_ptr = NULL;
2207 *fptr_ptr= func;
2208 *obj_ptr = NULL;
2209
2210 return SUCCESS;
2211}
2212/* }}} */
2213
2214static zend_object *zend_ffi_ctype_new(zend_class_entry *class_type) /* {{{ */
2215{
2217
2218 ctype = emalloc(sizeof(zend_ffi_ctype));
2219
2220 zend_ffi_object_init(&ctype->std, class_type);
2221
2222 ctype->type = NULL;
2223
2224 return &ctype->std;
2225}
2226/* }}} */
2227
2228static void zend_ffi_ctype_free_obj(zend_object *object) /* {{{ */
2229{
2231
2232 zend_ffi_type_dtor(ctype->type);
2233
2235 zend_weakrefs_notify(object);
2236 }
2237}
2238/* }}} */
2239
2240static bool zend_ffi_is_same_type(zend_ffi_type *type1, zend_ffi_type *type2) /* {{{ */
2241{
2242 while (1) {
2243 if (type1 == type2) {
2244 return 1;
2245 } else if (type1->kind == type2->kind) {
2246 if (type1->kind < ZEND_FFI_TYPE_POINTER) {
2247 return 1;
2248 } else if (type1->kind == ZEND_FFI_TYPE_POINTER) {
2249 type1 = ZEND_FFI_TYPE(type1->pointer.type);
2250 type2 = ZEND_FFI_TYPE(type2->pointer.type);
2251 if (type1->kind == ZEND_FFI_TYPE_VOID ||
2252 type2->kind == ZEND_FFI_TYPE_VOID) {
2253 return 1;
2254 }
2255 } else if (type1->kind == ZEND_FFI_TYPE_ARRAY &&
2256 type1->array.length == type2->array.length) {
2257 type1 = ZEND_FFI_TYPE(type1->array.type);
2258 type2 = ZEND_FFI_TYPE(type2->array.type);
2259 } else {
2260 break;
2261 }
2262 } else {
2263 break;
2264 }
2265 }
2266 return 0;
2267}
2268/* }}} */
2269
2270static zend_string *zend_ffi_ctype_get_class_name(const zend_object *zobj) /* {{{ */
2271{
2273
2274 return zend_ffi_get_class_name(zobj->ce->name, ZEND_FFI_TYPE(ctype->type));
2275}
2276/* }}} */
2277
2278static int zend_ffi_ctype_compare_objects(zval *o1, zval *o2) /* {{{ */
2279{
2280 if (Z_TYPE_P(o1) == IS_OBJECT && Z_OBJCE_P(o1) == zend_ffi_ctype_ce &&
2281 Z_TYPE_P(o2) == IS_OBJECT && Z_OBJCE_P(o2) == zend_ffi_ctype_ce) {
2282 zend_ffi_ctype *ctype1 = (zend_ffi_ctype*)Z_OBJ_P(o1);
2283 zend_ffi_ctype *ctype2 = (zend_ffi_ctype*)Z_OBJ_P(o2);
2286
2287 if (zend_ffi_is_same_type(type1, type2)) {
2288 return 0;
2289 } else {
2290 return 1;
2291 }
2292 }
2293 zend_throw_error(zend_ffi_exception_ce, "Comparison of incompatible C types");
2294 return 0;
2295}
2296/* }}} */
2297
2298static HashTable *zend_ffi_ctype_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
2299{
2300 return NULL;
2301}
2302/* }}} */
2303
2304static zend_object *zend_ffi_new(zend_class_entry *class_type) /* {{{ */
2305{
2306 zend_ffi *ffi;
2307
2308 ffi = emalloc(sizeof(zend_ffi));
2309
2310 zend_ffi_object_init(&ffi->std, class_type);
2311
2312 ffi->lib = NULL;
2313 ffi->symbols = NULL;
2314 ffi->tags = NULL;
2315 ffi->persistent = 0;
2316
2317 return &ffi->std;
2318}
2319/* }}} */
2320
2321static void _zend_ffi_type_dtor(zend_ffi_type *type) /* {{{ */
2322{
2324
2325 switch (type->kind) {
2326 case ZEND_FFI_TYPE_ENUM:
2327 if (type->enumeration.tag_name) {
2328 zend_string_release(type->enumeration.tag_name);
2329 }
2330 break;
2332 if (type->record.tag_name) {
2333 zend_string_release(type->record.tag_name);
2334 }
2335 zend_hash_destroy(&type->record.fields);
2336 break;
2338 zend_ffi_type_dtor(type->pointer.type);
2339 break;
2341 zend_ffi_type_dtor(type->array.type);
2342 break;
2343 case ZEND_FFI_TYPE_FUNC:
2344 if (type->func.args) {
2345 zend_hash_destroy(type->func.args);
2346 pefree(type->func.args, type->attr & ZEND_FFI_ATTR_PERSISTENT);
2347 }
2348 zend_ffi_type_dtor(type->func.ret_type);
2349 break;
2350 default:
2351 break;
2352 }
2354}
2355/* }}} */
2356
2357static void zend_ffi_type_hash_dtor(zval *zv) /* {{{ */
2358{
2360 zend_ffi_type_dtor(type);
2361}
2362/* }}} */
2363
2364static void zend_ffi_field_hash_dtor(zval *zv) /* {{{ */
2365{
2366 zend_ffi_field *field = Z_PTR_P(zv);
2367 zend_ffi_type_dtor(field->type);
2368 efree(field);
2369}
2370/* }}} */
2371
2372static void zend_ffi_field_hash_persistent_dtor(zval *zv) /* {{{ */
2373{
2374 zend_ffi_field *field = Z_PTR_P(zv);
2375 zend_ffi_type_dtor(field->type);
2376 free(field);
2377}
2378/* }}} */
2379
2380static void zend_ffi_symbol_hash_dtor(zval *zv) /* {{{ */
2381{
2382 zend_ffi_symbol *sym = Z_PTR_P(zv);
2383 zend_ffi_type_dtor(sym->type);
2384 efree(sym);
2385}
2386/* }}} */
2387
2388static void zend_ffi_symbol_hash_persistent_dtor(zval *zv) /* {{{ */
2389{
2390 zend_ffi_symbol *sym = Z_PTR_P(zv);
2391 zend_ffi_type_dtor(sym->type);
2392 free(sym);
2393}
2394/* }}} */
2395
2396static void zend_ffi_tag_hash_dtor(zval *zv) /* {{{ */
2397{
2398 zend_ffi_tag *tag = Z_PTR_P(zv);
2399 zend_ffi_type_dtor(tag->type);
2400 efree(tag);
2401}
2402/* }}} */
2403
2404static void zend_ffi_tag_hash_persistent_dtor(zval *zv) /* {{{ */
2405{
2406 zend_ffi_tag *tag = Z_PTR_P(zv);
2407 zend_ffi_type_dtor(tag->type);
2408 free(tag);
2409}
2410/* }}} */
2411
2412static void zend_ffi_cdata_dtor(zend_ffi_cdata *cdata) /* {{{ */
2413{
2414 zend_ffi_type_dtor(cdata->type);
2415 if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
2416 if (cdata->ptr != (void*)&cdata->ptr_holder) {
2418 } else {
2419 pefree(cdata->ptr_holder, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
2420 }
2421 }
2422}
2423/* }}} */
2424
2425static void zend_ffi_scope_hash_dtor(zval *zv) /* {{{ */
2426{
2428 if (scope->symbols) {
2429 zend_hash_destroy(scope->symbols);
2430 free(scope->symbols);
2431 }
2432 if (scope->tags) {
2433 zend_hash_destroy(scope->tags);
2434 free(scope->tags);
2435 }
2436 free(scope);
2437}
2438/* }}} */
2439
2440static void zend_ffi_free_obj(zend_object *object) /* {{{ */
2441{
2442 zend_ffi *ffi = (zend_ffi*)object;
2443
2444 if (ffi->persistent) {
2445 return;
2446 }
2447
2448 if (ffi->lib) {
2449 DL_UNLOAD(ffi->lib);
2450 ffi->lib = NULL;
2451 }
2452
2453 if (ffi->symbols) {
2454 zend_hash_destroy(ffi->symbols);
2455 efree(ffi->symbols);
2456 }
2457
2458 if (ffi->tags) {
2459 zend_hash_destroy(ffi->tags);
2460 efree(ffi->tags);
2461 }
2462
2464 zend_weakrefs_notify(object);
2465 }
2466}
2467/* }}} */
2468
2469static void zend_ffi_cdata_free_obj(zend_object *object) /* {{{ */
2470{
2472
2473 zend_ffi_cdata_dtor(cdata);
2474
2476 zend_weakrefs_notify(object);
2477 }
2478}
2479/* }}} */
2480
2481static zend_object *zend_ffi_cdata_clone_obj(zend_object *obj) /* {{{ */
2482{
2486
2487 new_cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
2488 if (type->kind < ZEND_FFI_TYPE_POINTER) {
2489 new_cdata->std.handlers = &zend_ffi_cdata_value_handlers;
2490 }
2491 new_cdata->type = type;
2492 new_cdata->ptr = emalloc(type->size);
2493 memcpy(new_cdata->ptr, old_cdata->ptr, type->size);
2495
2496 return &new_cdata->std;
2497}
2498/* }}} */
2499
2500static zval *zend_ffi_read_var(zend_object *obj, zend_string *var_name, int read_type, void **cache_slot, zval *rv) /* {{{ */
2501{
2502 zend_ffi *ffi = (zend_ffi*)obj;
2503 zend_ffi_symbol *sym = NULL;
2504
2505 if (ffi->symbols) {
2506 sym = zend_hash_find_ptr(ffi->symbols, var_name);
2507 if (sym && sym->kind != ZEND_FFI_SYM_VAR && sym->kind != ZEND_FFI_SYM_CONST && sym->kind != ZEND_FFI_SYM_FUNC) {
2508 sym = NULL;
2509 }
2510 }
2511 if (!sym) {
2512 zend_throw_error(zend_ffi_exception_ce, "Attempt to read undefined C variable '%s'", ZSTR_VAL(var_name));
2513 return &EG(uninitialized_zval);
2514 }
2515
2516 if (sym->kind == ZEND_FFI_SYM_VAR) {
2517 zend_ffi_cdata_to_zval(NULL, sym->addr, ZEND_FFI_TYPE(sym->type), read_type, rv, (zend_ffi_flags)sym->is_const, 0, 0);
2518 } else if (sym->kind == ZEND_FFI_SYM_FUNC) {
2521
2523 new_type->attr = 0;
2524 new_type->size = sizeof(void*);
2525 new_type->align = _Alignof(void*);
2526 new_type->pointer.type = ZEND_FFI_TYPE(sym->type);
2527
2528 cdata = emalloc(sizeof(zend_ffi_cdata));
2529 zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
2531 cdata->flags = ZEND_FFI_FLAG_CONST;
2532 cdata->ptr_holder = sym->addr;
2533 cdata->ptr = &cdata->ptr_holder;
2534 ZVAL_OBJ(rv, &cdata->std);
2535 } else {
2536 ZVAL_LONG(rv, sym->value);
2537 }
2538
2539 return rv;
2540}
2541/* }}} */
2542
2543static zval *zend_ffi_write_var(zend_object *obj, zend_string *var_name, zval *value, void **cache_slot) /* {{{ */
2544{
2545 zend_ffi *ffi = (zend_ffi*)obj;
2546 zend_ffi_symbol *sym = NULL;
2547
2548 if (ffi->symbols) {
2549 sym = zend_hash_find_ptr(ffi->symbols, var_name);
2550 if (sym && sym->kind != ZEND_FFI_SYM_VAR) {
2551 sym = NULL;
2552 }
2553 }
2554 if (!sym) {
2555 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign undefined C variable '%s'", ZSTR_VAL(var_name));
2556 return value;
2557 }
2558
2559 if (sym->is_const) {
2560 zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only C variable '%s'", ZSTR_VAL(var_name));
2561 return value;
2562 }
2563
2564 zend_ffi_zval_to_cdata(sym->addr, ZEND_FFI_TYPE(sym->type), value);
2565 return value;
2566}
2567/* }}} */
2568
2569static zend_result zend_ffi_pass_arg(zval *arg, zend_ffi_type *type, ffi_type **pass_type, void **arg_values, uint32_t n, zend_execute_data *execute_data) /* {{{ */
2570{
2571 zend_long lval;
2572 double dval;
2573 zend_string *str, *tmp_str;
2575
2576 ZVAL_DEREF(arg);
2577
2578again:
2579 switch (kind) {
2581 dval = zval_get_double(arg);
2582 *pass_type = &ffi_type_float;
2583 *(float*)arg_values[n] = (float)dval;
2584 break;
2586 dval = zval_get_double(arg);
2587 *pass_type = &ffi_type_double;
2588 *(double*)arg_values[n] = dval;
2589 break;
2590#ifdef HAVE_LONG_DOUBLE
2591 case ZEND_FFI_TYPE_LONGDOUBLE:
2592 dval = zval_get_double(arg);
2593 *pass_type = &ffi_type_double;
2594 *(long double*)arg_values[n] = (long double)dval;
2595 break;
2596#endif
2598 lval = zval_get_long(arg);
2599 *pass_type = &ffi_type_uint8;
2600 *(uint8_t*)arg_values[n] = (uint8_t)lval;
2601 break;
2603 lval = zval_get_long(arg);
2604 *pass_type = &ffi_type_sint8;
2605 *(int8_t*)arg_values[n] = (int8_t)lval;
2606 break;
2608 lval = zval_get_long(arg);
2609 *pass_type = &ffi_type_uint16;
2610 *(uint16_t*)arg_values[n] = (uint16_t)lval;
2611 break;
2613 lval = zval_get_long(arg);
2614 *pass_type = &ffi_type_sint16;
2615 *(int16_t*)arg_values[n] = (int16_t)lval;
2616 break;
2618 lval = zval_get_long(arg);
2619 *pass_type = &ffi_type_uint32;
2620 *(uint32_t*)arg_values[n] = (uint32_t)lval;
2621 break;
2623 lval = zval_get_long(arg);
2624 *pass_type = &ffi_type_sint32;
2625 *(int32_t*)arg_values[n] = (int32_t)lval;
2626 break;
2628 lval = zval_get_long(arg);
2629 *pass_type = &ffi_type_uint64;
2630 *(uint64_t*)arg_values[n] = (uint64_t)lval;
2631 break;
2633 lval = zval_get_long(arg);
2634 *pass_type = &ffi_type_sint64;
2635 *(int64_t*)arg_values[n] = (int64_t)lval;
2636 break;
2638 *pass_type = &ffi_type_pointer;
2639 if (Z_TYPE_P(arg) == IS_NULL) {
2640 *(void**)arg_values[n] = NULL;
2641 return SUCCESS;
2642 } else if (Z_TYPE_P(arg) == IS_STRING
2643 && ((ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR)
2644 || (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_VOID))) {
2645 *(void**)arg_values[n] = Z_STRVAL_P(arg);
2646 return SUCCESS;
2647 } else if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
2649
2650 if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
2651 if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
2652 if (!cdata->ptr) {
2653 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
2654 return FAILURE;
2655 }
2656 *(void**)arg_values[n] = *(void**)cdata->ptr;
2657 } else {
2658 *(void**)arg_values[n] = cdata->ptr;
2659 }
2660 return SUCCESS;
2661 }
2662#if FFI_CLOSURES
2663 } else if (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_FUNC) {
2664 void *callback = zend_ffi_create_callback(ZEND_FFI_TYPE(type->pointer.type), arg);
2665
2666 if (callback) {
2667 *(void**)arg_values[n] = callback;
2668 break;
2669 } else {
2670 return FAILURE;
2671 }
2672#endif
2673 }
2674 zend_ffi_pass_incompatible(arg, type, n, execute_data);
2675 return FAILURE;
2676 case ZEND_FFI_TYPE_BOOL:
2677 *pass_type = &ffi_type_uint8;
2678 *(uint8_t*)arg_values[n] = zend_is_true(arg);
2679 break;
2680 case ZEND_FFI_TYPE_CHAR:
2681 str = zval_get_tmp_string(arg, &tmp_str);
2682 *pass_type = &ffi_type_sint8;
2683 *(char*)arg_values[n] = ZSTR_VAL(str)[0];
2684 if (ZSTR_LEN(str) != 1) {
2685 zend_ffi_pass_incompatible(arg, type, n, execute_data);
2686 }
2687 zend_tmp_string_release(tmp_str);
2688 break;
2689 case ZEND_FFI_TYPE_ENUM:
2690 kind = type->enumeration.kind;
2691 goto again;
2693 if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
2695
2696 if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
2697 *pass_type = zend_ffi_make_fake_struct_type(type);
2698 arg_values[n] = cdata->ptr;
2699 break;
2700 }
2701 }
2702 zend_ffi_pass_incompatible(arg, type, n, execute_data);
2703 return FAILURE;
2704 default:
2705 zend_ffi_pass_unsupported(type);
2706 return FAILURE;
2707 }
2708 return SUCCESS;
2709}
2710/* }}} */
2711
2712static zend_result zend_ffi_pass_var_arg(zval *arg, ffi_type **pass_type, void **arg_values, uint32_t n, zend_execute_data *execute_data) /* {{{ */
2713{
2714 ZVAL_DEREF(arg);
2715 switch (Z_TYPE_P(arg)) {
2716 case IS_NULL:
2717 *pass_type = &ffi_type_pointer;
2718 *(void**)arg_values[n] = NULL;
2719 break;
2720 case IS_FALSE:
2721 *pass_type = &ffi_type_uint8;
2722 *(uint8_t*)arg_values[n] = 0;
2723 break;
2724 case IS_TRUE:
2725 *pass_type = &ffi_type_uint8;
2726 *(uint8_t*)arg_values[n] = 1;
2727 break;
2728 case IS_LONG:
2729 if (sizeof(zend_long) == 4) {
2730 *pass_type = &ffi_type_sint32;
2731 *(int32_t*)arg_values[n] = Z_LVAL_P(arg);
2732 } else {
2733 *pass_type = &ffi_type_sint64;
2734 *(int64_t*)arg_values[n] = Z_LVAL_P(arg);
2735 }
2736 break;
2737 case IS_DOUBLE:
2738 *pass_type = &ffi_type_double;
2739 *(double*)arg_values[n] = Z_DVAL_P(arg);
2740 break;
2741 case IS_STRING:
2742 *pass_type = &ffi_type_pointer;
2743 *(char**)arg_values[n] = Z_STRVAL_P(arg);
2744 break;
2745 case IS_OBJECT:
2746 if (Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
2749
2750 return zend_ffi_pass_arg(arg, type, pass_type, arg_values, n, execute_data);
2751 }
2753 default:
2754 zend_throw_error(zend_ffi_exception_ce, "Unsupported argument type");
2755 return FAILURE;
2756 }
2757 return SUCCESS;
2758}
2759/* }}} */
2760
2761static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
2762{
2763 zend_ffi_type *type = EX(func)->internal_function.reserved[0];
2764 void *addr = EX(func)->internal_function.reserved[1];
2765 ffi_cif cif;
2766 ffi_type *ret_type = NULL;
2767 ffi_type **arg_types = NULL;
2768 void **arg_values = NULL;
2769 uint32_t n, arg_count;
2770 void *ret;
2771 zend_ffi_type *arg_type;
2772 ALLOCA_FLAG(arg_types_use_heap = 0)
2773 ALLOCA_FLAG(arg_values_use_heap = 0)
2774 ALLOCA_FLAG(ret_use_heap = 0)
2775
2777 arg_count = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
2779 if (arg_count > EX_NUM_ARGS()) {
2780 zend_throw_error(zend_ffi_exception_ce, "Incorrect number of arguments for C function '%s', expecting at least %d parameter%s", ZSTR_VAL(EX(func)->internal_function.function_name), arg_count, (arg_count != 1) ? "s" : "");
2781 goto exit;
2782 }
2783 if (EX_NUM_ARGS()) {
2784 arg_types = do_alloca(
2785 sizeof(ffi_type*) * EX_NUM_ARGS(), arg_types_use_heap);
2786 arg_values = do_alloca(
2787 (sizeof(void*) + ZEND_FFI_SIZEOF_ARG) * EX_NUM_ARGS(), arg_values_use_heap);
2788 n = 0;
2789 if (type->func.args) {
2790 ZEND_HASH_PACKED_FOREACH_PTR(type->func.args, arg_type) {
2791 arg_type = ZEND_FFI_TYPE(arg_type);
2792 arg_values[n] = ((char*)arg_values) + (sizeof(void*) * EX_NUM_ARGS()) + (ZEND_FFI_SIZEOF_ARG * n);
2793 if (zend_ffi_pass_arg(EX_VAR_NUM(n), arg_type, &arg_types[n], arg_values, n, execute_data) == FAILURE) {
2794 free_alloca(arg_types, arg_types_use_heap);
2795 free_alloca(arg_values, arg_values_use_heap);
2796 goto exit;
2797 }
2798 n++;
2800 }
2801 for (; n < EX_NUM_ARGS(); n++) {
2802 arg_values[n] = ((char*)arg_values) + (sizeof(void*) * EX_NUM_ARGS()) + (ZEND_FFI_SIZEOF_ARG * n);
2803 if (zend_ffi_pass_var_arg(EX_VAR_NUM(n), &arg_types[n], arg_values, n, execute_data) == FAILURE) {
2804 free_alloca(arg_types, arg_types_use_heap);
2805 free_alloca(arg_values, arg_values_use_heap);
2806 goto exit;
2807 }
2808 }
2809 }
2810 ret_type = zend_ffi_get_type(ZEND_FFI_TYPE(type->func.ret_type));
2811 if (!ret_type) {
2812 zend_ffi_return_unsupported(type->func.ret_type);
2813 free_alloca(arg_types, arg_types_use_heap);
2814 free_alloca(arg_values, arg_values_use_heap);
2815 goto exit;
2816 }
2817 if (ffi_prep_cif_var(&cif, type->func.abi, arg_count, EX_NUM_ARGS(), ret_type, arg_types) != FFI_OK) {
2818 zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback CIF");
2819 free_alloca(arg_types, arg_types_use_heap);
2820 free_alloca(arg_values, arg_values_use_heap);
2821 goto exit;
2822 }
2823 } else {
2824 if (arg_count != EX_NUM_ARGS()) {
2825 zend_throw_error(zend_ffi_exception_ce, "Incorrect number of arguments for C function '%s', expecting exactly %d parameter%s", ZSTR_VAL(EX(func)->internal_function.function_name), arg_count, (arg_count != 1) ? "s" : "");
2826 goto exit;
2827 }
2828 if (EX_NUM_ARGS()) {
2829 arg_types = do_alloca(
2830 (sizeof(ffi_type*) + sizeof(ffi_type)) * EX_NUM_ARGS(), arg_types_use_heap);
2831 arg_values = do_alloca(
2832 (sizeof(void*) + ZEND_FFI_SIZEOF_ARG) * EX_NUM_ARGS(), arg_values_use_heap);
2833 n = 0;
2834 if (type->func.args) {
2835 ZEND_HASH_PACKED_FOREACH_PTR(type->func.args, arg_type) {
2836 arg_type = ZEND_FFI_TYPE(arg_type);
2837 arg_values[n] = ((char*)arg_values) + (sizeof(void*) * EX_NUM_ARGS()) + (ZEND_FFI_SIZEOF_ARG * n);
2838 if (zend_ffi_pass_arg(EX_VAR_NUM(n), arg_type, &arg_types[n], arg_values, n, execute_data) == FAILURE) {
2839 free_alloca(arg_types, arg_types_use_heap);
2840 free_alloca(arg_values, arg_values_use_heap);
2841 goto exit;
2842 }
2843 n++;
2845 }
2846 }
2847 ret_type = zend_ffi_get_type(ZEND_FFI_TYPE(type->func.ret_type));
2848 if (!ret_type) {
2849 zend_ffi_return_unsupported(type->func.ret_type);
2850 free_alloca(arg_types, arg_types_use_heap);
2851 free_alloca(arg_values, arg_values_use_heap);
2852 goto exit;
2853 }
2854 if (ffi_prep_cif(&cif, type->func.abi, arg_count, ret_type, arg_types) != FFI_OK) {
2855 zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback CIF");
2856 free_alloca(arg_types, arg_types_use_heap);
2857 free_alloca(arg_values, arg_values_use_heap);
2858 goto exit;
2859 }
2860 }
2861
2862 ret = do_alloca(MAX(ret_type->size, sizeof(ffi_arg)), ret_use_heap);
2863 ffi_call(&cif, addr, ret, arg_values);
2864
2865 for (n = 0; n < arg_count; n++) {
2866 if (arg_types[n]->type == FFI_TYPE_STRUCT) {
2867 efree(arg_types[n]);
2868 }
2869 }
2870 if (ret_type->type == FFI_TYPE_STRUCT) {
2871 efree(ret_type);
2872 }
2873
2874 if (EX_NUM_ARGS()) {
2875 free_alloca(arg_types, arg_types_use_heap);
2876 free_alloca(arg_values, arg_values_use_heap);
2877 }
2878
2879 if (ZEND_FFI_TYPE(type->func.ret_type)->kind != ZEND_FFI_TYPE_VOID) {
2880 zend_ffi_type *func_ret_type = ZEND_FFI_TYPE(type->func.ret_type);
2881
2882#ifdef WORDS_BIGENDIAN
2883 if (func_ret_type->size < sizeof(ffi_arg)
2884 && func_ret_type->kind >= ZEND_FFI_TYPE_UINT8
2885 && func_ret_type->kind < ZEND_FFI_TYPE_POINTER) {
2886
2887 /* We need to narrow the value (truncate) */
2888 switch (func_ret_type->size) {
2889 case 1:
2890 *(uint8_t*)ret = *(ffi_arg*)ret;
2891 break;
2892 case 2:
2893 *(uint16_t*)ret = *(ffi_arg*)ret;
2894 break;
2895 case 4:
2896 *(uint32_t*)ret = *(ffi_arg*)ret;
2897 break;
2898 default:
2899 break;
2900 }
2901 }
2902#endif
2903
2904 zend_ffi_cdata_to_zval(NULL, ret, func_ret_type, BP_VAR_R, return_value, 0, 1, 0);
2905 } else {
2907 }
2908 free_alloca(ret, ret_use_heap);
2909
2910exit:
2911 zend_string_release(EX(func)->common.function_name);
2912 if (EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
2914 EX(func) = NULL;
2915 }
2916}
2917/* }}} */
2918
2919static zend_function *zend_ffi_get_func(zend_object **obj, zend_string *name, const zval *key) /* {{{ */
2920{
2921 zend_ffi *ffi = (zend_ffi*)*obj;
2922 zend_ffi_symbol *sym = NULL;
2925
2926 if (ZSTR_LEN(name) == sizeof("new") -1
2927 && (ZSTR_VAL(name)[0] == 'n' || ZSTR_VAL(name)[0] == 'N')
2928 && (ZSTR_VAL(name)[1] == 'e' || ZSTR_VAL(name)[1] == 'E')
2929 && (ZSTR_VAL(name)[2] == 'w' || ZSTR_VAL(name)[2] == 'W')) {
2930 return (zend_function*)&zend_ffi_new_fn;
2931 } else if (ZSTR_LEN(name) == sizeof("cast") -1
2932 && (ZSTR_VAL(name)[0] == 'c' || ZSTR_VAL(name)[0] == 'C')
2933 && (ZSTR_VAL(name)[1] == 'a' || ZSTR_VAL(name)[1] == 'A')
2934 && (ZSTR_VAL(name)[2] == 's' || ZSTR_VAL(name)[2] == 'S')
2935 && (ZSTR_VAL(name)[3] == 't' || ZSTR_VAL(name)[3] == 'T')) {
2936 return (zend_function*)&zend_ffi_cast_fn;
2937 } else if (ZSTR_LEN(name) == sizeof("type") -1
2938 && (ZSTR_VAL(name)[0] == 't' || ZSTR_VAL(name)[0] == 'T')
2939 && (ZSTR_VAL(name)[1] == 'y' || ZSTR_VAL(name)[1] == 'Y')
2940 && (ZSTR_VAL(name)[2] == 'p' || ZSTR_VAL(name)[2] == 'P')
2941 && (ZSTR_VAL(name)[3] == 'e' || ZSTR_VAL(name)[3] == 'E')) {
2942 return (zend_function*)&zend_ffi_type_fn;
2943 }
2944
2945 if (ffi->symbols) {
2946 sym = zend_hash_find_ptr(ffi->symbols, name);
2947 if (sym && sym->kind != ZEND_FFI_SYM_FUNC) {
2948 sym = NULL;
2949 }
2950 }
2951 if (!sym) {
2952 zend_throw_error(zend_ffi_exception_ce, "Attempt to call undefined C function '%s'", ZSTR_VAL(name));
2953 return NULL;
2954 }
2955
2956 type = ZEND_FFI_TYPE(sym->type);
2958
2959 if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
2960 func = &EG(trampoline);
2961 } else {
2962 func = ecalloc(1, sizeof(zend_internal_function));
2963 }
2964 func->common.type = ZEND_INTERNAL_FUNCTION;
2965 func->common.arg_flags[0] = 0;
2966 func->common.arg_flags[1] = 0;
2967 func->common.arg_flags[2] = 0;
2968 func->common.fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE;
2969 func->common.function_name = zend_string_copy(name);
2970 /* set to 0 to avoid arg_info[] allocation, because all values are passed by value anyway */
2971 func->common.num_args = 0;
2972 func->common.required_num_args = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
2973 func->common.scope = NULL;
2974 func->common.prototype = NULL;
2975 func->common.arg_info = NULL;
2976 func->internal_function.handler = ZEND_FN(ffi_trampoline);
2977 func->internal_function.module = NULL;
2978 func->internal_function.doc_comment = NULL;
2979
2980 func->internal_function.reserved[0] = type;
2981 func->internal_function.reserved[1] = sym->addr;
2982
2983 return func;
2984}
2985/* }}} */
2986
2987static int zend_fake_compare_objects(zval *o1, zval *o2)
2988{
2989 zend_throw_error(zend_ffi_exception_ce, "Cannot compare FFI objects");
2990 return ZEND_UNCOMPARABLE;
2991}
2992
2993static zend_never_inline int zend_ffi_disabled(void) /* {{{ */
2994{
2995 zend_throw_error(zend_ffi_exception_ce, "FFI API is restricted by \"ffi.enable\" configuration directive");
2996 return 0;
2997}
2998/* }}} */
2999
3000static zend_always_inline bool zend_ffi_validate_api_restriction(zend_execute_data *execute_data) /* {{{ */
3001{
3004 if (FFI_G(is_cli)
3005 || (execute_data->prev_execute_data
3006 && (execute_data->prev_execute_data->func->common.fn_flags & ZEND_ACC_PRELOADED))
3007 || (CG(compiler_options) & ZEND_COMPILE_PRELOAD)) {
3008 return 1;
3009 }
3010 } else if (EXPECTED(FFI_G(restriction) == ZEND_FFI_ENABLED)) {
3011 return 1;
3012 }
3013 return zend_ffi_disabled();
3014}
3015/* }}} */
3016
3017#define ZEND_FFI_VALIDATE_API_RESTRICTION() do { \
3018 if (UNEXPECTED(!zend_ffi_validate_api_restriction(execute_data))) { \
3019 RETURN_THROWS(); \
3020 } \
3021 } while (0)
3022
3023ZEND_METHOD(FFI, cdef) /* {{{ */
3024{
3025 zend_string *code = NULL;
3029 char *err;
3030 void *addr;
3031
3035 Z_PARAM_STR(code)
3038
3040 handle = DL_LOAD(ZSTR_VAL(lib));
3041 if (!handle) {
3042 err = GET_DL_ERROR();
3043#ifdef PHP_WIN32
3044 if (err && err[0]) {
3045 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", ZSTR_VAL(lib), err);
3047 } else {
3048 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (Unknown reason)", ZSTR_VAL(lib));
3049 }
3050#else
3051 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", ZSTR_VAL(lib), err);
3052 GET_DL_ERROR(); /* free the buffer storing the error */
3053#endif
3054 RETURN_THROWS();
3055 }
3056
3057#ifdef RTLD_DEFAULT
3058 } else if (1) {
3059 // TODO: this might need to be disabled or protected ???
3061#endif
3062 }
3063
3066
3067 if (code && ZSTR_LEN(code)) {
3068 /* Parse C definitions */
3070
3071 if (zend_ffi_parse_decl(ZSTR_VAL(code), ZSTR_LEN(code)) == FAILURE) {
3072 if (FFI_G(symbols)) {
3075 FFI_G(symbols) = NULL;
3076 }
3077 if (FFI_G(tags)) {
3079 efree(FFI_G(tags));
3080 FFI_G(tags) = NULL;
3081 }
3082 RETURN_THROWS();
3083 }
3084
3085 if (FFI_G(symbols)) {
3087 zend_ffi_symbol *sym;
3088
3090 if (sym->kind == ZEND_FFI_SYM_VAR) {
3091 addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
3092 if (!addr) {
3093 zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name));
3094 RETURN_THROWS();
3095 }
3096 sym->addr = addr;
3097 } else if (sym->kind == ZEND_FFI_SYM_FUNC) {
3098 zend_string *mangled_name = zend_ffi_mangled_func_name(name, ZEND_FFI_TYPE(sym->type));
3099
3100 addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(mangled_name));
3101 zend_string_release(mangled_name);
3102 if (!addr) {
3103 zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
3104 RETURN_THROWS();
3105 }
3106 sym->addr = addr;
3107 }
3109 }
3110 }
3111
3112 ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3113 ffi->lib = handle;
3114 ffi->symbols = FFI_G(symbols);
3115 ffi->tags = FFI_G(tags);
3116
3117 FFI_G(symbols) = NULL;
3118 FFI_G(tags) = NULL;
3119
3120 RETURN_OBJ(&ffi->std);
3121}
3122/* }}} */
3123
3124static bool zend_ffi_same_types(zend_ffi_type *old, zend_ffi_type *type) /* {{{ */
3125{
3126 if (old == type) {
3127 return 1;
3128 }
3129
3130 if (old->kind != type->kind
3131 || old->size != type->size
3132 || old->align != type->align
3133 || old->attr != type->attr) {
3134 return 0;
3135 }
3136
3137 switch (old->kind) {
3138 case ZEND_FFI_TYPE_ENUM:
3139 return old->enumeration.kind == type->enumeration.kind;
3141 return old->array.length == type->array.length
3142 && zend_ffi_same_types(ZEND_FFI_TYPE(old->array.type), ZEND_FFI_TYPE(type->array.type));
3144 return zend_ffi_same_types(ZEND_FFI_TYPE(old->pointer.type), ZEND_FFI_TYPE(type->pointer.type));
3146 if (zend_hash_num_elements(&old->record.fields) != zend_hash_num_elements(&type->record.fields)) {
3147 return 0;
3148 } else {
3149 zend_ffi_field *old_field, *field;
3151 Bucket *b = type->record.fields.arData;
3152
3154 while (Z_TYPE(b->val) == IS_UNDEF) {
3155 b++;
3156 }
3157 if (key) {
3158 if (!b->key
3159 || !zend_string_equals(key, b->key)) {
3160 return 0;
3161 }
3162 } else if (b->key) {
3163 return 0;
3164 }
3165 field = Z_PTR(b->val);
3166 if (old_field->offset != field->offset
3167 || old_field->is_const != field->is_const
3168 || old_field->is_nested != field->is_nested
3169 || old_field->first_bit != field->first_bit
3170 || old_field->bits != field->bits
3171 || !zend_ffi_same_types(ZEND_FFI_TYPE(old_field->type), ZEND_FFI_TYPE(field->type))) {
3172 return 0;
3173 }
3174 b++;
3176 }
3177 break;
3178 case ZEND_FFI_TYPE_FUNC:
3179 if (old->func.abi != type->func.abi
3180 || ((old->func.args ? zend_hash_num_elements(old->func.args) : 0) != (type->func.args ? zend_hash_num_elements(type->func.args) : 0))
3181 || !zend_ffi_same_types(ZEND_FFI_TYPE(old->func.ret_type), ZEND_FFI_TYPE(type->func.ret_type))) {
3182 return 0;
3183 } else if (old->func.args) {
3184 zend_ffi_type *arg_type;
3185 zval *zv = type->func.args->arPacked;
3186
3187 ZEND_HASH_PACKED_FOREACH_PTR(old->func.args, arg_type) {
3188 while (Z_TYPE_P(zv) == IS_UNDEF) {
3189 zv++;
3190 }
3191 if (!zend_ffi_same_types(ZEND_FFI_TYPE(arg_type), ZEND_FFI_TYPE(Z_PTR_P(zv)))) {
3192 return 0;
3193 }
3194 zv++;
3196 }
3197 break;
3198 default:
3199 break;
3200 }
3201
3202 return 1;
3203}
3204/* }}} */
3205
3206static bool zend_ffi_same_symbols(zend_ffi_symbol *old, zend_ffi_symbol *sym) /* {{{ */
3207{
3208 if (old->kind != sym->kind || old->is_const != sym->is_const) {
3209 return 0;
3210 }
3211
3212 if (old->kind == ZEND_FFI_SYM_CONST) {
3213 if (old->value != sym->value) {
3214 return 0;
3215 }
3216 }
3217
3218 return zend_ffi_same_types(ZEND_FFI_TYPE(old->type), ZEND_FFI_TYPE(sym->type));
3219}
3220/* }}} */
3221
3222static bool zend_ffi_same_tags(zend_ffi_tag *old, zend_ffi_tag *tag) /* {{{ */
3223{
3224 if (old->kind != tag->kind) {
3225 return 0;
3226 }
3227
3228 return zend_ffi_same_types(ZEND_FFI_TYPE(old->type), ZEND_FFI_TYPE(tag->type));
3229}
3230/* }}} */
3231
3232static bool zend_ffi_subst_old_type(zend_ffi_type **dcl, zend_ffi_type *old, zend_ffi_type *type) /* {{{ */
3233{
3234 zend_ffi_type *dcl_type;
3235 zend_ffi_field *field;
3236
3237 if (ZEND_FFI_TYPE(*dcl) == type) {
3238 *dcl = old;
3239 return 1;
3240 }
3241 dcl_type = *dcl;
3242 switch (dcl_type->kind) {
3244 return zend_ffi_subst_old_type(&dcl_type->pointer.type, old, type);
3246 return zend_ffi_subst_old_type(&dcl_type->array.type, old, type);
3247 case ZEND_FFI_TYPE_FUNC:
3248 if (zend_ffi_subst_old_type(&dcl_type->func.ret_type, old, type)) {
3249 return 1;
3250 }
3251 if (dcl_type->func.args) {
3252 zval *zv;
3253
3255 if (zend_ffi_subst_old_type((zend_ffi_type**)&Z_PTR_P(zv), old, type)) {
3256 return 1;
3257 }
3259 }
3260 break;
3262 ZEND_HASH_MAP_FOREACH_PTR(&dcl_type->record.fields, field) {
3263 if (zend_ffi_subst_old_type(&field->type, old, type)) {
3264 return 1;
3265 }
3267 break;
3268 default:
3269 break;
3270 }
3271 return 0;
3272} /* }}} */
3273
3274static void zend_ffi_cleanup_type(zend_ffi_type *old, zend_ffi_type *type) /* {{{ */
3275{
3276 zend_ffi_symbol *sym;
3277 zend_ffi_tag *tag;
3278
3279 if (FFI_G(symbols)) {
3281 zend_ffi_subst_old_type(&sym->type, old, type);
3283 }
3284 if (FFI_G(tags)) {
3286 zend_ffi_subst_old_type(&tag->type, old, type);
3288 }
3289}
3290/* }}} */
3291
3292static zend_ffi_type *zend_ffi_remember_type(zend_ffi_type *type) /* {{{ */
3293{
3294 if (!FFI_G(weak_types)) {
3295 FFI_G(weak_types) = emalloc(sizeof(HashTable));
3296 zend_hash_init(FFI_G(weak_types), 0, NULL, zend_ffi_type_hash_dtor, 0);
3297 }
3298 // TODO: avoid dups ???
3299 type->attr |= ZEND_FFI_ATTR_STORED;
3300 zend_hash_next_index_insert_ptr(FFI_G(weak_types), ZEND_FFI_TYPE_MAKE_OWNED(type));
3301 return type;
3302}
3303/* }}} */
3304
3305static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */
3306{
3307 struct stat buf;
3308 int fd;
3309 char *code, *code_pos, *scope_name, *lib, *err;
3310 size_t code_size, scope_name_len;
3311 zend_ffi *ffi;
3315 zend_ffi_symbol *sym;
3316 zend_ffi_tag *tag;
3317 void *addr;
3318
3319 if (stat(filename, &buf) != 0) {
3320 if (preload) {
3321 zend_error(E_WARNING, "FFI: failed pre-loading '%s', file doesn't exist", filename);
3322 } else {
3323 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', file doesn't exist", filename);
3324 }
3325 return NULL;
3326 }
3327
3328 if ((buf.st_mode & S_IFMT) != S_IFREG) {
3329 if (preload) {
3330 zend_error(E_WARNING, "FFI: failed pre-loading '%s', not a regular file", filename);
3331 } else {
3332 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', not a regular file", filename);
3333 }
3334 return NULL;
3335 }
3336
3337 code_size = buf.st_size;
3338 code = emalloc(code_size + 1);
3339 int open_flags = O_RDONLY;
3340#ifdef PHP_WIN32
3341 open_flags |= _O_BINARY;
3342#endif
3343 fd = open(filename, open_flags, 0);
3344 if (fd < 0 || read(fd, code, code_size) != code_size) {
3345 if (preload) {
3346 zend_error(E_WARNING, "FFI: Failed pre-loading '%s', cannot read_file", filename);
3347 } else {
3348 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', cannot read_file", filename);
3349 }
3350 efree(code);
3351 close(fd);
3352 return NULL;
3353 }
3354 close(fd);
3355 code[code_size] = 0;
3356
3357 FFI_G(symbols) = NULL;
3358 FFI_G(tags) = NULL;
3363
3364 scope_name = NULL;
3365 scope_name_len = 0;
3366 lib = NULL;
3367 code_pos = zend_ffi_parse_directives(filename, code, &scope_name, &lib, preload);
3368 if (!code_pos) {
3369 efree(code);
3370 FFI_G(persistent) = 0;
3371 return NULL;
3372 }
3373 code_size -= code_pos - code;
3374
3375 if (zend_ffi_parse_decl(code_pos, code_size) == FAILURE) {
3376 if (preload) {
3377 zend_error(E_WARNING, "FFI: failed pre-loading '%s'", filename);
3378 } else {
3379 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", filename);
3380 }
3381 goto cleanup;
3382 }
3383
3384 if (lib) {
3385 handle = DL_LOAD(lib);
3386 if (!handle) {
3387 if (preload) {
3388 zend_error(E_WARNING, "FFI: Failed pre-loading '%s'", lib);
3389 } else {
3390 err = GET_DL_ERROR();
3391#ifdef PHP_WIN32
3392 if (err && err[0]) {
3393 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err);
3395 } else {
3396 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (Unknown reason)", lib);
3397 }
3398#else
3399 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err);
3400 GET_DL_ERROR(); /* free the buffer storing the error */
3401#endif
3402 }
3403 goto cleanup;
3404 }
3405#ifdef RTLD_DEFAULT
3406 } else if (1) {
3407 // TODO: this might need to be disabled or protected ???
3409#endif
3410 }
3411
3412 if (preload) {
3413 if (!scope_name) {
3414 scope_name = "C";
3415 }
3416 scope_name_len = strlen(scope_name);
3417 if (FFI_G(scopes)) {
3418 scope = zend_hash_str_find_ptr(FFI_G(scopes), scope_name, scope_name_len);
3419 }
3420 }
3421
3422 if (FFI_G(symbols)) {
3424 if (sym->kind == ZEND_FFI_SYM_VAR) {
3425 addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
3426 if (!addr) {
3427 if (preload) {
3428 zend_error(E_WARNING, "FFI: failed pre-loading '%s', cannot resolve C variable '%s'", filename, ZSTR_VAL(name));
3429 } else {
3430 zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name));
3431 }
3432 if (lib) {
3433 DL_UNLOAD(handle);
3434 }
3435 goto cleanup;
3436 }
3437 sym->addr = addr;
3438 } else if (sym->kind == ZEND_FFI_SYM_FUNC) {
3439 zend_string *mangled_name = zend_ffi_mangled_func_name(name, ZEND_FFI_TYPE(sym->type));
3440
3441 addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(mangled_name));
3442 zend_string_release(mangled_name);
3443 if (!addr) {
3444 if (preload) {
3445 zend_error(E_WARNING, "failed pre-loading '%s', cannot resolve C function '%s'", filename, ZSTR_VAL(name));
3446 } else {
3447 zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
3448 }
3449 if (lib) {
3450 DL_UNLOAD(handle);
3451 }
3452 goto cleanup;
3453 }
3454 sym->addr = addr;
3455 }
3456 if (scope && scope->symbols) {
3457 zend_ffi_symbol *old_sym = zend_hash_find_ptr(scope->symbols, name);
3458
3459 if (old_sym) {
3460 if (zend_ffi_same_symbols(old_sym, sym)) {
3462 && ZEND_FFI_TYPE(old_sym->type) != ZEND_FFI_TYPE(sym->type)) {
3464 zend_ffi_cleanup_type(ZEND_FFI_TYPE(old_sym->type), ZEND_FFI_TYPE(type));
3465 zend_ffi_type_dtor(type);
3466 }
3467 } else {
3468 zend_error(E_WARNING, "FFI: failed pre-loading '%s', redefinition of '%s'", filename, ZSTR_VAL(name));
3469 if (lib) {
3470 DL_UNLOAD(handle);
3471 }
3472 goto cleanup;
3473 }
3474 }
3475 }
3477 }
3478
3479 if (preload) {
3480 if (scope && scope->tags && FFI_G(tags)) {
3482 zend_ffi_tag *old_tag = zend_hash_find_ptr(scope->tags, name);
3483
3484 if (old_tag) {
3485 if (zend_ffi_same_tags(old_tag, tag)) {
3487 && ZEND_FFI_TYPE(old_tag->type) != ZEND_FFI_TYPE(tag->type)) {
3489 zend_ffi_cleanup_type(ZEND_FFI_TYPE(old_tag->type), ZEND_FFI_TYPE(type));
3490 zend_ffi_type_dtor(type);
3491 }
3492 } else {
3493 zend_error(E_WARNING, "FFI: failed pre-loading '%s', redefinition of '%s %s'", filename, zend_ffi_tag_kind_name[tag->kind], ZSTR_VAL(name));
3494 if (lib) {
3495 DL_UNLOAD(handle);
3496 }
3497 goto cleanup;
3498 }
3499 }
3501 }
3502
3503 if (!scope) {
3504 scope = malloc(sizeof(zend_ffi_scope));
3505 scope->symbols = FFI_G(symbols);
3506 scope->tags = FFI_G(tags);
3507
3508 if (!FFI_G(scopes)) {
3509 FFI_G(scopes) = malloc(sizeof(HashTable));
3510 zend_hash_init(FFI_G(scopes), 0, NULL, zend_ffi_scope_hash_dtor, 1);
3511 }
3512
3513 zend_hash_str_add_ptr(FFI_G(scopes), scope_name, scope_name_len, scope);
3514 } else {
3515 if (FFI_G(symbols)) {
3516 if (!scope->symbols) {
3517 scope->symbols = FFI_G(symbols);
3518 FFI_G(symbols) = NULL;
3519 } else {
3521 if (!zend_hash_add_ptr(scope->symbols, name, sym)) {
3522 zend_ffi_type_dtor(sym->type);
3523 free(sym);
3524 }
3526 FFI_G(symbols)->pDestructor = NULL;
3528 }
3529 }
3530 if (FFI_G(tags)) {
3531 if (!scope->tags) {
3532 scope->tags = FFI_G(tags);
3533 FFI_G(tags) = NULL;
3534 } else {
3536 if (!zend_hash_add_ptr(scope->tags, name, tag)) {
3537 zend_ffi_type_dtor(tag->type);
3538 free(tag);
3539 }
3541 FFI_G(tags)->pDestructor = NULL;
3543 }
3544 }
3545 }
3546
3547 if (EG(objects_store).object_buckets) {
3548 ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3549 } else {
3550 ffi = ecalloc(1, sizeof(zend_ffi));
3551 }
3552 ffi->symbols = scope->symbols;
3553 ffi->tags = scope->tags;
3554 ffi->persistent = 1;
3555 } else {
3556 ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3557 ffi->lib = handle;
3558 ffi->symbols = FFI_G(symbols);
3559 ffi->tags = FFI_G(tags);
3560 }
3561
3562 efree(code);
3563 FFI_G(symbols) = NULL;
3564 FFI_G(tags) = NULL;
3565 FFI_G(persistent) = 0;
3566
3567 return ffi;
3568
3569cleanup:
3570 efree(code);
3571 if (FFI_G(symbols)) {
3574 FFI_G(symbols) = NULL;
3575 }
3576 if (FFI_G(tags)) {
3579 FFI_G(tags) = NULL;
3580 }
3581 FFI_G(persistent) = 0;
3582 return NULL;
3583}
3584/* }}} */
3585
3586ZEND_METHOD(FFI, load) /* {{{ */
3587{
3588 zend_string *fn;
3589 zend_ffi *ffi;
3590
3593 Z_PARAM_STR(fn)
3595
3596 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD_IN_CHILD) {
3597 zend_throw_error(zend_ffi_exception_ce, "FFI::load() doesn't work in conjunction with \"opcache.preload_user\". Use \"ffi.preload\" instead.");
3598 RETURN_THROWS();
3599 }
3600
3601 ffi = zend_ffi_load(ZSTR_VAL(fn), (CG(compiler_options) & ZEND_COMPILE_PRELOAD) != 0);
3602
3603 if (ffi) {
3604 RETURN_OBJ(&ffi->std);
3605 }
3606}
3607/* }}} */
3608
3609ZEND_METHOD(FFI, scope) /* {{{ */
3610{
3611 zend_string *scope_name;
3613 zend_ffi *ffi;
3614
3617 Z_PARAM_STR(scope_name)
3619
3621 scope = zend_hash_find_ptr(FFI_G(scopes), scope_name);
3622 }
3623
3624 if (!scope) {
3625 zend_throw_error(zend_ffi_exception_ce, "Failed loading scope '%s'", ZSTR_VAL(scope_name));
3626 RETURN_THROWS();
3627 }
3628
3629 ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3630
3631 ffi->symbols = scope->symbols;
3632 ffi->tags = scope->tags;
3633 ffi->persistent = 1;
3634
3635 RETURN_OBJ(&ffi->std);
3636}
3637/* }}} */
3638
3640{
3641 if (dcl) {
3642 zend_ffi_type_dtor(dcl->type);
3643 dcl->type = NULL;
3644 }
3645}
3646/* }}} */
3647
3648static void zend_ffi_throw_parser_error(const char *format, ...) /* {{{ */
3649{
3650 va_list va;
3651 char *message = NULL;
3652
3653 va_start(va, format);
3654 zend_vspprintf(&message, 0, format, va);
3655
3656 if (EG(current_execute_data)) {
3657 zend_throw_exception(zend_ffi_parser_exception_ce, message, 0);
3658 } else {
3659 zend_error(E_WARNING, "FFI Parser: %s", message);
3660 }
3661
3662 efree(message);
3663 va_end(va);
3664}
3665/* }}} */
3666
3667static zend_result zend_ffi_validate_vla(zend_ffi_type *type) /* {{{ */
3668{
3669 if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) {
3670 zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line));
3671 return FAILURE;
3672 }
3673 return SUCCESS;
3674}
3675/* }}} */
3676
3677static zend_result zend_ffi_validate_incomplete_type(zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */
3678{
3679 if (!allow_incomplete_tag && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
3680 if (FFI_G(tags)) {
3682 zend_ffi_tag *tag;
3683
3685 if (ZEND_FFI_TYPE(tag->type) == type) {
3686 if (type->kind == ZEND_FFI_TYPE_ENUM) {
3687 zend_ffi_throw_parser_error("Incomplete enum \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3688 } else if (type->attr & ZEND_FFI_ATTR_UNION) {
3689 zend_ffi_throw_parser_error("Incomplete union \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3690 } else {
3691 zend_ffi_throw_parser_error("Incomplete struct \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3692 }
3693 return FAILURE;
3694 }
3696 }
3697 if (FFI_G(symbols)) {
3699 zend_ffi_symbol *sym;
3700
3702 if (type == ZEND_FFI_TYPE(sym->type)) {
3703 zend_ffi_throw_parser_error("Incomplete C type %s at line %d", ZSTR_VAL(key), FFI_G(line));
3704 return FAILURE;
3705 }
3707 }
3708 zend_ffi_throw_parser_error("Incomplete type at line %d", FFI_G(line));
3709 return FAILURE;
3710 } else if (!allow_incomplete_array && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
3711 zend_ffi_throw_parser_error("\"[]\" is not allowed at line %d", FFI_G(line));
3712 return FAILURE;
3713 } else if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) {
3714 zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line));
3715 return FAILURE;
3716 }
3717 return SUCCESS;
3718}
3719/* }}} */
3720
3721static zend_result zend_ffi_validate_type(zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */
3722{
3723 if (type->kind == ZEND_FFI_TYPE_VOID) {
3724 zend_ffi_throw_parser_error("void type is not allowed at line %d", FFI_G(line));
3725 return FAILURE;
3726 }
3727 return zend_ffi_validate_incomplete_type(type, allow_incomplete_tag, allow_incomplete_array);
3728}
3729/* }}} */
3730
3731static zend_result zend_ffi_validate_var_type(zend_ffi_type *type, bool allow_incomplete_array) /* {{{ */
3732{
3733 if (type->kind == ZEND_FFI_TYPE_FUNC) {
3734 zend_ffi_throw_parser_error("function type is not allowed at line %d", FFI_G(line));
3735 return FAILURE;
3736 }
3737 return zend_ffi_validate_type(type, 0, allow_incomplete_array);
3738}
3739/* }}} */
3740
3742{
3743 zend_ffi_finalize_type(dcl);
3744 if (zend_ffi_validate_var_type(ZEND_FFI_TYPE(dcl->type), 0) == FAILURE) {
3747 }
3748}
3749/* }}} */
3750
3751static bool zend_ffi_subst_type(zend_ffi_type **dcl, zend_ffi_type *type) /* {{{ */
3752{
3753 zend_ffi_type *dcl_type;
3754 zend_ffi_field *field;
3755
3756 if (*dcl == type) {
3758 return 1;
3759 }
3760 dcl_type = *dcl;
3761 switch (dcl_type->kind) {
3763 return zend_ffi_subst_type(&dcl_type->pointer.type, type);
3765 return zend_ffi_subst_type(&dcl_type->array.type, type);
3766 case ZEND_FFI_TYPE_FUNC:
3767 if (zend_ffi_subst_type(&dcl_type->func.ret_type, type)) {
3768 return 1;
3769 }
3770 if (dcl_type->func.args) {
3771 zval *zv;
3772
3774 if (zend_ffi_subst_type((zend_ffi_type**)&Z_PTR_P(zv), type)) {
3775 return 1;
3776 }
3778 }
3779 break;
3781 ZEND_HASH_MAP_FOREACH_PTR(&dcl_type->record.fields, field) {
3782 if (zend_ffi_subst_type(&field->type, type)) {
3783 return 1;
3784 }
3786 break;
3787 default:
3788 break;
3789 }
3790 return 0;
3791} /* }}} */
3792
3793static void zend_ffi_tags_cleanup(zend_ffi_dcl *dcl) /* {{{ */
3794{
3795 zend_ffi_tag *tag;
3797 if (ZEND_FFI_TYPE_IS_OWNED(tag->type)) {
3799 zend_ffi_subst_type(&dcl->type, type);
3800 tag->type = type;
3801 }
3804 efree(FFI_G(tags));
3805}
3806/* }}} */
3807
3808ZEND_METHOD(FFI, new) /* {{{ */
3809{
3814 void *ptr;
3815 bool owned = 1;
3816 bool persistent = 0;
3817 bool is_const = 0;
3820
3823 Z_PARAM_OBJ_OF_CLASS_OR_STR(type_obj, zend_ffi_ctype_ce, type_def)
3828
3830 zend_error(E_DEPRECATED, "Calling FFI::new() statically is deprecated");
3831 if (EG(exception)) {
3832 RETURN_THROWS();
3833 }
3834 }
3835
3836 if (!owned) {
3838 }
3839
3843
3846
3847 if (!is_static_call) {
3848 zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
3849 FFI_G(symbols) = ffi->symbols;
3850 FFI_G(tags) = ffi->tags;
3851 } else {
3852 FFI_G(symbols) = NULL;
3853 FFI_G(tags) = NULL;
3854 }
3855 bool clean_symbols = FFI_G(symbols) == NULL;
3856 bool clean_tags = FFI_G(tags) == NULL;
3857
3859
3861 zend_ffi_type_dtor(dcl.type);
3862 if (clean_tags && FFI_G(tags)) {
3864 efree(FFI_G(tags));
3865 FFI_G(tags) = NULL;
3866 }
3867 if (clean_symbols && FFI_G(symbols)) {
3870 FFI_G(symbols) = NULL;
3871 }
3872 return;
3873 }
3874
3875 type = ZEND_FFI_TYPE(dcl.type);
3876 if (dcl.attr & ZEND_FFI_ATTR_CONST) {
3877 is_const = 1;
3878 }
3879
3880 if (clean_tags && FFI_G(tags)) {
3881 zend_ffi_tags_cleanup(&dcl);
3882 }
3883 if (clean_symbols && FFI_G(symbols)) {
3886 FFI_G(symbols) = NULL;
3887 }
3888 FFI_G(symbols) = NULL;
3889 FFI_G(tags) = NULL;
3890
3891 type_ptr = dcl.type;
3892 } else {
3894
3895 type_ptr = type = ctype->type;
3898 if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
3899 if (GC_REFCOUNT(&ctype->std) == 1) {
3900 /* transfer type ownership */
3901 ctype->type = type;
3902 } else {
3903 ctype->type = type_ptr = type = zend_ffi_remember_type(type);
3904 }
3905 }
3906 }
3907 }
3908
3909 if (type->size == 0) {
3910 zend_throw_error(zend_ffi_exception_ce, "Cannot instantiate FFI\\CData of zero size");
3911 zend_ffi_type_dtor(type_ptr);
3912 return;
3913 }
3914
3916 memset(ptr, 0, type->size);
3917
3918 cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
3920 cdata->std.handlers = &zend_ffi_cdata_value_handlers;
3921 }
3922 cdata->type = type_ptr;
3923 cdata->ptr = ptr;
3924 cdata->flags = flags;
3926 cdata->flags |= ZEND_FFI_FLAG_CONST;
3927 }
3928
3929 RETURN_OBJ(&cdata->std);
3930}
3931/* }}} */
3932
3933ZEND_METHOD(FFI, free) /* {{{ */
3934{
3935 zval *zv;
3937
3940 Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
3942
3944
3946 if (!cdata->ptr) {
3947 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
3948 RETURN_THROWS();
3949 }
3950 if (cdata->ptr != (void*)&cdata->ptr_holder) {
3951 pefree(*(void**)cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
3952 } else {
3953 pefree(cdata->ptr_holder, (cdata->flags & ZEND_FFI_FLAG_PERSISTENT) || !is_zend_ptr(cdata->ptr_holder));
3954 }
3955 *(void**)cdata->ptr = NULL;
3956 } else if (!(cdata->flags & ZEND_FFI_FLAG_OWNED)) {
3957 pefree(cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
3958 cdata->ptr = NULL;
3959 cdata->flags &= ~(ZEND_FFI_FLAG_OWNED|ZEND_FFI_FLAG_PERSISTENT);
3960 cdata->std.handlers = &zend_ffi_cdata_free_handlers;
3961 } else {
3962 zend_throw_error(zend_ffi_exception_ce, "free() non a C pointer");
3963 }
3964}
3965/* }}} */
3966
3967ZEND_METHOD(FFI, cast) /* {{{ */
3968{
3973 bool is_const = 0;
3974 bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
3976 void *ptr;
3977
3980 Z_PARAM_OBJ_OF_CLASS_OR_STR(ztype, zend_ffi_ctype_ce, type_def)
3983
3984 if (is_static_call) {
3985 zend_error(E_DEPRECATED, "Calling FFI::cast() statically is deprecated");
3986 if (EG(exception)) {
3987 RETURN_THROWS();
3988 }
3989 }
3990
3991 arg = zv;
3993
3994 if (type_def) {
3996
3997 if (!is_static_call) {
3998 zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
3999 FFI_G(symbols) = ffi->symbols;
4000 FFI_G(tags) = ffi->tags;
4001 } else {
4002 FFI_G(symbols) = NULL;
4003 FFI_G(tags) = NULL;
4004 }
4005 bool clean_symbols = FFI_G(symbols) == NULL;
4006 bool clean_tags = FFI_G(tags) == NULL;
4007
4009
4011 zend_ffi_type_dtor(dcl.type);
4012 if (clean_tags && FFI_G(tags)) {
4014 efree(FFI_G(tags));
4015 FFI_G(tags) = NULL;
4016 }
4017 if (clean_symbols && FFI_G(symbols)) {
4020 FFI_G(symbols) = NULL;
4021 }
4022 return;
4023 }
4024
4025 type = ZEND_FFI_TYPE(dcl.type);
4026 if (dcl.attr & ZEND_FFI_ATTR_CONST) {
4027 is_const = 1;
4028 }
4029
4030 if (clean_tags && FFI_G(tags)) {
4031 zend_ffi_tags_cleanup(&dcl);
4032 }
4033 if (clean_symbols && FFI_G(symbols)) {
4036 FFI_G(symbols) = NULL;
4037 }
4038 FFI_G(symbols) = NULL;
4039 FFI_G(tags) = NULL;
4040
4041 type_ptr = dcl.type;
4042 } else {
4044
4045 type_ptr = type = ctype->type;
4048 if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
4049 if (GC_REFCOUNT(&ctype->std) == 1) {
4050 /* transfer type ownership */
4051 ctype->type = type;
4052 } else {
4053 ctype->type = type_ptr = type = zend_ffi_remember_type(type);
4054 }
4055 }
4056 }
4057 }
4058
4059 if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4060 if (type->kind < ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) < IS_STRING) {
4061 /* numeric conversion */
4062 cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4063 cdata->std.handlers = &zend_ffi_cdata_value_handlers;
4064 cdata->type = type_ptr;
4065 cdata->ptr = emalloc(type->size);
4066 zend_ffi_zval_to_cdata(cdata->ptr, type, zv);
4067 cdata->flags = ZEND_FFI_FLAG_OWNED;
4068 if (is_const) {
4069 cdata->flags |= ZEND_FFI_FLAG_CONST;
4070 }
4071 RETURN_OBJ(&cdata->std);
4072 } else if (type->kind == ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) == IS_LONG) {
4073 /* number to pointer conversion */
4074 cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4075 cdata->type = type_ptr;
4076 cdata->ptr = &cdata->ptr_holder;
4077 cdata->ptr_holder = (void*)(intptr_t)Z_LVAL_P(zv);
4078 if (is_const) {
4079 cdata->flags |= ZEND_FFI_FLAG_CONST;
4080 }
4081 RETURN_OBJ(&cdata->std);
4082 } else if (type->kind == ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) == IS_NULL) {
4083 /* null -> pointer */
4084 cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4085 cdata->type = type_ptr;
4086 cdata->ptr = &cdata->ptr_holder;
4087 cdata->ptr_holder = NULL;
4088 if (is_const) {
4089 cdata->flags |= ZEND_FFI_FLAG_CONST;
4090 }
4091 RETURN_OBJ(&cdata->std);
4092 } else {
4093 zend_wrong_parameter_class_error(2, "FFI\\CData", zv);
4094 RETURN_THROWS();
4095 }
4096 }
4097
4100 ptr = old_cdata->ptr;
4101
4102 cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4103 if (type->kind < ZEND_FFI_TYPE_POINTER) {
4104 cdata->std.handlers = &zend_ffi_cdata_value_handlers;
4105 }
4106 cdata->type = type_ptr;
4107
4109 && type->kind != ZEND_FFI_TYPE_POINTER
4110 && ZEND_FFI_TYPE(old_type->pointer.type)->kind == ZEND_FFI_TYPE_VOID) {
4111 /* automatically dereference void* pointers ??? */
4112 cdata->ptr = *(void**)ptr;
4113 } else if (old_type->kind == ZEND_FFI_TYPE_ARRAY
4114 && type->kind == ZEND_FFI_TYPE_POINTER
4115 && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->array.type), ZEND_FFI_TYPE(type->pointer.type))) { cdata->ptr = &cdata->ptr_holder;
4116 cdata->ptr = &cdata->ptr_holder;
4117 cdata->ptr_holder = old_cdata->ptr;
4118 } else if (old_type->kind == ZEND_FFI_TYPE_POINTER
4119 && type->kind == ZEND_FFI_TYPE_ARRAY
4120 && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->pointer.type), ZEND_FFI_TYPE(type->array.type))) {
4121 cdata->ptr = old_cdata->ptr_holder;
4122 } else if (type->size > old_type->size) {
4123 zend_object_release(&cdata->std);
4124 zend_throw_error(zend_ffi_exception_ce, "attempt to cast to larger type");
4125 RETURN_THROWS();
4126 } else if (ptr != &old_cdata->ptr_holder) {
4127 cdata->ptr = ptr;
4128 } else {
4129 cdata->ptr = &cdata->ptr_holder;
4130 cdata->ptr_holder = old_cdata->ptr_holder;
4131 }
4132 if (is_const) {
4133 cdata->flags |= ZEND_FFI_FLAG_CONST;
4134 }
4135
4137 if (GC_REFCOUNT(&old_cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4138 /* transfer ownership */
4140 cdata->flags |= ZEND_FFI_FLAG_OWNED;
4141 } else {
4142 //???zend_throw_error(zend_ffi_exception_ce, "Attempt to cast owned C pointer");
4143 }
4144 }
4145
4146 RETURN_OBJ(&cdata->std);
4147}
4148/* }}} */
4149
4150ZEND_METHOD(FFI, type) /* {{{ */
4151{
4155 bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
4156
4161
4162 if (is_static_call) {
4163 zend_error(E_DEPRECATED, "Calling FFI::type() statically is deprecated");
4164 if (EG(exception)) {
4165 RETURN_THROWS();
4166 }
4167 }
4168
4169 if (!is_static_call) {
4170 zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
4171 FFI_G(symbols) = ffi->symbols;
4172 FFI_G(tags) = ffi->tags;
4173 } else {
4174 FFI_G(symbols) = NULL;
4175 FFI_G(tags) = NULL;
4176 }
4179
4181
4183 zend_ffi_type_dtor(dcl.type);
4184 if (clean_tags && FFI_G(tags)) {
4186 efree(FFI_G(tags));
4187 FFI_G(tags) = NULL;
4188 }
4189 if (clean_symbols && FFI_G(symbols)) {
4192 FFI_G(symbols) = NULL;
4193 }
4194 return;
4195 }
4196
4198 zend_ffi_tags_cleanup(&dcl);
4199 }
4205 FFI_G(symbols) = NULL;
4206 FFI_G(tags) = NULL;
4207
4208 ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4209 ctype->type = dcl.type;
4210
4211 RETURN_OBJ(&ctype->std);
4212}
4213/* }}} */
4214
4215ZEND_METHOD(FFI, typeof) /* {{{ */
4216{
4217 zval *zv, *arg;
4220
4225
4226 arg = zv;
4227 ZVAL_DEREF(zv);
4228 if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4230
4231 type = cdata->type;
4234 if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
4235 if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4236 /* transfer type ownership */
4237 cdata->type = type;
4239 } else {
4240 cdata->type = type = zend_ffi_remember_type(type);
4241 }
4242 }
4243 }
4244 } else {
4245 zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4247 }
4248
4249 ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4250 ctype->type = type;
4251
4252 RETURN_OBJ(&ctype->std);
4253}
4254/* }}} */
4255
4256ZEND_METHOD(FFI, arrayType) /* {{{ */
4257{
4258 zval *ztype;
4263
4266 Z_PARAM_OBJECT_OF_CLASS(ztype, zend_ffi_ctype_ce)
4269
4272
4274 zend_throw_error(zend_ffi_exception_ce, "Array of functions is not allowed");
4275 RETURN_THROWS();
4276 } else if (type->kind == ZEND_FFI_TYPE_ARRAY && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
4277 zend_throw_error(zend_ffi_exception_ce, "Only the leftmost array can be undimensioned");
4278 RETURN_THROWS();
4279 } else if (type->kind == ZEND_FFI_TYPE_VOID) {
4280 zend_throw_error(zend_ffi_exception_ce, "Array of void type is not allowed");
4281 RETURN_THROWS();
4283 zend_throw_error(zend_ffi_exception_ce, "Array of incomplete type is not allowed");
4284 RETURN_THROWS();
4285 }
4286
4288 if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
4289 if (GC_REFCOUNT(&ctype->std) == 1) {
4290 /* transfer type ownership */
4291 ctype->type = type;
4293 } else {
4294 ctype->type = type = zend_ffi_remember_type(type);
4295 }
4296 }
4297 }
4298
4300 zend_long n = zval_get_long(val);
4302
4303 if (n < 0) {
4304 zend_throw_error(zend_ffi_exception_ce, "negative array index");
4305 zend_ffi_type_dtor(type);
4306 RETURN_THROWS();
4308 zend_throw_error(zend_ffi_exception_ce, "only the leftmost array can be undimensioned");
4309 zend_ffi_type_dtor(type);
4310 RETURN_THROWS();
4311 }
4312
4313 new_type = emalloc(sizeof(zend_ffi_type));
4315 new_type->attr = 0;
4316 new_type->size = n * ZEND_FFI_TYPE(type)->size;
4317 new_type->align = ZEND_FFI_TYPE(type)->align;
4318 new_type->array.type = type;
4319 new_type->array.length = n;
4320
4321 if (n == 0) {
4323 }
4324
4327
4328 ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4329 ctype->type = type;
4330
4331 RETURN_OBJ(&ctype->std);
4332}
4333/* }}} */
4334
4335ZEND_METHOD(FFI, addr) /* {{{ */
4336{
4339 zval *zv, *arg;
4340
4345
4346 arg = zv;
4347 ZVAL_DEREF(zv);
4348 if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4349 zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4350 RETURN_THROWS();
4351 }
4352
4354 type = ZEND_FFI_TYPE(cdata->type);
4355
4356 if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1 && type->kind == ZEND_FFI_TYPE_POINTER
4357 && cdata->ptr == &cdata->ptr_holder) {
4358 zend_throw_error(zend_ffi_exception_ce, "FFI::addr() cannot create a reference to a temporary pointer");
4359 RETURN_THROWS();
4360 }
4361
4364 new_type->attr = 0;
4365 new_type->size = sizeof(void*);
4366 new_type->align = _Alignof(void*);
4367 /* life-time (source must relive the resulting pointer) ??? */
4368 new_type->pointer.type = type;
4369
4370 new_cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4372 new_cdata->ptr_holder = cdata->ptr;
4373 new_cdata->ptr = &new_cdata->ptr_holder;
4374
4375 if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4376 if (ZEND_FFI_TYPE_IS_OWNED(cdata->type)) {
4377 /* transfer type ownership */
4378 cdata->type = type;
4379 new_type->pointer.type = ZEND_FFI_TYPE_MAKE_OWNED(type);
4380 }
4381 if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
4382 /* transfer ownership */
4383 cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
4385 }
4386 }
4387
4388 RETURN_OBJ(&new_cdata->std);
4389}
4390/* }}} */
4391
4392ZEND_METHOD(FFI, sizeof) /* {{{ */
4393{
4394 zval *zv;
4396
4401
4402 ZVAL_DEREF(zv);
4403 if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4405 type = ZEND_FFI_TYPE(cdata->type);
4406 } else if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_ctype_ce) {
4408 type = ZEND_FFI_TYPE(ctype->type);
4409 } else {
4410 zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
4411 RETURN_THROWS();
4412 }
4413
4415}
4416/* }}} */
4417
4418ZEND_METHOD(FFI, alignof) /* {{{ */
4419{
4420 zval *zv;
4422
4427
4428 ZVAL_DEREF(zv);
4429 if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4431 type = ZEND_FFI_TYPE(cdata->type);
4432 } else if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_ctype_ce) {
4434 type = ZEND_FFI_TYPE(ctype->type);
4435 } else {
4436 zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
4437 RETURN_THROWS();
4438 }
4439
4440 RETURN_LONG(type->align);
4441}
4442/* }}} */
4443
4444ZEND_METHOD(FFI, memcpy) /* {{{ */
4445{
4446 zval *zv1, *zv2;
4449 void *ptr1, *ptr2;
4451
4454 Z_PARAM_OBJECT_OF_CLASS_EX(zv1, zend_ffi_cdata_ce, 0, 1);
4455 Z_PARAM_ZVAL(zv2)
4458
4459 cdata1 = (zend_ffi_cdata*)Z_OBJ_P(zv1);
4462 ptr1 = *(void**)cdata1->ptr;
4463 } else {
4464 ptr1 = cdata1->ptr;
4465 if (type1->kind != ZEND_FFI_TYPE_POINTER && size > type1->size) {
4466 zend_throw_error(zend_ffi_exception_ce, "Attempt to write over data boundary");
4467 RETURN_THROWS();
4468 }
4469 }
4470
4472 if (Z_TYPE_P(zv2) == IS_STRING) {
4473 ptr2 = Z_STRVAL_P(zv2);
4474 if (size > Z_STRLEN_P(zv2)) {
4475 zend_throw_error(zend_ffi_exception_ce, "Attempt to read over string boundary");
4476 RETURN_THROWS();
4477 }
4478 } else if (Z_TYPE_P(zv2) == IS_OBJECT && Z_OBJCE_P(zv2) == zend_ffi_cdata_ce) {
4479 cdata2 = (zend_ffi_cdata*)Z_OBJ_P(zv2);
4480 type2 = ZEND_FFI_TYPE(cdata2->type);
4481 if (type2->kind == ZEND_FFI_TYPE_POINTER) {
4482 ptr2 = *(void**)cdata2->ptr;
4483 } else {
4484 ptr2 = cdata2->ptr;
4485 if (type2->kind != ZEND_FFI_TYPE_POINTER && size > type2->size) {
4486 zend_throw_error(zend_ffi_exception_ce, "Attempt to read over data boundary");
4487 RETURN_THROWS();
4488 }
4489 }
4490 } else {
4491 zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
4492 RETURN_THROWS();
4493 }
4494
4496}
4497/* }}} */
4498
4499ZEND_METHOD(FFI, memcmp) /* {{{ */
4500{
4501 zval *zv1, *zv2;
4504 void *ptr1, *ptr2;
4506 int ret;
4507
4514
4517 ptr1 = Z_STRVAL_P(zv1);
4518 if (size > Z_STRLEN_P(zv1)) {
4519 zend_throw_error(zend_ffi_exception_ce, "attempt to read over string boundary");
4520 RETURN_THROWS();
4521 }
4522 } else if (Z_TYPE_P(zv1) == IS_OBJECT && Z_OBJCE_P(zv1) == zend_ffi_cdata_ce) {
4523 cdata1 = (zend_ffi_cdata*)Z_OBJ_P(zv1);
4524 type1 = ZEND_FFI_TYPE(cdata1->type);
4525 if (type1->kind == ZEND_FFI_TYPE_POINTER) {
4526 ptr1 = *(void**)cdata1->ptr;
4527 } else {
4528 ptr1 = cdata1->ptr;
4529 if (type1->kind != ZEND_FFI_TYPE_POINTER && size > type1->size) {
4530 zend_throw_error(zend_ffi_exception_ce, "attempt to read over data boundary");
4531 RETURN_THROWS();
4532 }
4533 }
4534 } else {
4535 zend_wrong_parameter_class_error(1, "FFI\\CData or string", zv1);
4536 RETURN_THROWS();
4537 }
4538
4539 ZVAL_DEREF(zv2);
4540 if (Z_TYPE_P(zv2) == IS_STRING) {
4541 ptr2 = Z_STRVAL_P(zv2);
4542 if (size > Z_STRLEN_P(zv2)) {
4543 zend_throw_error(zend_ffi_exception_ce, "Attempt to read over string boundary");
4544 RETURN_THROWS();
4545 }
4546 } else if (Z_TYPE_P(zv2) == IS_OBJECT && Z_OBJCE_P(zv2) == zend_ffi_cdata_ce) {
4547 cdata2 = (zend_ffi_cdata*)Z_OBJ_P(zv2);
4548 type2 = ZEND_FFI_TYPE(cdata2->type);
4549 if (type2->kind == ZEND_FFI_TYPE_POINTER) {
4550 ptr2 = *(void**)cdata2->ptr;
4551 } else {
4552 ptr2 = cdata2->ptr;
4553 if (type2->kind != ZEND_FFI_TYPE_POINTER && size > type2->size) {
4554 zend_throw_error(zend_ffi_exception_ce, "Attempt to read over data boundary");
4555 RETURN_THROWS();
4556 }
4557 }
4558 } else {
4559 zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
4560 RETURN_THROWS();
4561 }
4562
4563 ret = memcmp(ptr1, ptr2, size);
4564 if (ret == 0) {
4565 RETVAL_LONG(0);
4566 } else if (ret < 0) {
4567 RETVAL_LONG(-1);
4568 } else {
4569 RETVAL_LONG(1);
4570 }
4571}
4572/* }}} */
4573
4574ZEND_METHOD(FFI, memset) /* {{{ */
4575{
4576 zval *zv;
4579 void *ptr;
4581
4584 Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
4588
4592 ptr = *(void**)cdata->ptr;
4593 } else {
4594 ptr = cdata->ptr;
4595 if (type->kind != ZEND_FFI_TYPE_POINTER && size > type->size) {
4596 zend_throw_error(zend_ffi_exception_ce, "attempt to write over data boundary");
4597 RETURN_THROWS();
4598 }
4599 }
4600
4602}
4603/* }}} */
4604
4605ZEND_METHOD(FFI, string) /* {{{ */
4606{
4607 zval *zv;
4610 void *ptr;
4613
4616 Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
4620
4623 if (!size_is_null) {
4624 if (type->kind == ZEND_FFI_TYPE_POINTER) {
4625 ptr = *(void**)cdata->ptr;
4626 } else {
4627 ptr = cdata->ptr;
4628 if (type->kind != ZEND_FFI_TYPE_POINTER && size > type->size) {
4629 zend_throw_error(zend_ffi_exception_ce, "attempt to read over data boundary");
4630 RETURN_THROWS();
4631 }
4632 }
4633 RETURN_STRINGL((char*)ptr, size);
4634 } else {
4635 if (type->kind == ZEND_FFI_TYPE_POINTER && ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
4636 ptr = *(void**)cdata->ptr;
4637 } else if (type->kind == ZEND_FFI_TYPE_ARRAY && ZEND_FFI_TYPE(type->array.type)->kind == ZEND_FFI_TYPE_CHAR) {
4638 ptr = cdata->ptr;
4639 } else {
4640 zend_throw_error(zend_ffi_exception_ce, "FFI\\Cdata is not a C string");
4641 RETURN_THROWS();
4642 }
4643 RETURN_STRING((char*)ptr);
4644 }
4645}
4646/* }}} */
4647
4648ZEND_METHOD(FFI, isNull) /* {{{ */
4649{
4650 zval *zv;
4653
4658
4659 ZVAL_DEREF(zv);
4660 if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4661 zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4662 RETURN_THROWS();
4663 }
4664
4666 type = ZEND_FFI_TYPE(cdata->type);
4667
4669 zend_throw_error(zend_ffi_exception_ce, "FFI\\Cdata is not a pointer");
4670 RETURN_THROWS();
4671 }
4672
4673 RETURN_BOOL(*(void**)cdata->ptr == NULL);
4674}
4675/* }}} */
4676
4677
4678ZEND_METHOD(FFI_CType, getName) /* {{{ */
4679{
4684
4686
4687 buf.start = buf.end = buf.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
4688 if (!zend_ffi_ctype_name(&buf, ZEND_FFI_TYPE(ctype->type))) {
4690 } else {
4691 size_t len = buf.end - buf.start;
4692 zend_string *res = zend_string_init(buf.start, len, 0);
4694 }
4695}
4696/* }}} */
4697
4698ZEND_METHOD(FFI_CType, getKind) /* {{{ */
4699{
4702
4704 RETURN_THROWS();
4705 }
4706
4707 type = ZEND_FFI_TYPE(ctype->type);
4708 RETURN_LONG(type->kind);
4709}
4710/* }}} */
4711
4712ZEND_METHOD(FFI_CType, getSize) /* {{{ */
4713{
4716
4718 RETURN_THROWS();
4719 }
4720
4721 type = ZEND_FFI_TYPE(ctype->type);
4722 RETURN_LONG(type->size);
4723}
4724/* }}} */
4725
4726ZEND_METHOD(FFI_CType, getAlignment) /* {{{ */
4727{
4730
4732 RETURN_THROWS();
4733 }
4734
4735 type = ZEND_FFI_TYPE(ctype->type);
4736 RETURN_LONG(type->align);
4737}
4738/* }}} */
4739
4740ZEND_METHOD(FFI_CType, getAttributes) /* {{{ */
4741{
4744
4746 RETURN_THROWS();
4747 }
4748
4749 type = ZEND_FFI_TYPE(ctype->type);
4750 RETURN_LONG(type->attr);
4751}
4752/* }}} */
4753
4754ZEND_METHOD(FFI_CType, getEnumKind) /* {{{ */
4755{
4758
4760 RETURN_THROWS();
4761 }
4762
4763 type = ZEND_FFI_TYPE(ctype->type);
4764 if (type->kind != ZEND_FFI_TYPE_ENUM) {
4765 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an enumeration");
4766 RETURN_THROWS();
4767 }
4768 RETURN_LONG(type->enumeration.kind);
4769}
4770/* }}} */
4771
4772ZEND_METHOD(FFI_CType, getArrayElementType) /* {{{ */
4773{
4777
4779 RETURN_THROWS();
4780 }
4781
4782 type = ZEND_FFI_TYPE(ctype->type);
4783 if (type->kind != ZEND_FFI_TYPE_ARRAY) {
4784 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array");
4785 RETURN_THROWS();
4786 }
4787
4788 ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4789 ret->type = ZEND_FFI_TYPE(type->array.type);
4790 RETURN_OBJ(&ret->std);
4791}
4792/* }}} */
4793
4794ZEND_METHOD(FFI_CType, getArrayLength) /* {{{ */
4795{
4798
4800 RETURN_THROWS();
4801 }
4802
4803 type = ZEND_FFI_TYPE(ctype->type);
4804 if (type->kind != ZEND_FFI_TYPE_ARRAY) {
4805 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array");
4806 RETURN_THROWS();
4807 }
4808 RETURN_LONG(type->array.length);
4809}
4810/* }}} */
4811
4812ZEND_METHOD(FFI_CType, getPointerType) /* {{{ */
4813{
4817
4819 RETURN_THROWS();
4820 }
4821
4822 type = ZEND_FFI_TYPE(ctype->type);
4823 if (type->kind != ZEND_FFI_TYPE_POINTER) {
4824 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a pointer");
4825 RETURN_THROWS();
4826 }
4827
4828 ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4829 ret->type = ZEND_FFI_TYPE(type->pointer.type);
4830 RETURN_OBJ(&ret->std);
4831}
4832/* }}} */
4833
4834ZEND_METHOD(FFI_CType, getStructFieldNames) /* {{{ */
4835{
4840 zval zv;
4841
4843 RETURN_THROWS();
4844 }
4845
4846 type = ZEND_FFI_TYPE(ctype->type);
4847 if (type->kind != ZEND_FFI_TYPE_STRUCT) {
4848 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4849 RETURN_THROWS();
4850 }
4851
4852 ht = zend_new_array(zend_hash_num_elements(&type->record.fields));
4854 ZEND_HASH_MAP_FOREACH_STR_KEY(&type->record.fields, name) {
4858}
4859/* }}} */
4860
4861ZEND_METHOD(FFI_CType, getStructFieldOffset) /* {{{ */
4862{
4867
4871
4874 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4875 RETURN_THROWS();
4876 }
4877
4878 ptr = zend_hash_find_ptr(&type->record.fields, name);
4879 if (!ptr) {
4880 zend_throw_error(zend_ffi_exception_ce, "Wrong field name");
4881 RETURN_THROWS();
4882 }
4884}
4885/* }}} */
4886
4887ZEND_METHOD(FFI_CType, getStructFieldType) /* {{{ */
4888{
4894
4898
4901 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4902 RETURN_THROWS();
4903 }
4904
4905 ptr = zend_hash_find_ptr(&type->record.fields, name);
4906 if (!ptr) {
4907 zend_throw_error(zend_ffi_exception_ce, "Wrong field name");
4908 RETURN_THROWS();
4909 }
4910
4911 ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4912 ret->type = ZEND_FFI_TYPE(ptr->type);
4913 RETURN_OBJ(&ret->std);
4914}
4915/* }}} */
4916
4917ZEND_METHOD(FFI_CType, getFuncABI) /* {{{ */
4918{
4921
4923 RETURN_THROWS();
4924 }
4925
4926 type = ZEND_FFI_TYPE(ctype->type);
4927 if (type->kind != ZEND_FFI_TYPE_FUNC) {
4928 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4929 RETURN_THROWS();
4930 }
4931 RETURN_LONG(type->func.abi);
4932}
4933/* }}} */
4934
4935ZEND_METHOD(FFI_CType, getFuncReturnType) /* {{{ */
4936{
4940
4942 RETURN_THROWS();
4943 }
4944
4945 type = ZEND_FFI_TYPE(ctype->type);
4946 if (type->kind != ZEND_FFI_TYPE_FUNC) {
4947 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4948 RETURN_THROWS();
4949 }
4950
4951 ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4952 ret->type = ZEND_FFI_TYPE(type->func.ret_type);
4953 RETURN_OBJ(&ret->std);
4954}
4955/* }}} */
4956
4957ZEND_METHOD(FFI_CType, getFuncParameterCount) /* {{{ */
4958{
4961
4963 RETURN_THROWS();
4964 }
4965
4966 type = ZEND_FFI_TYPE(ctype->type);
4967 if (type->kind != ZEND_FFI_TYPE_FUNC) {
4968 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4969 RETURN_THROWS();
4970 }
4971 RETURN_LONG(type->func.args ? zend_hash_num_elements(type->func.args) : 0);
4972}
4973/* }}} */
4974
4975ZEND_METHOD(FFI_CType, getFuncParameterType) /* {{{ */
4976{
4981
4985
4988 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4989 RETURN_THROWS();
4990 }
4991
4992 if (!type->func.args) {
4993 zend_throw_error(zend_ffi_exception_ce, "Wrong argument number");
4994 RETURN_THROWS();
4995 }
4996
4997 ptr = zend_hash_index_find_ptr(type->func.args, n);
4998 if (!ptr) {
4999 zend_throw_error(zend_ffi_exception_ce, "Wrong argument number");
5000 RETURN_THROWS();
5001 }
5002
5003 ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
5004 ret->type = ZEND_FFI_TYPE(ptr);
5005 RETURN_OBJ(&ret->std);
5006}
5007/* }}} */
5008
5009static char *zend_ffi_skip_ws_and_comments(char *p, bool allow_standalone_newline)
5010{
5011 while (true) {
5012 if (*p == ' ' || *p == '\t') {
5013 p++;
5014 } else if (allow_standalone_newline && (*p == '\r' || *p == '\n' || *p == '\f' || *p == '\v')) {
5015 p++;
5016 } else if (allow_standalone_newline && *p == '/' && p[1] == '/') {
5017 p += 2;
5018 while (*p && *p != '\r' && *p != '\n') {
5019 p++;
5020 }
5021 } else if (*p == '/' && p[1] == '*') {
5022 p += 2;
5023 while (*p && (*p != '*' || p[1] != '/')) {
5024 p++;
5025 }
5026 if (*p == '*') {
5027 p++;
5028 if (*p == '/') {
5029 p++;
5030 }
5031 }
5032 } else {
5033 break;
5034 }
5035 }
5036
5037 return p;
5038}
5039
5040static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, bool preload) /* {{{ */
5041{
5042 char *p;
5043
5044 code_pos = zend_ffi_skip_ws_and_comments(code_pos, true);
5045
5046 *scope_name = NULL;
5047 *lib = NULL;
5048 while (*code_pos == '#') {
5049 if (strncmp(code_pos, ZEND_STRL("#define")) == 0) {
5050 p = zend_ffi_skip_ws_and_comments(code_pos + sizeof("#define") - 1, false);
5051
5052 char **target = NULL;
5053 const char *target_name = NULL;
5054 if (strncmp(p, ZEND_STRL("FFI_SCOPE")) == 0) {
5055 p = zend_ffi_skip_ws_and_comments(p + sizeof("FFI_SCOPE") - 1, false);
5056 target = scope_name;
5057 target_name = "FFI_SCOPE";
5058 } else if (strncmp(p, ZEND_STRL("FFI_LIB")) == 0) {
5059 p = zend_ffi_skip_ws_and_comments(p + sizeof("FFI_LIB") - 1, false);
5060 target = lib;
5061 target_name = "FFI_LIB";
5062 } else {
5063 while (*p && *p != '\n' && *p != '\r') {
5064 p++;
5065 }
5066 code_pos = zend_ffi_skip_ws_and_comments(p, true);
5067 continue;
5068 }
5069
5070 if (*p != '"') {
5071 if (preload) {
5072 zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad %s define", filename, target_name);
5073 } else {
5074 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad %s define", filename, target_name);
5075 }
5076 return NULL;
5077 }
5078 p++;
5079 if (*target) {
5080 if (preload) {
5081 zend_error(E_WARNING, "FFI: failed pre-loading '%s', %s defined twice", filename, target_name);
5082 } else {
5083 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', %s defined twice", filename, target_name);
5084 }
5085 return NULL;
5086 }
5087 *target = p;
5088 while (1) {
5089 if (*p == '\"') {
5090 *p = 0;
5091 p++;
5092 break;
5093 } else if (*p <= ' ') {
5094 if (preload) {
5095 zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad %s define", filename, target_name);
5096 } else {
5097 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad %s define", filename, target_name);
5098 }
5099 return NULL;
5100 }
5101 p++;
5102 }
5103
5104 code_pos = zend_ffi_skip_ws_and_comments(p, true);
5105 } else {
5106 break;
5107 }
5108 }
5109 return code_pos;
5110}
5111/* }}} */
5112
5113static ZEND_COLD zend_function *zend_fake_get_constructor(zend_object *object) /* {{{ */
5114{
5115 zend_throw_error(NULL, "Instantiation of %s is not allowed", ZSTR_VAL(object->ce->name));
5116 return NULL;
5117}
5118/* }}} */
5119
5120static ZEND_COLD zend_never_inline void zend_bad_array_access(zend_class_entry *ce) /* {{{ */
5121{
5122 zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
5123}
5124/* }}} */
5125
5126static ZEND_COLD zval *zend_fake_read_dimension(zend_object *obj, zval *offset, int type, zval *rv) /* {{{ */
5127{
5128 zend_bad_array_access(obj->ce);
5129 return NULL;
5130}
5131/* }}} */
5132
5133static ZEND_COLD void zend_fake_write_dimension(zend_object *obj, zval *offset, zval *value) /* {{{ */
5134{
5135 zend_bad_array_access(obj->ce);
5136}
5137/* }}} */
5138
5139static ZEND_COLD int zend_fake_has_dimension(zend_object *obj, zval *offset, int check_empty) /* {{{ */
5140{
5141 zend_bad_array_access(obj->ce);
5142 return 0;
5143}
5144/* }}} */
5145
5146static ZEND_COLD void zend_fake_unset_dimension(zend_object *obj, zval *offset) /* {{{ */
5147{
5148 zend_bad_array_access(obj->ce);
5149}
5150/* }}} */
5151
5152static ZEND_COLD zend_never_inline void zend_bad_property_access(zend_class_entry *ce) /* {{{ */
5153{
5154 zend_throw_error(NULL, "Cannot access property of object of type %s", ZSTR_VAL(ce->name));
5155}
5156/* }}} */
5157
5158static ZEND_COLD zval *zend_fake_read_property(zend_object *obj, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
5159{
5160 zend_bad_property_access(obj->ce);
5161 return &EG(uninitialized_zval);
5162}
5163/* }}} */
5164
5165static ZEND_COLD zval *zend_fake_write_property(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
5166{
5167 zend_bad_array_access(obj->ce);
5168 return value;
5169}
5170/* }}} */
5171
5172static ZEND_COLD int zend_fake_has_property(zend_object *obj, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */
5173{
5174 zend_bad_array_access(obj->ce);
5175 return 0;
5176}
5177/* }}} */
5178
5179static ZEND_COLD void zend_fake_unset_property(zend_object *obj, zend_string *member, void **cache_slot) /* {{{ */
5180{
5181 zend_bad_array_access(obj->ce);
5182}
5183/* }}} */
5184
5185static zval *zend_fake_get_property_ptr_ptr(zend_object *obj, zend_string *member, int type, void **cache_slot) /* {{{ */
5186{
5187 return NULL;
5188}
5189/* }}} */
5190
5191static ZEND_COLD zend_function *zend_fake_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key) /* {{{ */
5192{
5193 zend_class_entry *ce = (*obj_ptr)->ce;
5194 zend_throw_error(NULL, "Object of type %s does not support method calls", ZSTR_VAL(ce->name));
5195 return NULL;
5196}
5197/* }}} */
5198
5199static HashTable *zend_fake_get_properties(zend_object *obj) /* {{{ */
5200{
5201 return (HashTable*)&zend_empty_array;
5202}
5203/* }}} */
5204
5205static HashTable *zend_fake_get_gc(zend_object *ob, zval **table, int *n) /* {{{ */
5206{
5207 *table = NULL;
5208 *n = 0;
5209 return NULL;
5210}
5211/* }}} */
5212
5213static zend_result zend_fake_cast_object(zend_object *obj, zval *result, int type)
5214{
5215 switch (type) {
5216 case _IS_BOOL:
5218 return SUCCESS;
5219 default:
5220 return FAILURE;
5221 }
5222}
5223
5224static ZEND_COLD zend_never_inline void zend_ffi_use_after_free(void) /* {{{ */
5225{
5226 zend_throw_error(zend_ffi_exception_ce, "Use after free()");
5227}
5228/* }}} */
5229
5230static zend_object *zend_ffi_free_clone_obj(zend_object *obj) /* {{{ */
5231{
5232 zend_ffi_use_after_free();
5233 return NULL;
5234}
5235/* }}} */
5236
5237static ZEND_COLD zval *zend_ffi_free_read_dimension(zend_object *obj, zval *offset, int type, zval *rv) /* {{{ */
5238{
5239 zend_ffi_use_after_free();
5240 return NULL;
5241}
5242/* }}} */
5243
5244static ZEND_COLD void zend_ffi_free_write_dimension(zend_object *obj, zval *offset, zval *value) /* {{{ */
5245{
5246 zend_ffi_use_after_free();
5247}
5248/* }}} */
5249
5250static ZEND_COLD int zend_ffi_free_has_dimension(zend_object *obj, zval *offset, int check_empty) /* {{{ */
5251{
5252 zend_ffi_use_after_free();
5253 return 0;
5254}
5255/* }}} */
5256
5257static ZEND_COLD void zend_ffi_free_unset_dimension(zend_object *obj, zval *offset) /* {{{ */
5258{
5259 zend_ffi_use_after_free();
5260}
5261/* }}} */
5262
5263static ZEND_COLD zval *zend_ffi_free_read_property(zend_object *obj, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
5264{
5265 zend_ffi_use_after_free();
5266 return &EG(uninitialized_zval);
5267}
5268/* }}} */
5269
5270static ZEND_COLD zval *zend_ffi_free_write_property(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
5271{
5272 zend_ffi_use_after_free();
5273 return value;
5274}
5275/* }}} */
5276
5277static ZEND_COLD int zend_ffi_free_has_property(zend_object *obj, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */
5278{
5279 zend_ffi_use_after_free();
5280 return 0;
5281}
5282/* }}} */
5283
5284static ZEND_COLD void zend_ffi_free_unset_property(zend_object *obj, zend_string *member, void **cache_slot) /* {{{ */
5285{
5286 zend_ffi_use_after_free();
5287}
5288/* }}} */
5289
5290static HashTable *zend_ffi_free_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
5291{
5292 zend_ffi_use_after_free();
5293 return NULL;
5294}
5295/* }}} */
5296
5297static ZEND_INI_MH(OnUpdateFFIEnable) /* {{{ */
5298{
5299 if (zend_string_equals_literal_ci(new_value, "preload")) {
5301 } else {
5303 }
5304 return SUCCESS;
5305}
5306/* }}} */
5307
5308static ZEND_INI_DISP(zend_ffi_enable_displayer_cb) /* {{{ */
5309{
5311 ZEND_PUTS("preload");
5312 } else if (FFI_G(restriction) == ZEND_FFI_ENABLED) {
5313 ZEND_PUTS("On");
5314 } else {
5315 ZEND_PUTS("Off");
5316 }
5317}
5318/* }}} */
5319
5321 ZEND_INI_ENTRY_EX("ffi.enable", "preload", ZEND_INI_SYSTEM, OnUpdateFFIEnable, zend_ffi_enable_displayer_cb)
5322 STD_ZEND_INI_ENTRY("ffi.preload", NULL, ZEND_INI_SYSTEM, OnUpdateString, preload, zend_ffi_globals, ffi_globals)
5324
5325static zend_result zend_ffi_preload_glob(const char *filename) /* {{{ */
5326{
5327#ifdef HAVE_GLOB
5328 glob_t globbuf;
5329 int ret;
5330 unsigned int i;
5331
5332 memset(&globbuf, 0, sizeof(glob_t));
5333
5334 ret = glob(filename, 0, NULL, &globbuf);
5335#ifdef GLOB_NOMATCH
5336 if (ret == GLOB_NOMATCH || !globbuf.gl_pathc) {
5337#else
5338 if (!globbuf.gl_pathc) {
5339#endif
5340 /* pass */
5341 } else {
5342 for(i=0 ; i<globbuf.gl_pathc; i++) {
5343 zend_ffi *ffi = zend_ffi_load(globbuf.gl_pathv[i], 1);
5344 if (!ffi) {
5345 globfree(&globbuf);
5346 return FAILURE;
5347 }
5348 efree(ffi);
5349 }
5350 globfree(&globbuf);
5351 }
5352#else
5353 zend_ffi *ffi = zend_ffi_load(filename, 1);
5354 if (!ffi) {
5355 return FAILURE;
5356 }
5357 efree(ffi);
5358#endif
5359
5360 return SUCCESS;
5361}
5362/* }}} */
5363
5364static zend_result zend_ffi_preload(char *preload) /* {{{ */
5365{
5366 zend_ffi *ffi;
5367 char *s = NULL, *e, *filename;
5368 bool is_glob = 0;
5369
5370 e = preload;
5371 while (*e) {
5372 switch (*e) {
5374 if (s) {
5375 filename = estrndup(s, e-s);
5376 s = NULL;
5377 if (!is_glob) {
5378 ffi = zend_ffi_load(filename, 1);
5379 efree(filename);
5380 if (!ffi) {
5381 return FAILURE;
5382 }
5383 efree(ffi);
5384 } else {
5385 zend_result ret = zend_ffi_preload_glob(filename);
5386
5387 efree(filename);
5388 if (ret == FAILURE) {
5389 return FAILURE;
5390 }
5391 is_glob = 0;
5392 }
5393 }
5394 break;
5395 case '*':
5396 case '?':
5397 case '[':
5398 is_glob = 1;
5399 break;
5400 default:
5401 if (!s) {
5402 s = e;
5403 }
5404 break;
5405 }
5406 e++;
5407 }
5408 if (s) {
5409 filename = estrndup(s, e-s);
5410 if (!is_glob) {
5411 ffi = zend_ffi_load(filename, 1);
5412 efree(filename);
5413 if (!ffi) {
5414 return FAILURE;
5415 }
5416 efree(ffi);
5417 } else {
5418 zend_result ret = zend_ffi_preload_glob(filename);
5419 efree(filename);
5420 if (ret == FAILURE) {
5421 return FAILURE;
5422 }
5423 }
5424 }
5425
5426 return SUCCESS;
5427}
5428/* }}} */
5429
5430/* The startup code for observers adds a temporary to each function for internal use.
5431 * The "new", "cast", and "type" functions in FFI are both static and non-static.
5432 * Only the static versions are in the function table and the non-static versions are not.
5433 * This means the non-static versions will be skipped by the observers startup code.
5434 * This function fixes that by incrementing the temporary count for the non-static versions.
5435 */
5436static zend_result (*prev_zend_post_startup_cb)(void);
5437static zend_result ffi_fixup_temporaries(void) {
5439 ++zend_ffi_new_fn.T;
5440 ++zend_ffi_cast_fn.T;
5441 ++zend_ffi_type_fn.T;
5442 }
5443#ifndef ZTS
5444 ZEND_MAP_PTR(zend_ffi_new_fn.run_time_cache) = ZEND_MAP_PTR(((zend_internal_function *)zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "new", sizeof("new")-1))->run_time_cache);
5445 ZEND_MAP_PTR(zend_ffi_cast_fn.run_time_cache) = ZEND_MAP_PTR(((zend_internal_function *)zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "cast", sizeof("cast")-1))->run_time_cache);
5446 ZEND_MAP_PTR(zend_ffi_type_fn.run_time_cache) = ZEND_MAP_PTR(((zend_internal_function *)zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1))->run_time_cache);
5447#endif
5448 if (prev_zend_post_startup_cb) {
5449 return prev_zend_post_startup_cb();
5450 }
5451 return SUCCESS;
5452}
5453
5454/* {{{ ZEND_MINIT_FUNCTION */
5456{
5458
5459 FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0;
5460
5461 zend_ffi_exception_ce = register_class_FFI_Exception(zend_ce_error);
5462
5463 zend_ffi_parser_exception_ce = register_class_FFI_ParserException(zend_ffi_exception_ce);
5464
5465 zend_ffi_ce = register_class_FFI();
5466 zend_ffi_ce->create_object = zend_ffi_new;
5467 zend_ffi_ce->default_object_handlers = &zend_ffi_handlers;
5468
5469 memcpy(&zend_ffi_new_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "new", sizeof("new")-1), sizeof(zend_internal_function));
5470 zend_ffi_new_fn.fn_flags &= ~ZEND_ACC_STATIC;
5471 memcpy(&zend_ffi_cast_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "cast", sizeof("cast")-1), sizeof(zend_internal_function));
5472 zend_ffi_cast_fn.fn_flags &= ~ZEND_ACC_STATIC;
5473 memcpy(&zend_ffi_type_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1), sizeof(zend_internal_function));
5474 zend_ffi_type_fn.fn_flags &= ~ZEND_ACC_STATIC;
5475
5476 prev_zend_post_startup_cb = zend_post_startup_cb;
5477 zend_post_startup_cb = ffi_fixup_temporaries;
5478
5479 memcpy(&zend_ffi_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5480 zend_ffi_handlers.get_constructor = zend_fake_get_constructor;
5481 zend_ffi_handlers.free_obj = zend_ffi_free_obj;
5482 zend_ffi_handlers.clone_obj = NULL;
5483 zend_ffi_handlers.read_property = zend_ffi_read_var;
5484 zend_ffi_handlers.write_property = zend_ffi_write_var;
5485 zend_ffi_handlers.read_dimension = zend_fake_read_dimension;
5486 zend_ffi_handlers.write_dimension = zend_fake_write_dimension;
5487 zend_ffi_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5488 zend_ffi_handlers.has_property = zend_fake_has_property;
5489 zend_ffi_handlers.unset_property = zend_fake_unset_property;
5490 zend_ffi_handlers.has_dimension = zend_fake_has_dimension;
5491 zend_ffi_handlers.unset_dimension = zend_fake_unset_dimension;
5492 zend_ffi_handlers.get_method = zend_ffi_get_func;
5493 zend_ffi_handlers.compare = zend_fake_compare_objects;
5494 zend_ffi_handlers.cast_object = zend_fake_cast_object;
5495 zend_ffi_handlers.get_debug_info = NULL;
5496 zend_ffi_handlers.get_closure = NULL;
5497 zend_ffi_handlers.get_properties = zend_fake_get_properties;
5498 zend_ffi_handlers.get_gc = zend_fake_get_gc;
5499
5500 zend_ffi_cdata_ce = register_class_FFI_CData();
5501 zend_ffi_cdata_ce->create_object = zend_ffi_cdata_new;
5502 zend_ffi_cdata_ce->default_object_handlers = &zend_ffi_cdata_handlers;
5503 zend_ffi_cdata_ce->get_iterator = zend_ffi_cdata_get_iterator;
5504
5505 memcpy(&zend_ffi_cdata_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5506 zend_ffi_cdata_handlers.get_constructor = zend_fake_get_constructor;
5507 zend_ffi_cdata_handlers.free_obj = zend_ffi_cdata_free_obj;
5508 zend_ffi_cdata_handlers.clone_obj = zend_ffi_cdata_clone_obj;
5509 zend_ffi_cdata_handlers.read_property = zend_ffi_cdata_read_field;
5510 zend_ffi_cdata_handlers.write_property = zend_ffi_cdata_write_field;
5511 zend_ffi_cdata_handlers.read_dimension = zend_ffi_cdata_read_dim;
5512 zend_ffi_cdata_handlers.write_dimension = zend_ffi_cdata_write_dim;
5513 zend_ffi_cdata_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5514 zend_ffi_cdata_handlers.has_property = zend_fake_has_property;
5515 zend_ffi_cdata_handlers.unset_property = zend_fake_unset_property;
5516 zend_ffi_cdata_handlers.has_dimension = zend_fake_has_dimension;
5517 zend_ffi_cdata_handlers.unset_dimension = zend_fake_unset_dimension;
5518 zend_ffi_cdata_handlers.get_method = zend_fake_get_method;
5519 zend_ffi_cdata_handlers.get_class_name = zend_ffi_cdata_get_class_name;
5520 zend_ffi_cdata_handlers.do_operation = zend_ffi_cdata_do_operation;
5521 zend_ffi_cdata_handlers.compare = zend_ffi_cdata_compare_objects;
5522 zend_ffi_cdata_handlers.cast_object = zend_ffi_cdata_cast_object;
5523 zend_ffi_cdata_handlers.count_elements = zend_ffi_cdata_count_elements;
5524 zend_ffi_cdata_handlers.get_debug_info = zend_ffi_cdata_get_debug_info;
5525 zend_ffi_cdata_handlers.get_closure = zend_ffi_cdata_get_closure;
5526 zend_ffi_cdata_handlers.get_properties = zend_fake_get_properties;
5527 zend_ffi_cdata_handlers.get_gc = zend_fake_get_gc;
5528
5529 memcpy(&zend_ffi_cdata_value_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5530 zend_ffi_cdata_value_handlers.get_constructor = zend_fake_get_constructor;
5531 zend_ffi_cdata_value_handlers.free_obj = zend_ffi_cdata_free_obj;
5532 zend_ffi_cdata_value_handlers.clone_obj = zend_ffi_cdata_clone_obj;
5533 zend_ffi_cdata_value_handlers.read_property = zend_ffi_cdata_get;
5534 zend_ffi_cdata_value_handlers.write_property = zend_ffi_cdata_set;
5535 zend_ffi_cdata_value_handlers.read_dimension = zend_fake_read_dimension;
5536 zend_ffi_cdata_value_handlers.write_dimension = zend_fake_write_dimension;
5537 zend_ffi_cdata_value_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5538 zend_ffi_cdata_value_handlers.has_property = zend_fake_has_property;
5539 zend_ffi_cdata_value_handlers.unset_property = zend_fake_unset_property;
5540 zend_ffi_cdata_value_handlers.has_dimension = zend_fake_has_dimension;
5541 zend_ffi_cdata_value_handlers.unset_dimension = zend_fake_unset_dimension;
5542 zend_ffi_cdata_value_handlers.get_method = zend_fake_get_method;
5543 zend_ffi_cdata_value_handlers.get_class_name = zend_ffi_cdata_get_class_name;
5544 zend_ffi_cdata_value_handlers.compare = zend_ffi_cdata_compare_objects;
5545 zend_ffi_cdata_value_handlers.cast_object = zend_ffi_cdata_cast_object;
5546 zend_ffi_cdata_value_handlers.count_elements = NULL;
5547 zend_ffi_cdata_value_handlers.get_debug_info = zend_ffi_cdata_get_debug_info;
5548 zend_ffi_cdata_value_handlers.get_closure = NULL;
5549 zend_ffi_cdata_value_handlers.get_properties = zend_fake_get_properties;
5550 zend_ffi_cdata_value_handlers.get_gc = zend_fake_get_gc;
5551
5552 memcpy(&zend_ffi_cdata_free_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5553 zend_ffi_cdata_free_handlers.get_constructor = zend_fake_get_constructor;
5554 zend_ffi_cdata_free_handlers.free_obj = zend_ffi_cdata_free_obj;
5555 zend_ffi_cdata_free_handlers.clone_obj = zend_ffi_free_clone_obj;
5556 zend_ffi_cdata_free_handlers.read_property = zend_ffi_free_read_property;
5557 zend_ffi_cdata_free_handlers.write_property = zend_ffi_free_write_property;
5558 zend_ffi_cdata_free_handlers.read_dimension = zend_ffi_free_read_dimension;
5559 zend_ffi_cdata_free_handlers.write_dimension = zend_ffi_free_write_dimension;
5560 zend_ffi_cdata_free_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5561 zend_ffi_cdata_free_handlers.has_property = zend_ffi_free_has_property;
5562 zend_ffi_cdata_free_handlers.unset_property = zend_ffi_free_unset_property;
5563 zend_ffi_cdata_free_handlers.has_dimension = zend_ffi_free_has_dimension;
5564 zend_ffi_cdata_free_handlers.unset_dimension = zend_ffi_free_unset_dimension;
5565 zend_ffi_cdata_free_handlers.get_method = zend_fake_get_method;
5566 zend_ffi_cdata_free_handlers.get_class_name = zend_ffi_cdata_get_class_name;
5567 zend_ffi_cdata_free_handlers.compare = zend_ffi_cdata_compare_objects;
5568 zend_ffi_cdata_free_handlers.cast_object = zend_fake_cast_object;
5569 zend_ffi_cdata_free_handlers.count_elements = NULL;
5570 zend_ffi_cdata_free_handlers.get_debug_info = zend_ffi_free_get_debug_info;
5571 zend_ffi_cdata_free_handlers.get_closure = NULL;
5572 zend_ffi_cdata_free_handlers.get_properties = zend_fake_get_properties;
5573 zend_ffi_cdata_free_handlers.get_gc = zend_fake_get_gc;
5574
5575 zend_ffi_ctype_ce = register_class_FFI_CType();
5576 zend_ffi_ctype_ce->create_object = zend_ffi_ctype_new;
5577 zend_ffi_ctype_ce->default_object_handlers = &zend_ffi_ctype_handlers;
5578
5579 memcpy(&zend_ffi_ctype_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5580 zend_ffi_ctype_handlers.get_constructor = zend_fake_get_constructor;
5581 zend_ffi_ctype_handlers.free_obj = zend_ffi_ctype_free_obj;
5582 zend_ffi_ctype_handlers.clone_obj = NULL;
5583 zend_ffi_ctype_handlers.read_property = zend_fake_read_property;
5584 zend_ffi_ctype_handlers.write_property = zend_fake_write_property;
5585 zend_ffi_ctype_handlers.read_dimension = zend_fake_read_dimension;
5586 zend_ffi_ctype_handlers.write_dimension = zend_fake_write_dimension;
5587 zend_ffi_ctype_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5588 zend_ffi_ctype_handlers.has_property = zend_fake_has_property;
5589 zend_ffi_ctype_handlers.unset_property = zend_fake_unset_property;
5590 zend_ffi_ctype_handlers.has_dimension = zend_fake_has_dimension;
5591 zend_ffi_ctype_handlers.unset_dimension = zend_fake_unset_dimension;
5592 //zend_ffi_ctype_handlers.get_method = zend_fake_get_method;
5593 zend_ffi_ctype_handlers.get_class_name = zend_ffi_ctype_get_class_name;
5594 zend_ffi_ctype_handlers.compare = zend_ffi_ctype_compare_objects;
5595 zend_ffi_ctype_handlers.cast_object = zend_fake_cast_object;
5596 zend_ffi_ctype_handlers.count_elements = NULL;
5597 zend_ffi_ctype_handlers.get_debug_info = zend_ffi_ctype_get_debug_info;
5598 zend_ffi_ctype_handlers.get_closure = NULL;
5599 zend_ffi_ctype_handlers.get_properties = zend_fake_get_properties;
5600 zend_ffi_ctype_handlers.get_gc = zend_fake_get_gc;
5601
5602 if (FFI_G(preload)) {
5603 return zend_ffi_preload(FFI_G(preload));
5604 }
5605
5606 return SUCCESS;
5607}
5608/* }}} */
5609
5610/* {{{ ZEND_RSHUTDOWN_FUNCTION */
5612{
5613 if (FFI_G(callbacks)) {
5616 FFI_G(callbacks) = NULL;
5617 }
5618 if (FFI_G(weak_types)) {
5619#if 0
5620 fprintf(stderr, "WeakTypes: %d\n", zend_hash_num_elements(FFI_G(weak_types)));
5621#endif
5625 }
5626 return SUCCESS;
5627}
5628/* }}} */
5629
5630/* {{{ ZEND_MINFO_FUNCTION */
5632{
5634 php_info_print_table_row(2, "FFI support", "enabled");
5636
5638}
5639/* }}} */
5640
5641static const zend_ffi_type zend_ffi_type_void = {.kind=ZEND_FFI_TYPE_VOID, .size=1, .align=1};
5642static const zend_ffi_type zend_ffi_type_char = {.kind=ZEND_FFI_TYPE_CHAR, .size=1, .align=_Alignof(char)};
5643static const zend_ffi_type zend_ffi_type_bool = {.kind=ZEND_FFI_TYPE_BOOL, .size=1, .align=_Alignof(uint8_t)};
5644static const zend_ffi_type zend_ffi_type_sint8 = {.kind=ZEND_FFI_TYPE_SINT8, .size=1, .align=_Alignof(int8_t)};
5645static const zend_ffi_type zend_ffi_type_uint8 = {.kind=ZEND_FFI_TYPE_UINT8, .size=1, .align=_Alignof(uint8_t)};
5646static const zend_ffi_type zend_ffi_type_sint16 = {.kind=ZEND_FFI_TYPE_SINT16, .size=2, .align=_Alignof(int16_t)};
5647static const zend_ffi_type zend_ffi_type_uint16 = {.kind=ZEND_FFI_TYPE_UINT16, .size=2, .align=_Alignof(uint16_t)};
5648static const zend_ffi_type zend_ffi_type_sint32 = {.kind=ZEND_FFI_TYPE_SINT32, .size=4, .align=_Alignof(int32_t)};
5649static const zend_ffi_type zend_ffi_type_uint32 = {.kind=ZEND_FFI_TYPE_UINT32, .size=4, .align=_Alignof(uint32_t)};
5650static const zend_ffi_type zend_ffi_type_sint64 = {.kind=ZEND_FFI_TYPE_SINT64, .size=8, .align=_Alignof(int64_t)};
5651static const zend_ffi_type zend_ffi_type_uint64 = {.kind=ZEND_FFI_TYPE_UINT64, .size=8, .align=_Alignof(uint64_t)};
5652static const zend_ffi_type zend_ffi_type_float = {.kind=ZEND_FFI_TYPE_FLOAT, .size=sizeof(float), .align=_Alignof(float)};
5653static const zend_ffi_type zend_ffi_type_double = {.kind=ZEND_FFI_TYPE_DOUBLE, .size=sizeof(double), .align=_Alignof(double)};
5654
5655#ifdef HAVE_LONG_DOUBLE
5656static const zend_ffi_type zend_ffi_type_long_double = {.kind=ZEND_FFI_TYPE_LONGDOUBLE, .size=sizeof(long double), .align=_Alignof(long double)};
5657#endif
5658
5659static const zend_ffi_type zend_ffi_type_ptr = {.kind=ZEND_FFI_TYPE_POINTER, .size=sizeof(void*), .align=_Alignof(void*), .pointer.type = (zend_ffi_type*)&zend_ffi_type_void};
5660
5661static const struct {
5662 const char *name;
5663 const zend_ffi_type *type;
5664} zend_ffi_types[] = {
5665 {"void", &zend_ffi_type_void},
5666 {"char", &zend_ffi_type_char},
5667 {"bool", &zend_ffi_type_bool},
5668 {"int8_t", &zend_ffi_type_sint8},
5669 {"uint8_t", &zend_ffi_type_uint8},
5670 {"int16_t", &zend_ffi_type_sint16},
5671 {"uint16_t", &zend_ffi_type_uint16},
5672 {"int32_t", &zend_ffi_type_sint32},
5673 {"uint32_t", &zend_ffi_type_uint32},
5674 {"int64_t", &zend_ffi_type_sint64},
5675 {"uint64_t", &zend_ffi_type_uint64},
5676 {"float", &zend_ffi_type_float},
5677 {"double", &zend_ffi_type_double},
5678#ifdef HAVE_LONG_DOUBLE
5679 {"long double", &zend_ffi_type_long_double},
5680#endif
5681#if SIZEOF_SIZE_T == 4
5682 {"uintptr_t", &zend_ffi_type_uint32},
5683 {"intptr_t", &zend_ffi_type_sint32},
5684 {"size_t", &zend_ffi_type_uint32},
5685 {"ssize_t", &zend_ffi_type_sint32},
5686 {"ptrdiff_t", &zend_ffi_type_sint32},
5687#else
5688 {"uintptr_t", &zend_ffi_type_uint64},
5689 {"intptr_t", &zend_ffi_type_sint64},
5690 {"size_t", &zend_ffi_type_uint64},
5691 {"ssize_t", &zend_ffi_type_sint64},
5692 {"ptrdiff_t", &zend_ffi_type_sint64},
5693#endif
5694#if SIZEOF_OFF_T == 4
5695 {"off_t", &zend_ffi_type_sint32},
5696#else
5697 {"off_t", &zend_ffi_type_sint64},
5698#endif
5699
5700 {"va_list", &zend_ffi_type_ptr},
5701 {"__builtin_va_list", &zend_ffi_type_ptr},
5702 {"__gnuc_va_list", &zend_ffi_type_ptr},
5703};
5704
5705/* {{{ ZEND_GINIT_FUNCTION */
5707{
5708 size_t i;
5709
5710#if defined(COMPILE_DL_FFI) && defined(ZTS)
5712#endif
5713 memset(ffi_globals, 0, sizeof(*ffi_globals));
5714 zend_hash_init(&ffi_globals->types, 0, NULL, NULL, 1);
5715 for (i = 0; i < sizeof(zend_ffi_types)/sizeof(zend_ffi_types[0]); i++) {
5716 zend_hash_str_add_new_ptr(&ffi_globals->types, zend_ffi_types[i].name, strlen(zend_ffi_types[i].name), (void*)zend_ffi_types[i].type);
5717 }
5718}
5719/* }}} */
5720
5721/* {{{ ZEND_GINIT_FUNCTION */
5723{
5724 if (ffi_globals->scopes) {
5725 zend_hash_destroy(ffi_globals->scopes);
5726 free(ffi_globals->scopes);
5727 }
5728 zend_hash_destroy(&ffi_globals->types);
5729}
5730/* }}} */
5731
5732/* {{{ ffi_module_entry */
5735 "FFI", /* Extension name */
5736 NULL, /* zend_function_entry */
5737 ZEND_MINIT(ffi), /* ZEND_MINIT - Module initialization */
5738 NULL, /* ZEND_MSHUTDOWN - Module shutdown */
5739 NULL, /* ZEND_RINIT - Request initialization */
5740 ZEND_RSHUTDOWN(ffi), /* ZEND_RSHUTDOWN - Request shutdown */
5741 ZEND_MINFO(ffi), /* ZEND_MINFO - Module info */
5742 PHP_VERSION, /* Version */
5744 ZEND_GINIT(ffi),
5746 NULL,
5748};
5749/* }}} */
5750
5751#ifdef COMPILE_DL_FFI
5752# ifdef ZTS
5754# endif
5756#endif
5757
5758/* parser callbacks */
5759void zend_ffi_parser_error(const char *format, ...) /* {{{ */
5760{
5761 va_list va;
5762 char *message = NULL;
5763
5764 va_start(va, format);
5765 zend_vspprintf(&message, 0, format, va);
5766
5767 if (EG(current_execute_data)) {
5768 zend_throw_exception(zend_ffi_parser_exception_ce, message, 0);
5769 } else {
5770 zend_error(E_WARNING, "FFI Parser: %s", message);
5771 }
5772
5773 efree(message);
5774 va_end(va);
5775
5777}
5778/* }}} */
5779
5780static void zend_ffi_finalize_type(zend_ffi_dcl *dcl) /* {{{ */
5781{
5782 if (!dcl->type) {
5783 switch (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) {
5784 case ZEND_FFI_DCL_VOID:
5785 dcl->type = (zend_ffi_type*)&zend_ffi_type_void;
5786 break;
5787 case ZEND_FFI_DCL_CHAR:
5788 dcl->type = (zend_ffi_type*)&zend_ffi_type_char;
5789 break;
5791 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint8;
5792 break;
5794 case ZEND_FFI_DCL_BOOL:
5795 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint8;
5796 break;
5797 case ZEND_FFI_DCL_SHORT:
5801 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint16;
5802 break;
5805 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint16;
5806 break;
5807 case ZEND_FFI_DCL_INT:
5810 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint32;
5811 break;
5814 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint32;
5815 break;
5816 case ZEND_FFI_DCL_LONG:
5820 if (sizeof(long) == 4) {
5821 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint32;
5822 } else {
5823 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint64;
5824 }
5825 break;
5828 if (sizeof(long) == 4) {
5829 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint32;
5830 } else {
5831 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint64;
5832 }
5833 break;
5838 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint64;
5839 break;
5842 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint64;
5843 break;
5844 case ZEND_FFI_DCL_FLOAT:
5845 dcl->type = (zend_ffi_type*)&zend_ffi_type_float;
5846 break;
5848 dcl->type = (zend_ffi_type*)&zend_ffi_type_double;
5849 break;
5851#ifdef _WIN32
5852 dcl->type = (zend_ffi_type*)&zend_ffi_type_double;
5853#else
5854 dcl->type = (zend_ffi_type*)&zend_ffi_type_long_double;
5855#endif
5856 break;
5860 zend_ffi_parser_error("Unsupported type _Complex at line %d", FFI_G(line));
5861 break;
5862 default:
5863 zend_ffi_parser_error("Unsupported type specifier combination at line %d", FFI_G(line));
5864 break;
5865 }
5868 }
5869}
5870/* }}} */
5871
5872bool zend_ffi_is_typedef_name(const char *name, size_t name_len) /* {{{ */
5873{
5874 zend_ffi_symbol *sym;
5876
5877 if (FFI_G(symbols)) {
5878 sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5879 if (sym) {
5880 return (sym->kind == ZEND_FFI_SYM_TYPE);
5881 }
5882 }
5883 type = zend_hash_str_find_ptr(&FFI_G(types), name, name_len);
5884 if (type) {
5885 return 1;
5886 }
5887 return 0;
5888}
5889/* }}} */
5890
5891void zend_ffi_resolve_typedef(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* {{{ */
5892{
5893 zend_ffi_symbol *sym;
5895
5896 if (FFI_G(symbols)) {
5897 sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5898 if (sym && sym->kind == ZEND_FFI_SYM_TYPE) {
5899 dcl->type = ZEND_FFI_TYPE(sym->type);
5900 if (sym->is_const) {
5901 dcl->attr |= ZEND_FFI_ATTR_CONST;
5902 }
5903 return;
5904 }
5905 }
5906 type = zend_hash_str_find_ptr(&FFI_G(types), name, name_len);
5907 if (type) {
5908 dcl->type = type;
5909 return;
5910 }
5911 zend_ffi_parser_error("Undefined C type \"%.*s\" at line %d", name_len, name, FFI_G(line));
5912}
5913/* }}} */
5914
5915void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */
5916{
5917 zend_ffi_symbol *sym;
5918
5920 val->kind = ZEND_FFI_VAL_NAME;
5921 val->str = name;
5922 val->len = name_len;
5923 return;
5924 } else if (FFI_G(symbols)) {
5925 sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5926 if (sym && sym->kind == ZEND_FFI_SYM_CONST) {
5927 val->i64 = sym->value;
5928 switch (sym->type->kind) {
5932 val->kind = ZEND_FFI_VAL_INT32;
5933 break;
5935 val->kind = ZEND_FFI_VAL_INT64;
5936 break;
5940 val->kind = ZEND_FFI_VAL_UINT32;
5941 break;
5943 val->kind = ZEND_FFI_VAL_UINT64;
5944 break;
5945 default:
5947 }
5948 return;
5949 }
5950 }
5951 val->kind = ZEND_FFI_VAL_ERROR;
5952}
5953/* }}} */
5954
5956{
5958 type->kind = ZEND_FFI_TYPE_ENUM;
5959 type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_ENUM_ATTRS);
5960 type->enumeration.tag_name = NULL;
5961 if (type->attr & ZEND_FFI_ATTR_PACKED) {
5962 type->size = zend_ffi_type_uint8.size;
5963 type->align = zend_ffi_type_uint8.align;
5964 type->enumeration.kind = ZEND_FFI_TYPE_UINT8;
5965 } else {
5966 type->size = zend_ffi_type_uint32.size;
5967 type->align = zend_ffi_type_uint32.align;
5968 type->enumeration.kind = ZEND_FFI_TYPE_UINT32;
5969 }
5971 dcl->attr &= ~ZEND_FFI_ENUM_ATTRS;
5972}
5973/* }}} */
5974
5975void zend_ffi_add_enum_val(zend_ffi_dcl *enum_dcl, const char *name, size_t name_len, zend_ffi_val *val, int64_t *min, int64_t *max, int64_t *last) /* {{{ */
5976{
5977 zend_ffi_symbol *sym;
5978 const zend_ffi_type *sym_type;
5979 int64_t value;
5980 zend_ffi_type *enum_type = ZEND_FFI_TYPE(enum_dcl->type);
5981 bool overflow = 0;
5982 bool is_signed =
5983 (enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT8 ||
5984 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT16 ||
5985 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT32 ||
5986 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT64);
5987
5988 ZEND_ASSERT(enum_type && enum_type->kind == ZEND_FFI_TYPE_ENUM);
5989 if (val->kind == ZEND_FFI_VAL_EMPTY) {
5990 if (is_signed) {
5991 if (*last == 0x7FFFFFFFFFFFFFFFLL) {
5992 overflow = 1;
5993 }
5994 } else {
5995 if ((*min != 0 || *max != 0)
5996 && (uint64_t)*last == 0xFFFFFFFFFFFFFFFFULL) {
5997 overflow = 1;
5998 }
5999 }
6000 value = *last + 1;
6001 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
6002 if (!is_signed && val->ch < 0) {
6003 if ((uint64_t)*max > 0x7FFFFFFFFFFFFFFFULL) {
6004 overflow = 1;
6005 } else {
6006 is_signed = 1;
6007 }
6008 }
6009 value = val->ch;
6010 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
6011 if (!is_signed && val->i64 < 0) {
6012 if ((uint64_t)*max > 0x7FFFFFFFFFFFFFFFULL) {
6013 overflow = 1;
6014 } else {
6015 is_signed = 1;
6016 }
6017 }
6018 value = val->i64;
6019 } else if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
6020 if (is_signed && val->u64 > 0x7FFFFFFFFFFFFFFFULL) {
6021 overflow = 1;
6022 }
6023 value = val->u64;
6024 } else {
6025 zend_ffi_parser_error("Enumerator value \"%.*s\" must be an integer at line %d", name_len, name, FFI_G(line));
6026 return;
6027 }
6028
6029 if (overflow) {
6030 zend_ffi_parser_error("Overflow in enumeration values \"%.*s\" at line %d", name_len, name, FFI_G(line));
6031 return;
6032 }
6033
6034 if (is_signed) {
6035 *min = MIN(*min, value);
6036 *max = MAX(*max, value);
6037 if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
6038 && *min >= -0x7FLL-1 && *max <= 0x7FLL) {
6039 sym_type = &zend_ffi_type_sint8;
6040 } else if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
6041 && *min >= -0x7FFFLL-1 && *max <= 0x7FFFLL) {
6042 sym_type = &zend_ffi_type_sint16;
6043 } else if (*min >= -0x7FFFFFFFLL-1 && *max <= 0x7FFFFFFFLL) {
6044 sym_type = &zend_ffi_type_sint32;
6045 } else {
6046 sym_type = &zend_ffi_type_sint64;
6047 }
6048 } else {
6049 *min = MIN((uint64_t)*min, (uint64_t)value);
6050 *max = MAX((uint64_t)*max, (uint64_t)value);
6051 if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
6052 && (uint64_t)*max <= 0xFFULL) {
6053 sym_type = &zend_ffi_type_uint8;
6054 } else if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
6055 && (uint64_t)*max <= 0xFFFFULL) {
6056 sym_type = &zend_ffi_type_uint16;
6057 } else if ((uint64_t)*max <= 0xFFFFFFFFULL) {
6058 sym_type = &zend_ffi_type_uint32;
6059 } else {
6060 sym_type = &zend_ffi_type_uint64;
6061 }
6062 }
6063 enum_type->enumeration.kind = sym_type->kind;
6064 enum_type->size = sym_type->size;
6065 enum_type->align = sym_type->align;
6066 *last = value;
6067
6068 if (!FFI_G(symbols)) {
6070 zend_hash_init(FFI_G(symbols), 0, NULL, FFI_G(persistent) ? zend_ffi_symbol_hash_persistent_dtor : zend_ffi_symbol_hash_dtor, FFI_G(persistent));
6071 }
6072 sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
6073 if (sym) {
6074 zend_ffi_parser_error("Redeclaration of \"%.*s\" at line %d", name_len, name, FFI_G(line));
6075 } else {
6076 sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6077 sym->kind = ZEND_FFI_SYM_CONST;
6078 sym->type = (zend_ffi_type*)sym_type;
6079 sym->value = value;
6080 zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6081 }
6082}
6083/* }}} */
6084
6086{
6088 type->kind = ZEND_FFI_TYPE_STRUCT;
6090 type->size = 0;
6091 type->align = dcl->align > 1 ? dcl->align : 1;
6092 if (dcl->flags & ZEND_FFI_DCL_UNION) {
6093 type->attr |= ZEND_FFI_ATTR_UNION;
6094 }
6096 type->record.tag_name = NULL;
6097 zend_hash_init(&type->record.fields, 0, NULL, FFI_G(persistent) ? zend_ffi_field_hash_persistent_dtor :zend_ffi_field_hash_dtor, FFI_G(persistent));
6098 dcl->attr &= ~ZEND_FFI_STRUCT_ATTRS;
6099 dcl->align = 0;
6100}
6101/* }}} */
6102
6103static zend_result zend_ffi_validate_prev_field_type(zend_ffi_type *struct_type) /* {{{ */
6104{
6105 if (zend_hash_num_elements(&struct_type->record.fields) > 0) {
6106 zend_ffi_field *field = NULL;
6107
6108 ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&struct_type->record.fields, field) {
6109 break;
6111 if (ZEND_FFI_TYPE(field->type)->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY) {
6112 zend_ffi_throw_parser_error("Flexible array member not at end of struct at line %d", FFI_G(line));
6113 return FAILURE;
6114 }
6115 }
6116 return SUCCESS;
6117}
6118/* }}} */
6119
6120static zend_result zend_ffi_validate_field_type(zend_ffi_type *type, zend_ffi_type *struct_type) /* {{{ */
6121{
6122 if (type == struct_type) {
6123 zend_ffi_throw_parser_error("Struct/union can't contain an instance of itself at line %d", FFI_G(line));
6124 return FAILURE;
6125 } else if (zend_ffi_validate_var_type(type, 1) == FAILURE) {
6126 return FAILURE;
6127 } else if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6129 zend_ffi_throw_parser_error("Flexible array member in union at line %d", FFI_G(line));
6130 return FAILURE;
6131 }
6132 }
6133 return zend_ffi_validate_prev_field_type(struct_type);
6134}
6135/* }}} */
6136
6137void zend_ffi_add_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl) /* {{{ */
6138{
6139 zend_ffi_field *field;
6140 zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
6141 zend_ffi_type *field_type;
6142
6143 ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6144 zend_ffi_finalize_type(field_dcl);
6145 field_type = ZEND_FFI_TYPE(field_dcl->type);
6146 if (zend_ffi_validate_field_type(field_type, struct_type) == FAILURE) {
6147 zend_ffi_cleanup_dcl(field_dcl);
6149 }
6150
6151 field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
6152 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6153 struct_type->align = MAX(struct_type->align, MAX(field_type->align, field_dcl->align));
6154 }
6155 if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6156 field->offset = 0;
6157 struct_type->size = MAX(struct_type->size, field_type->size);
6158 } else {
6159 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6160 uint32_t field_align = MAX(field_type->align, field_dcl->align);
6161 struct_type->size = ((struct_type->size + (field_align - 1)) / field_align) * field_align;
6162 }
6163 field->offset = struct_type->size;
6164 struct_type->size += field_type->size;
6165 }
6166 field->type = field_dcl->type;
6167 field->is_const = (bool)(field_dcl->attr & ZEND_FFI_ATTR_CONST);
6168 field->is_nested = 0;
6169 field->first_bit = 0;
6170 field->bits = 0;
6171 field_dcl->type = field_type; /* reset "owned" flag */
6172
6173 if (!zend_hash_str_add_ptr(&struct_type->record.fields, name, name_len, field)) {
6174 zend_ffi_type_dtor(field->type);
6175 pefree(field, FFI_G(persistent));
6176 zend_ffi_parser_error("Duplicate field name \"%.*s\" at line %d", name_len, name, FFI_G(line));
6177 }
6178}
6179/* }}} */
6180
6181void zend_ffi_add_anonymous_field(zend_ffi_dcl *struct_dcl, zend_ffi_dcl *field_dcl) /* {{{ */
6182{
6183 zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
6184 zend_ffi_type *field_type;
6185 zend_ffi_field *field;
6187
6188 ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6189 zend_ffi_finalize_type(field_dcl);
6190 field_type = ZEND_FFI_TYPE(field_dcl->type);
6191 if (field_type->kind != ZEND_FFI_TYPE_STRUCT) {
6192 zend_ffi_cleanup_dcl(field_dcl);
6193 zend_ffi_parser_error("Declaration does not declare anything at line %d", FFI_G(line));
6194 return;
6195 }
6196
6197 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6198 struct_type->align = MAX(struct_type->align, MAX(field_type->align, field_dcl->align));
6199 }
6200 if (!(struct_type->attr & ZEND_FFI_ATTR_UNION)) {
6201 if (zend_ffi_validate_prev_field_type(struct_type) == FAILURE) {
6202 zend_ffi_cleanup_dcl(field_dcl);
6204 }
6205 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6206 uint32_t field_align = MAX(field_type->align, field_dcl->align);
6207 struct_type->size = ((struct_type->size + (field_align - 1)) / field_align) * field_align;
6208 }
6209 }
6210
6211 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&field_type->record.fields, key, field) {
6212 zend_ffi_field *new_field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
6213
6214 if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6215 new_field->offset = field->offset;
6216 } else {
6217 new_field->offset = struct_type->size + field->offset;
6218 }
6219 new_field->type = field->type;
6220 new_field->is_const = field->is_const;
6221 new_field->is_nested = 1;
6222 new_field->first_bit = field->first_bit;
6223 new_field->bits = field->bits;
6224 field->type = ZEND_FFI_TYPE(field->type); /* reset "owned" flag */
6225
6226 if (key) {
6227 if (!zend_hash_add_ptr(&struct_type->record.fields, key, new_field)) {
6228 zend_ffi_type_dtor(new_field->type);
6229 pefree(new_field, FFI_G(persistent));
6230 zend_ffi_parser_error("Duplicate field name \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
6231 return;
6232 }
6233 } else {
6234 zend_hash_next_index_insert_ptr(&struct_type->record.fields, field);
6235 }
6237
6238 if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6239 struct_type->size = MAX(struct_type->size, field_type->size);
6240 } else {
6241 struct_type->size += field_type->size;
6242 }
6243
6244 zend_ffi_type_dtor(field_dcl->type);
6245 field_dcl->type = NULL;
6246}
6247/* }}} */
6248
6249void zend_ffi_add_bit_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl, zend_ffi_val *bits) /* {{{ */
6250{
6251 zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
6252 zend_ffi_type *field_type;
6253 zend_ffi_field *field;
6254
6255 ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6256 zend_ffi_finalize_type(field_dcl);
6257 field_type = ZEND_FFI_TYPE(field_dcl->type);
6258 if (zend_ffi_validate_field_type(field_type, struct_type) == FAILURE) {
6259 zend_ffi_cleanup_dcl(field_dcl);
6261 }
6262
6263 if (field_type->kind < ZEND_FFI_TYPE_UINT8 || field_type->kind > ZEND_FFI_TYPE_BOOL) {
6264 zend_ffi_cleanup_dcl(field_dcl);
6265 zend_ffi_parser_error("Wrong type of bit field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
6266 }
6267
6268 if (bits->kind == ZEND_FFI_VAL_INT32 || bits->kind == ZEND_FFI_VAL_INT64) {
6269 if (bits->i64 < 0) {
6270 zend_ffi_cleanup_dcl(field_dcl);
6271 zend_ffi_parser_error("Negative width in bit-field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
6272 } else if (bits->i64 == 0) {
6273 zend_ffi_cleanup_dcl(field_dcl);
6274 if (name) {
6275 zend_ffi_parser_error("Zero width in bit-field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
6276 }
6277 return;
6278 } else if (bits->i64 > field_type->size * 8) {
6279 zend_ffi_cleanup_dcl(field_dcl);
6280 zend_ffi_parser_error("Width of \"%.*s\" exceeds its type at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
6281 }
6282 } else if (bits->kind == ZEND_FFI_VAL_UINT32 || bits->kind == ZEND_FFI_VAL_UINT64) {
6283 if (bits->u64 == 0) {
6284 zend_ffi_cleanup_dcl(field_dcl);
6285 if (name) {
6286 zend_ffi_parser_error("Zero width in bit-field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
6287 }
6288 return;
6289 } else if (bits->u64 > field_type->size * 8) {
6290 zend_ffi_cleanup_dcl(field_dcl);
6291 zend_ffi_parser_error("Width of \"%.*s\" exceeds its type at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
6292 }
6293 } else {
6294 zend_ffi_cleanup_dcl(field_dcl);
6295 zend_ffi_parser_error("Bit field \"%.*s\" width not an integer constant at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
6296 }
6297
6298 field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
6299 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED)) {
6300 struct_type->align = MAX(struct_type->align, sizeof(uint32_t));
6301 }
6302 if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6303 field->offset = 0;
6304 field->first_bit = 0;
6305 field->bits = bits->u64;
6306 if (struct_type->attr & ZEND_FFI_ATTR_PACKED) {
6307 struct_type->size = MAX(struct_type->size, (bits->u64 + 7) / 8);
6308 } else {
6309 struct_type->size = MAX(struct_type->size, ((bits->u64 + 31) / 32) * 4);
6310 }
6311 } else {
6312 zend_ffi_field *prev_field = NULL;
6313
6314 if (zend_hash_num_elements(&struct_type->record.fields) > 0) {
6315 ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&struct_type->record.fields, prev_field) {
6316 break;
6318 }
6319 if (prev_field && prev_field->bits) {
6320 field->offset = prev_field->offset;
6321 field->first_bit = prev_field->first_bit + prev_field->bits;
6322 field->bits = bits->u64;
6323 } else {
6324 field->offset = struct_type->size;
6325 field->first_bit = 0;
6326 field->bits = bits->u64;
6327 }
6328 if (struct_type->attr & ZEND_FFI_ATTR_PACKED) {
6329 struct_type->size = field->offset + ((field->first_bit + field->bits) + 7) / 8;
6330 } else {
6331 struct_type->size = field->offset + (((field->first_bit + field->bits) + 31) / 32) * 4;
6332 }
6333 }
6334 field->type = field_dcl->type;
6335 field->is_const = (bool)(field_dcl->attr & ZEND_FFI_ATTR_CONST);
6336 field->is_nested = 0;
6337 field_dcl->type = field_type; /* reset "owned" flag */
6338
6339 if (name) {
6340 if (!zend_hash_str_add_ptr(&struct_type->record.fields, name, name_len, field)) {
6341 zend_ffi_type_dtor(field->type);
6342 pefree(field, FFI_G(persistent));
6343 zend_ffi_parser_error("Duplicate field name \"%.*s\" at line %d", name_len, name, FFI_G(line));
6344 }
6345 } else {
6346 zend_hash_next_index_insert_ptr(&struct_type->record.fields, field);
6347 }
6348}
6349/* }}} */
6350
6352{
6353 zend_ffi_type *struct_type = ZEND_FFI_TYPE(dcl->type);
6354
6355 ZEND_ASSERT(struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6356 if (dcl->align > struct_type->align) {
6357 struct_type->align = dcl->align;
6358 }
6359 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED)) {
6360 struct_type->size = ((struct_type->size + (struct_type->align - 1)) / struct_type->align) * struct_type->align;
6361 }
6362 dcl->align = 0;
6363}
6364/* }}} */
6365
6367{
6371 type->size = sizeof(void*);
6372 type->align = _Alignof(void*);
6373 zend_ffi_finalize_type(dcl);
6374 if (zend_ffi_validate_vla(ZEND_FFI_TYPE(dcl->type)) == FAILURE) {
6377 }
6378 type->pointer.type = dcl->type;
6382 dcl->align = 0;
6383}
6384/* }}} */
6385
6386static zend_result zend_ffi_validate_array_element_type(zend_ffi_type *type) /* {{{ */
6387{
6388 if (type->kind == ZEND_FFI_TYPE_FUNC) {
6389 zend_ffi_throw_parser_error("Array of functions is not allowed at line %d", FFI_G(line));
6390 return FAILURE;
6391 } else if (type->kind == ZEND_FFI_TYPE_ARRAY && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
6392 zend_ffi_throw_parser_error("Only the leftmost array can be undimensioned at line %d", FFI_G(line));
6393 return FAILURE;
6394 }
6395 return zend_ffi_validate_type(type, 0, 1);
6396}
6397/* }}} */
6398
6400{
6401 int length = 0;
6402 zend_ffi_type *element_type;
6404
6405 zend_ffi_finalize_type(dcl);
6406 element_type = ZEND_FFI_TYPE(dcl->type);
6407
6408 if (len->kind == ZEND_FFI_VAL_EMPTY) {
6409 length = 0;
6410 } else if (len->kind == ZEND_FFI_VAL_UINT32 || len->kind == ZEND_FFI_VAL_UINT64) {
6411 length = len->u64;
6412 } else if (len->kind == ZEND_FFI_VAL_INT32 || len->kind == ZEND_FFI_VAL_INT64) {
6413 length = len->i64;
6414 } else if (len->kind == ZEND_FFI_VAL_CHAR) {
6415 length = len->ch;
6416 } else {
6418 zend_ffi_parser_error("Unsupported array index type at line %d", FFI_G(line));
6419 return;
6420 }
6421 if (length < 0) {
6423 zend_ffi_parser_error("Negative array index at line %d", FFI_G(line));
6424 return;
6425 }
6426
6427 if (zend_ffi_validate_array_element_type(element_type) == FAILURE) {
6430 }
6431
6433 type->kind = ZEND_FFI_TYPE_ARRAY;
6435 type->size = length * element_type->size;
6436 type->align = element_type->align;
6437 type->array.type = dcl->type;
6438 type->array.length = length;
6441 dcl->attr &= ~ZEND_FFI_ARRAY_ATTRS;
6442 dcl->align = 0;
6443}
6444/* }}} */
6445
6446static zend_result zend_ffi_validate_func_ret_type(zend_ffi_type *type) /* {{{ */
6447{
6448 if (type->kind == ZEND_FFI_TYPE_FUNC) {
6449 zend_ffi_throw_parser_error("Function returning function is not allowed at line %d", FFI_G(line));
6450 return FAILURE;
6451 } else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
6452 zend_ffi_throw_parser_error("Function returning array is not allowed at line %d", FFI_G(line));
6453 return FAILURE;
6454 }
6455 return zend_ffi_validate_incomplete_type(type, 1, 0);
6456}
6457/* }}} */
6458
6460{
6462 zend_ffi_type *ret_type;
6463
6464 zend_ffi_finalize_type(dcl);
6465 ret_type = ZEND_FFI_TYPE(dcl->type);
6466
6467 if (args) {
6468 int no_args = 0;
6469 zend_ffi_type *arg_type;
6470
6472 arg_type = ZEND_FFI_TYPE(arg_type);
6473 if (arg_type->kind == ZEND_FFI_TYPE_VOID) {
6474 if (zend_hash_num_elements(args) != 1) {
6475 zend_ffi_cleanup_dcl(nested_dcl);
6479 zend_ffi_parser_error("void type is not allowed at line %d", FFI_G(line));
6480 return;
6481 } else {
6482 no_args = 1;
6483 }
6484 }
6486 if (no_args) {
6489 args = NULL;
6490 }
6491 }
6492
6493#ifdef HAVE_FFI_VECTORCALL_PARTIAL
6494 if (dcl->abi == ZEND_FFI_ABI_VECTORCALL && args) {
6495 zend_ulong i;
6496 zend_ffi_type *arg_type;
6497
6499 arg_type = ZEND_FFI_TYPE(arg_type);
6500# ifdef _WIN64
6501 if (i >= 4 && i <= 5 && (arg_type->kind == ZEND_FFI_TYPE_FLOAT || arg_type->kind == ZEND_FFI_TYPE_DOUBLE)) {
6502# else
6503 if (i < 6 && (arg_type->kind == ZEND_FFI_TYPE_FLOAT || arg_type->kind == ZEND_FFI_TYPE_DOUBLE)) {
6504# endif
6505 zend_ffi_cleanup_dcl(nested_dcl);
6509 zend_ffi_parser_error("Type float/double is not allowed at position " ZEND_ULONG_FMT " with __vectorcall at line %d", i+1, FFI_G(line));
6510 return;
6511 }
6513 }
6514#endif
6515
6516 if (zend_ffi_validate_func_ret_type(ret_type) == FAILURE) {
6517 zend_ffi_cleanup_dcl(nested_dcl);
6519 if (args) {
6522 }
6524 }
6525
6527 type->kind = ZEND_FFI_TYPE_FUNC;
6528 type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_FUNC_ATTRS);
6529 type->size = sizeof(void*);
6530 type->align = 1;
6531 type->func.ret_type = dcl->type;
6532 switch (dcl->abi) {
6534 case ZEND_FFI_ABI_CDECL:
6535 type->func.abi = FFI_DEFAULT_ABI;
6536 break;
6537#ifdef HAVE_FFI_FASTCALL
6539 type->func.abi = FFI_FASTCALL;
6540 break;
6541#endif
6542#ifdef HAVE_FFI_THISCALL
6544 type->func.abi = FFI_THISCALL;
6545 break;
6546#endif
6547#ifdef HAVE_FFI_STDCALL
6549 type->func.abi = FFI_STDCALL;
6550 break;
6551#endif
6552#ifdef HAVE_FFI_PASCAL
6554 type->func.abi = FFI_PASCAL;
6555 break;
6556#endif
6557#ifdef HAVE_FFI_REGISTER
6559 type->func.abi = FFI_REGISTER;
6560 break;
6561#endif
6562#ifdef HAVE_FFI_MS_CDECL
6563 case ZEND_FFI_ABI_MS:
6564 type->func.abi = FFI_MS_CDECL;
6565 break;
6566#endif
6567#ifdef HAVE_FFI_SYSV
6568 case ZEND_FFI_ABI_SYSV:
6569 type->func.abi = FFI_SYSV;
6570 break;
6571#endif
6572#ifdef HAVE_FFI_VECTORCALL_PARTIAL
6574 type->func.abi = FFI_VECTORCALL_PARTIAL;
6575 break;
6576#endif
6577 default:
6578 type->func.abi = FFI_DEFAULT_ABI;
6579 zend_ffi_cleanup_dcl(nested_dcl);
6580 if (args) {
6583 }
6584 type->func.args = NULL;
6585 _zend_ffi_type_dtor(type);
6586 zend_ffi_parser_error("Unsupported calling convention line %d", FFI_G(line));
6587 break;
6588 }
6589 type->func.args = args;
6591 dcl->attr &= ~ZEND_FFI_FUNC_ATTRS;
6592 dcl->align = 0;
6593 dcl->abi = 0;
6594}
6595/* }}} */
6596
6597void zend_ffi_add_arg(HashTable **args, const char *name, size_t name_len, zend_ffi_dcl *arg_dcl) /* {{{ */
6598{
6600
6601 if (!*args) {
6602 *args = pemalloc(sizeof(HashTable), FFI_G(persistent));
6603 zend_hash_init(*args, 0, NULL, zend_ffi_type_hash_dtor, FFI_G(persistent));
6604 }
6605 zend_ffi_finalize_type(arg_dcl);
6606 type = ZEND_FFI_TYPE(arg_dcl->type);
6607 if (type->kind == ZEND_FFI_TYPE_ARRAY) {
6608 if (ZEND_FFI_TYPE_IS_OWNED(arg_dcl->type)) {
6610 type->size = sizeof(void*);
6611 } else {
6615 new_type->size = sizeof(void*);
6616 new_type->align = _Alignof(void*);
6617 new_type->pointer.type = ZEND_FFI_TYPE(type->array.type);
6619 }
6620 } else if (type->kind == ZEND_FFI_TYPE_FUNC) {
6624 new_type->size = sizeof(void*);
6625 new_type->align = _Alignof(void*);
6626 new_type->pointer.type = arg_dcl->type;
6628 }
6629 if (zend_ffi_validate_incomplete_type(type, 1, 1) == FAILURE) {
6630 zend_ffi_cleanup_dcl(arg_dcl);
6633 *args = NULL;
6635 }
6636 zend_hash_next_index_insert_ptr(*args, (void*)arg_dcl->type);
6637}
6638/* }}} */
6639
6640void zend_ffi_declare(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* {{{ */
6641{
6642 zend_ffi_symbol *sym;
6643
6644 if (!FFI_G(symbols)) {
6646 zend_hash_init(FFI_G(symbols), 0, NULL, FFI_G(persistent) ? zend_ffi_symbol_hash_persistent_dtor : zend_ffi_symbol_hash_dtor, FFI_G(persistent));
6647 }
6648 zend_ffi_finalize_type(dcl);
6649 sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
6650 if (sym) {
6652 && sym->kind == ZEND_FFI_SYM_TYPE
6653 && zend_ffi_is_same_type(ZEND_FFI_TYPE(sym->type), ZEND_FFI_TYPE(dcl->type))
6654 && sym->is_const == (bool)(dcl->attr & ZEND_FFI_ATTR_CONST)) {
6655 /* allowed redeclaration */
6656 zend_ffi_type_dtor(dcl->type);
6657 return;
6658 } else if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0
6661
6662 if (type->kind == ZEND_FFI_TYPE_FUNC) {
6663 if (sym->kind == ZEND_FFI_SYM_FUNC
6664 && zend_ffi_same_types(ZEND_FFI_TYPE(sym->type), type)) {
6665 /* allowed redeclaration */
6666 zend_ffi_type_dtor(dcl->type);
6667 return;
6668 }
6669 } else {
6670 if (sym->kind == ZEND_FFI_SYM_VAR
6671 && zend_ffi_is_same_type(ZEND_FFI_TYPE(sym->type), type)
6672 && sym->is_const == (bool)(dcl->attr & ZEND_FFI_ATTR_CONST)) {
6673 /* allowed redeclaration */
6674 zend_ffi_type_dtor(dcl->type);
6675 return;
6676 }
6677 }
6678 }
6679 zend_ffi_parser_error("Redeclaration of \"%.*s\" at line %d", name_len, name, FFI_G(line));
6680 } else {
6682 if (zend_ffi_validate_vla(ZEND_FFI_TYPE(dcl->type)) == FAILURE) {
6685 }
6686 if (dcl->align && dcl->align > ZEND_FFI_TYPE(dcl->type)->align) {
6687 if (ZEND_FFI_TYPE_IS_OWNED(dcl->type)) {
6688 ZEND_FFI_TYPE(dcl->type)->align = dcl->align;
6689 } else {
6691
6692 memcpy(type, ZEND_FFI_TYPE(dcl->type), sizeof(zend_ffi_type));
6693 type->attr |= FFI_G(default_type_attr);
6694 type->align = dcl->align;
6696 }
6697 }
6698 sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6699 sym->kind = ZEND_FFI_SYM_TYPE;
6700 sym->type = dcl->type;
6701 sym->is_const = (bool)(dcl->attr & ZEND_FFI_ATTR_CONST);
6702 dcl->type = ZEND_FFI_TYPE(dcl->type); /* reset "owned" flag */
6703 zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6704 } else {
6706
6707 type = ZEND_FFI_TYPE(dcl->type);
6708 if (zend_ffi_validate_type(type, (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN, 1) == FAILURE) {
6711 }
6712 if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0 ||
6714 sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6716 sym->type = dcl->type;
6717 sym->is_const = (bool)(dcl->attr & ZEND_FFI_ATTR_CONST);
6718 dcl->type = type; /* reset "owned" flag */
6719 zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6720 } else {
6721 /* useless declaration */
6722 zend_ffi_type_dtor(dcl->type);
6723 }
6724 }
6725 }
6726}
6727/* }}} */
6728
6729void zend_ffi_declare_tag(const char *name, size_t name_len, zend_ffi_dcl *dcl, bool incomplete) /* {{{ */
6730{
6731 zend_ffi_tag *tag;
6733
6734 if (!FFI_G(tags)) {
6736 zend_hash_init(FFI_G(tags), 0, NULL, FFI_G(persistent) ? zend_ffi_tag_hash_persistent_dtor : zend_ffi_tag_hash_dtor, FFI_G(persistent));
6737 }
6738 tag = zend_hash_str_find_ptr(FFI_G(tags), name, name_len);
6739 if (tag) {
6741
6742 if (dcl->flags & ZEND_FFI_DCL_STRUCT) {
6743 if (tag->kind != ZEND_FFI_TAG_STRUCT) {
6744 zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6745 return;
6746 } else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6747 zend_ffi_parser_error("Redefinition of \"struct %.*s\" at line %d", name_len, name, FFI_G(line));
6748 return;
6749 }
6750 } else if (dcl->flags & ZEND_FFI_DCL_UNION) {
6751 if (tag->kind != ZEND_FFI_TAG_UNION) {
6752 zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6753 return;
6754 } else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6755 zend_ffi_parser_error("Redefinition of \"union %.*s\" at line %d", name_len, name, FFI_G(line));
6756 return;
6757 }
6758 } else if (dcl->flags & ZEND_FFI_DCL_ENUM) {
6759 if (tag->kind != ZEND_FFI_TAG_ENUM) {
6760 zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6761 return;
6762 } else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6763 zend_ffi_parser_error("Redefinition of \"enum %.*s\" at line %d", name_len, name, FFI_G(line));
6764 return;
6765 }
6766 } else {
6768 return;
6769 }
6770 dcl->type = type;
6771 if (!incomplete) {
6773 }
6774 } else {
6776 zend_string *tag_name = zend_string_init(name, name_len, FFI_G(persistent));
6777
6778 if (dcl->flags & ZEND_FFI_DCL_STRUCT) {
6781 type = ZEND_FFI_TYPE(dcl->type);
6782 type->record.tag_name = zend_string_copy(tag_name);
6783 } else if (dcl->flags & ZEND_FFI_DCL_UNION) {
6784 tag->kind = ZEND_FFI_TAG_UNION;
6786 type = ZEND_FFI_TYPE(dcl->type);
6787 type->record.tag_name = zend_string_copy(tag_name);
6788 } else if (dcl->flags & ZEND_FFI_DCL_ENUM) {
6789 tag->kind = ZEND_FFI_TAG_ENUM;
6791 type = ZEND_FFI_TYPE(dcl->type);
6792 type->enumeration.tag_name = zend_string_copy(tag_name);
6793 } else {
6795 }
6796 tag->type = ZEND_FFI_TYPE_MAKE_OWNED(dcl->type);
6797 dcl->type = ZEND_FFI_TYPE(dcl->type);
6798 if (incomplete) {
6799 dcl->type->attr |= ZEND_FFI_ATTR_INCOMPLETE_TAG;
6800 }
6801 zend_hash_add_new_ptr(FFI_G(tags), tag_name, tag);
6802 zend_string_release(tag_name);
6803 }
6804}
6805/* }}} */
6806
6807void zend_ffi_set_abi(zend_ffi_dcl *dcl, uint16_t abi) /* {{{ */
6808{
6809 if (dcl->abi != ZEND_FFI_ABI_DEFAULT) {
6810 zend_ffi_parser_error("Multiple calling convention specifiers at line %d", FFI_G(line));
6811 } else {
6812 dcl->abi = abi;
6813 }
6814}
6815/* }}} */
6816
6817#define SIMPLE_ATTRIBUTES(_) \
6818 _(cdecl) \
6819 _(fastcall) \
6820 _(thiscall) \
6821 _(stdcall) \
6822 _(ms_abi) \
6823 _(sysv_abi) \
6824 _(vectorcall) \
6825 _(aligned) \
6826 _(packed) \
6827 _(ms_struct) \
6828 _(gcc_struct) \
6829 _(const) \
6830 _(malloc) \
6831 _(deprecated) \
6832 _(nothrow) \
6833 _(leaf) \
6834 _(pure) \
6835 _(noreturn) \
6836 _(warn_unused_result)
6837
6838#define ATTR_ID(name) attr_ ## name,
6839#define ATTR_NAME(name) {sizeof(#name)-1, #name},
6840
6841void zend_ffi_add_attribute(zend_ffi_dcl *dcl, const char *name, size_t name_len) /* {{{ */
6842{
6843 enum {
6845 attr_unsupported
6846 };
6847 static const struct {
6848 size_t len;
6849 const char * const name;
6850 } names[] = {
6852 {0, NULL}
6853 };
6854 int id;
6855
6856 if (name_len > 4
6857 && name[0] == '_'
6858 && name[1] == '_'
6859 && name[name_len-2] == '_'
6860 && name[name_len-1] == '_') {
6861 name += 2;
6862 name_len -= 4;
6863 }
6864 for (id = 0; names[id].len != 0; id++) {
6865 if (name_len == names[id].len) {
6866 if (memcmp(name, names[id].name, name_len) == 0) {
6867 break;
6868 }
6869 }
6870 }
6871 switch (id) {
6872 case attr_cdecl:
6874 break;
6875 case attr_fastcall:
6877 break;
6878 case attr_thiscall:
6880 break;
6881 case attr_stdcall:
6883 break;
6884 case attr_ms_abi:
6886 break;
6887 case attr_sysv_abi:
6889 break;
6890 case attr_vectorcall:
6892 break;
6893 case attr_aligned:
6894 dcl->align = __BIGGEST_ALIGNMENT__;
6895 break;
6896 case attr_packed:
6897 dcl->attr |= ZEND_FFI_ATTR_PACKED;
6898 break;
6899 case attr_ms_struct:
6901 break;
6902 case attr_gcc_struct:
6904 break;
6905 case attr_unsupported:
6906 zend_ffi_parser_error("Unsupported attribute \"%.*s\" at line %d", name_len, name, FFI_G(line));
6907 break;
6908 default:
6909 /* ignore */
6910 break;
6911 }
6912}
6913/* }}} */
6914
6915#define VALUE_ATTRIBUTES(_) \
6916 _(regparam) \
6917 _(aligned) \
6918 _(mode) \
6919 _(nonnull) \
6920 _(alloc_size) \
6921 _(format) \
6922 _(deprecated)
6923
6924void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, int n, zend_ffi_val *val) /* {{{ */
6925{
6926 enum {
6928 attr_unsupported
6929 };
6930 static const struct {
6931 size_t len;
6932 const char * const name;
6933 } names[] = {
6935 {0, NULL}
6936 };
6937 int id;
6938
6939 if (name_len > 4
6940 && name[0] == '_'
6941 && name[1] == '_'
6942 && name[name_len-2] == '_'
6943 && name[name_len-1] == '_') {
6944 name += 2;
6945 name_len -= 4;
6946 }
6947 for (id = 0; names[id].len != 0; id++) {
6948 if (name_len == names[id].len) {
6949 if (memcmp(name, names[id].name, name_len) == 0) {
6950 break;
6951 }
6952 }
6953 }
6954 switch (id) {
6955 case attr_regparam:
6956 if (n == 0
6957 && (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
6958 && val->i64 == 3) {
6960 } else {
6961 zend_ffi_parser_error("Incorrect \"regparam\" value at line %d", FFI_G(line));
6962 }
6963 break;
6964 case attr_aligned:
6965 if (n == 0
6966 && (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
6967 && val->i64 > 0 && val->i64 <= 0x80000000 && (val->i64 & (val->i64 - 1)) == 0) {
6968 dcl->align = val->i64;
6969 } else {
6970 zend_ffi_parser_error("Incorrect \"alignment\" value at line %d", FFI_G(line));
6971 }
6972 break;
6973 case attr_mode:
6974 if (n == 0
6975 && (val->kind == ZEND_FFI_VAL_NAME)) {
6976 const char *str = val->str;
6977 size_t len = val->len;
6978 if (len > 4
6979 && str[0] == '_'
6980 && str[1] == '_'
6981 && str[len-2] == '_'
6982 && str[len-1] == '_') {
6983 str += 2;
6984 len -= 4;
6985 }
6986 // TODO: Add support for vector type 'VnXX' ???
6987 if (len == 2) {
6988 if (str[1] == 'I') {
6990 /* inappropriate type */
6991 } else if (str[0] == 'Q') {
6993 dcl->flags |= ZEND_FFI_DCL_CHAR;
6994 break;
6995 } else if (str[0] == 'H') {
6997 dcl->flags |= ZEND_FFI_DCL_SHORT;
6998 break;
6999 } else if (str[0] == 'S') {
7001 dcl->flags |= ZEND_FFI_DCL_INT;
7002 break;
7003 } else if (str[0] == 'D') {
7005 if (sizeof(long) == 8) {
7006 dcl->flags |= ZEND_FFI_DCL_LONG;
7007 } else {
7009 }
7010 break;
7011 }
7012 } else if (str[1] == 'F') {
7014 /* inappropriate type */
7015 } else if (str[0] == 'S') {
7017 dcl->flags |= ZEND_FFI_DCL_FLOAT;
7018 break;
7019 } else if (str[0] == 'D') {
7021 dcl->flags |= ZEND_FFI_DCL_DOUBLE;
7022 break;
7023 }
7024 }
7025 }
7026 }
7027 zend_ffi_parser_error("Unsupported \"mode\" value at line %d", FFI_G(line));
7028 // TODO: ???
7029 case attr_unsupported:
7030 zend_ffi_parser_error("Unsupported attribute \"%.*s\" at line %d", name_len, name, FFI_G(line));
7031 break;
7032 default:
7033 /* ignore */
7034 break;
7035 }
7036}
7037/* }}} */
7038
7039void zend_ffi_add_msvc_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */
7040{
7041 if (name_len == sizeof("align")-1 && memcmp(name, "align", sizeof("align")-1) == 0) {
7042 if ((val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
7043 && val->i64 > 0 && val->i64 <= 0x80000000 && (val->i64 & (val->i64 - 1)) == 0) {
7044 dcl->align = val->i64;
7045 } else {
7046 zend_ffi_parser_error("Incorrect \"alignment\" value at line %d", FFI_G(line));
7047 }
7048 } else {
7049 /* ignore */
7050 }
7051}
7052/* }}} */
7053
7054static zend_result zend_ffi_nested_type(zend_ffi_type *type, zend_ffi_type *nested_type) /* {{{ */
7055{
7056 nested_type = ZEND_FFI_TYPE(nested_type);
7057 switch (nested_type->kind) {
7059 /* "char" is used as a terminator of nested declaration */
7060 if (nested_type->pointer.type == &zend_ffi_type_char) {
7061 nested_type->pointer.type = type;
7062 return zend_ffi_validate_vla(ZEND_FFI_TYPE(type));
7063 } else {
7064 return zend_ffi_nested_type(type, nested_type->pointer.type);
7065 }
7066 break;
7068 /* "char" is used as a terminator of nested declaration */
7069 if (nested_type->array.type == &zend_ffi_type_char) {
7070 nested_type->array.type = type;
7071 if (zend_ffi_validate_array_element_type(ZEND_FFI_TYPE(type)) == FAILURE) {
7072 return FAILURE;
7073 }
7074 } else {
7075 if (zend_ffi_nested_type(type, nested_type->array.type) != SUCCESS) {
7076 return FAILURE;
7077 }
7078 }
7079 nested_type->size = nested_type->array.length * ZEND_FFI_TYPE(nested_type->array.type)->size;
7080 nested_type->align = ZEND_FFI_TYPE(nested_type->array.type)->align;
7081 return SUCCESS;
7082 break;
7083 case ZEND_FFI_TYPE_FUNC:
7084 /* "char" is used as a terminator of nested declaration */
7085 if (nested_type->func.ret_type == &zend_ffi_type_char) {
7086 nested_type->func.ret_type = type;
7087 return zend_ffi_validate_func_ret_type(ZEND_FFI_TYPE(type));
7088 } else {
7089 return zend_ffi_nested_type(type, nested_type->func.ret_type);
7090 }
7091 break;
7092 default:
7094 }
7095}
7096/* }}} */
7097
7099{
7100 /* "char" is used as a terminator of nested declaration */
7101 zend_ffi_finalize_type(dcl);
7102 if (!nested_dcl->type || nested_dcl->type == &zend_ffi_type_char) {
7103 nested_dcl->type = dcl->type;
7104 } else {
7105 if (zend_ffi_nested_type(dcl->type, nested_dcl->type) == FAILURE) {
7106 zend_ffi_cleanup_dcl(nested_dcl);
7108 }
7109 }
7110 dcl->type = nested_dcl->type;
7111}
7112/* }}} */
7113
7115{
7116 zend_ffi_finalize_type(align_dcl);
7117 dcl->align = MAX(align_dcl->align, ZEND_FFI_TYPE(align_dcl->type)->align);
7118}
7119/* }}} */
7120
7122{
7123 switch (align_val->kind) {
7124 case ZEND_FFI_VAL_INT32:
7126 dcl->align = zend_ffi_type_uint32.align;
7127 break;
7128 case ZEND_FFI_VAL_INT64:
7130 dcl->align = zend_ffi_type_uint64.align;
7131 break;
7132 case ZEND_FFI_VAL_FLOAT:
7133 dcl->align = zend_ffi_type_float.align;
7134 break;
7136 dcl->align = zend_ffi_type_double.align;
7137 break;
7138#ifdef HAVE_LONG_DOUBLE
7140 dcl->align = zend_ffi_type_long_double.align;
7141 break;
7142#endif
7143 case ZEND_FFI_VAL_CHAR:
7145 dcl->align = zend_ffi_type_char.align;
7146 break;
7147 default:
7148 break;
7149 }
7150}
7151/* }}} */
7152
7153#define zend_ffi_expr_bool(val) do { \
7154 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7155 val->kind = ZEND_FFI_VAL_INT32; \
7156 val->i64 = !!val->u64; \
7157 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7158 val->kind = ZEND_FFI_VAL_INT32; \
7159 val->i64 = !!val->i64; \
7160 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7161 val->kind = ZEND_FFI_VAL_INT32; \
7162 val->i64 = !!val->d; \
7163 } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7164 val->kind = ZEND_FFI_VAL_INT32; \
7165 val->i64 = !!val->ch; \
7166 } else { \
7167 val->kind = ZEND_FFI_VAL_ERROR; \
7168 } \
7169} while (0)
7170
7171#define zend_ffi_expr_math(val, op2, OP) do { \
7172 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7173 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7174 val->kind = MAX(val->kind, op2->kind); \
7175 val->u64 = val->u64 OP op2->u64; \
7176 } else if (op2->kind == ZEND_FFI_VAL_INT32) { \
7177 val->u64 = val->u64 OP op2->i64; \
7178 } else if (op2->kind == ZEND_FFI_VAL_INT64) { \
7179 val->u64 = val->u64 OP op2->i64; \
7180 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7181 val->kind = op2->kind; \
7182 val->d = (zend_ffi_double)val->u64 OP op2->d; \
7183 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7184 val->u64 = val->u64 OP op2->ch; \
7185 } else { \
7186 val->kind = ZEND_FFI_VAL_ERROR; \
7187 } \
7188 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7189 if (op2->kind == ZEND_FFI_VAL_UINT32) { \
7190 val->i64 = val->i64 OP op2->u64; \
7191 } else if (op2->kind == ZEND_FFI_VAL_UINT64) { \
7192 val->i64 = val->i64 OP op2->u64; \
7193 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7194 val->kind = MAX(val->kind, op2->kind); \
7195 val->i64 = val->i64 OP op2->i64; \
7196 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7197 val->kind = op2->kind; \
7198 val->d = (zend_ffi_double)val->i64 OP op2->d; \
7199 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7200 val->i64 = val->i64 OP op2->ch; \
7201 } else { \
7202 val->kind = ZEND_FFI_VAL_ERROR; \
7203 } \
7204 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7205 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7206 val->d = val->d OP (zend_ffi_double)op2->u64; \
7207 } else if (op2->kind == ZEND_FFI_VAL_INT32 ||op2->kind == ZEND_FFI_VAL_INT64) { \
7208 val->d = val->d OP (zend_ffi_double)op2->i64; \
7209 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7210 val->kind = MAX(val->kind, op2->kind); \
7211 val->d = val->d OP op2->d; \
7212 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7213 val->d = val->d OP (zend_ffi_double)op2->ch; \
7214 } else { \
7215 val->kind = ZEND_FFI_VAL_ERROR; \
7216 } \
7217 } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7218 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7219 val->kind = op2->kind; \
7220 val->u64 = val->ch OP op2->u64; \
7221 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7222 val->kind = ZEND_FFI_VAL_INT64; \
7223 val->i64 = val->ch OP op2->i64; \
7224 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7225 val->kind = op2->kind; \
7226 val->d = (zend_ffi_double)val->ch OP op2->d; \
7227 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7228 val->ch = val->ch OP op2->ch; \
7229 } else { \
7230 val->kind = ZEND_FFI_VAL_ERROR; \
7231 } \
7232 } else { \
7233 val->kind = ZEND_FFI_VAL_ERROR; \
7234 } \
7235} while (0)
7236
7237#define zend_ffi_expr_int_math(val, op2, OP) do { \
7238 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7239 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7240 val->kind = MAX(val->kind, op2->kind); \
7241 val->u64 = val->u64 OP op2->u64; \
7242 } else if (op2->kind == ZEND_FFI_VAL_INT32) { \
7243 val->u64 = val->u64 OP op2->i64; \
7244 } else if (op2->kind == ZEND_FFI_VAL_INT64) { \
7245 val->u64 = val->u64 OP op2->i64; \
7246 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7247 val->u64 = val->u64 OP (uint64_t)op2->d; \
7248 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7249 val->u64 = val->u64 OP op2->ch; \
7250 } else { \
7251 val->kind = ZEND_FFI_VAL_ERROR; \
7252 } \
7253 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7254 if (op2->kind == ZEND_FFI_VAL_UINT32) { \
7255 val->i64 = val->i64 OP op2->u64; \
7256 } else if (op2->kind == ZEND_FFI_VAL_UINT64) { \
7257 val->i64 = val->i64 OP op2->u64; \
7258 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7259 val->kind = MAX(val->kind, op2->kind); \
7260 val->i64 = val->i64 OP op2->i64; \
7261 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7262 val->u64 = val->u64 OP (int64_t)op2->d; \
7263 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7264 val->i64 = val->i64 OP op2->ch; \
7265 } else { \
7266 val->kind = ZEND_FFI_VAL_ERROR; \
7267 } \
7268 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7269 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7270 val->kind = op2->kind; \
7271 val->u64 = (uint64_t)val->d OP op2->u64; \
7272 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7273 val->kind = op2->kind; \
7274 val->i64 = (int64_t)val->d OP op2->i64; \
7275 } else { \
7276 val->kind = ZEND_FFI_VAL_ERROR; \
7277 } \
7278 } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7279 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7280 val->kind = op2->kind; \
7281 val->u64 = (uint64_t)val->ch OP op2->u64; \
7282 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7283 val->kind = op2->kind; \
7284 val->i64 = (int64_t)val->ch OP op2->u64; \
7285 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7286 val->ch = val->ch OP op2->ch; \
7287 } else { \
7288 val->kind = ZEND_FFI_VAL_ERROR; \
7289 } \
7290 } else { \
7291 val->kind = ZEND_FFI_VAL_ERROR; \
7292 } \
7293} while (0)
7294
7295#define zend_ffi_expr_cmp(val, op2, OP) do { \
7296 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7297 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7298 val->kind = ZEND_FFI_VAL_INT32; \
7299 val->i64 = val->u64 OP op2->u64; \
7300 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7301 val->kind = ZEND_FFI_VAL_INT32; \
7302 val->i64 = val->u64 OP op2->u64; /*signed/unsigned */ \
7303 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7304 val->kind = ZEND_FFI_VAL_INT32; \
7305 val->i64 = (zend_ffi_double)val->u64 OP op2->d; \
7306 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7307 val->kind = ZEND_FFI_VAL_INT32; \
7308 val->i64 = val->u64 OP op2->d; \
7309 } else { \
7310 val->kind = ZEND_FFI_VAL_ERROR; \
7311 } \
7312 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7313 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7314 val->kind = ZEND_FFI_VAL_INT32; \
7315 val->i64 = val->i64 OP op2->i64; /* signed/unsigned */ \
7316 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7317 val->kind = ZEND_FFI_VAL_INT32; \
7318 val->i64 = val->i64 OP op2->i64; \
7319 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7320 val->kind = ZEND_FFI_VAL_INT32; \
7321 val->i64 = (zend_ffi_double)val->i64 OP op2->d; \
7322 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7323 val->kind = ZEND_FFI_VAL_INT32; \
7324 val->i64 = val->i64 OP op2->ch; \
7325 } else { \
7326 val->kind = ZEND_FFI_VAL_ERROR; \
7327 } \
7328 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7329 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7330 val->kind = ZEND_FFI_VAL_INT32; \
7331 val->i64 = val->d OP (zend_ffi_double)op2->u64; \
7332 } else if (op2->kind == ZEND_FFI_VAL_INT32 ||op2->kind == ZEND_FFI_VAL_INT64) { \
7333 val->kind = ZEND_FFI_VAL_INT32; \
7334 val->i64 = val->d OP (zend_ffi_double)op2->i64; \
7335 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7336 val->kind = ZEND_FFI_VAL_INT32; \
7337 val->i64 = val->d OP op2->d; \
7338 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7339 val->kind = ZEND_FFI_VAL_INT32; \
7340 val->i64 = val->d OP (zend_ffi_double)op2->ch; \
7341 } else { \
7342 val->kind = ZEND_FFI_VAL_ERROR; \
7343 } \
7344 } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7345 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7346 val->kind = ZEND_FFI_VAL_INT32; \
7347 val->i64 = val->ch OP op2->i64; /* signed/unsigned */ \
7348 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7349 val->kind = ZEND_FFI_VAL_INT32; \
7350 val->i64 = val->ch OP op2->i64; \
7351 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7352 val->kind = ZEND_FFI_VAL_INT32; \
7353 val->i64 = (zend_ffi_double)val->ch OP op2->d; \
7354 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7355 val->kind = ZEND_FFI_VAL_INT32; \
7356 val->i64 = val->ch OP op2->ch; \
7357 } else { \
7358 val->kind = ZEND_FFI_VAL_ERROR; \
7359 } \
7360 } else { \
7361 val->kind = ZEND_FFI_VAL_ERROR; \
7362 } \
7363} while (0)
7364
7366{
7368 if (val->kind == ZEND_FFI_VAL_INT32) {
7369 if (val->i64) {
7370 *val = *op2;
7371 } else {
7372 *val = *op3;
7373 }
7374 }
7375}
7376/* }}} */
7377
7379{
7382 if (val->kind == ZEND_FFI_VAL_INT32 && op2->kind == ZEND_FFI_VAL_INT32) {
7383 val->i64 = val->i64 || op2->i64;
7384 } else {
7385 val->kind = ZEND_FFI_VAL_ERROR;
7386 }
7387}
7388/* }}} */
7389
7391{
7394 if (val->kind == ZEND_FFI_VAL_INT32 && op2->kind == ZEND_FFI_VAL_INT32) {
7395 val->i64 = val->i64 && op2->i64;
7396 } else {
7397 val->kind = ZEND_FFI_VAL_ERROR;
7398 }
7399}
7400/* }}} */
7401
7406/* }}} */
7407
7412/* }}} */
7413
7418/* }}} */
7419
7424/* }}} */
7425
7430/* }}} */
7431
7436/* }}} */
7437
7442/* }}} */
7443
7448/* }}} */
7449
7454/* }}} */
7455
7460/* }}} */
7461
7466/* }}} */
7467
7472/* }}} */
7473
7478/* }}} */
7479
7484/* }}} */
7485
7490/* }}} */
7491
7493{
7494 zend_ffi_expr_int_math(val, op2, %); // ???
7495}
7496/* }}} */
7497
7499{
7500 zend_ffi_finalize_type(dcl);
7501 switch (ZEND_FFI_TYPE(dcl->type)->kind) {
7503 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7504 val->kind = ZEND_FFI_VAL_FLOAT;
7505 val->d = val->u64;
7506 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7507 val->kind = ZEND_FFI_VAL_FLOAT;
7508 val->d = val->i64;
7509 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7510 val->kind = ZEND_FFI_VAL_FLOAT;
7511 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7512 val->kind = ZEND_FFI_VAL_FLOAT;
7513 val->d = val->ch;
7514 } else {
7515 val->kind = ZEND_FFI_VAL_ERROR;
7516 }
7517 break;
7519 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7520 val->kind = ZEND_FFI_VAL_DOUBLE;
7521 val->d = val->u64;
7522 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7523 val->kind = ZEND_FFI_VAL_DOUBLE;
7524 val->d = val->i64;
7525 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7526 val->kind = ZEND_FFI_VAL_DOUBLE;
7527 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7528 val->kind = ZEND_FFI_VAL_DOUBLE;
7529 val->d = val->ch;
7530 } else {
7531 val->kind = ZEND_FFI_VAL_ERROR;
7532 }
7533 break;
7534#ifdef HAVE_LONG_DOUBLE
7535 case ZEND_FFI_TYPE_LONGDOUBLE:
7536 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7538 val->d = val->u64;
7539 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7541 val->d = val->i64;
7542 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7544 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7546 val->d = val->ch;
7547 } else {
7548 val->kind = ZEND_FFI_VAL_ERROR;
7549 }
7550 break;
7551#endif
7555 case ZEND_FFI_TYPE_BOOL:
7556 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7557 val->kind = ZEND_FFI_VAL_UINT32;
7558 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7559 val->kind = ZEND_FFI_VAL_UINT32;
7560 val->u64 = val->d;
7561 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7562 val->kind = ZEND_FFI_VAL_UINT32;
7563 val->u64 = val->ch;
7564 } else {
7565 val->kind = ZEND_FFI_VAL_ERROR;
7566 }
7567 break;
7571 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7572 val->kind = ZEND_FFI_VAL_INT32;
7573 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7574 val->kind = ZEND_FFI_VAL_INT32;
7575 val->i64 = val->d;
7576 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7577 val->kind = ZEND_FFI_VAL_INT32;
7578 val->i64 = val->ch;
7579 } else {
7580 val->kind = ZEND_FFI_VAL_ERROR;
7581 }
7582 break;
7584 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7585 val->kind = ZEND_FFI_VAL_UINT64;
7586 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7587 val->kind = ZEND_FFI_VAL_UINT64;
7588 val->u64 = val->d;
7589 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7590 val->kind = ZEND_FFI_VAL_UINT64;
7591 val->u64 = val->ch;
7592 } else {
7593 val->kind = ZEND_FFI_VAL_ERROR;
7594 }
7595 break;
7597 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7598 val->kind = ZEND_FFI_VAL_CHAR;
7599 val->ch = val->u64;
7600 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7601 val->kind = ZEND_FFI_VAL_CHAR;
7602 val->ch = val->i64;
7603 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7604 val->kind = ZEND_FFI_VAL_CHAR;
7605 val->ch = val->d;
7606 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7607 } else {
7608 val->kind = ZEND_FFI_VAL_ERROR;
7609 }
7610 break;
7611 case ZEND_FFI_TYPE_CHAR:
7612 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7613 val->kind = ZEND_FFI_VAL_UINT32;
7614 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7615 val->kind = ZEND_FFI_VAL_UINT32;
7616 val->u64 = val->d;
7617 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7618 val->kind = ZEND_FFI_VAL_UINT32;
7619 val->u64 = val->ch;
7620 } else {
7621 val->kind = ZEND_FFI_VAL_ERROR;
7622 }
7623 break;
7624 default:
7625 val->kind = ZEND_FFI_VAL_ERROR;
7626 break;
7627 }
7628 zend_ffi_type_dtor(dcl->type);
7629}
7630/* }}} */
7631
7633{
7634 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7635 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7636 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7637 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7638 } else {
7639 val->kind = ZEND_FFI_VAL_ERROR;
7640 }
7641}
7642/* }}} */
7643
7645{
7646 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7647 val->u64 = -val->u64;
7648 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7649 val->i64 = -val->i64;
7650 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7651 val->d = -val->d;
7652 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7653 val->ch = -val->ch;
7654 } else {
7655 val->kind = ZEND_FFI_VAL_ERROR;
7656 }
7657}
7658/* }}} */
7659
7661{
7662 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7663 val->u64 = ~val->u64;
7664 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7665 val->i64 = ~val->i64;
7666 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7667 val->ch = ~val->ch;
7668 } else {
7669 val->kind = ZEND_FFI_VAL_ERROR;
7670 }
7671}
7672/* }}} */
7673
7675{
7677 if (val->kind == ZEND_FFI_VAL_INT32) {
7678 val->i64 = !val->i64;
7679 }
7680}
7681/* }}} */
7682
7684{
7685 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT32) {
7686 val->kind = ZEND_FFI_VAL_UINT32;
7687 val->u64 = zend_ffi_type_uint32.size;
7688 } else if (val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT64) {
7689 val->kind = ZEND_FFI_VAL_UINT32;
7690 val->u64 = zend_ffi_type_uint64.size;
7691 } else if (val->kind == ZEND_FFI_VAL_FLOAT) {
7692 val->kind = ZEND_FFI_VAL_UINT32;
7693 val->u64 = zend_ffi_type_float.size;
7694 } else if (val->kind == ZEND_FFI_VAL_DOUBLE) {
7695 val->kind = ZEND_FFI_VAL_UINT32;
7696 val->u64 = zend_ffi_type_double.size;
7697 } else if (val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7698 val->kind = ZEND_FFI_VAL_UINT32;
7699#ifdef _WIN32
7700 val->u64 = zend_ffi_type_double.size;
7701#else
7702 val->u64 = zend_ffi_type_long_double.size;
7703#endif
7704 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7705 val->kind = ZEND_FFI_VAL_UINT32;
7706 val->u64 = zend_ffi_type_char.size;
7707 } else if (val->kind == ZEND_FFI_VAL_STRING) {
7708 if (memchr(val->str, '\\', val->len)) {
7709 // TODO: support for escape sequences ???
7710 val->kind = ZEND_FFI_VAL_ERROR;
7711 } else {
7712 val->kind = ZEND_FFI_VAL_UINT32;
7713 val->u64 = val->len + 1;
7714 }
7715 } else {
7716 val->kind = ZEND_FFI_VAL_ERROR;
7717 }
7718}
7719/* }}} */
7720
7722{
7724
7725 zend_ffi_finalize_type(dcl);
7726 type = ZEND_FFI_TYPE(dcl->type);
7727 val->kind = (type->size > 0xffffffff) ? ZEND_FFI_VAL_UINT64 : ZEND_FFI_VAL_UINT32;
7728 val->u64 = type->size;
7729 zend_ffi_type_dtor(dcl->type);
7730}
7731/* }}} */
7732
7734{
7735 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT32) {
7736 val->kind = ZEND_FFI_VAL_UINT32;
7737 val->u64 = zend_ffi_type_uint32.align;
7738 } else if (val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT64) {
7739 val->kind = ZEND_FFI_VAL_UINT32;
7740 val->u64 = zend_ffi_type_uint64.align;
7741 } else if (val->kind == ZEND_FFI_VAL_FLOAT) {
7742 val->kind = ZEND_FFI_VAL_UINT32;
7743 val->u64 = zend_ffi_type_float.align;
7744 } else if (val->kind == ZEND_FFI_VAL_DOUBLE) {
7745 val->kind = ZEND_FFI_VAL_UINT32;
7746 val->u64 = zend_ffi_type_double.align;
7747#ifdef HAVE_LONG_DOUBLE
7748 } else if (val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7749 val->kind = ZEND_FFI_VAL_UINT32;
7750 val->u64 = zend_ffi_type_long_double.align;
7751#endif
7752 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7753 val->kind = ZEND_FFI_VAL_UINT32;
7754 val->u64 = zend_ffi_type_char.size;
7755 } else if (val->kind == ZEND_FFI_VAL_STRING) {
7756 val->kind = ZEND_FFI_VAL_UINT32;
7757 val->u64 = _Alignof(char*);
7758 } else {
7759 val->kind = ZEND_FFI_VAL_ERROR;
7760 }
7761}
7762/* }}} */
7763
7765{
7766 zend_ffi_finalize_type(dcl);
7767 val->kind = ZEND_FFI_VAL_UINT32;
7768 val->u64 = ZEND_FFI_TYPE(dcl->type)->align;
7769 zend_ffi_type_dtor(dcl->type);
7770}
7771/* }}} */
7772
7773void zend_ffi_val_number(zend_ffi_val *val, int base, const char *str, size_t str_len) /* {{{ */
7774{
7775 int u = 0;
7776 int l = 0;
7777
7778 if (str[str_len-1] == 'u' || str[str_len-1] == 'U') {
7779 u = 1;
7780 if (str[str_len-2] == 'l' || str[str_len-2] == 'L') {
7781 l = 1;
7782 if (str[str_len-3] == 'l' || str[str_len-3] == 'L') {
7783 l = 2;
7784 }
7785 }
7786 } else if (str[str_len-1] == 'l' || str[str_len-1] == 'L') {
7787 l = 1;
7788 if (str[str_len-2] == 'l' || str[str_len-2] == 'L') {
7789 l = 2;
7790 if (str[str_len-3] == 'u' || str[str_len-3] == 'U') {
7791 u = 1;
7792 }
7793 } else if (str[str_len-2] == 'u' || str[str_len-2] == 'U') {
7794 u = 1;
7795 }
7796 }
7797 if (u) {
7798 val->u64 = strtoull(str, NULL, base);
7799 if (l == 0) {
7800 val->kind = ZEND_FFI_VAL_UINT32;
7801 } else if (l == 1) {
7802 val->kind = (sizeof(long) == 4) ? ZEND_FFI_VAL_UINT32 : ZEND_FFI_VAL_UINT64;
7803 } else if (l == 2) {
7804 val->kind = ZEND_FFI_VAL_UINT64;
7805 }
7806 } else {
7807 val->i64 = strtoll(str, NULL, base);
7808 if (l == 0) {
7809 val->kind = ZEND_FFI_VAL_INT32;
7810 } else if (l == 1) {
7811 val->kind = (sizeof(long) == 4) ? ZEND_FFI_VAL_INT32 : ZEND_FFI_VAL_INT64;
7812 } else if (l == 2) {
7813 val->kind = ZEND_FFI_VAL_INT64;
7814 }
7815 }
7816}
7817/* }}} */
7818
7819void zend_ffi_val_float_number(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7820{
7821 val->d = strtold(str, NULL);
7822 if (str[str_len-1] == 'f' || str[str_len-1] == 'F') {
7823 val->kind = ZEND_FFI_VAL_FLOAT;
7824 } else if (str[str_len-1] == 'l' || str[str_len-1] == 'L') {
7826 } else {
7827 val->kind = ZEND_FFI_VAL_DOUBLE;
7828 }
7829}
7830/* }}} */
7831
7832void zend_ffi_val_string(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7833{
7834 if (str[0] != '\"') {
7835 val->kind = ZEND_FFI_VAL_ERROR;
7836 } else {
7837 val->kind = ZEND_FFI_VAL_STRING;
7838 val->str = str + 1;
7839 val->len = str_len - 2;
7840 }
7841}
7842/* }}} */
7843
7844void zend_ffi_val_character(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7845{
7846 int n;
7847
7848 if (str[0] != '\'') {
7849 val->kind = ZEND_FFI_VAL_ERROR;
7850 } else {
7851 val->kind = ZEND_FFI_VAL_CHAR;
7852 if (str_len == 3) {
7853 val->ch = str[1];
7854 } else if (str[1] == '\\') {
7855 if (str[2] == 'a') {
7856 } else if (str[2] == 'b' && str_len == 4) {
7857 val->ch = '\b';
7858 } else if (str[2] == 'f' && str_len == 4) {
7859 val->ch = '\f';
7860 } else if (str[2] == 'n' && str_len == 4) {
7861 val->ch = '\n';
7862 } else if (str[2] == 'r' && str_len == 4) {
7863 val->ch = '\r';
7864 } else if (str[2] == 't' && str_len == 4) {
7865 val->ch = '\t';
7866 } else if (str[2] == 'v' && str_len == 4) {
7867 val->ch = '\v';
7868 } else if (str[2] >= '0' && str[2] <= '7') {
7869 n = str[2] - '0';
7870 if (str[3] >= '0' && str[3] <= '7') {
7871 n = n * 8 + (str[3] - '0');
7872 if ((str[4] >= '0' && str[4] <= '7') && str_len == 6) {
7873 n = n * 8 + (str[4] - '0');
7874 } else if (str_len != 5) {
7875 val->kind = ZEND_FFI_VAL_ERROR;
7876 }
7877 } else if (str_len != 4) {
7878 val->kind = ZEND_FFI_VAL_ERROR;
7879 }
7880 if (n <= 0xff) {
7881 val->ch = n;
7882 } else {
7883 val->kind = ZEND_FFI_VAL_ERROR;
7884 }
7885 } else if (str[2] == 'x') {
7886 if (str[3] >= '0' && str[3] <= '9') {
7887 n = str[3] - '0';
7888 } else if (str[3] >= 'A' && str[3] <= 'F') {
7889 n = str[3] - 'A';
7890 } else if (str[3] >= 'a' && str[3] <= 'f') {
7891 n = str[3] - 'a';
7892 } else {
7893 val->kind = ZEND_FFI_VAL_ERROR;
7894 return;
7895 }
7896 if ((str[4] >= '0' && str[4] <= '9') && str_len == 6) {
7897 n = n * 16 + (str[4] - '0');
7898 } else if ((str[4] >= 'A' && str[4] <= 'F') && str_len == 6) {
7899 n = n * 16 + (str[4] - 'A');
7900 } else if ((str[4] >= 'a' && str[4] <= 'f') && str_len == 6) {
7901 n = n * 16 + (str[4] - 'a');
7902 } else if (str_len != 5) {
7903 val->kind = ZEND_FFI_VAL_ERROR;
7904 return;
7905 }
7906 val->ch = n;
7907 } else if (str_len == 4) {
7908 val->ch = str[2];
7909 } else {
7910 val->kind = ZEND_FFI_VAL_ERROR;
7911 }
7912 } else {
7913 val->kind = ZEND_FFI_VAL_ERROR;
7914 }
7915 }
7916}
7917/* }}} */
SAPI_API sapi_module_struct sapi_module
Definition SAPI.c:65
size_t len
Definition apprentice.c:174
bool exception
Definition assert.c:30
zval callback
Definition assert.c:25
fprintf($stream, string $format, mixed ... $values)
count(Countable|array $value, int $mode=COUNT_NORMAL)
glob(string $pattern, int $flags=0)
stat(string $filename)
char s[4]
Definition cdf.c:77
uint32_t u
Definition cdf.c:78
zend_long ptrdiff_t
#define max(a, b)
Definition exif.c:60
error($message)
Definition ext_skel.php:22
void zend_ffi_resolve_typedef(const char *name, size_t name_len, zend_ffi_dcl *dcl)
Definition ffi.c:5891
void zend_ffi_add_arg(HashTable **args, const char *name, size_t name_len, zend_ffi_dcl *arg_dcl)
Definition ffi.c:6597
HashTable * dims
Definition ffi.c:4261
bool is_const
Definition ffi.c:3817
void zend_ffi_expr_cast(zend_ffi_val *val, zend_ffi_dcl *dcl)
Definition ffi.c:7498
bool zend_ffi_is_typedef_name(const char *name, size_t name_len)
Definition ffi.c:5872
zend_ffi_type * type
Definition ffi.c:3812
void zend_ffi_expr_plus(zend_ffi_val *val)
Definition ffi.c:7632
void zend_ffi_expr_sizeof_val(zend_ffi_val *val)
Definition ffi.c:7683
#define zend_ffi_expr_cmp(val, op2, OP)
Definition ffi.c:7295
void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl)
Definition ffi.c:3639
#define zend_ffi_expr_math(val, op2, OP)
Definition ffi.c:7171
void zend_ffi_align_as_val(zend_ffi_dcl *dcl, zend_ffi_val *align_val)
Definition ffi.c:7121
_zend_ffi_symbol_kind
Definition ffi.c:147
@ ZEND_FFI_SYM_FUNC
Definition ffi.c:151
@ ZEND_FFI_SYM_TYPE
Definition ffi.c:148
@ ZEND_FFI_SYM_VAR
Definition ffi.c:150
@ ZEND_FFI_SYM_CONST
Definition ffi.c:149
#define ATTR_NAME(name)
Definition ffi.c:6839
void zend_ffi_add_enum_val(zend_ffi_dcl *enum_dcl, const char *name, size_t name_len, zend_ffi_val *val, int64_t *min, int64_t *max, int64_t *last)
Definition ffi.c:5975
zend_ffi_cdata * new_cdata
Definition ffi.c:4338
void zend_ffi_expr_alignof_val(zend_ffi_val *val)
Definition ffi.c:7733
void zend_ffi_expr_neg(zend_ffi_val *val)
Definition ffi.c:7644
void zend_ffi_expr_alignof_type(zend_ffi_val *val, zend_ffi_dcl *dcl)
Definition ffi.c:7764
zend_ffi_cdata * cdata2
Definition ffi.c:4447
struct _zend_ffi_scope zend_ffi_scope
struct _zend_ffi_symbol zend_ffi_symbol
void zend_ffi_expr_bool_or(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7378
zend_ffi_type * type1
Definition ffi.c:4448
zval * zv
Definition ffi.c:3975
void zend_ffi_add_bit_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl, zend_ffi_val *bits)
Definition ffi.c:6249
#define MAX_TYPE_NAME_LEN
Definition ffi.c:1503
#define __BIGGEST_ALIGNMENT__
Definition ffi.c:58
DL_HANDLE handle
Definition ffi.c:3028
void zend_ffi_adjust_struct_size(zend_ffi_dcl *dcl)
Definition ffi.c:6351
ffi tags
Definition ffi.c:3115
zend_long ch
Definition ffi.c:4580
zend_long n
Definition ffi.c:4979
void zend_ffi_expr_div(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7486
void zend_ffi_expr_shift_left(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7456
void zend_ffi_expr_bw_or(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7402
new_type
Definition ffi.c:4362
new_type size
Definition ffi.c:4365
struct _zend_ffi_ctype_name_buf zend_ffi_ctype_name_buf
void zend_ffi_expr_is_less_or_equal(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7444
void zend_ffi_make_pointer_type(zend_ffi_dcl *dcl)
Definition ffi.c:6366
new_type kind
Definition ffi.c:4363
#define ZEND_FFI_TYPE(t)
Definition ffi.c:179
enum _zend_ffi_type_kind zend_ffi_type_kind
zend_object * type_obj
Definition ffi.c:3811
_zend_ffi_tag_kind
Definition ffi.c:63
@ ZEND_FFI_TAG_ENUM
Definition ffi.c:64
@ ZEND_FFI_TAG_UNION
Definition ffi.c:66
@ ZEND_FFI_TAG_STRUCT
Definition ffi.c:65
zend_module_entry ffi_module_entry
Definition ffi.c:5733
void zend_ffi_add_anonymous_field(zend_ffi_dcl *struct_dcl, zend_ffi_dcl *field_dcl)
Definition ffi.c:6181
ctype
Definition ffi.c:4208
void zend_ffi_expr_is_not_equal(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7426
void zend_ffi_expr_bw_not(zend_ffi_val *val)
Definition ffi.c:7660
void zend_ffi_declare(const char *name, size_t name_len, zend_ffi_dcl *dcl)
Definition ffi.c:6640
zend_ffi_cdata * cdata
Definition ffi.c:3813
void zend_ffi_nested_declaration(zend_ffi_dcl *dcl, zend_ffi_dcl *nested_dcl)
Definition ffi.c:7098
void * ptr1
Definition ffi.c:4449
void zend_ffi_expr_is_greater_or_equal(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7450
zend_string * res
Definition ffi.c:4692
zend_ffi_cdata * old_cdata
Definition ffi.c:3972
void zend_ffi_expr_sizeof_type(zend_ffi_val *val, zend_ffi_dcl *dcl)
Definition ffi.c:7721
void zend_ffi_expr_mul(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7480
void * ptr2
Definition ffi.c:4449
zend_ffi * ffi
Definition ffi.c:3027
void * ptr
Definition ffi.c:3814
bool is_static_call
Definition ffi.c:3818
void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, int n, zend_ffi_val *val)
Definition ffi.c:6924
memcpy(ptr1, ptr2, size)
zend_ffi_type * type2
Definition ffi.c:4448
char * err
Definition ffi.c:3029
#define ZEND_FFI_VALIDATE_API_RESTRICTION()
Definition ffi.c:3017
zval * arg
Definition ffi.c:3975
ffi symbols
Definition ffi.c:3114
#define SIMPLE_ATTRIBUTES(_)
Definition ffi.c:6817
zend_ffi_dcl dcl
Definition ffi.c:4153
memset(ptr, 0, type->size)
zend_ffi_type * type_ptr
Definition ffi.c:3812
RETURN_THROWS()
void zend_ffi_parser_error(const char *format,...)
Definition ffi.c:5759
#define VALUE_ATTRIBUTES(_)
Definition ffi.c:6915
struct _zend_ffi_ctype zend_ffi_ctype
void zend_ffi_expr_mod(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7492
void zend_ffi_expr_bool_and(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7390
bool clean_symbols
Definition ffi.c:4177
void zend_ffi_expr_shift_right(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7462
#define zend_ffi_expr_bool(val)
Definition ffi.c:7153
zend_hash_next_index_insert_new(ht, &zv)
#define ZEND_FFI_TYPE_IS_OWNED(t)
Definition ffi.c:182
bool clean_tags
Definition ffi.c:4178
struct _zend_ffi_cdata_iterator zend_ffi_cdata_iterator
void zend_ffi_make_struct_type(zend_ffi_dcl *dcl)
Definition ffi.c:6085
new_type attr
Definition ffi.c:4364
zval * val
Definition ffi.c:4262
HashTable * ht
Definition ffi.c:4838
struct _zend_ffi_cdata zend_ffi_cdata
void zend_ffi_expr_is_less(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7432
#define ATTR_ID(name)
Definition ffi.c:6838
zend_string * lib
Definition ffi.c:3026
zend_ffi_cdata * cdata1
Definition ffi.c:4447
bool owned
Definition ffi.c:3815
void zend_ffi_expr_bw_xor(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7408
_zend_ffi_flags
Definition ffi.c:103
@ ZEND_FFI_FLAG_PERSISTENT
Definition ffi.c:106
@ ZEND_FFI_FLAG_CONST
Definition ffi.c:104
@ ZEND_FFI_FLAG_OWNED
Definition ffi.c:105
void zend_ffi_make_func_type(zend_ffi_dcl *dcl, HashTable *args, zend_ffi_dcl *nested_dcl)
Definition ffi.c:6459
void zend_ffi_val_character(zend_ffi_val *val, const char *str, size_t str_len)
Definition ffi.c:7844
void zend_ffi_validate_type_name(zend_ffi_dcl *dcl)
Definition ffi.c:3741
_zend_ffi_type_kind
Definition ffi.c:77
@ ZEND_FFI_TYPE_UINT32
Definition ffi.c:88
@ ZEND_FFI_TYPE_UINT16
Definition ffi.c:86
@ ZEND_FFI_TYPE_FLOAT
Definition ffi.c:79
@ ZEND_FFI_TYPE_SINT8
Definition ffi.c:85
@ ZEND_FFI_TYPE_DOUBLE
Definition ffi.c:80
@ ZEND_FFI_TYPE_CHAR
Definition ffi.c:94
@ ZEND_FFI_TYPE_SINT64
Definition ffi.c:91
@ ZEND_FFI_TYPE_ARRAY
Definition ffi.c:97
@ ZEND_FFI_TYPE_UINT64
Definition ffi.c:90
@ ZEND_FFI_TYPE_ENUM
Definition ffi.c:92
@ ZEND_FFI_TYPE_FUNC
Definition ffi.c:96
@ ZEND_FFI_TYPE_UINT8
Definition ffi.c:84
@ ZEND_FFI_TYPE_SINT32
Definition ffi.c:89
@ ZEND_FFI_TYPE_STRUCT
Definition ffi.c:98
@ ZEND_FFI_TYPE_POINTER
Definition ffi.c:95
@ ZEND_FFI_TYPE_SINT16
Definition ffi.c:87
@ ZEND_FFI_TYPE_BOOL
Definition ffi.c:93
@ ZEND_FFI_TYPE_VOID
Definition ffi.c:78
void zend_ffi_expr_bw_and(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7414
bool size_is_null
Definition ffi.c:4612
void zend_ffi_set_abi(zend_ffi_dcl *dcl, uint16_t abi)
Definition ffi.c:6807
void zend_ffi_make_enum_type(zend_ffi_dcl *dcl)
Definition ffi.c:5955
zend_object * ztype
Definition ffi.c:3970
void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val)
Definition ffi.c:5915
void zend_ffi_declare_tag(const char *name, size_t name_len, zend_ffi_dcl *dcl, bool incomplete)
Definition ffi.c:6729
void zend_ffi_val_number(zend_ffi_val *val, int base, const char *str, size_t str_len)
Definition ffi.c:7773
void zend_ffi_add_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl)
Definition ffi.c:6137
void zend_ffi_val_float_number(zend_ffi_val *val, const char *str, size_t str_len)
Definition ffi.c:7819
struct _zend_ffi zend_ffi
void zend_ffi_expr_is_greater(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7438
#define ZEND_FFI_SIZEOF_ARG
Definition ffi.c:188
ZEND_HASH_FOREACH_END()
void zend_ffi_expr_bool_not(zend_ffi_val *val)
Definition ffi.c:7674
void zend_ffi_val_string(zend_ffi_val *val, const char *str, size_t str_len)
Definition ffi.c:7832
void zend_ffi_add_msvc_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, zend_ffi_val *val)
Definition ffi.c:7039
enum _zend_ffi_flags zend_ffi_flags
void zend_ffi_expr_sub(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7474
ffi persistent
Definition ffi.c:3633
void zend_ffi_add_attribute(zend_ffi_dcl *dcl, const char *name, size_t name_len)
Definition ffi.c:6841
struct _zend_ffi_field zend_ffi_field
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
enum _zend_ffi_tag_kind zend_ffi_tag_kind
#define ZEND_FFI_TYPE_MAKE_OWNED(t)
Definition ffi.c:185
#define zend_ffi_expr_int_math(val, op2, OP)
Definition ffi.c:7237
void zend_ffi_make_array_type(zend_ffi_dcl *dcl, zend_ffi_val *len)
Definition ffi.c:6399
void zend_ffi_expr_conditional(zend_ffi_val *val, zend_ffi_val *op2, zend_ffi_val *op3)
Definition ffi.c:7365
zend_ffi_type * old_type
Definition ffi.c:3971
new_type align
Definition ffi.c:4366
enum _zend_ffi_symbol_kind zend_ffi_symbol_kind
struct _zend_ffi_tag zend_ffi_tag
void zend_ffi_expr_is_equal(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7420
void zend_ffi_align_as_type(zend_ffi_dcl *dcl, zend_ffi_dcl *align_dcl)
Definition ffi.c:7114
zend_string * type_def
Definition ffi.c:4154
void zend_ffi_expr_add(zend_ffi_val *val, zend_ffi_val *op2)
Definition ffi.c:7468
zend_result zend_ffi_parse_decl(const char *str, size_t len)
zend_result zend_ffi_parse_type(const char *str, size_t len, zend_ffi_dcl *dcl)
zend_long offset
#define NULL
Definition gdcache.h:45
#define prefix
PHPAPI void globfree(glob_t *pglob)
Definition glob.c:777
#define GLOB_NOMATCH
Definition glob.h:94
#define SUCCESS
Definition hash_sha3.c:261
foreach($dp as $el) foreach( $dp as $el) if( $pass2< 2) echo ""
#define cast(t, exp)
Definition minilua.c:215
#define strtoll(s, f, b)
Definition parse_date.c:43
php_info_print_table_start()
Definition info.c:1064
php_info_print_table_row(2, "PDO Driver for Firebird", "enabled")
php_info_print_table_end()
Definition info.c:1074
#define ZEND_FFI_ATTR_VARIADIC
Definition php_ffi.h:137
#define ZEND_FFI_ABI_THISCALL
Definition php_ffi.h:127
HashTable * callbacks
Definition php_ffi.h:43
#define ZEND_FFI_DCL_SHORT
Definition php_ffi.h:77
uint32_t default_type_attr
Definition php_ffi.h:60
#define ZEND_FFI_ARRAY_ATTRS
Definition php_ffi.h:155
@ ZEND_FFI_VAL_FLOAT
Definition php_ffi.h:181
@ ZEND_FFI_VAL_INT32
Definition php_ffi.h:177
@ ZEND_FFI_VAL_LONG_DOUBLE
Definition php_ffi.h:183
@ ZEND_FFI_VAL_NAME
Definition php_ffi.h:186
@ ZEND_FFI_VAL_ERROR
Definition php_ffi.h:176
@ ZEND_FFI_VAL_EMPTY
Definition php_ffi.h:175
@ ZEND_FFI_VAL_UINT32
Definition php_ffi.h:179
@ ZEND_FFI_VAL_STRING
Definition php_ffi.h:185
@ ZEND_FFI_VAL_UINT64
Definition php_ffi.h:180
@ ZEND_FFI_VAL_INT64
Definition php_ffi.h:178
@ ZEND_FFI_VAL_DOUBLE
Definition php_ffi.h:182
@ ZEND_FFI_VAL_CHAR
Definition php_ffi.h:184
#define ZEND_FFI_DCL_TYPE_QUALIFIERS
Definition php_ffi.h:116
#define ZEND_FFI_ENUM_ATTRS
Definition php_ffi.h:152
#define ZEND_FFI_DCL_STORAGE_CLASS
Definition php_ffi.h:107
#define ZEND_FFI_DCL_SIGNED
Definition php_ffi.h:83
#define ZEND_FFI_ABI_MS
Definition php_ffi.h:131
@ ZEND_FFI_ENABLED
Definition php_ffi.h:25
@ ZEND_FFI_PRELOAD
Definition php_ffi.h:26
#define ZEND_FFI_DCL_TYPEDEF_NAME
Definition php_ffi.h:91
#define ZEND_FFI_ATTR_UNION
Definition php_ffi.h:140
#define ZEND_FFI_ABI_SYSV
Definition php_ffi.h:132
#define ZEND_FFI_DCL_LONG_LONG
Definition php_ffi.h:80
#define ZEND_FFI_ATTR_INCOMPLETE_ARRAY
Definition php_ffi.h:138
#define ZEND_FFI_DCL_UNSIGNED
Definition php_ffi.h:84
#define ZEND_FFI_ATTR_INCOMPLETE_TAG
Definition php_ffi.h:136
int line
Definition php_ffi.h:54
#define ZEND_FFI_ATTR_INIT
Definition php_ffi.h:172
#define ZEND_FFI_FUNC_ATTRS
Definition php_ffi.h:158
HashTable types
Definition php_ffi.h:36
#define ZEND_FFI_DCL_VOID
Definition php_ffi.h:75
#define ZEND_FFI_DCL_BOOL
Definition php_ffi.h:85
#define ZEND_FFI_DCL_DOUBLE
Definition php_ffi.h:82
#define ZEND_FFI_DCL_TYPE_SPECIFIERS
Definition php_ffi.h:93
struct _zend_ffi_val zend_ffi_val
#define ZEND_FFI_DCL_CHAR
Definition php_ffi.h:76
#define ZEND_FFI_DCL_LONG
Definition php_ffi.h:79
#define ZEND_FFI_ABI_VECTORCALL
Definition php_ffi.h:133
bool is_cli
Definition php_ffi.h:33
#define ZEND_FFI_ABI_CDECL
Definition php_ffi.h:125
#define ZEND_FFI_STRUCT_ATTRS
Definition php_ffi.h:148
#define ZEND_FFI_DCL_INT
Definition php_ffi.h:78
#define ZEND_FFI_ATTR_PERSISTENT
Definition php_ffi.h:145
unsigned const char * pos
Definition php_ffi.h:52
#define ZEND_FFI_ATTR_CONST
Definition php_ffi.h:135
#define ZEND_FFI_ATTR_GCC_STRUCT
Definition php_ffi.h:143
#define ZEND_FFI_ATTR_VLA
Definition php_ffi.h:139
struct _zend_ffi_type zend_ffi_type
Definition php_ffi.h:29
#define ZEND_FFI_ABI_REGISTER
Definition php_ffi.h:130
HashTable * weak_types
Definition php_ffi.h:46
struct _zend_ffi_dcl zend_ffi_dcl
char * preload
Definition php_ffi.h:39
#define ZEND_FFI_DCL_UNION
Definition php_ffi.h:89
#define ZEND_FFI_ATTR_MS_STRUCT
Definition php_ffi.h:142
#define ZEND_FFI_ABI_PASCAL
Definition php_ffi.h:129
#define ZEND_FFI_POINTER_ATTRS
Definition php_ffi.h:161
#define ZEND_FFI_DCL_ENUM
Definition php_ffi.h:90
#define ZEND_FFI_ABI_STDCALL
Definition php_ffi.h:128
#define ZEND_FFI_DCL_FLOAT
Definition php_ffi.h:81
#define ZEND_FFI_ATTR_STORED
Definition php_ffi.h:146
HashTable * scopes
Definition php_ffi.h:40
JMP_BUF bailout
Definition php_ffi.h:49
#define ZEND_FFI_DCL_STRUCT
Definition php_ffi.h:88
#define ZEND_FFI_ATTR_PACKED
Definition php_ffi.h:141
#define ZEND_FFI_ABI_DEFAULT
Definition php_ffi.h:123
#define ZEND_FFI_DCL_COMPLEX
Definition php_ffi.h:86
bool attribute_parsing
Definition php_ffi.h:58
#define ZEND_FFI_DCL_TYPEDEF
Definition php_ffi.h:101
zend_ffi_api_restriction restriction
Definition php_ffi.h:32
bool allow_vla
Definition php_ffi.h:57
#define FFI_G(v)
Definition php_ffi.h:73
enum _zend_ffi_api_restriction zend_ffi_api_restriction
#define ZEND_FFI_DCL_EXTERN
Definition php_ffi.h:102
#define ZEND_FFI_ABI_FASTCALL
Definition php_ffi.h:126
#define t1
#define t2
#define min(a, b)
unsigned char key[REFLECTION_KEY_LEN]
#define PHP_VERSION
Definition php_version.h:7
int fd
Definition phpdbg.h:282
#define zend_hash_str_add(...)
Definition phpdbg.h:77
zend_constant * data
#define RTLD_DEFAULT
zval rv
Definition session.c:1024
zend_string * var_name
Definition session.c:966
p
Definition session.c:1105
#define strpprintf
Definition spprintf.h:30
zend_string * key
Definition zend_types.h:383
zval val
Definition zend_types.h:381
zend_string * name
Definition zend.h:149
const zend_object_handlers * default_object_handlers
Definition zend.h:186
zend_function * function_handler
Definition zend_API.h:60
HashTable * named_params
Definition zend_API.h:56
uint32_t param_count
Definition zend_API.h:51
zend_object * object
Definition zend_API.h:50
zend_object_iterator it
Definition ffi.c:1946
void * ptr
Definition ffi.c:194
zend_object std
Definition ffi.c:192
zend_ffi_flags flags
Definition ffi.c:196
void * ptr_holder
Definition ffi.c:195
zend_ffi_type * type
Definition ffi.c:193
char buf[MAX_TYPE_NAME_LEN]
Definition ffi.c:1508
zend_object std
Definition ffi.c:200
zend_ffi_type * type
Definition ffi.c:201
uint32_t align
Definition php_ffi.h:166
zend_ffi_type * type
Definition php_ffi.h:169
uint16_t attr
Definition php_ffi.h:167
zend_ffi_type * type
Definition ffi.c:144
bool is_nested
Definition ffi.c:141
uint8_t bits
Definition ffi.c:143
uint8_t first_bit
Definition ffi.c:142
size_t offset
Definition ffi.c:139
bool is_const
Definition ffi.c:140
HashTable * tags
Definition ffi.c:166
HashTable * symbols
Definition ffi.c:165
bool is_const
Definition ffi.c:156
zend_ffi_symbol_kind kind
Definition ffi.c:155
zend_ffi_type * type
Definition ffi.c:157
void * addr
Definition ffi.c:159
int64_t value
Definition ffi.c:160
zend_ffi_type * type
Definition ffi.c:74
zend_ffi_tag_kind kind
Definition ffi.c:73
struct _zend_ffi_type::@016056046110312112304362000360146030316332334371::@264332254304206364037301264275004040070170034140 enumeration
HashTable fields
Definition ffi.c:128
size_t size
Definition ffi.c:111
HashTable * args
Definition ffi.c:132
zend_ffi_type_kind kind
Definition ffi.c:110
ffi_abi abi
Definition ffi.c:133
struct _zend_ffi_type::@016056046110312112304362000360146030316332334371::@016273327024364333303163264267270207017133345054 record
struct _zend_ffi_type::@016056046110312112304362000360146030316332334371::@053310066131114376053345112132043236062316034044 func
struct _zend_ffi_type::@016056046110312112304362000360146030316332334371::@052202136307211065107064172217256343171104062000 array
struct _zend_ffi_type::@016056046110312112304362000360146030316332334371::@260375113037176215306035042226230373011016312351 pointer
zend_long length
Definition ffi.c:121
zend_ffi_type * ret_type
Definition ffi.c:131
uint32_t attr
Definition ffi.c:113
zend_ffi_type * type
Definition ffi.c:120
zend_string * tag_name
Definition ffi.c:116
uint32_t align
Definition ffi.c:112
zend_ffi_val_kind kind
Definition php_ffi.h:196
int64_t i64
Definition php_ffi.h:199
uint64_t u64
Definition php_ffi.h:198
HashTable * tags
Definition ffi.c:173
bool persistent
Definition ffi.c:174
zend_object std
Definition ffi.c:170
HashTable * symbols
Definition ffi.c:172
DL_HANDLE lib
Definition ffi.c:171
const zend_object_iterator_funcs * funcs
zend_class_entry * ce
Definition zend_types.h:560
Definition glob.h:51
int gl_pathc
Definition glob.h:52
char ** gl_pathv
Definition glob.h:56
struct _zend_function::@236135173067030250234125302313220025134003177336 common
uint32_t fn_flags
Definition tar.h:51
#define close(a)
PHP_WINUTIL_API void php_win32_error_msg_free(char *msg)
Definition winutil.c:50
ZEND_API zend_string * zend_strpprintf(size_t max_len, const char *format,...)
Definition zend.c:353
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format,...)
Definition zend.c:1703
ZEND_API zend_result(* zend_post_startup_cb)(void)
Definition zend.c:95
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API ZEND_COLD void zend_error(int type, const char *format,...)
Definition zend.c:1666
ZEND_API size_t zend_vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap)
Definition zend.c:283
#define ZEND_TSRMLS_CACHE_UPDATE()
Definition zend.h:69
#define ZEND_PUTS(str)
Definition zend.h:335
#define ZEND_TSRMLS_CACHE_DEFINE()
Definition zend.h:68
ZEND_API const char * zend_zval_value_name(const zval *arg)
Definition zend_API.c:148
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_error(uint32_t num, const char *name, zval *arg)
Definition zend_API.c:305
ZEND_API bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error)
Definition zend_API.c:4271
#define ZEND_MINIT
Definition zend_API.h:1066
struct _zend_fcall_info_cache zend_fcall_info_cache
#define Z_PARAM_OBJ_OF_CLASS_OR_STR(destination_object, base_ce, destination_string)
Definition zend_API.h:1788
#define RETURN_STRING(s)
Definition zend_API.h:1043
#define ZEND_MINFO
Definition zend_API.h:1070
#define RETURN_STRINGL(s, l)
Definition zend_API.h:1044
#define RETURN_OBJ(r)
Definition zend_API.h:1052
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define Z_PARAM_STR_OR_NULL(dest)
Definition zend_API.h:2089
#define ZEND_MINIT_FUNCTION
Definition zend_API.h:1074
#define ZEND_FN(name)
Definition zend_API.h:71
#define ZEND_GSHUTDOWN_FUNCTION
Definition zend_API.h:1080
#define ZVAL_STRING(z, s)
Definition zend_API.h:956
#define ZEND_DECLARE_MODULE_GLOBALS(module_name)
Definition zend_API.h:268
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define ZEND_RSHUTDOWN
Definition zend_API.h:1069
#define ZEND_GET_MODULE(name)
Definition zend_API.h:241
#define zend_parse_parameters_none()
Definition zend_API.h:353
#define RETVAL_ARR(r)
Definition zend_API.h:1024
#define Z_PARAM_STR(dest)
Definition zend_API.h:2086
#define ZVAL_CHAR(z, c)
Definition zend_API.h:978
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, check_null, deref)
Definition zend_API.h:1962
#define ZEND_GSHUTDOWN(module)
Definition zend_API.h:1072
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define ZEND_RSHUTDOWN_FUNCTION
Definition zend_API.h:1077
#define RETURN_BOOL(b)
Definition zend_API.h:1035
#define ZEND_MINFO_FUNCTION
Definition zend_API.h:1078
struct _zend_fcall_info zend_fcall_info
#define ZEND_METHOD(classname, name)
Definition zend_API.h:76
#define Z_PARAM_ARRAY_HT(dest)
Definition zend_API.h:1852
#define RETURN_STR(s)
Definition zend_API.h:1039
#define ZEND_THIS
Definition zend_API.h:523
#define ZEND_GINIT(module)
Definition zend_API.h:1071
#define Z_PARAM_LONG_OR_NULL(dest, is_null)
Definition zend_API.h:1899
#define RETVAL_LONG(l)
Definition zend_API.h:1011
#define Z_PARAM_BOOL(dest)
Definition zend_API.h:1726
#define Z_PARAM_OBJECT_OF_CLASS(dest, _ce)
Definition zend_API.h:1976
#define Z_PARAM_ZVAL(dest)
Definition zend_API.h:2100
#define ZEND_GINIT_FUNCTION
Definition zend_API.h:1079
ZEND_API zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
#define ZEND_FUNCTION(name)
Definition zend_API.h:75
#define RETURN_STR_COPY(s)
Definition zend_API.h:1042
#define estrndup(s, length)
Definition zend_alloc.h:165
#define ecalloc(nmemb, size)
Definition zend_alloc.h:158
#define efree(ptr)
Definition zend_alloc.h:155
#define pefree(ptr, persistent)
Definition zend_alloc.h:191
#define pemalloc(size, persistent)
Definition zend_alloc.h:189
#define erealloc(ptr, size)
Definition zend_alloc.h:159
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
strncmp(string $string1, string $string2, int $length)
exit(string|int $status=0)
strcmp(string $string1, string $string2)
execute_data func
zval * args
#define ZEND_CLOSURE_OBJECT(op_array)
#define BP_VAR_R
#define EX_VAR_NUM(n)
#define ZEND_COMPILE_PRELOAD
#define ZEND_INTERNAL_FUNCTION
#define EX_NUM_ARGS()
#define EX(element)
#define ZEND_ACC_CALL_VIA_TRAMPOLINE
#define ZEND_ACC_PRELOADED
#define ZEND_ACC_STATIC
#define BP_VAR_RW
struct _zend_internal_function zend_internal_function
#define ZEND_ACC_CLOSURE
#define ZEND_COMPILE_PRELOAD_IN_CHILD
#define E_ERROR
Definition zend_errors.h:23
#define E_WARNING
Definition zend_errors.h:24
#define E_DEPRECATED
Definition zend_errors.h:37
ZEND_API ZEND_COLD zend_object * zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code)
ZEND_API zend_class_entry * zend_ce_error
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
union _zend_function zend_function
#define CG(v)
#define EG(v)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API zval *ZEND_FASTCALL zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData)
Definition zend_hash.c:1209
ZEND_API zval *ZEND_FASTCALL zend_hash_index_add_new(HashTable *ht, zend_ulong h, zval *pData)
Definition zend_hash.c:1214
ZEND_API zval *ZEND_FASTCALL zend_hash_add(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:992
ZEND_API const HashTable zend_empty_array
Definition zend_hash.c:248
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define ZEND_HASH_REVERSE_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1106
#define ZEND_HASH_PACKED_FOREACH_KEY_PTR(ht, _h, _ptr)
Definition zend_hash.h:1513
#define ZEND_HASH_MAP_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1326
#define ZEND_HASH_PACKED_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1487
#define zend_new_array(size)
Definition zend_hash.h:338
#define ZEND_HASH_MAP_FOREACH_STR_KEY(ht, _key)
Definition zend_hash.h:1346
#define ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(ht, _key, _ptr)
Definition zend_hash.h:1433
#define ZEND_HASH_PACKED_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1479
#define ZEND_HASH_MAP_REVERSE_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1334
ZEND_API bool zend_ini_parse_bool(zend_string *str)
Definition zend_ini.c:573
#define ZEND_INI_BEGIN()
Definition zend_ini.h:150
#define ZEND_INI_SYSTEM
Definition zend_ini.h:26
#define ZEND_INI_ENTRY_EX(name, default_value, modifiable, on_modify, displayer)
Definition zend_ini.h:171
#define REGISTER_INI_ENTRIES()
Definition zend_ini.h:203
#define DISPLAY_INI_ENTRIES()
Definition zend_ini.h:205
#define ZEND_INI_MH(name)
Definition zend_ini.h:30
#define ZEND_INI_DISP(name)
Definition zend_ini.h:31
#define ZEND_INI_END()
Definition zend_ini.h:151
#define STD_ZEND_INI_ENTRY(name, default_value, modifiable, on_modify, property_name, struct_type, struct_ptr)
Definition zend_ini.h:185
ZEND_API void zend_iterator_init(zend_object_iterator *iter)
struct _zend_object_iterator zend_object_iterator
struct _zend_object_iterator_funcs zend_object_iterator_funcs
#define ZEND_ULONG_FMT
Definition zend_long.h:88
int32_t zend_long
Definition zend_long.h:42
#define MAX_LENGTH_OF_LONG
Definition zend_long.h:109
uint32_t zend_ulong
Definition zend_long.h:43
struct _zend_string zend_string
#define ZEND_MAP_PTR(ptr)
#define STANDARD_MODULE_HEADER
#define ZEND_MODULE_GLOBALS(module_name)
struct _zend_module_entry zend_module_entry
#define STANDARD_MODULE_PROPERTIES_EX
#define zend_free_trampoline(func)
#define zend_get_std_object_handlers()
ZEND_API void ZEND_FASTCALL zend_objects_store_put(zend_object *object)
#define OBJ_RELEASE(obj)
#define ZEND_OBSERVER_ENABLED
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
#define ZEND_UNCOMPARABLE
#define convert_to_string(op)
int last
#define ALLOCA_FLAG(name)
#define zend_never_inline
#define MIN(a, b)
#define DL_HANDLE
#define ZEND_ELEMENT_COUNT(m)
#define ZEND_FALLTHROUGH
#define EXPECTED(condition)
#define do_alloca(p, use_heap)
#define LONGJMP(a, b)
#define zend_always_inline
#define ZEND_ASSERT(c)
#define ZEND_UNREACHABLE()
#define ZEND_STRL(str)
#define free_alloca(p, use_heap)
#define ZEND_COLD
#define ZEND_PATHS_SEPARATOR
#define UNEXPECTED(condition)
#define MAX(a, b)
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
ZEND_API zend_string * zend_string_concat3(const char *str1, size_t str1_len, const char *str2, size_t str2_len, const char *str3, size_t str3_len)
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_KNOWN(idx)
#define zend_string_equals_literal(str, literal)
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define zend_string_equals_literal_ci(str, c)
#define dval(x)
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define IS_TRUE
Definition zend_types.h:603
#define ZVAL_STR(z, s)
#define ZVAL_UNDEF(z)
#define GC_SET_REFCOUNT(p, rc)
Definition zend_types.h:708
#define IS_FALSE
Definition zend_types.h:602
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_UNDEF
Definition zend_types.h:600
#define ZVAL_TRUE(z)
#define ZVAL_NULL(z)
#define ZVAL_DEREF(z)
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
#define ZVAL_STR_COPY(z, s)
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define IS_DOUBLE
Definition zend_types.h:605
#define Z_PTR_P(zval_p)
#define GC_FLAGS(p)
Definition zend_types.h:756
#define GC_ADDREF(p)
Definition zend_types.h:709
#define IS_OBJ_DESTRUCTOR_CALLED
Definition zend_types.h:828
#define Z_ADDREF_P(pz)
#define Z_PTR(zval)
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define IS_NULL
Definition zend_types.h:601
#define Z_OBJCE_P(zval_p)
#define ZVAL_OBJ(z, o)
@ FAILURE
Definition zend_types.h:61
#define GC_OBJECT
Definition zend_types.h:787
#define IS_OBJECT
Definition zend_types.h:608
#define IS_LONG
Definition zend_types.h:604
#define _IS_BOOL
Definition zend_types.h:629
struct _Bucket Bucket
#define ZVAL_DOUBLE(z, d)
#define Z_REFCOUNT_P(pz)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define IS_OBJ_WEAKLY_REFERENCED
Definition zend_types.h:827
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define GC_REFCOUNT(p)
Definition zend_types.h:707
#define Z_TYPE(zval)
Definition zend_types.h:659
#define Z_DVAL_P(zval_p)
Definition zend_types.h:969
struct _zend_execute_data zend_execute_data
Definition zend_types.h:91
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_BOOL(z, b)
#define GC_FLAGS_SHIFT
Definition zend_types.h:739
#define GC_TYPE_INFO(p)
Definition zend_types.h:754
#define Z_OBJ(zval)
Definition zend_types.h:989
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zval retval
zval * return_value
zval * dim
zend_string * name
bool result
op2
op1
execute_data
object
zval * ret
value
new_op_array scope
zend_object * zobj
#define ZEND_SUB
#define ZEND_ADD
void zend_weakrefs_notify(zend_object *object)