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