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