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[] 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 int open_flags = O_RDONLY;
3287 #ifdef PHP_WIN32
3288 open_flags |= _O_BINARY;
3289 #endif
3290 fd = open(filename, open_flags, 0);
3291 if (fd < 0 || read(fd, code, code_size) != code_size) {
3292 if (preload) {
3293 zend_error(E_WARNING, "FFI: Failed pre-loading '%s', cannot read_file", filename);
3294 } else {
3295 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', cannot read_file", filename);
3296 }
3297 efree(code);
3298 close(fd);
3299 return NULL;
3300 }
3301 close(fd);
3302 code[code_size] = 0;
3303
3304 FFI_G(symbols) = NULL;
3305 FFI_G(tags) = NULL;
3306 FFI_G(persistent) = preload;
3307 FFI_G(default_type_attr) = preload ?
3308 ZEND_FFI_ATTR_STORED | ZEND_FFI_ATTR_PERSISTENT :
3309 ZEND_FFI_ATTR_STORED;
3310
3311 scope_name = NULL;
3312 scope_name_len = 0;
3313 lib = NULL;
3314 code_pos = zend_ffi_parse_directives(filename, code, &scope_name, &lib, preload);
3315 if (!code_pos) {
3316 efree(code);
3317 FFI_G(persistent) = 0;
3318 return NULL;
3319 }
3320 code_size -= code_pos - code;
3321
3322 if (zend_ffi_parse_decl(code_pos, code_size) == FAILURE) {
3323 if (preload) {
3324 zend_error(E_WARNING, "FFI: failed pre-loading '%s'", filename);
3325 } else {
3326 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", filename);
3327 }
3328 goto cleanup;
3329 }
3330
3331 if (lib) {
3332 handle = DL_LOAD(lib);
3333 if (!handle) {
3334 if (preload) {
3335 zend_error(E_WARNING, "FFI: Failed pre-loading '%s'", lib);
3336 } else {
3337 err = GET_DL_ERROR();
3338 #ifdef PHP_WIN32
3339 if (err && err[0]) {
3340 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err);
3341 php_win32_error_msg_free(err);
3342 } else {
3343 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (Unknown reason)", lib);
3344 }
3345 #else
3346 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err);
3347 GET_DL_ERROR(); /* free the buffer storing the error */
3348 #endif
3349 }
3350 goto cleanup;
3351 }
3352 #ifdef RTLD_DEFAULT
3353 } else if (1) {
3354 // TODO: this might need to be disabled or protected ???
3355 handle = RTLD_DEFAULT;
3356 #endif
3357 }
3358
3359 if (preload) {
3360 if (!scope_name) {
3361 scope_name = "C";
3362 }
3363 scope_name_len = strlen(scope_name);
3364 if (FFI_G(scopes)) {
3365 scope = zend_hash_str_find_ptr(FFI_G(scopes), scope_name, scope_name_len);
3366 }
3367 }
3368
3369 if (FFI_G(symbols)) {
3370 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) {
3371 if (sym->kind == ZEND_FFI_SYM_VAR) {
3372 addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
3373 if (!addr) {
3374 if (preload) {
3375 zend_error(E_WARNING, "FFI: failed pre-loading '%s', cannot resolve C variable '%s'", filename, ZSTR_VAL(name));
3376 } else {
3377 zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name));
3378 }
3379 if (lib) {
3380 DL_UNLOAD(handle);
3381 }
3382 goto cleanup;
3383 }
3384 sym->addr = addr;
3385 } else if (sym->kind == ZEND_FFI_SYM_FUNC) {
3386 zend_string *mangled_name = zend_ffi_mangled_func_name(name, ZEND_FFI_TYPE(sym->type));
3387
3388 addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(mangled_name));
3389 zend_string_release(mangled_name);
3390 if (!addr) {
3391 if (preload) {
3392 zend_error(E_WARNING, "failed pre-loading '%s', cannot resolve C function '%s'", filename, ZSTR_VAL(name));
3393 } else {
3394 zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
3395 }
3396 if (lib) {
3397 DL_UNLOAD(handle);
3398 }
3399 goto cleanup;
3400 }
3401 sym->addr = addr;
3402 }
3403 if (scope && scope->symbols) {
3404 zend_ffi_symbol *old_sym = zend_hash_find_ptr(scope->symbols, name);
3405
3406 if (old_sym) {
3407 if (zend_ffi_same_symbols(old_sym, sym)) {
3408 if (ZEND_FFI_TYPE_IS_OWNED(sym->type)
3409 && ZEND_FFI_TYPE(old_sym->type) != ZEND_FFI_TYPE(sym->type)) {
3410 zend_ffi_type *type = ZEND_FFI_TYPE(sym->type);
3411 zend_ffi_cleanup_type(ZEND_FFI_TYPE(old_sym->type), ZEND_FFI_TYPE(type));
3412 zend_ffi_type_dtor(type);
3413 }
3414 } else {
3415 zend_error(E_WARNING, "FFI: failed pre-loading '%s', redefinition of '%s'", filename, ZSTR_VAL(name));
3416 if (lib) {
3417 DL_UNLOAD(handle);
3418 }
3419 goto cleanup;
3420 }
3421 }
3422 }
3423 } ZEND_HASH_FOREACH_END();
3424 }
3425
3426 if (preload) {
3427 if (scope && scope->tags && FFI_G(tags)) {
3428 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(tags), name, tag) {
3429 zend_ffi_tag *old_tag = zend_hash_find_ptr(scope->tags, name);
3430
3431 if (old_tag) {
3432 if (zend_ffi_same_tags(old_tag, tag)) {
3433 if (ZEND_FFI_TYPE_IS_OWNED(tag->type)
3434 && ZEND_FFI_TYPE(old_tag->type) != ZEND_FFI_TYPE(tag->type)) {
3435 zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
3436 zend_ffi_cleanup_type(ZEND_FFI_TYPE(old_tag->type), ZEND_FFI_TYPE(type));
3437 zend_ffi_type_dtor(type);
3438 }
3439 } else {
3440 zend_error(E_WARNING, "FFI: failed pre-loading '%s', redefinition of '%s %s'", filename, zend_ffi_tag_kind_name[tag->kind], ZSTR_VAL(name));
3441 if (lib) {
3442 DL_UNLOAD(handle);
3443 }
3444 goto cleanup;
3445 }
3446 }
3447 } ZEND_HASH_FOREACH_END();
3448 }
3449
3450 if (!scope) {
3451 scope = malloc(sizeof(zend_ffi_scope));
3452 scope->symbols = FFI_G(symbols);
3453 scope->tags = FFI_G(tags);
3454
3455 if (!FFI_G(scopes)) {
3456 FFI_G(scopes) = malloc(sizeof(HashTable));
3457 zend_hash_init(FFI_G(scopes), 0, NULL, zend_ffi_scope_hash_dtor, 1);
3458 }
3459
3460 zend_hash_str_add_ptr(FFI_G(scopes), scope_name, scope_name_len, scope);
3461 } else {
3462 if (FFI_G(symbols)) {
3463 if (!scope->symbols) {
3464 scope->symbols = FFI_G(symbols);
3465 FFI_G(symbols) = NULL;
3466 } else {
3467 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) {
3468 if (!zend_hash_add_ptr(scope->symbols, name, sym)) {
3469 zend_ffi_type_dtor(sym->type);
3470 free(sym);
3471 }
3472 } ZEND_HASH_FOREACH_END();
3473 FFI_G(symbols)->pDestructor = NULL;
3474 zend_hash_destroy(FFI_G(symbols));
3475 }
3476 }
3477 if (FFI_G(tags)) {
3478 if (!scope->tags) {
3479 scope->tags = FFI_G(tags);
3480 FFI_G(tags) = NULL;
3481 } else {
3482 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(tags), name, tag) {
3483 if (!zend_hash_add_ptr(scope->tags, name, tag)) {
3484 zend_ffi_type_dtor(tag->type);
3485 free(tag);
3486 }
3487 } ZEND_HASH_FOREACH_END();
3488 FFI_G(tags)->pDestructor = NULL;
3489 zend_hash_destroy(FFI_G(tags));
3490 }
3491 }
3492 }
3493
3494 if (EG(objects_store).object_buckets) {
3495 ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3496 } else {
3497 ffi = ecalloc(1, sizeof(zend_ffi));
3498 }
3499 ffi->symbols = scope->symbols;
3500 ffi->tags = scope->tags;
3501 ffi->persistent = 1;
3502 } else {
3503 ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3504 ffi->lib = handle;
3505 ffi->symbols = FFI_G(symbols);
3506 ffi->tags = FFI_G(tags);
3507 }
3508
3509 efree(code);
3510 FFI_G(symbols) = NULL;
3511 FFI_G(tags) = NULL;
3512 FFI_G(persistent) = 0;
3513
3514 return ffi;
3515
3516 cleanup:
3517 efree(code);
3518 if (FFI_G(symbols)) {
3519 zend_hash_destroy(FFI_G(symbols));
3520 pefree(FFI_G(symbols), preload);
3521 FFI_G(symbols) = NULL;
3522 }
3523 if (FFI_G(tags)) {
3524 zend_hash_destroy(FFI_G(tags));
3525 pefree(FFI_G(tags), preload);
3526 FFI_G(tags) = NULL;
3527 }
3528 FFI_G(persistent) = 0;
3529 return NULL;
3530 }
3531 /* }}} */
3532
ZEND_METHOD(FFI,load)3533 ZEND_METHOD(FFI, load) /* {{{ */
3534 {
3535 zend_string *fn;
3536 zend_ffi *ffi;
3537
3538 ZEND_FFI_VALIDATE_API_RESTRICTION();
3539 ZEND_PARSE_PARAMETERS_START(1, 1)
3540 Z_PARAM_STR(fn)
3541 ZEND_PARSE_PARAMETERS_END();
3542
3543 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD_IN_CHILD) {
3544 zend_throw_error(zend_ffi_exception_ce, "FFI::load() doesn't work in conjunction with \"opcache.preload_user\". Use \"ffi.preload\" instead.");
3545 RETURN_THROWS();
3546 }
3547
3548 ffi = zend_ffi_load(ZSTR_VAL(fn), (CG(compiler_options) & ZEND_COMPILE_PRELOAD) != 0);
3549
3550 if (ffi) {
3551 RETURN_OBJ(&ffi->std);
3552 }
3553 }
3554 /* }}} */
3555
ZEND_METHOD(FFI,scope)3556 ZEND_METHOD(FFI, scope) /* {{{ */
3557 {
3558 zend_string *scope_name;
3559 zend_ffi_scope *scope = NULL;
3560 zend_ffi *ffi;
3561
3562 ZEND_FFI_VALIDATE_API_RESTRICTION();
3563 ZEND_PARSE_PARAMETERS_START(1, 1)
3564 Z_PARAM_STR(scope_name)
3565 ZEND_PARSE_PARAMETERS_END();
3566
3567 if (FFI_G(scopes)) {
3568 scope = zend_hash_find_ptr(FFI_G(scopes), scope_name);
3569 }
3570
3571 if (!scope) {
3572 zend_throw_error(zend_ffi_exception_ce, "Failed loading scope '%s'", ZSTR_VAL(scope_name));
3573 RETURN_THROWS();
3574 }
3575
3576 ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3577
3578 ffi->symbols = scope->symbols;
3579 ffi->tags = scope->tags;
3580 ffi->persistent = 1;
3581
3582 RETURN_OBJ(&ffi->std);
3583 }
3584 /* }}} */
3585
zend_ffi_cleanup_dcl(zend_ffi_dcl * dcl)3586 static void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl) /* {{{ */
3587 {
3588 if (dcl) {
3589 zend_ffi_type_dtor(dcl->type);
3590 dcl->type = NULL;
3591 }
3592 }
3593 /* }}} */
3594
zend_ffi_throw_parser_error(const char * format,...)3595 static void zend_ffi_throw_parser_error(const char *format, ...) /* {{{ */
3596 {
3597 va_list va;
3598 char *message = NULL;
3599
3600 va_start(va, format);
3601 zend_vspprintf(&message, 0, format, va);
3602
3603 if (EG(current_execute_data)) {
3604 zend_throw_exception(zend_ffi_parser_exception_ce, message, 0);
3605 } else {
3606 zend_error(E_WARNING, "FFI Parser: %s", message);
3607 }
3608
3609 efree(message);
3610 va_end(va);
3611 }
3612 /* }}} */
3613
zend_ffi_validate_vla(zend_ffi_type * type)3614 static zend_result zend_ffi_validate_vla(zend_ffi_type *type) /* {{{ */
3615 {
3616 if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) {
3617 zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line));
3618 return FAILURE;
3619 }
3620 return SUCCESS;
3621 }
3622 /* }}} */
3623
zend_ffi_validate_incomplete_type(zend_ffi_type * type,bool allow_incomplete_tag,bool allow_incomplete_array)3624 static zend_result zend_ffi_validate_incomplete_type(zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */
3625 {
3626 if (!allow_incomplete_tag && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
3627 if (FFI_G(tags)) {
3628 zend_string *key;
3629 zend_ffi_tag *tag;
3630
3631 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(tags), key, tag) {
3632 if (ZEND_FFI_TYPE(tag->type) == type) {
3633 if (type->kind == ZEND_FFI_TYPE_ENUM) {
3634 zend_ffi_throw_parser_error("Incomplete enum \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3635 } else if (type->attr & ZEND_FFI_ATTR_UNION) {
3636 zend_ffi_throw_parser_error("Incomplete union \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3637 } else {
3638 zend_ffi_throw_parser_error("Incomplete struct \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3639 }
3640 return FAILURE;
3641 }
3642 } ZEND_HASH_FOREACH_END();
3643 }
3644 if (FFI_G(symbols)) {
3645 zend_string *key;
3646 zend_ffi_symbol *sym;
3647
3648 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(symbols), key, sym) {
3649 if (type == ZEND_FFI_TYPE(sym->type)) {
3650 zend_ffi_throw_parser_error("Incomplete C type %s at line %d", ZSTR_VAL(key), FFI_G(line));
3651 return FAILURE;
3652 }
3653 } ZEND_HASH_FOREACH_END();
3654 }
3655 zend_ffi_throw_parser_error("Incomplete type at line %d", FFI_G(line));
3656 return FAILURE;
3657 } else if (!allow_incomplete_array && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
3658 zend_ffi_throw_parser_error("\"[]\" is not allowed at line %d", FFI_G(line));
3659 return FAILURE;
3660 } else if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) {
3661 zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line));
3662 return FAILURE;
3663 }
3664 return SUCCESS;
3665 }
3666 /* }}} */
3667
zend_ffi_validate_type(zend_ffi_type * type,bool allow_incomplete_tag,bool allow_incomplete_array)3668 static zend_result zend_ffi_validate_type(zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */
3669 {
3670 if (type->kind == ZEND_FFI_TYPE_VOID) {
3671 zend_ffi_throw_parser_error("void type is not allowed at line %d", FFI_G(line));
3672 return FAILURE;
3673 }
3674 return zend_ffi_validate_incomplete_type(type, allow_incomplete_tag, allow_incomplete_array);
3675 }
3676 /* }}} */
3677
zend_ffi_validate_var_type(zend_ffi_type * type,bool allow_incomplete_array)3678 static zend_result zend_ffi_validate_var_type(zend_ffi_type *type, bool allow_incomplete_array) /* {{{ */
3679 {
3680 if (type->kind == ZEND_FFI_TYPE_FUNC) {
3681 zend_ffi_throw_parser_error("function type is not allowed at line %d", FFI_G(line));
3682 return FAILURE;
3683 }
3684 return zend_ffi_validate_type(type, 0, allow_incomplete_array);
3685 }
3686 /* }}} */
3687
zend_ffi_validate_type_name(zend_ffi_dcl * dcl)3688 void zend_ffi_validate_type_name(zend_ffi_dcl *dcl) /* {{{ */
3689 {
3690 zend_ffi_finalize_type(dcl);
3691 if (zend_ffi_validate_var_type(ZEND_FFI_TYPE(dcl->type), 0) == FAILURE) {
3692 zend_ffi_cleanup_dcl(dcl);
3693 LONGJMP(FFI_G(bailout), FAILURE);
3694 }
3695 }
3696 /* }}} */
3697
zend_ffi_subst_type(zend_ffi_type ** dcl,zend_ffi_type * type)3698 static bool zend_ffi_subst_type(zend_ffi_type **dcl, zend_ffi_type *type) /* {{{ */
3699 {
3700 zend_ffi_type *dcl_type;
3701 zend_ffi_field *field;
3702
3703 if (*dcl == type) {
3704 *dcl = ZEND_FFI_TYPE_MAKE_OWNED(type);
3705 return 1;
3706 }
3707 dcl_type = *dcl;
3708 switch (dcl_type->kind) {
3709 case ZEND_FFI_TYPE_POINTER:
3710 return zend_ffi_subst_type(&dcl_type->pointer.type, type);
3711 case ZEND_FFI_TYPE_ARRAY:
3712 return zend_ffi_subst_type(&dcl_type->array.type, type);
3713 case ZEND_FFI_TYPE_FUNC:
3714 if (zend_ffi_subst_type(&dcl_type->func.ret_type, type)) {
3715 return 1;
3716 }
3717 if (dcl_type->func.args) {
3718 zval *zv;
3719
3720 ZEND_HASH_PACKED_FOREACH_VAL(dcl_type->func.args, zv) {
3721 if (zend_ffi_subst_type((zend_ffi_type**)&Z_PTR_P(zv), type)) {
3722 return 1;
3723 }
3724 } ZEND_HASH_FOREACH_END();
3725 }
3726 break;
3727 case ZEND_FFI_TYPE_STRUCT:
3728 ZEND_HASH_MAP_FOREACH_PTR(&dcl_type->record.fields, field) {
3729 if (zend_ffi_subst_type(&field->type, type)) {
3730 return 1;
3731 }
3732 } ZEND_HASH_FOREACH_END();
3733 break;
3734 default:
3735 break;
3736 }
3737 return 0;
3738 } /* }}} */
3739
zend_ffi_tags_cleanup(zend_ffi_dcl * dcl)3740 static void zend_ffi_tags_cleanup(zend_ffi_dcl *dcl) /* {{{ */
3741 {
3742 zend_ffi_tag *tag;
3743 ZEND_HASH_MAP_FOREACH_PTR(FFI_G(tags), tag) {
3744 if (ZEND_FFI_TYPE_IS_OWNED(tag->type)) {
3745 zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
3746 zend_ffi_subst_type(&dcl->type, type);
3747 tag->type = type;
3748 }
3749 } ZEND_HASH_FOREACH_END();
3750 zend_hash_destroy(FFI_G(tags));
3751 efree(FFI_G(tags));
3752 }
3753 /* }}} */
3754
ZEND_METHOD(FFI,new)3755 ZEND_METHOD(FFI, new) /* {{{ */
3756 {
3757 zend_string *type_def = NULL;
3758 zend_object *type_obj = NULL;
3759 zend_ffi_type *type, *type_ptr;
3760 zend_ffi_cdata *cdata;
3761 void *ptr;
3762 bool owned = 1;
3763 bool persistent = 0;
3764 bool is_const = 0;
3765 bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
3766 zend_ffi_flags flags = ZEND_FFI_FLAG_OWNED;
3767
3768 ZEND_FFI_VALIDATE_API_RESTRICTION();
3769 ZEND_PARSE_PARAMETERS_START(1, 3)
3770 Z_PARAM_OBJ_OF_CLASS_OR_STR(type_obj, zend_ffi_ctype_ce, type_def)
3771 Z_PARAM_OPTIONAL
3772 Z_PARAM_BOOL(owned)
3773 Z_PARAM_BOOL(persistent)
3774 ZEND_PARSE_PARAMETERS_END();
3775
3776 if (is_static_call) {
3777 zend_error(E_DEPRECATED, "Calling FFI::new() statically is deprecated");
3778 if (EG(exception)) {
3779 RETURN_THROWS();
3780 }
3781 }
3782
3783 if (!owned) {
3784 flags &= ~ZEND_FFI_FLAG_OWNED;
3785 }
3786
3787 if (persistent) {
3788 flags |= ZEND_FFI_FLAG_PERSISTENT;
3789 }
3790
3791 if (type_def) {
3792 zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
3793
3794 if (!is_static_call) {
3795 zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
3796 FFI_G(symbols) = ffi->symbols;
3797 FFI_G(tags) = ffi->tags;
3798 } else {
3799 FFI_G(symbols) = NULL;
3800 FFI_G(tags) = NULL;
3801 }
3802 bool clean_symbols = FFI_G(symbols) == NULL;
3803 bool clean_tags = FFI_G(tags) == NULL;
3804
3805 FFI_G(default_type_attr) = 0;
3806
3807 if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) == FAILURE) {
3808 zend_ffi_type_dtor(dcl.type);
3809 if (clean_tags && FFI_G(tags)) {
3810 zend_hash_destroy(FFI_G(tags));
3811 efree(FFI_G(tags));
3812 FFI_G(tags) = NULL;
3813 }
3814 if (clean_symbols && FFI_G(symbols)) {
3815 zend_hash_destroy(FFI_G(symbols));
3816 efree(FFI_G(symbols));
3817 FFI_G(symbols) = NULL;
3818 }
3819 return;
3820 }
3821
3822 type = ZEND_FFI_TYPE(dcl.type);
3823 if (dcl.attr & ZEND_FFI_ATTR_CONST) {
3824 is_const = 1;
3825 }
3826
3827 if (clean_tags && FFI_G(tags)) {
3828 zend_ffi_tags_cleanup(&dcl);
3829 }
3830 if (clean_symbols && FFI_G(symbols)) {
3831 zend_hash_destroy(FFI_G(symbols));
3832 efree(FFI_G(symbols));
3833 FFI_G(symbols) = NULL;
3834 }
3835 FFI_G(symbols) = NULL;
3836 FFI_G(tags) = NULL;
3837
3838 type_ptr = dcl.type;
3839 } else {
3840 zend_ffi_ctype *ctype = (zend_ffi_ctype*) type_obj;
3841
3842 type_ptr = type = ctype->type;
3843 if (ZEND_FFI_TYPE_IS_OWNED(type)) {
3844 type = ZEND_FFI_TYPE(type);
3845 if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
3846 if (GC_REFCOUNT(&ctype->std) == 1) {
3847 /* transfer type ownership */
3848 ctype->type = type;
3849 } else {
3850 ctype->type = type_ptr = type = zend_ffi_remember_type(type);
3851 }
3852 }
3853 }
3854 }
3855
3856 if (type->size == 0) {
3857 zend_throw_error(zend_ffi_exception_ce, "Cannot instantiate FFI\\CData of zero size");
3858 zend_ffi_type_dtor(type_ptr);
3859 return;
3860 }
3861
3862 ptr = pemalloc(type->size, flags & ZEND_FFI_FLAG_PERSISTENT);
3863 memset(ptr, 0, type->size);
3864
3865 cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
3866 if (type->kind < ZEND_FFI_TYPE_POINTER) {
3867 cdata->std.handlers = &zend_ffi_cdata_value_handlers;
3868 }
3869 cdata->type = type_ptr;
3870 cdata->ptr = ptr;
3871 cdata->flags = flags;
3872 if (is_const) {
3873 cdata->flags |= ZEND_FFI_FLAG_CONST;
3874 }
3875
3876 RETURN_OBJ(&cdata->std);
3877 }
3878 /* }}} */
3879
ZEND_METHOD(FFI,free)3880 ZEND_METHOD(FFI, free) /* {{{ */
3881 {
3882 zval *zv;
3883 zend_ffi_cdata *cdata;
3884
3885 ZEND_FFI_VALIDATE_API_RESTRICTION();
3886 ZEND_PARSE_PARAMETERS_START(1, 1)
3887 Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
3888 ZEND_PARSE_PARAMETERS_END();
3889
3890 cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
3891
3892 if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
3893 if (!cdata->ptr) {
3894 zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
3895 RETURN_THROWS();
3896 }
3897 if (cdata->ptr != (void*)&cdata->ptr_holder) {
3898 pefree(*(void**)cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
3899 } else {
3900 pefree(cdata->ptr_holder, (cdata->flags & ZEND_FFI_FLAG_PERSISTENT) || !is_zend_ptr(cdata->ptr_holder));
3901 }
3902 *(void**)cdata->ptr = NULL;
3903 } else if (!(cdata->flags & ZEND_FFI_FLAG_OWNED)) {
3904 pefree(cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
3905 cdata->ptr = NULL;
3906 cdata->flags &= ~(ZEND_FFI_FLAG_OWNED|ZEND_FFI_FLAG_PERSISTENT);
3907 cdata->std.handlers = &zend_ffi_cdata_free_handlers;
3908 } else {
3909 zend_throw_error(zend_ffi_exception_ce, "free() non a C pointer");
3910 }
3911 }
3912 /* }}} */
3913
ZEND_METHOD(FFI,cast)3914 ZEND_METHOD(FFI, cast) /* {{{ */
3915 {
3916 zend_string *type_def = NULL;
3917 zend_object *ztype = NULL;
3918 zend_ffi_type *old_type, *type, *type_ptr;
3919 zend_ffi_cdata *old_cdata, *cdata;
3920 bool is_const = 0;
3921 bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
3922 zval *zv, *arg;
3923 void *ptr;
3924
3925 ZEND_FFI_VALIDATE_API_RESTRICTION();
3926 ZEND_PARSE_PARAMETERS_START(2, 2)
3927 Z_PARAM_OBJ_OF_CLASS_OR_STR(ztype, zend_ffi_ctype_ce, type_def)
3928 Z_PARAM_ZVAL(zv)
3929 ZEND_PARSE_PARAMETERS_END();
3930
3931 if (is_static_call) {
3932 zend_error(E_DEPRECATED, "Calling FFI::cast() statically is deprecated");
3933 if (EG(exception)) {
3934 RETURN_THROWS();
3935 }
3936 }
3937
3938 arg = zv;
3939 ZVAL_DEREF(zv);
3940
3941 if (type_def) {
3942 zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
3943
3944 if (!is_static_call) {
3945 zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
3946 FFI_G(symbols) = ffi->symbols;
3947 FFI_G(tags) = ffi->tags;
3948 } else {
3949 FFI_G(symbols) = NULL;
3950 FFI_G(tags) = NULL;
3951 }
3952 bool clean_symbols = FFI_G(symbols) == NULL;
3953 bool clean_tags = FFI_G(tags) == NULL;
3954
3955 FFI_G(default_type_attr) = 0;
3956
3957 if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) == FAILURE) {
3958 zend_ffi_type_dtor(dcl.type);
3959 if (clean_tags && FFI_G(tags)) {
3960 zend_hash_destroy(FFI_G(tags));
3961 efree(FFI_G(tags));
3962 FFI_G(tags) = NULL;
3963 }
3964 if (clean_symbols && FFI_G(symbols)) {
3965 zend_hash_destroy(FFI_G(symbols));
3966 efree(FFI_G(symbols));
3967 FFI_G(symbols) = NULL;
3968 }
3969 return;
3970 }
3971
3972 type = ZEND_FFI_TYPE(dcl.type);
3973 if (dcl.attr & ZEND_FFI_ATTR_CONST) {
3974 is_const = 1;
3975 }
3976
3977 if (clean_tags && FFI_G(tags)) {
3978 zend_ffi_tags_cleanup(&dcl);
3979 }
3980 if (clean_symbols && FFI_G(symbols)) {
3981 zend_hash_destroy(FFI_G(symbols));
3982 efree(FFI_G(symbols));
3983 FFI_G(symbols) = NULL;
3984 }
3985 FFI_G(symbols) = NULL;
3986 FFI_G(tags) = NULL;
3987
3988 type_ptr = dcl.type;
3989 } else {
3990 zend_ffi_ctype *ctype = (zend_ffi_ctype*) ztype;
3991
3992 type_ptr = type = ctype->type;
3993 if (ZEND_FFI_TYPE_IS_OWNED(type)) {
3994 type = ZEND_FFI_TYPE(type);
3995 if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
3996 if (GC_REFCOUNT(&ctype->std) == 1) {
3997 /* transfer type ownership */
3998 ctype->type = type;
3999 } else {
4000 ctype->type = type_ptr = type = zend_ffi_remember_type(type);
4001 }
4002 }
4003 }
4004 }
4005
4006 if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4007 if (type->kind < ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) < IS_STRING) {
4008 /* numeric conversion */
4009 cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4010 cdata->std.handlers = &zend_ffi_cdata_value_handlers;
4011 cdata->type = type_ptr;
4012 cdata->ptr = emalloc(type->size);
4013 zend_ffi_zval_to_cdata(cdata->ptr, type, zv);
4014 cdata->flags = ZEND_FFI_FLAG_OWNED;
4015 if (is_const) {
4016 cdata->flags |= ZEND_FFI_FLAG_CONST;
4017 }
4018 RETURN_OBJ(&cdata->std);
4019 } else if (type->kind == ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) == IS_LONG) {
4020 /* number to pointer conversion */
4021 cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4022 cdata->type = type_ptr;
4023 cdata->ptr = &cdata->ptr_holder;
4024 cdata->ptr_holder = (void*)(intptr_t)Z_LVAL_P(zv);
4025 if (is_const) {
4026 cdata->flags |= ZEND_FFI_FLAG_CONST;
4027 }
4028 RETURN_OBJ(&cdata->std);
4029 } else if (type->kind == ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) == IS_NULL) {
4030 /* null -> pointer */
4031 cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4032 cdata->type = type_ptr;
4033 cdata->ptr = &cdata->ptr_holder;
4034 cdata->ptr_holder = NULL;
4035 if (is_const) {
4036 cdata->flags |= ZEND_FFI_FLAG_CONST;
4037 }
4038 RETURN_OBJ(&cdata->std);
4039 } else {
4040 zend_wrong_parameter_class_error(2, "FFI\\CData", zv);
4041 RETURN_THROWS();
4042 }
4043 }
4044
4045 old_cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4046 old_type = ZEND_FFI_TYPE(old_cdata->type);
4047 ptr = old_cdata->ptr;
4048
4049 cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4050 if (type->kind < ZEND_FFI_TYPE_POINTER) {
4051 cdata->std.handlers = &zend_ffi_cdata_value_handlers;
4052 }
4053 cdata->type = type_ptr;
4054
4055 if (old_type->kind == ZEND_FFI_TYPE_POINTER
4056 && type->kind != ZEND_FFI_TYPE_POINTER
4057 && ZEND_FFI_TYPE(old_type->pointer.type)->kind == ZEND_FFI_TYPE_VOID) {
4058 /* automatically dereference void* pointers ??? */
4059 cdata->ptr = *(void**)ptr;
4060 } else if (old_type->kind == ZEND_FFI_TYPE_ARRAY
4061 && type->kind == ZEND_FFI_TYPE_POINTER
4062 && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->array.type), ZEND_FFI_TYPE(type->pointer.type))) { cdata->ptr = &cdata->ptr_holder;
4063 cdata->ptr = &cdata->ptr_holder;
4064 cdata->ptr_holder = old_cdata->ptr;
4065 } else if (old_type->kind == ZEND_FFI_TYPE_POINTER
4066 && type->kind == ZEND_FFI_TYPE_ARRAY
4067 && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->pointer.type), ZEND_FFI_TYPE(type->array.type))) {
4068 cdata->ptr = old_cdata->ptr_holder;
4069 } else if (type->size > old_type->size) {
4070 zend_object_release(&cdata->std);
4071 zend_throw_error(zend_ffi_exception_ce, "attempt to cast to larger type");
4072 RETURN_THROWS();
4073 } else if (ptr != &old_cdata->ptr_holder) {
4074 cdata->ptr = ptr;
4075 } else {
4076 cdata->ptr = &cdata->ptr_holder;
4077 cdata->ptr_holder = old_cdata->ptr_holder;
4078 }
4079 if (is_const) {
4080 cdata->flags |= ZEND_FFI_FLAG_CONST;
4081 }
4082
4083 if (old_cdata->flags & ZEND_FFI_FLAG_OWNED) {
4084 if (GC_REFCOUNT(&old_cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4085 /* transfer ownership */
4086 old_cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
4087 cdata->flags |= ZEND_FFI_FLAG_OWNED;
4088 } else {
4089 //???zend_throw_error(zend_ffi_exception_ce, "Attempt to cast owned C pointer");
4090 }
4091 }
4092
4093 RETURN_OBJ(&cdata->std);
4094 }
4095 /* }}} */
4096
ZEND_METHOD(FFI,type)4097 ZEND_METHOD(FFI, type) /* {{{ */
4098 {
4099 zend_ffi_ctype *ctype;
4100 zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
4101 zend_string *type_def;
4102 bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
4103
4104 ZEND_FFI_VALIDATE_API_RESTRICTION();
4105 ZEND_PARSE_PARAMETERS_START(1, 1)
4106 Z_PARAM_STR(type_def);
4107 ZEND_PARSE_PARAMETERS_END();
4108
4109 if (is_static_call) {
4110 zend_error(E_DEPRECATED, "Calling FFI::type() statically is deprecated");
4111 if (EG(exception)) {
4112 RETURN_THROWS();
4113 }
4114 }
4115
4116 if (!is_static_call) {
4117 zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
4118 FFI_G(symbols) = ffi->symbols;
4119 FFI_G(tags) = ffi->tags;
4120 } else {
4121 FFI_G(symbols) = NULL;
4122 FFI_G(tags) = NULL;
4123 }
4124 bool clean_symbols = FFI_G(symbols) == NULL;
4125 bool clean_tags = FFI_G(tags) == NULL;
4126
4127 FFI_G(default_type_attr) = 0;
4128
4129 if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) == FAILURE) {
4130 zend_ffi_type_dtor(dcl.type);
4131 if (clean_tags && FFI_G(tags)) {
4132 zend_hash_destroy(FFI_G(tags));
4133 efree(FFI_G(tags));
4134 FFI_G(tags) = NULL;
4135 }
4136 if (clean_symbols && FFI_G(symbols)) {
4137 zend_hash_destroy(FFI_G(symbols));
4138 efree(FFI_G(symbols));
4139 FFI_G(symbols) = NULL;
4140 }
4141 return;
4142 }
4143
4144 if (clean_tags && FFI_G(tags)) {
4145 zend_ffi_tags_cleanup(&dcl);
4146 }
4147 if (clean_symbols && FFI_G(symbols)) {
4148 zend_hash_destroy(FFI_G(symbols));
4149 efree(FFI_G(symbols));
4150 FFI_G(symbols) = NULL;
4151 }
4152 FFI_G(symbols) = NULL;
4153 FFI_G(tags) = NULL;
4154
4155 ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4156 ctype->type = dcl.type;
4157
4158 RETURN_OBJ(&ctype->std);
4159 }
4160 /* }}} */
4161
ZEND_METHOD(FFI,typeof)4162 ZEND_METHOD(FFI, typeof) /* {{{ */
4163 {
4164 zval *zv, *arg;
4165 zend_ffi_ctype *ctype;
4166 zend_ffi_type *type;
4167
4168 ZEND_FFI_VALIDATE_API_RESTRICTION();
4169 ZEND_PARSE_PARAMETERS_START(1, 1)
4170 Z_PARAM_ZVAL(zv);
4171 ZEND_PARSE_PARAMETERS_END();
4172
4173 arg = zv;
4174 ZVAL_DEREF(zv);
4175 if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4176 zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4177
4178 type = cdata->type;
4179 if (ZEND_FFI_TYPE_IS_OWNED(type)) {
4180 type = ZEND_FFI_TYPE(type);
4181 if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
4182 if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4183 /* transfer type ownership */
4184 cdata->type = type;
4185 type = ZEND_FFI_TYPE_MAKE_OWNED(type);
4186 } else {
4187 cdata->type = type = zend_ffi_remember_type(type);
4188 }
4189 }
4190 }
4191 } else {
4192 zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4193 RETURN_THROWS();
4194 }
4195
4196 ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4197 ctype->type = type;
4198
4199 RETURN_OBJ(&ctype->std);
4200 }
4201 /* }}} */
4202
ZEND_METHOD(FFI,arrayType)4203 ZEND_METHOD(FFI, arrayType) /* {{{ */
4204 {
4205 zval *ztype;
4206 zend_ffi_ctype *ctype;
4207 zend_ffi_type *type;
4208 HashTable *dims;
4209 zval *val;
4210
4211 ZEND_FFI_VALIDATE_API_RESTRICTION();
4212 ZEND_PARSE_PARAMETERS_START(2, 2)
4213 Z_PARAM_OBJECT_OF_CLASS(ztype, zend_ffi_ctype_ce)
4214 Z_PARAM_ARRAY_HT(dims)
4215 ZEND_PARSE_PARAMETERS_END();
4216
4217 ctype = (zend_ffi_ctype*)Z_OBJ_P(ztype);
4218 type = ZEND_FFI_TYPE(ctype->type);
4219
4220 if (type->kind == ZEND_FFI_TYPE_FUNC) {
4221 zend_throw_error(zend_ffi_exception_ce, "Array of functions is not allowed");
4222 RETURN_THROWS();
4223 } else if (type->kind == ZEND_FFI_TYPE_ARRAY && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
4224 zend_throw_error(zend_ffi_exception_ce, "Only the leftmost array can be undimensioned");
4225 RETURN_THROWS();
4226 } else if (type->kind == ZEND_FFI_TYPE_VOID) {
4227 zend_throw_error(zend_ffi_exception_ce, "Array of void type is not allowed");
4228 RETURN_THROWS();
4229 } else if (type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG) {
4230 zend_throw_error(zend_ffi_exception_ce, "Array of incomplete type is not allowed");
4231 RETURN_THROWS();
4232 }
4233
4234 if (ZEND_FFI_TYPE_IS_OWNED(ctype->type)) {
4235 if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
4236 if (GC_REFCOUNT(&ctype->std) == 1) {
4237 /* transfer type ownership */
4238 ctype->type = type;
4239 type = ZEND_FFI_TYPE_MAKE_OWNED(type);
4240 } else {
4241 ctype->type = type = zend_ffi_remember_type(type);
4242 }
4243 }
4244 }
4245
4246 ZEND_HASH_REVERSE_FOREACH_VAL(dims, val) {
4247 zend_long n = zval_get_long(val);
4248 zend_ffi_type *new_type;
4249
4250 if (n < 0) {
4251 zend_throw_error(zend_ffi_exception_ce, "negative array index");
4252 zend_ffi_type_dtor(type);
4253 RETURN_THROWS();
4254 } else if (ZEND_FFI_TYPE(type)->kind == ZEND_FFI_TYPE_ARRAY && (ZEND_FFI_TYPE(type)->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
4255 zend_throw_error(zend_ffi_exception_ce, "only the leftmost array can be undimensioned");
4256 zend_ffi_type_dtor(type);
4257 RETURN_THROWS();
4258 }
4259
4260 new_type = emalloc(sizeof(zend_ffi_type));
4261 new_type->kind = ZEND_FFI_TYPE_ARRAY;
4262 new_type->attr = 0;
4263 new_type->size = n * ZEND_FFI_TYPE(type)->size;
4264 new_type->align = ZEND_FFI_TYPE(type)->align;
4265 new_type->array.type = type;
4266 new_type->array.length = n;
4267
4268 if (n == 0) {
4269 new_type->attr |= ZEND_FFI_ATTR_INCOMPLETE_ARRAY;
4270 }
4271
4272 type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
4273 } ZEND_HASH_FOREACH_END();
4274
4275 ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4276 ctype->type = type;
4277
4278 RETURN_OBJ(&ctype->std);
4279 }
4280 /* }}} */
4281
ZEND_METHOD(FFI,addr)4282 ZEND_METHOD(FFI, addr) /* {{{ */
4283 {
4284 zend_ffi_type *type, *new_type;
4285 zend_ffi_cdata *cdata, *new_cdata;
4286 zval *zv, *arg;
4287
4288 ZEND_FFI_VALIDATE_API_RESTRICTION();
4289 ZEND_PARSE_PARAMETERS_START(1, 1)
4290 Z_PARAM_ZVAL(zv)
4291 ZEND_PARSE_PARAMETERS_END();
4292
4293 arg = zv;
4294 ZVAL_DEREF(zv);
4295 if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4296 zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4297 RETURN_THROWS();
4298 }
4299
4300 cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4301 type = ZEND_FFI_TYPE(cdata->type);
4302
4303 if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1 && type->kind == ZEND_FFI_TYPE_POINTER
4304 && cdata->ptr == &cdata->ptr_holder) {
4305 zend_throw_error(zend_ffi_exception_ce, "FFI::addr() cannot create a reference to a temporary pointer");
4306 RETURN_THROWS();
4307 }
4308
4309 new_type = emalloc(sizeof(zend_ffi_type));
4310 new_type->kind = ZEND_FFI_TYPE_POINTER;
4311 new_type->attr = 0;
4312 new_type->size = sizeof(void*);
4313 new_type->align = _Alignof(void*);
4314 /* life-time (source must relive the resulting pointer) ??? */
4315 new_type->pointer.type = type;
4316
4317 new_cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4318 new_cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
4319 new_cdata->ptr_holder = cdata->ptr;
4320 new_cdata->ptr = &new_cdata->ptr_holder;
4321
4322 if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4323 if (ZEND_FFI_TYPE_IS_OWNED(cdata->type)) {
4324 /* transfer type ownership */
4325 cdata->type = type;
4326 new_type->pointer.type = ZEND_FFI_TYPE_MAKE_OWNED(type);
4327 }
4328 if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
4329 /* transfer ownership */
4330 cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
4331 new_cdata->flags |= ZEND_FFI_FLAG_OWNED;
4332 }
4333 }
4334
4335 RETURN_OBJ(&new_cdata->std);
4336 }
4337 /* }}} */
4338
ZEND_METHOD(FFI,sizeof)4339 ZEND_METHOD(FFI, sizeof) /* {{{ */
4340 {
4341 zval *zv;
4342 zend_ffi_type *type;
4343
4344 ZEND_FFI_VALIDATE_API_RESTRICTION();
4345 ZEND_PARSE_PARAMETERS_START(1, 1)
4346 Z_PARAM_ZVAL(zv);
4347 ZEND_PARSE_PARAMETERS_END();
4348
4349 ZVAL_DEREF(zv);
4350 if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4351 zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4352 type = ZEND_FFI_TYPE(cdata->type);
4353 } else if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_ctype_ce) {
4354 zend_ffi_ctype *ctype = (zend_ffi_ctype*)Z_OBJ_P(zv);
4355 type = ZEND_FFI_TYPE(ctype->type);
4356 } else {
4357 zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
4358 RETURN_THROWS();
4359 }
4360
4361 RETURN_LONG(type->size);
4362 }
4363 /* }}} */
4364
ZEND_METHOD(FFI,alignof)4365 ZEND_METHOD(FFI, alignof) /* {{{ */
4366 {
4367 zval *zv;
4368 zend_ffi_type *type;
4369
4370 ZEND_FFI_VALIDATE_API_RESTRICTION();
4371 ZEND_PARSE_PARAMETERS_START(1, 1)
4372 Z_PARAM_ZVAL(zv);
4373 ZEND_PARSE_PARAMETERS_END();
4374
4375 ZVAL_DEREF(zv);
4376 if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4377 zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4378 type = ZEND_FFI_TYPE(cdata->type);
4379 } else if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_ctype_ce) {
4380 zend_ffi_ctype *ctype = (zend_ffi_ctype*)Z_OBJ_P(zv);
4381 type = ZEND_FFI_TYPE(ctype->type);
4382 } else {
4383 zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
4384 RETURN_THROWS();
4385 }
4386
4387 RETURN_LONG(type->align);
4388 }
4389 /* }}} */
4390
ZEND_METHOD(FFI,memcpy)4391 ZEND_METHOD(FFI, memcpy) /* {{{ */
4392 {
4393 zval *zv1, *zv2;
4394 zend_ffi_cdata *cdata1, *cdata2;
4395 zend_ffi_type *type1, *type2;
4396 void *ptr1, *ptr2;
4397 zend_long size;
4398
4399 ZEND_FFI_VALIDATE_API_RESTRICTION();
4400 ZEND_PARSE_PARAMETERS_START(3, 3)
4401 Z_PARAM_OBJECT_OF_CLASS_EX(zv1, zend_ffi_cdata_ce, 0, 1);
4402 Z_PARAM_ZVAL(zv2)
4403 Z_PARAM_LONG(size)
4404 ZEND_PARSE_PARAMETERS_END();
4405
4406 cdata1 = (zend_ffi_cdata*)Z_OBJ_P(zv1);
4407 type1 = ZEND_FFI_TYPE(cdata1->type);
4408 if (type1->kind == ZEND_FFI_TYPE_POINTER) {
4409 ptr1 = *(void**)cdata1->ptr;
4410 } else {
4411 ptr1 = cdata1->ptr;
4412 if (type1->kind != ZEND_FFI_TYPE_POINTER && size > type1->size) {
4413 zend_throw_error(zend_ffi_exception_ce, "Attempt to write over data boundary");
4414 RETURN_THROWS();
4415 }
4416 }
4417
4418 ZVAL_DEREF(zv2);
4419 if (Z_TYPE_P(zv2) == IS_STRING) {
4420 ptr2 = Z_STRVAL_P(zv2);
4421 if (size > Z_STRLEN_P(zv2)) {
4422 zend_throw_error(zend_ffi_exception_ce, "Attempt to read over string boundary");
4423 RETURN_THROWS();
4424 }
4425 } else if (Z_TYPE_P(zv2) == IS_OBJECT && Z_OBJCE_P(zv2) == zend_ffi_cdata_ce) {
4426 cdata2 = (zend_ffi_cdata*)Z_OBJ_P(zv2);
4427 type2 = ZEND_FFI_TYPE(cdata2->type);
4428 if (type2->kind == ZEND_FFI_TYPE_POINTER) {
4429 ptr2 = *(void**)cdata2->ptr;
4430 } else {
4431 ptr2 = cdata2->ptr;
4432 if (type2->kind != ZEND_FFI_TYPE_POINTER && size > type2->size) {
4433 zend_throw_error(zend_ffi_exception_ce, "Attempt to read over data boundary");
4434 RETURN_THROWS();
4435 }
4436 }
4437 } else {
4438 zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
4439 RETURN_THROWS();
4440 }
4441
4442 memcpy(ptr1, ptr2, size);
4443 }
4444 /* }}} */
4445
ZEND_METHOD(FFI,memcmp)4446 ZEND_METHOD(FFI, memcmp) /* {{{ */
4447 {
4448 zval *zv1, *zv2;
4449 zend_ffi_cdata *cdata1, *cdata2;
4450 zend_ffi_type *type1, *type2;
4451 void *ptr1, *ptr2;
4452 zend_long size;
4453 int ret;
4454
4455 ZEND_FFI_VALIDATE_API_RESTRICTION();
4456 ZEND_PARSE_PARAMETERS_START(3, 3)
4457 Z_PARAM_ZVAL(zv1);
4458 Z_PARAM_ZVAL(zv2);
4459 Z_PARAM_LONG(size)
4460 ZEND_PARSE_PARAMETERS_END();
4461
4462 ZVAL_DEREF(zv1);
4463 if (Z_TYPE_P(zv1) == IS_STRING) {
4464 ptr1 = Z_STRVAL_P(zv1);
4465 if (size > Z_STRLEN_P(zv1)) {
4466 zend_throw_error(zend_ffi_exception_ce, "attempt to read over string boundary");
4467 RETURN_THROWS();
4468 }
4469 } else if (Z_TYPE_P(zv1) == IS_OBJECT && Z_OBJCE_P(zv1) == zend_ffi_cdata_ce) {
4470 cdata1 = (zend_ffi_cdata*)Z_OBJ_P(zv1);
4471 type1 = ZEND_FFI_TYPE(cdata1->type);
4472 if (type1->kind == ZEND_FFI_TYPE_POINTER) {
4473 ptr1 = *(void**)cdata1->ptr;
4474 } else {
4475 ptr1 = cdata1->ptr;
4476 if (type1->kind != ZEND_FFI_TYPE_POINTER && size > type1->size) {
4477 zend_throw_error(zend_ffi_exception_ce, "attempt to read over data boundary");
4478 RETURN_THROWS();
4479 }
4480 }
4481 } else {
4482 zend_wrong_parameter_class_error(1, "FFI\\CData or string", zv1);
4483 RETURN_THROWS();
4484 }
4485
4486 ZVAL_DEREF(zv2);
4487 if (Z_TYPE_P(zv2) == IS_STRING) {
4488 ptr2 = Z_STRVAL_P(zv2);
4489 if (size > Z_STRLEN_P(zv2)) {
4490 zend_throw_error(zend_ffi_exception_ce, "Attempt to read over string boundary");
4491 RETURN_THROWS();
4492 }
4493 } else if (Z_TYPE_P(zv2) == IS_OBJECT && Z_OBJCE_P(zv2) == zend_ffi_cdata_ce) {
4494 cdata2 = (zend_ffi_cdata*)Z_OBJ_P(zv2);
4495 type2 = ZEND_FFI_TYPE(cdata2->type);
4496 if (type2->kind == ZEND_FFI_TYPE_POINTER) {
4497 ptr2 = *(void**)cdata2->ptr;
4498 } else {
4499 ptr2 = cdata2->ptr;
4500 if (type2->kind != ZEND_FFI_TYPE_POINTER && size > type2->size) {
4501 zend_throw_error(zend_ffi_exception_ce, "Attempt to read over data boundary");
4502 RETURN_THROWS();
4503 }
4504 }
4505 } else {
4506 zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
4507 RETURN_THROWS();
4508 }
4509
4510 ret = memcmp(ptr1, ptr2, size);
4511 if (ret == 0) {
4512 RETVAL_LONG(0);
4513 } else if (ret < 0) {
4514 RETVAL_LONG(-1);
4515 } else {
4516 RETVAL_LONG(1);
4517 }
4518 }
4519 /* }}} */
4520
ZEND_METHOD(FFI,memset)4521 ZEND_METHOD(FFI, memset) /* {{{ */
4522 {
4523 zval *zv;
4524 zend_ffi_cdata *cdata;
4525 zend_ffi_type *type;
4526 void *ptr;
4527 zend_long ch, size;
4528
4529 ZEND_FFI_VALIDATE_API_RESTRICTION();
4530 ZEND_PARSE_PARAMETERS_START(3, 3)
4531 Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
4532 Z_PARAM_LONG(ch)
4533 Z_PARAM_LONG(size)
4534 ZEND_PARSE_PARAMETERS_END();
4535
4536 cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4537 type = ZEND_FFI_TYPE(cdata->type);
4538 if (type->kind == ZEND_FFI_TYPE_POINTER) {
4539 ptr = *(void**)cdata->ptr;
4540 } else {
4541 ptr = cdata->ptr;
4542 if (type->kind != ZEND_FFI_TYPE_POINTER && size > type->size) {
4543 zend_throw_error(zend_ffi_exception_ce, "attempt to write over data boundary");
4544 RETURN_THROWS();
4545 }
4546 }
4547
4548 memset(ptr, ch, size);
4549 }
4550 /* }}} */
4551
ZEND_METHOD(FFI,string)4552 ZEND_METHOD(FFI, string) /* {{{ */
4553 {
4554 zval *zv;
4555 zend_ffi_cdata *cdata;
4556 zend_ffi_type *type;
4557 void *ptr;
4558 zend_long size;
4559 bool size_is_null = 1;
4560
4561 ZEND_FFI_VALIDATE_API_RESTRICTION();
4562 ZEND_PARSE_PARAMETERS_START(1, 2)
4563 Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
4564 Z_PARAM_OPTIONAL
4565 Z_PARAM_LONG_OR_NULL(size, size_is_null)
4566 ZEND_PARSE_PARAMETERS_END();
4567
4568 cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4569 type = ZEND_FFI_TYPE(cdata->type);
4570 if (!size_is_null) {
4571 if (type->kind == ZEND_FFI_TYPE_POINTER) {
4572 ptr = *(void**)cdata->ptr;
4573 } else {
4574 ptr = cdata->ptr;
4575 if (type->kind != ZEND_FFI_TYPE_POINTER && size > type->size) {
4576 zend_throw_error(zend_ffi_exception_ce, "attempt to read over data boundary");
4577 RETURN_THROWS();
4578 }
4579 }
4580 RETURN_STRINGL((char*)ptr, size);
4581 } else {
4582 if (type->kind == ZEND_FFI_TYPE_POINTER && ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
4583 ptr = *(void**)cdata->ptr;
4584 } else if (type->kind == ZEND_FFI_TYPE_ARRAY && ZEND_FFI_TYPE(type->array.type)->kind == ZEND_FFI_TYPE_CHAR) {
4585 ptr = cdata->ptr;
4586 } else {
4587 zend_throw_error(zend_ffi_exception_ce, "FFI\\Cdata is not a C string");
4588 RETURN_THROWS();
4589 }
4590 RETURN_STRING((char*)ptr);
4591 }
4592 }
4593 /* }}} */
4594
ZEND_METHOD(FFI,isNull)4595 ZEND_METHOD(FFI, isNull) /* {{{ */
4596 {
4597 zval *zv;
4598 zend_ffi_cdata *cdata;
4599 zend_ffi_type *type;
4600
4601 ZEND_FFI_VALIDATE_API_RESTRICTION();
4602 ZEND_PARSE_PARAMETERS_START(1, 1)
4603 Z_PARAM_ZVAL(zv);
4604 ZEND_PARSE_PARAMETERS_END();
4605
4606 ZVAL_DEREF(zv);
4607 if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4608 zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4609 RETURN_THROWS();
4610 }
4611
4612 cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4613 type = ZEND_FFI_TYPE(cdata->type);
4614
4615 if (type->kind != ZEND_FFI_TYPE_POINTER){
4616 zend_throw_error(zend_ffi_exception_ce, "FFI\\Cdata is not a pointer");
4617 RETURN_THROWS();
4618 }
4619
4620 RETURN_BOOL(*(void**)cdata->ptr == NULL);
4621 }
4622 /* }}} */
4623
4624
ZEND_METHOD(FFI_CType,getName)4625 ZEND_METHOD(FFI_CType, getName) /* {{{ */
4626 {
4627 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4628 if (zend_parse_parameters_none() == FAILURE) {
4629 RETURN_THROWS();
4630 }
4631
4632 zend_ffi_ctype_name_buf buf;
4633
4634 buf.start = buf.end = buf.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
4635 if (!zend_ffi_ctype_name(&buf, ZEND_FFI_TYPE(ctype->type))) {
4636 RETURN_STR_COPY(Z_OBJ_P(ZEND_THIS)->ce->name);
4637 } else {
4638 size_t len = buf.end - buf.start;
4639 zend_string *res = zend_string_init(buf.start, len, 0);
4640 RETURN_STR(res);
4641 }
4642 }
4643 /* }}} */
4644
ZEND_METHOD(FFI_CType,getKind)4645 ZEND_METHOD(FFI_CType, getKind) /* {{{ */
4646 {
4647 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4648 zend_ffi_type *type;
4649
4650 if (zend_parse_parameters_none() == FAILURE) {
4651 RETURN_THROWS();
4652 }
4653
4654 type = ZEND_FFI_TYPE(ctype->type);
4655 RETURN_LONG(type->kind);
4656 }
4657 /* }}} */
4658
ZEND_METHOD(FFI_CType,getSize)4659 ZEND_METHOD(FFI_CType, getSize) /* {{{ */
4660 {
4661 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4662 zend_ffi_type *type;
4663
4664 if (zend_parse_parameters_none() == FAILURE) {
4665 RETURN_THROWS();
4666 }
4667
4668 type = ZEND_FFI_TYPE(ctype->type);
4669 RETURN_LONG(type->size);
4670 }
4671 /* }}} */
4672
ZEND_METHOD(FFI_CType,getAlignment)4673 ZEND_METHOD(FFI_CType, getAlignment) /* {{{ */
4674 {
4675 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4676 zend_ffi_type *type;
4677
4678 if (zend_parse_parameters_none() == FAILURE) {
4679 RETURN_THROWS();
4680 }
4681
4682 type = ZEND_FFI_TYPE(ctype->type);
4683 RETURN_LONG(type->align);
4684 }
4685 /* }}} */
4686
ZEND_METHOD(FFI_CType,getAttributes)4687 ZEND_METHOD(FFI_CType, getAttributes) /* {{{ */
4688 {
4689 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4690 zend_ffi_type *type;
4691
4692 if (zend_parse_parameters_none() == FAILURE) {
4693 RETURN_THROWS();
4694 }
4695
4696 type = ZEND_FFI_TYPE(ctype->type);
4697 RETURN_LONG(type->attr);
4698 }
4699 /* }}} */
4700
ZEND_METHOD(FFI_CType,getEnumKind)4701 ZEND_METHOD(FFI_CType, getEnumKind) /* {{{ */
4702 {
4703 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4704 zend_ffi_type *type;
4705
4706 if (zend_parse_parameters_none() == FAILURE) {
4707 RETURN_THROWS();
4708 }
4709
4710 type = ZEND_FFI_TYPE(ctype->type);
4711 if (type->kind != ZEND_FFI_TYPE_ENUM) {
4712 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an enumeration");
4713 RETURN_THROWS();
4714 }
4715 RETURN_LONG(type->enumeration.kind);
4716 }
4717 /* }}} */
4718
ZEND_METHOD(FFI_CType,getArrayElementType)4719 ZEND_METHOD(FFI_CType, getArrayElementType) /* {{{ */
4720 {
4721 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4722 zend_ffi_type *type;
4723 zend_ffi_ctype *ret;
4724
4725 if (zend_parse_parameters_none() == FAILURE) {
4726 RETURN_THROWS();
4727 }
4728
4729 type = ZEND_FFI_TYPE(ctype->type);
4730 if (type->kind != ZEND_FFI_TYPE_ARRAY) {
4731 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array");
4732 RETURN_THROWS();
4733 }
4734
4735 ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4736 ret->type = ZEND_FFI_TYPE(type->array.type);
4737 RETURN_OBJ(&ret->std);
4738 }
4739 /* }}} */
4740
ZEND_METHOD(FFI_CType,getArrayLength)4741 ZEND_METHOD(FFI_CType, getArrayLength) /* {{{ */
4742 {
4743 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4744 zend_ffi_type *type;
4745
4746 if (zend_parse_parameters_none() == FAILURE) {
4747 RETURN_THROWS();
4748 }
4749
4750 type = ZEND_FFI_TYPE(ctype->type);
4751 if (type->kind != ZEND_FFI_TYPE_ARRAY) {
4752 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array");
4753 RETURN_THROWS();
4754 }
4755 RETURN_LONG(type->array.length);
4756 }
4757 /* }}} */
4758
ZEND_METHOD(FFI_CType,getPointerType)4759 ZEND_METHOD(FFI_CType, getPointerType) /* {{{ */
4760 {
4761 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4762 zend_ffi_ctype *ret;
4763 zend_ffi_type *type;
4764
4765 if (zend_parse_parameters_none() == FAILURE) {
4766 RETURN_THROWS();
4767 }
4768
4769 type = ZEND_FFI_TYPE(ctype->type);
4770 if (type->kind != ZEND_FFI_TYPE_POINTER) {
4771 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a pointer");
4772 RETURN_THROWS();
4773 }
4774
4775 ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4776 ret->type = ZEND_FFI_TYPE(type->pointer.type);
4777 RETURN_OBJ(&ret->std);
4778 }
4779 /* }}} */
4780
ZEND_METHOD(FFI_CType,getStructFieldNames)4781 ZEND_METHOD(FFI_CType, getStructFieldNames) /* {{{ */
4782 {
4783 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4784 zend_ffi_type *type;
4785 HashTable *ht;
4786 zend_string* name;
4787 zval zv;
4788
4789 if (zend_parse_parameters_none() == FAILURE) {
4790 RETURN_THROWS();
4791 }
4792
4793 type = ZEND_FFI_TYPE(ctype->type);
4794 if (type->kind != ZEND_FFI_TYPE_STRUCT) {
4795 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4796 RETURN_THROWS();
4797 }
4798
4799 ht = zend_new_array(zend_hash_num_elements(&type->record.fields));
4800 RETVAL_ARR(ht);
4801 ZEND_HASH_MAP_FOREACH_STR_KEY(&type->record.fields, name) {
4802 ZVAL_STR_COPY(&zv, name);
4803 zend_hash_next_index_insert_new(ht, &zv);
4804 } ZEND_HASH_FOREACH_END();
4805 }
4806 /* }}} */
4807
ZEND_METHOD(FFI_CType,getStructFieldOffset)4808 ZEND_METHOD(FFI_CType, getStructFieldOffset) /* {{{ */
4809 {
4810 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4811 zend_ffi_type *type;
4812 zend_string *name;
4813 zend_ffi_field *ptr;
4814
4815 ZEND_PARSE_PARAMETERS_START(1, 1)
4816 Z_PARAM_STR(name)
4817 ZEND_PARSE_PARAMETERS_END();
4818
4819 type = ZEND_FFI_TYPE(ctype->type);
4820 if (type->kind != ZEND_FFI_TYPE_STRUCT) {
4821 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4822 RETURN_THROWS();
4823 }
4824
4825 ptr = zend_hash_find_ptr(&type->record.fields, name);
4826 if (!ptr) {
4827 zend_throw_error(zend_ffi_exception_ce, "Wrong field name");
4828 RETURN_THROWS();
4829 }
4830 RETURN_LONG(ptr->offset);
4831 }
4832 /* }}} */
4833
ZEND_METHOD(FFI_CType,getStructFieldType)4834 ZEND_METHOD(FFI_CType, getStructFieldType) /* {{{ */
4835 {
4836 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4837 zend_ffi_type *type;
4838 zend_string *name;
4839 zend_ffi_field *ptr;
4840 zend_ffi_ctype *ret;
4841
4842 ZEND_PARSE_PARAMETERS_START(1, 1)
4843 Z_PARAM_STR(name)
4844 ZEND_PARSE_PARAMETERS_END();
4845
4846 type = ZEND_FFI_TYPE(ctype->type);
4847 if (type->kind != ZEND_FFI_TYPE_STRUCT) {
4848 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4849 RETURN_THROWS();
4850 }
4851
4852 ptr = zend_hash_find_ptr(&type->record.fields, name);
4853 if (!ptr) {
4854 zend_throw_error(zend_ffi_exception_ce, "Wrong field name");
4855 RETURN_THROWS();
4856 }
4857
4858 ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4859 ret->type = ZEND_FFI_TYPE(ptr->type);
4860 RETURN_OBJ(&ret->std);
4861 }
4862 /* }}} */
4863
ZEND_METHOD(FFI_CType,getFuncABI)4864 ZEND_METHOD(FFI_CType, getFuncABI) /* {{{ */
4865 {
4866 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4867 zend_ffi_type *type;
4868
4869 if (zend_parse_parameters_none() == FAILURE) {
4870 RETURN_THROWS();
4871 }
4872
4873 type = ZEND_FFI_TYPE(ctype->type);
4874 if (type->kind != ZEND_FFI_TYPE_FUNC) {
4875 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4876 RETURN_THROWS();
4877 }
4878 RETURN_LONG(type->func.abi);
4879 }
4880 /* }}} */
4881
ZEND_METHOD(FFI_CType,getFuncReturnType)4882 ZEND_METHOD(FFI_CType, getFuncReturnType) /* {{{ */
4883 {
4884 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4885 zend_ffi_ctype *ret;
4886 zend_ffi_type *type;
4887
4888 if (zend_parse_parameters_none() == FAILURE) {
4889 RETURN_THROWS();
4890 }
4891
4892 type = ZEND_FFI_TYPE(ctype->type);
4893 if (type->kind != ZEND_FFI_TYPE_FUNC) {
4894 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4895 RETURN_THROWS();
4896 }
4897
4898 ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4899 ret->type = ZEND_FFI_TYPE(type->func.ret_type);
4900 RETURN_OBJ(&ret->std);
4901 }
4902 /* }}} */
4903
ZEND_METHOD(FFI_CType,getFuncParameterCount)4904 ZEND_METHOD(FFI_CType, getFuncParameterCount) /* {{{ */
4905 {
4906 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4907 zend_ffi_type *type;
4908
4909 if (zend_parse_parameters_none() == FAILURE) {
4910 RETURN_THROWS();
4911 }
4912
4913 type = ZEND_FFI_TYPE(ctype->type);
4914 if (type->kind != ZEND_FFI_TYPE_FUNC) {
4915 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4916 RETURN_THROWS();
4917 }
4918 RETURN_LONG(type->func.args ? zend_hash_num_elements(type->func.args) : 0);
4919 }
4920 /* }}} */
4921
ZEND_METHOD(FFI_CType,getFuncParameterType)4922 ZEND_METHOD(FFI_CType, getFuncParameterType) /* {{{ */
4923 {
4924 zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4925 zend_ffi_type *type, *ptr;
4926 zend_long n;
4927 zend_ffi_ctype *ret;
4928
4929 ZEND_PARSE_PARAMETERS_START(1, 1)
4930 Z_PARAM_LONG(n)
4931 ZEND_PARSE_PARAMETERS_END();
4932
4933 type = ZEND_FFI_TYPE(ctype->type);
4934 if (type->kind != ZEND_FFI_TYPE_FUNC) {
4935 zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4936 RETURN_THROWS();
4937 }
4938
4939 if (!type->func.args) {
4940 zend_throw_error(zend_ffi_exception_ce, "Wrong argument number");
4941 RETURN_THROWS();
4942 }
4943
4944 ptr = zend_hash_index_find_ptr(type->func.args, n);
4945 if (!ptr) {
4946 zend_throw_error(zend_ffi_exception_ce, "Wrong argument number");
4947 RETURN_THROWS();
4948 }
4949
4950 ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4951 ret->type = ZEND_FFI_TYPE(ptr);
4952 RETURN_OBJ(&ret->std);
4953 }
4954 /* }}} */
4955
zend_ffi_parse_directives(const char * filename,char * code_pos,char ** scope_name,char ** lib,bool preload)4956 static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, bool preload) /* {{{ */
4957 {
4958 char *p;
4959
4960 *scope_name = NULL;
4961 *lib = NULL;
4962 while (*code_pos == '#') {
4963 if (strncmp(code_pos, "#define FFI_SCOPE", sizeof("#define FFI_SCOPE") - 1) == 0
4964 && (code_pos[sizeof("#define FFI_SCOPE") - 1] == ' '
4965 || code_pos[sizeof("#define FFI_SCOPE") - 1] == '\t')) {
4966 p = code_pos + sizeof("#define FFI_SCOPE");
4967 while (*p == ' ' || *p == '\t') {
4968 p++;
4969 }
4970 if (*p != '"') {
4971 if (preload) {
4972 zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_SCOPE define", filename);
4973 } else {
4974 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_SCOPE define", filename);
4975 }
4976 return NULL;
4977 }
4978 p++;
4979 if (*scope_name) {
4980 if (preload) {
4981 zend_error(E_WARNING, "FFI: failed pre-loading '%s', FFI_SCOPE defined twice", filename);
4982 } else {
4983 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', FFI_SCOPE defined twice", filename);
4984 }
4985 return NULL;
4986 }
4987 *scope_name = p;
4988 while (1) {
4989 if (*p == '\"') {
4990 *p = 0;
4991 p++;
4992 break;
4993 } else if (*p <= ' ') {
4994 if (preload) {
4995 zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_SCOPE define", filename);
4996 } else {
4997 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_SCOPE define", filename);
4998 }
4999 return NULL;
5000 }
5001 p++;
5002 }
5003 while (*p == ' ' || *p == '\t') {
5004 p++;
5005 }
5006 while (*p == '\r' || *p == '\n') {
5007 p++;
5008 }
5009 code_pos = p;
5010 } else if (strncmp(code_pos, "#define FFI_LIB", sizeof("#define FFI_LIB") - 1) == 0
5011 && (code_pos[sizeof("#define FFI_LIB") - 1] == ' '
5012 || code_pos[sizeof("#define FFI_LIB") - 1] == '\t')) {
5013 p = code_pos + sizeof("#define FFI_LIB");
5014 while (*p == ' ' || *p == '\t') {
5015 p++;
5016 }
5017 if (*p != '"') {
5018 if (preload) {
5019 zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_LIB define", filename);
5020 } else {
5021 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_LIB define", filename);
5022 }
5023 return NULL;
5024 }
5025 p++;
5026 if (*lib) {
5027 if (preload) {
5028 zend_error(E_WARNING, "FFI: failed pre-loading '%s', FFI_LIB defined twice", filename);
5029 } else {
5030 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', FFI_LIB defined twice", filename);
5031 }
5032 return NULL;
5033 }
5034 *lib = p;
5035 while (1) {
5036 if (*p == '\"') {
5037 *p = 0;
5038 p++;
5039 break;
5040 } else if (*p <= ' ') {
5041 if (preload) {
5042 zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_LIB define", filename);
5043 } else {
5044 zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_LIB define", filename);
5045 }
5046 return NULL;
5047 }
5048 p++;
5049 }
5050 while (*p == ' ' || *p == '\t') {
5051 p++;
5052 }
5053 while (*p == '\r' || *p == '\n') {
5054 p++;
5055 }
5056 code_pos = p;
5057 } else {
5058 break;
5059 }
5060 }
5061 return code_pos;
5062 }
5063 /* }}} */
5064
zend_fake_get_constructor(zend_object * object)5065 static ZEND_COLD zend_function *zend_fake_get_constructor(zend_object *object) /* {{{ */
5066 {
5067 zend_throw_error(NULL, "Instantiation of %s is not allowed", ZSTR_VAL(object->ce->name));
5068 return NULL;
5069 }
5070 /* }}} */
5071
zend_bad_array_access(zend_class_entry * ce)5072 static ZEND_COLD zend_never_inline void zend_bad_array_access(zend_class_entry *ce) /* {{{ */
5073 {
5074 zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
5075 }
5076 /* }}} */
5077
zend_fake_read_dimension(zend_object * obj,zval * offset,int type,zval * rv)5078 static ZEND_COLD zval *zend_fake_read_dimension(zend_object *obj, zval *offset, int type, zval *rv) /* {{{ */
5079 {
5080 zend_bad_array_access(obj->ce);
5081 return NULL;
5082 }
5083 /* }}} */
5084
zend_fake_write_dimension(zend_object * obj,zval * offset,zval * value)5085 static ZEND_COLD void zend_fake_write_dimension(zend_object *obj, zval *offset, zval *value) /* {{{ */
5086 {
5087 zend_bad_array_access(obj->ce);
5088 }
5089 /* }}} */
5090
zend_fake_has_dimension(zend_object * obj,zval * offset,int check_empty)5091 static ZEND_COLD int zend_fake_has_dimension(zend_object *obj, zval *offset, int check_empty) /* {{{ */
5092 {
5093 zend_bad_array_access(obj->ce);
5094 return 0;
5095 }
5096 /* }}} */
5097
zend_fake_unset_dimension(zend_object * obj,zval * offset)5098 static ZEND_COLD void zend_fake_unset_dimension(zend_object *obj, zval *offset) /* {{{ */
5099 {
5100 zend_bad_array_access(obj->ce);
5101 }
5102 /* }}} */
5103
zend_bad_property_access(zend_class_entry * ce)5104 static ZEND_COLD zend_never_inline void zend_bad_property_access(zend_class_entry *ce) /* {{{ */
5105 {
5106 zend_throw_error(NULL, "Cannot access property of object of type %s", ZSTR_VAL(ce->name));
5107 }
5108 /* }}} */
5109
zend_fake_read_property(zend_object * obj,zend_string * member,int type,void ** cache_slot,zval * rv)5110 static ZEND_COLD zval *zend_fake_read_property(zend_object *obj, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
5111 {
5112 zend_bad_property_access(obj->ce);
5113 return &EG(uninitialized_zval);
5114 }
5115 /* }}} */
5116
zend_fake_write_property(zend_object * obj,zend_string * member,zval * value,void ** cache_slot)5117 static ZEND_COLD zval *zend_fake_write_property(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
5118 {
5119 zend_bad_array_access(obj->ce);
5120 return value;
5121 }
5122 /* }}} */
5123
zend_fake_has_property(zend_object * obj,zend_string * member,int has_set_exists,void ** cache_slot)5124 static ZEND_COLD int zend_fake_has_property(zend_object *obj, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */
5125 {
5126 zend_bad_array_access(obj->ce);
5127 return 0;
5128 }
5129 /* }}} */
5130
zend_fake_unset_property(zend_object * obj,zend_string * member,void ** cache_slot)5131 static ZEND_COLD void zend_fake_unset_property(zend_object *obj, zend_string *member, void **cache_slot) /* {{{ */
5132 {
5133 zend_bad_array_access(obj->ce);
5134 }
5135 /* }}} */
5136
zend_fake_get_property_ptr_ptr(zend_object * obj,zend_string * member,int type,void ** cache_slot)5137 static zval *zend_fake_get_property_ptr_ptr(zend_object *obj, zend_string *member, int type, void **cache_slot) /* {{{ */
5138 {
5139 return NULL;
5140 }
5141 /* }}} */
5142
zend_fake_get_method(zend_object ** obj_ptr,zend_string * method_name,const zval * key)5143 static ZEND_COLD zend_function *zend_fake_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key) /* {{{ */
5144 {
5145 zend_class_entry *ce = (*obj_ptr)->ce;
5146 zend_throw_error(NULL, "Object of type %s does not support method calls", ZSTR_VAL(ce->name));
5147 return NULL;
5148 }
5149 /* }}} */
5150
zend_fake_get_properties(zend_object * obj)5151 static HashTable *zend_fake_get_properties(zend_object *obj) /* {{{ */
5152 {
5153 return (HashTable*)&zend_empty_array;
5154 }
5155 /* }}} */
5156
zend_fake_get_gc(zend_object * ob,zval ** table,int * n)5157 static HashTable *zend_fake_get_gc(zend_object *ob, zval **table, int *n) /* {{{ */
5158 {
5159 *table = NULL;
5160 *n = 0;
5161 return NULL;
5162 }
5163 /* }}} */
5164
zend_fake_cast_object(zend_object * obj,zval * result,int type)5165 static zend_result zend_fake_cast_object(zend_object *obj, zval *result, int type)
5166 {
5167 switch (type) {
5168 case _IS_BOOL:
5169 ZVAL_TRUE(result);
5170 return SUCCESS;
5171 default:
5172 return FAILURE;
5173 }
5174 }
5175
zend_ffi_use_after_free(void)5176 static ZEND_COLD zend_never_inline void zend_ffi_use_after_free(void) /* {{{ */
5177 {
5178 zend_throw_error(zend_ffi_exception_ce, "Use after free()");
5179 }
5180 /* }}} */
5181
zend_ffi_free_clone_obj(zend_object * obj)5182 static zend_object *zend_ffi_free_clone_obj(zend_object *obj) /* {{{ */
5183 {
5184 zend_ffi_use_after_free();
5185 return NULL;
5186 }
5187 /* }}} */
5188
zend_ffi_free_read_dimension(zend_object * obj,zval * offset,int type,zval * rv)5189 static ZEND_COLD zval *zend_ffi_free_read_dimension(zend_object *obj, zval *offset, int type, zval *rv) /* {{{ */
5190 {
5191 zend_ffi_use_after_free();
5192 return NULL;
5193 }
5194 /* }}} */
5195
zend_ffi_free_write_dimension(zend_object * obj,zval * offset,zval * value)5196 static ZEND_COLD void zend_ffi_free_write_dimension(zend_object *obj, zval *offset, zval *value) /* {{{ */
5197 {
5198 zend_ffi_use_after_free();
5199 }
5200 /* }}} */
5201
zend_ffi_free_has_dimension(zend_object * obj,zval * offset,int check_empty)5202 static ZEND_COLD int zend_ffi_free_has_dimension(zend_object *obj, zval *offset, int check_empty) /* {{{ */
5203 {
5204 zend_ffi_use_after_free();
5205 return 0;
5206 }
5207 /* }}} */
5208
zend_ffi_free_unset_dimension(zend_object * obj,zval * offset)5209 static ZEND_COLD void zend_ffi_free_unset_dimension(zend_object *obj, zval *offset) /* {{{ */
5210 {
5211 zend_ffi_use_after_free();
5212 }
5213 /* }}} */
5214
zend_ffi_free_read_property(zend_object * obj,zend_string * member,int type,void ** cache_slot,zval * rv)5215 static ZEND_COLD zval *zend_ffi_free_read_property(zend_object *obj, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
5216 {
5217 zend_ffi_use_after_free();
5218 return &EG(uninitialized_zval);
5219 }
5220 /* }}} */
5221
zend_ffi_free_write_property(zend_object * obj,zend_string * member,zval * value,void ** cache_slot)5222 static ZEND_COLD zval *zend_ffi_free_write_property(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
5223 {
5224 zend_ffi_use_after_free();
5225 return value;
5226 }
5227 /* }}} */
5228
zend_ffi_free_has_property(zend_object * obj,zend_string * member,int has_set_exists,void ** cache_slot)5229 static ZEND_COLD int zend_ffi_free_has_property(zend_object *obj, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */
5230 {
5231 zend_ffi_use_after_free();
5232 return 0;
5233 }
5234 /* }}} */
5235
zend_ffi_free_unset_property(zend_object * obj,zend_string * member,void ** cache_slot)5236 static ZEND_COLD void zend_ffi_free_unset_property(zend_object *obj, zend_string *member, void **cache_slot) /* {{{ */
5237 {
5238 zend_ffi_use_after_free();
5239 }
5240 /* }}} */
5241
zend_ffi_free_get_debug_info(zend_object * obj,int * is_temp)5242 static HashTable *zend_ffi_free_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
5243 {
5244 zend_ffi_use_after_free();
5245 return NULL;
5246 }
5247 /* }}} */
5248
ZEND_INI_MH(OnUpdateFFIEnable)5249 static ZEND_INI_MH(OnUpdateFFIEnable) /* {{{ */
5250 {
5251 if (zend_string_equals_literal_ci(new_value, "preload")) {
5252 FFI_G(restriction) = ZEND_FFI_PRELOAD;
5253 } else {
5254 FFI_G(restriction) = (zend_ffi_api_restriction)zend_ini_parse_bool(new_value);
5255 }
5256 return SUCCESS;
5257 }
5258 /* }}} */
5259
ZEND_INI_DISP(zend_ffi_enable_displayer_cb)5260 static ZEND_INI_DISP(zend_ffi_enable_displayer_cb) /* {{{ */
5261 {
5262 if (FFI_G(restriction) == ZEND_FFI_PRELOAD) {
5263 ZEND_PUTS("preload");
5264 } else if (FFI_G(restriction) == ZEND_FFI_ENABLED) {
5265 ZEND_PUTS("On");
5266 } else {
5267 ZEND_PUTS("Off");
5268 }
5269 }
5270 /* }}} */
5271
5272 ZEND_INI_BEGIN()
5273 ZEND_INI_ENTRY_EX("ffi.enable", "preload", ZEND_INI_SYSTEM, OnUpdateFFIEnable, zend_ffi_enable_displayer_cb)
5274 STD_ZEND_INI_ENTRY("ffi.preload", NULL, ZEND_INI_SYSTEM, OnUpdateString, preload, zend_ffi_globals, ffi_globals)
ZEND_INI_END()5275 ZEND_INI_END()
5276
5277 static zend_result zend_ffi_preload_glob(const char *filename) /* {{{ */
5278 {
5279 #ifdef HAVE_GLOB
5280 glob_t globbuf;
5281 int ret;
5282 unsigned int i;
5283
5284 memset(&globbuf, 0, sizeof(glob_t));
5285
5286 ret = glob(filename, 0, NULL, &globbuf);
5287 #ifdef GLOB_NOMATCH
5288 if (ret == GLOB_NOMATCH || !globbuf.gl_pathc) {
5289 #else
5290 if (!globbuf.gl_pathc) {
5291 #endif
5292 /* pass */
5293 } else {
5294 for(i=0 ; i<globbuf.gl_pathc; i++) {
5295 zend_ffi *ffi = zend_ffi_load(globbuf.gl_pathv[i], 1);
5296 if (!ffi) {
5297 globfree(&globbuf);
5298 return FAILURE;
5299 }
5300 efree(ffi);
5301 }
5302 globfree(&globbuf);
5303 }
5304 #else
5305 zend_ffi *ffi = zend_ffi_load(filename, 1);
5306 if (!ffi) {
5307 return FAILURE;
5308 }
5309 efree(ffi);
5310 #endif
5311
5312 return SUCCESS;
5313 }
5314 /* }}} */
5315
5316 static zend_result zend_ffi_preload(char *preload) /* {{{ */
5317 {
5318 zend_ffi *ffi;
5319 char *s = NULL, *e, *filename;
5320 bool is_glob = 0;
5321
5322 e = preload;
5323 while (*e) {
5324 switch (*e) {
5325 case ZEND_PATHS_SEPARATOR:
5326 if (s) {
5327 filename = estrndup(s, e-s);
5328 s = NULL;
5329 if (!is_glob) {
5330 ffi = zend_ffi_load(filename, 1);
5331 efree(filename);
5332 if (!ffi) {
5333 return FAILURE;
5334 }
5335 efree(ffi);
5336 } else {
5337 zend_result ret = zend_ffi_preload_glob(filename);
5338
5339 efree(filename);
5340 if (ret == FAILURE) {
5341 return FAILURE;
5342 }
5343 is_glob = 0;
5344 }
5345 }
5346 break;
5347 case '*':
5348 case '?':
5349 case '[':
5350 is_glob = 1;
5351 break;
5352 default:
5353 if (!s) {
5354 s = e;
5355 }
5356 break;
5357 }
5358 e++;
5359 }
5360 if (s) {
5361 filename = estrndup(s, e-s);
5362 if (!is_glob) {
5363 ffi = zend_ffi_load(filename, 1);
5364 efree(filename);
5365 if (!ffi) {
5366 return FAILURE;
5367 }
5368 efree(ffi);
5369 } else {
5370 zend_result ret = zend_ffi_preload_glob(filename);
5371 efree(filename);
5372 if (ret == FAILURE) {
5373 return FAILURE;
5374 }
5375 }
5376 }
5377
5378 return SUCCESS;
5379 }
5380 /* }}} */
5381
5382 /* The startup code for observers adds a temporary to each function for internal use.
5383 * The "new", "cast", and "type" functions in FFI are both static and non-static.
5384 * Only the static versions are in the function table and the non-static versions are not.
5385 * This means the non-static versions will be skipped by the observers startup code.
5386 * This function fixes that by incrementing the temporary count for the non-static versions.
5387 */
5388 static zend_result (*prev_zend_post_startup_cb)(void);
5389 static zend_result ffi_fixup_temporaries(void) {
5390 if (ZEND_OBSERVER_ENABLED) {
5391 ++zend_ffi_new_fn.T;
5392 ++zend_ffi_cast_fn.T;
5393 ++zend_ffi_type_fn.T;
5394 }
5395 if (prev_zend_post_startup_cb) {
5396 return prev_zend_post_startup_cb();
5397 }
5398 return SUCCESS;
5399 }
5400
5401 /* {{{ ZEND_MINIT_FUNCTION */
5402 ZEND_MINIT_FUNCTION(ffi)
5403 {
5404 REGISTER_INI_ENTRIES();
5405
5406 FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0;
5407
5408 zend_ffi_exception_ce = register_class_FFI_Exception(zend_ce_error);
5409
5410 zend_ffi_parser_exception_ce = register_class_FFI_ParserException(zend_ffi_exception_ce);
5411
5412 zend_ffi_ce = register_class_FFI();
5413 zend_ffi_ce->create_object = zend_ffi_new;
5414 zend_ffi_ce->default_object_handlers = &zend_ffi_handlers;
5415
5416 memcpy(&zend_ffi_new_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "new", sizeof("new")-1), sizeof(zend_internal_function));
5417 zend_ffi_new_fn.fn_flags &= ~ZEND_ACC_STATIC;
5418 memcpy(&zend_ffi_cast_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "cast", sizeof("cast")-1), sizeof(zend_internal_function));
5419 zend_ffi_cast_fn.fn_flags &= ~ZEND_ACC_STATIC;
5420 memcpy(&zend_ffi_type_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1), sizeof(zend_internal_function));
5421 zend_ffi_type_fn.fn_flags &= ~ZEND_ACC_STATIC;
5422
5423 prev_zend_post_startup_cb = zend_post_startup_cb;
5424 zend_post_startup_cb = ffi_fixup_temporaries;
5425
5426 memcpy(&zend_ffi_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5427 zend_ffi_handlers.get_constructor = zend_fake_get_constructor;
5428 zend_ffi_handlers.free_obj = zend_ffi_free_obj;
5429 zend_ffi_handlers.clone_obj = NULL;
5430 zend_ffi_handlers.read_property = zend_ffi_read_var;
5431 zend_ffi_handlers.write_property = zend_ffi_write_var;
5432 zend_ffi_handlers.read_dimension = zend_fake_read_dimension;
5433 zend_ffi_handlers.write_dimension = zend_fake_write_dimension;
5434 zend_ffi_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5435 zend_ffi_handlers.has_property = zend_fake_has_property;
5436 zend_ffi_handlers.unset_property = zend_fake_unset_property;
5437 zend_ffi_handlers.has_dimension = zend_fake_has_dimension;
5438 zend_ffi_handlers.unset_dimension = zend_fake_unset_dimension;
5439 zend_ffi_handlers.get_method = zend_ffi_get_func;
5440 zend_ffi_handlers.compare = NULL;
5441 zend_ffi_handlers.cast_object = zend_fake_cast_object;
5442 zend_ffi_handlers.get_debug_info = NULL;
5443 zend_ffi_handlers.get_closure = NULL;
5444 zend_ffi_handlers.get_properties = zend_fake_get_properties;
5445 zend_ffi_handlers.get_gc = zend_fake_get_gc;
5446
5447 zend_ffi_cdata_ce = register_class_FFI_CData();
5448 zend_ffi_cdata_ce->create_object = zend_ffi_cdata_new;
5449 zend_ffi_cdata_ce->default_object_handlers = &zend_ffi_cdata_handlers;
5450 zend_ffi_cdata_ce->get_iterator = zend_ffi_cdata_get_iterator;
5451
5452 memcpy(&zend_ffi_cdata_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5453 zend_ffi_cdata_handlers.get_constructor = zend_fake_get_constructor;
5454 zend_ffi_cdata_handlers.free_obj = zend_ffi_cdata_free_obj;
5455 zend_ffi_cdata_handlers.clone_obj = zend_ffi_cdata_clone_obj;
5456 zend_ffi_cdata_handlers.read_property = zend_ffi_cdata_read_field;
5457 zend_ffi_cdata_handlers.write_property = zend_ffi_cdata_write_field;
5458 zend_ffi_cdata_handlers.read_dimension = zend_ffi_cdata_read_dim;
5459 zend_ffi_cdata_handlers.write_dimension = zend_ffi_cdata_write_dim;
5460 zend_ffi_cdata_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5461 zend_ffi_cdata_handlers.has_property = zend_fake_has_property;
5462 zend_ffi_cdata_handlers.unset_property = zend_fake_unset_property;
5463 zend_ffi_cdata_handlers.has_dimension = zend_fake_has_dimension;
5464 zend_ffi_cdata_handlers.unset_dimension = zend_fake_unset_dimension;
5465 zend_ffi_cdata_handlers.get_method = zend_fake_get_method;
5466 zend_ffi_cdata_handlers.get_class_name = zend_ffi_cdata_get_class_name;
5467 zend_ffi_cdata_handlers.do_operation = zend_ffi_cdata_do_operation;
5468 zend_ffi_cdata_handlers.compare = zend_ffi_cdata_compare_objects;
5469 zend_ffi_cdata_handlers.cast_object = zend_ffi_cdata_cast_object;
5470 zend_ffi_cdata_handlers.count_elements = zend_ffi_cdata_count_elements;
5471 zend_ffi_cdata_handlers.get_debug_info = zend_ffi_cdata_get_debug_info;
5472 zend_ffi_cdata_handlers.get_closure = zend_ffi_cdata_get_closure;
5473 zend_ffi_cdata_handlers.get_properties = zend_fake_get_properties;
5474 zend_ffi_cdata_handlers.get_gc = zend_fake_get_gc;
5475
5476 memcpy(&zend_ffi_cdata_value_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5477 zend_ffi_cdata_value_handlers.get_constructor = zend_fake_get_constructor;
5478 zend_ffi_cdata_value_handlers.free_obj = zend_ffi_cdata_free_obj;
5479 zend_ffi_cdata_value_handlers.clone_obj = zend_ffi_cdata_clone_obj;
5480 zend_ffi_cdata_value_handlers.read_property = zend_ffi_cdata_get;
5481 zend_ffi_cdata_value_handlers.write_property = zend_ffi_cdata_set;
5482 zend_ffi_cdata_value_handlers.read_dimension = zend_fake_read_dimension;
5483 zend_ffi_cdata_value_handlers.write_dimension = zend_fake_write_dimension;
5484 zend_ffi_cdata_value_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5485 zend_ffi_cdata_value_handlers.has_property = zend_fake_has_property;
5486 zend_ffi_cdata_value_handlers.unset_property = zend_fake_unset_property;
5487 zend_ffi_cdata_value_handlers.has_dimension = zend_fake_has_dimension;
5488 zend_ffi_cdata_value_handlers.unset_dimension = zend_fake_unset_dimension;
5489 zend_ffi_cdata_value_handlers.get_method = zend_fake_get_method;
5490 zend_ffi_cdata_value_handlers.get_class_name = zend_ffi_cdata_get_class_name;
5491 zend_ffi_cdata_value_handlers.compare = zend_ffi_cdata_compare_objects;
5492 zend_ffi_cdata_value_handlers.cast_object = zend_ffi_cdata_cast_object;
5493 zend_ffi_cdata_value_handlers.count_elements = NULL;
5494 zend_ffi_cdata_value_handlers.get_debug_info = zend_ffi_cdata_get_debug_info;
5495 zend_ffi_cdata_value_handlers.get_closure = NULL;
5496 zend_ffi_cdata_value_handlers.get_properties = zend_fake_get_properties;
5497 zend_ffi_cdata_value_handlers.get_gc = zend_fake_get_gc;
5498
5499 memcpy(&zend_ffi_cdata_free_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5500 zend_ffi_cdata_free_handlers.get_constructor = zend_fake_get_constructor;
5501 zend_ffi_cdata_free_handlers.free_obj = zend_ffi_cdata_free_obj;
5502 zend_ffi_cdata_free_handlers.clone_obj = zend_ffi_free_clone_obj;
5503 zend_ffi_cdata_free_handlers.read_property = zend_ffi_free_read_property;
5504 zend_ffi_cdata_free_handlers.write_property = zend_ffi_free_write_property;
5505 zend_ffi_cdata_free_handlers.read_dimension = zend_ffi_free_read_dimension;
5506 zend_ffi_cdata_free_handlers.write_dimension = zend_ffi_free_write_dimension;
5507 zend_ffi_cdata_free_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5508 zend_ffi_cdata_free_handlers.has_property = zend_ffi_free_has_property;
5509 zend_ffi_cdata_free_handlers.unset_property = zend_ffi_free_unset_property;
5510 zend_ffi_cdata_free_handlers.has_dimension = zend_ffi_free_has_dimension;
5511 zend_ffi_cdata_free_handlers.unset_dimension = zend_ffi_free_unset_dimension;
5512 zend_ffi_cdata_free_handlers.get_method = zend_fake_get_method;
5513 zend_ffi_cdata_free_handlers.get_class_name = zend_ffi_cdata_get_class_name;
5514 zend_ffi_cdata_free_handlers.compare = zend_ffi_cdata_compare_objects;
5515 zend_ffi_cdata_free_handlers.cast_object = zend_fake_cast_object;
5516 zend_ffi_cdata_free_handlers.count_elements = NULL;
5517 zend_ffi_cdata_free_handlers.get_debug_info = zend_ffi_free_get_debug_info;
5518 zend_ffi_cdata_free_handlers.get_closure = NULL;
5519 zend_ffi_cdata_free_handlers.get_properties = zend_fake_get_properties;
5520 zend_ffi_cdata_free_handlers.get_gc = zend_fake_get_gc;
5521
5522 zend_ffi_ctype_ce = register_class_FFI_CType();
5523 zend_ffi_ctype_ce->create_object = zend_ffi_ctype_new;
5524 zend_ffi_ctype_ce->default_object_handlers = &zend_ffi_ctype_handlers;
5525
5526 memcpy(&zend_ffi_ctype_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5527 zend_ffi_ctype_handlers.get_constructor = zend_fake_get_constructor;
5528 zend_ffi_ctype_handlers.free_obj = zend_ffi_ctype_free_obj;
5529 zend_ffi_ctype_handlers.clone_obj = NULL;
5530 zend_ffi_ctype_handlers.read_property = zend_fake_read_property;
5531 zend_ffi_ctype_handlers.write_property = zend_fake_write_property;
5532 zend_ffi_ctype_handlers.read_dimension = zend_fake_read_dimension;
5533 zend_ffi_ctype_handlers.write_dimension = zend_fake_write_dimension;
5534 zend_ffi_ctype_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5535 zend_ffi_ctype_handlers.has_property = zend_fake_has_property;
5536 zend_ffi_ctype_handlers.unset_property = zend_fake_unset_property;
5537 zend_ffi_ctype_handlers.has_dimension = zend_fake_has_dimension;
5538 zend_ffi_ctype_handlers.unset_dimension = zend_fake_unset_dimension;
5539 //zend_ffi_ctype_handlers.get_method = zend_fake_get_method;
5540 zend_ffi_ctype_handlers.get_class_name = zend_ffi_ctype_get_class_name;
5541 zend_ffi_ctype_handlers.compare = zend_ffi_ctype_compare_objects;
5542 zend_ffi_ctype_handlers.cast_object = zend_fake_cast_object;
5543 zend_ffi_ctype_handlers.count_elements = NULL;
5544 zend_ffi_ctype_handlers.get_debug_info = zend_ffi_ctype_get_debug_info;
5545 zend_ffi_ctype_handlers.get_closure = NULL;
5546 zend_ffi_ctype_handlers.get_properties = zend_fake_get_properties;
5547 zend_ffi_ctype_handlers.get_gc = zend_fake_get_gc;
5548
5549 if (FFI_G(preload)) {
5550 return zend_ffi_preload(FFI_G(preload));
5551 }
5552
5553 return SUCCESS;
5554 }
5555 /* }}} */
5556
5557 /* {{{ ZEND_RSHUTDOWN_FUNCTION */
5558 ZEND_RSHUTDOWN_FUNCTION(ffi)
5559 {
5560 if (FFI_G(callbacks)) {
5561 zend_hash_destroy(FFI_G(callbacks));
5562 efree(FFI_G(callbacks));
5563 FFI_G(callbacks) = NULL;
5564 }
5565 if (FFI_G(weak_types)) {
5566 #if 0
5567 fprintf(stderr, "WeakTypes: %d\n", zend_hash_num_elements(FFI_G(weak_types)));
5568 #endif
5569 zend_hash_destroy(FFI_G(weak_types));
5570 efree(FFI_G(weak_types));
5571 FFI_G(weak_types) = NULL;
5572 }
5573 return SUCCESS;
5574 }
5575 /* }}} */
5576
5577 /* {{{ ZEND_MINFO_FUNCTION */
5578 ZEND_MINFO_FUNCTION(ffi)
5579 {
5580 php_info_print_table_start();
5581 php_info_print_table_row(2, "FFI support", "enabled");
5582 php_info_print_table_end();
5583
5584 DISPLAY_INI_ENTRIES();
5585 }
5586 /* }}} */
5587
5588 static const zend_ffi_type zend_ffi_type_void = {.kind=ZEND_FFI_TYPE_VOID, .size=1, .align=1};
5589 static const zend_ffi_type zend_ffi_type_char = {.kind=ZEND_FFI_TYPE_CHAR, .size=1, .align=_Alignof(char)};
5590 static const zend_ffi_type zend_ffi_type_bool = {.kind=ZEND_FFI_TYPE_BOOL, .size=1, .align=_Alignof(uint8_t)};
5591 static const zend_ffi_type zend_ffi_type_sint8 = {.kind=ZEND_FFI_TYPE_SINT8, .size=1, .align=_Alignof(int8_t)};
5592 static const zend_ffi_type zend_ffi_type_uint8 = {.kind=ZEND_FFI_TYPE_UINT8, .size=1, .align=_Alignof(uint8_t)};
5593 static const zend_ffi_type zend_ffi_type_sint16 = {.kind=ZEND_FFI_TYPE_SINT16, .size=2, .align=_Alignof(int16_t)};
5594 static const zend_ffi_type zend_ffi_type_uint16 = {.kind=ZEND_FFI_TYPE_UINT16, .size=2, .align=_Alignof(uint16_t)};
5595 static const zend_ffi_type zend_ffi_type_sint32 = {.kind=ZEND_FFI_TYPE_SINT32, .size=4, .align=_Alignof(int32_t)};
5596 static const zend_ffi_type zend_ffi_type_uint32 = {.kind=ZEND_FFI_TYPE_UINT32, .size=4, .align=_Alignof(uint32_t)};
5597 static const zend_ffi_type zend_ffi_type_sint64 = {.kind=ZEND_FFI_TYPE_SINT64, .size=8, .align=_Alignof(int64_t)};
5598 static const zend_ffi_type zend_ffi_type_uint64 = {.kind=ZEND_FFI_TYPE_UINT64, .size=8, .align=_Alignof(uint64_t)};
5599 static const zend_ffi_type zend_ffi_type_float = {.kind=ZEND_FFI_TYPE_FLOAT, .size=sizeof(float), .align=_Alignof(float)};
5600 static const zend_ffi_type zend_ffi_type_double = {.kind=ZEND_FFI_TYPE_DOUBLE, .size=sizeof(double), .align=_Alignof(double)};
5601
5602 #ifdef HAVE_LONG_DOUBLE
5603 static const zend_ffi_type zend_ffi_type_long_double = {.kind=ZEND_FFI_TYPE_LONGDOUBLE, .size=sizeof(long double), .align=_Alignof(long double)};
5604 #endif
5605
5606 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};
5607
5608 static const struct {
5609 const char *name;
5610 const zend_ffi_type *type;
5611 } zend_ffi_types[] = {
5612 {"void", &zend_ffi_type_void},
5613 {"char", &zend_ffi_type_char},
5614 {"bool", &zend_ffi_type_bool},
5615 {"int8_t", &zend_ffi_type_sint8},
5616 {"uint8_t", &zend_ffi_type_uint8},
5617 {"int16_t", &zend_ffi_type_sint16},
5618 {"uint16_t", &zend_ffi_type_uint16},
5619 {"int32_t", &zend_ffi_type_sint32},
5620 {"uint32_t", &zend_ffi_type_uint32},
5621 {"int64_t", &zend_ffi_type_sint64},
5622 {"uint64_t", &zend_ffi_type_uint64},
5623 {"float", &zend_ffi_type_float},
5624 {"double", &zend_ffi_type_double},
5625 #ifdef HAVE_LONG_DOUBLE
5626 {"long double", &zend_ffi_type_long_double},
5627 #endif
5628 #if SIZEOF_SIZE_T == 4
5629 {"uintptr_t", &zend_ffi_type_uint32},
5630 {"intptr_t", &zend_ffi_type_sint32},
5631 {"size_t", &zend_ffi_type_uint32},
5632 {"ssize_t", &zend_ffi_type_sint32},
5633 {"ptrdiff_t", &zend_ffi_type_sint32},
5634 #else
5635 {"uintptr_t", &zend_ffi_type_uint64},
5636 {"intptr_t", &zend_ffi_type_sint64},
5637 {"size_t", &zend_ffi_type_uint64},
5638 {"ssize_t", &zend_ffi_type_sint64},
5639 {"ptrdiff_t", &zend_ffi_type_sint64},
5640 #endif
5641 #if SIZEOF_OFF_T == 4
5642 {"off_t", &zend_ffi_type_sint32},
5643 #else
5644 {"off_t", &zend_ffi_type_sint64},
5645 #endif
5646
5647 {"va_list", &zend_ffi_type_ptr},
5648 {"__builtin_va_list", &zend_ffi_type_ptr},
5649 {"__gnuc_va_list", &zend_ffi_type_ptr},
5650 };
5651
5652 /* {{{ ZEND_GINIT_FUNCTION */
5653 static ZEND_GINIT_FUNCTION(ffi)
5654 {
5655 size_t i;
5656
5657 #if defined(COMPILE_DL_FFI) && defined(ZTS)
5658 ZEND_TSRMLS_CACHE_UPDATE();
5659 #endif
5660 memset(ffi_globals, 0, sizeof(*ffi_globals));
5661 zend_hash_init(&ffi_globals->types, 0, NULL, NULL, 1);
5662 for (i = 0; i < sizeof(zend_ffi_types)/sizeof(zend_ffi_types[0]); i++) {
5663 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);
5664 }
5665 }
5666 /* }}} */
5667
5668 /* {{{ ZEND_GINIT_FUNCTION */
5669 static ZEND_GSHUTDOWN_FUNCTION(ffi)
5670 {
5671 if (ffi_globals->scopes) {
5672 zend_hash_destroy(ffi_globals->scopes);
5673 free(ffi_globals->scopes);
5674 }
5675 zend_hash_destroy(&ffi_globals->types);
5676 }
5677 /* }}} */
5678
5679 /* {{{ ffi_module_entry */
5680 zend_module_entry ffi_module_entry = {
5681 STANDARD_MODULE_HEADER,
5682 "FFI", /* Extension name */
5683 NULL, /* zend_function_entry */
5684 ZEND_MINIT(ffi), /* ZEND_MINIT - Module initialization */
5685 NULL, /* ZEND_MSHUTDOWN - Module shutdown */
5686 NULL, /* ZEND_RINIT - Request initialization */
5687 ZEND_RSHUTDOWN(ffi), /* ZEND_RSHUTDOWN - Request shutdown */
5688 ZEND_MINFO(ffi), /* ZEND_MINFO - Module info */
5689 PHP_VERSION, /* Version */
5690 ZEND_MODULE_GLOBALS(ffi),
5691 ZEND_GINIT(ffi),
5692 ZEND_GSHUTDOWN(ffi),
5693 NULL,
5694 STANDARD_MODULE_PROPERTIES_EX
5695 };
5696 /* }}} */
5697
5698 #ifdef COMPILE_DL_FFI
5699 # ifdef ZTS
5700 ZEND_TSRMLS_CACHE_DEFINE()
5701 # endif
5702 ZEND_GET_MODULE(ffi)
5703 #endif
5704
5705 /* parser callbacks */
5706 void zend_ffi_parser_error(const char *format, ...) /* {{{ */
5707 {
5708 va_list va;
5709 char *message = NULL;
5710
5711 va_start(va, format);
5712 zend_vspprintf(&message, 0, format, va);
5713
5714 if (EG(current_execute_data)) {
5715 zend_throw_exception(zend_ffi_parser_exception_ce, message, 0);
5716 } else {
5717 zend_error(E_WARNING, "FFI Parser: %s", message);
5718 }
5719
5720 efree(message);
5721 va_end(va);
5722
5723 LONGJMP(FFI_G(bailout), FAILURE);
5724 }
5725 /* }}} */
5726
5727 static void zend_ffi_finalize_type(zend_ffi_dcl *dcl) /* {{{ */
5728 {
5729 if (!dcl->type) {
5730 switch (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) {
5731 case ZEND_FFI_DCL_VOID:
5732 dcl->type = (zend_ffi_type*)&zend_ffi_type_void;
5733 break;
5734 case ZEND_FFI_DCL_CHAR:
5735 dcl->type = (zend_ffi_type*)&zend_ffi_type_char;
5736 break;
5737 case ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SIGNED:
5738 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint8;
5739 break;
5740 case ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_UNSIGNED:
5741 case ZEND_FFI_DCL_BOOL:
5742 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint8;
5743 break;
5744 case ZEND_FFI_DCL_SHORT:
5745 case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_SIGNED:
5746 case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT:
5747 case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5748 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint16;
5749 break;
5750 case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_UNSIGNED:
5751 case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5752 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint16;
5753 break;
5754 case ZEND_FFI_DCL_INT:
5755 case ZEND_FFI_DCL_SIGNED:
5756 case ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5757 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint32;
5758 break;
5759 case ZEND_FFI_DCL_UNSIGNED:
5760 case ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5761 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint32;
5762 break;
5763 case ZEND_FFI_DCL_LONG:
5764 case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED:
5765 case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_INT:
5766 case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5767 if (sizeof(long) == 4) {
5768 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint32;
5769 } else {
5770 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint64;
5771 }
5772 break;
5773 case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED:
5774 case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5775 if (sizeof(long) == 4) {
5776 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint32;
5777 } else {
5778 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint64;
5779 }
5780 break;
5781 case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG:
5782 case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED:
5783 case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_INT:
5784 case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5785 dcl->type = (zend_ffi_type*)&zend_ffi_type_sint64;
5786 break;
5787 case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED:
5788 case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5789 dcl->type = (zend_ffi_type*)&zend_ffi_type_uint64;
5790 break;
5791 case ZEND_FFI_DCL_FLOAT:
5792 dcl->type = (zend_ffi_type*)&zend_ffi_type_float;
5793 break;
5794 case ZEND_FFI_DCL_DOUBLE:
5795 dcl->type = (zend_ffi_type*)&zend_ffi_type_double;
5796 break;
5797 case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_DOUBLE:
5798 #ifdef _WIN32
5799 dcl->type = (zend_ffi_type*)&zend_ffi_type_double;
5800 #else
5801 dcl->type = (zend_ffi_type*)&zend_ffi_type_long_double;
5802 #endif
5803 break;
5804 case ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_COMPLEX:
5805 case ZEND_FFI_DCL_DOUBLE|ZEND_FFI_DCL_COMPLEX:
5806 case ZEND_FFI_DCL_DOUBLE|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_COMPLEX:
5807 zend_ffi_parser_error("Unsupported type _Complex at line %d", FFI_G(line));
5808 break;
5809 default:
5810 zend_ffi_parser_error("Unsupported type specifier combination at line %d", FFI_G(line));
5811 break;
5812 }
5813 dcl->flags &= ~ZEND_FFI_DCL_TYPE_SPECIFIERS;
5814 dcl->flags |= ZEND_FFI_DCL_TYPEDEF_NAME;
5815 }
5816 }
5817 /* }}} */
5818
5819 bool zend_ffi_is_typedef_name(const char *name, size_t name_len) /* {{{ */
5820 {
5821 zend_ffi_symbol *sym;
5822 zend_ffi_type *type;
5823
5824 if (FFI_G(symbols)) {
5825 sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5826 if (sym) {
5827 return (sym->kind == ZEND_FFI_SYM_TYPE);
5828 }
5829 }
5830 type = zend_hash_str_find_ptr(&FFI_G(types), name, name_len);
5831 if (type) {
5832 return 1;
5833 }
5834 return 0;
5835 }
5836 /* }}} */
5837
5838 void zend_ffi_resolve_typedef(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* {{{ */
5839 {
5840 zend_ffi_symbol *sym;
5841 zend_ffi_type *type;
5842
5843 if (FFI_G(symbols)) {
5844 sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5845 if (sym && sym->kind == ZEND_FFI_SYM_TYPE) {
5846 dcl->type = ZEND_FFI_TYPE(sym->type);
5847 if (sym->is_const) {
5848 dcl->attr |= ZEND_FFI_ATTR_CONST;
5849 }
5850 return;
5851 }
5852 }
5853 type = zend_hash_str_find_ptr(&FFI_G(types), name, name_len);
5854 if (type) {
5855 dcl->type = type;
5856 return;
5857 }
5858 zend_ffi_parser_error("Undefined C type \"%.*s\" at line %d", name_len, name, FFI_G(line));
5859 }
5860 /* }}} */
5861
5862 void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */
5863 {
5864 zend_ffi_symbol *sym;
5865
5866 if (UNEXPECTED(FFI_G(attribute_parsing))) {
5867 val->kind = ZEND_FFI_VAL_NAME;
5868 val->str = name;
5869 val->len = name_len;
5870 return;
5871 } else if (FFI_G(symbols)) {
5872 sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5873 if (sym && sym->kind == ZEND_FFI_SYM_CONST) {
5874 val->i64 = sym->value;
5875 switch (sym->type->kind) {
5876 case ZEND_FFI_TYPE_SINT8:
5877 case ZEND_FFI_TYPE_SINT16:
5878 case ZEND_FFI_TYPE_SINT32:
5879 val->kind = ZEND_FFI_VAL_INT32;
5880 break;
5881 case ZEND_FFI_TYPE_SINT64:
5882 val->kind = ZEND_FFI_VAL_INT64;
5883 break;
5884 case ZEND_FFI_TYPE_UINT8:
5885 case ZEND_FFI_TYPE_UINT16:
5886 case ZEND_FFI_TYPE_UINT32:
5887 val->kind = ZEND_FFI_VAL_UINT32;
5888 break;
5889 case ZEND_FFI_TYPE_UINT64:
5890 val->kind = ZEND_FFI_VAL_UINT64;
5891 break;
5892 default:
5893 ZEND_UNREACHABLE();
5894 }
5895 return;
5896 }
5897 }
5898 val->kind = ZEND_FFI_VAL_ERROR;
5899 }
5900 /* }}} */
5901
5902 void zend_ffi_make_enum_type(zend_ffi_dcl *dcl) /* {{{ */
5903 {
5904 zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
5905 type->kind = ZEND_FFI_TYPE_ENUM;
5906 type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_ENUM_ATTRS);
5907 type->enumeration.tag_name = NULL;
5908 if (type->attr & ZEND_FFI_ATTR_PACKED) {
5909 type->size = zend_ffi_type_uint8.size;
5910 type->align = zend_ffi_type_uint8.align;
5911 type->enumeration.kind = ZEND_FFI_TYPE_UINT8;
5912 } else {
5913 type->size = zend_ffi_type_uint32.size;
5914 type->align = zend_ffi_type_uint32.align;
5915 type->enumeration.kind = ZEND_FFI_TYPE_UINT32;
5916 }
5917 dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
5918 dcl->attr &= ~ZEND_FFI_ENUM_ATTRS;
5919 }
5920 /* }}} */
5921
5922 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) /* {{{ */
5923 {
5924 zend_ffi_symbol *sym;
5925 const zend_ffi_type *sym_type;
5926 int64_t value;
5927 zend_ffi_type *enum_type = ZEND_FFI_TYPE(enum_dcl->type);
5928 bool overflow = 0;
5929 bool is_signed =
5930 (enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT8 ||
5931 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT16 ||
5932 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT32 ||
5933 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT64);
5934
5935 ZEND_ASSERT(enum_type && enum_type->kind == ZEND_FFI_TYPE_ENUM);
5936 if (val->kind == ZEND_FFI_VAL_EMPTY) {
5937 if (is_signed) {
5938 if (*last == 0x7FFFFFFFFFFFFFFFLL) {
5939 overflow = 1;
5940 }
5941 } else {
5942 if ((*min != 0 || *max != 0)
5943 && (uint64_t)*last == 0xFFFFFFFFFFFFFFFFULL) {
5944 overflow = 1;
5945 }
5946 }
5947 value = *last + 1;
5948 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
5949 if (!is_signed && val->ch < 0) {
5950 if ((uint64_t)*max > 0x7FFFFFFFFFFFFFFFULL) {
5951 overflow = 1;
5952 } else {
5953 is_signed = 1;
5954 }
5955 }
5956 value = val->ch;
5957 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
5958 if (!is_signed && val->i64 < 0) {
5959 if ((uint64_t)*max > 0x7FFFFFFFFFFFFFFFULL) {
5960 overflow = 1;
5961 } else {
5962 is_signed = 1;
5963 }
5964 }
5965 value = val->i64;
5966 } else if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
5967 if (is_signed && val->u64 > 0x7FFFFFFFFFFFFFFFULL) {
5968 overflow = 1;
5969 }
5970 value = val->u64;
5971 } else {
5972 zend_ffi_parser_error("Enumerator value \"%.*s\" must be an integer at line %d", name_len, name, FFI_G(line));
5973 return;
5974 }
5975
5976 if (overflow) {
5977 zend_ffi_parser_error("Overflow in enumeration values \"%.*s\" at line %d", name_len, name, FFI_G(line));
5978 return;
5979 }
5980
5981 if (is_signed) {
5982 *min = MIN(*min, value);
5983 *max = MAX(*max, value);
5984 if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
5985 && *min >= -0x7FLL-1 && *max <= 0x7FLL) {
5986 sym_type = &zend_ffi_type_sint8;
5987 } else if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
5988 && *min >= -0x7FFFLL-1 && *max <= 0x7FFFLL) {
5989 sym_type = &zend_ffi_type_sint16;
5990 } else if (*min >= -0x7FFFFFFFLL-1 && *max <= 0x7FFFFFFFLL) {
5991 sym_type = &zend_ffi_type_sint32;
5992 } else {
5993 sym_type = &zend_ffi_type_sint64;
5994 }
5995 } else {
5996 *min = MIN((uint64_t)*min, (uint64_t)value);
5997 *max = MAX((uint64_t)*max, (uint64_t)value);
5998 if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
5999 && (uint64_t)*max <= 0xFFULL) {
6000 sym_type = &zend_ffi_type_uint8;
6001 } else if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
6002 && (uint64_t)*max <= 0xFFFFULL) {
6003 sym_type = &zend_ffi_type_uint16;
6004 } else if ((uint64_t)*max <= 0xFFFFFFFFULL) {
6005 sym_type = &zend_ffi_type_uint32;
6006 } else {
6007 sym_type = &zend_ffi_type_uint64;
6008 }
6009 }
6010 enum_type->enumeration.kind = sym_type->kind;
6011 enum_type->size = sym_type->size;
6012 enum_type->align = sym_type->align;
6013 *last = value;
6014
6015 if (!FFI_G(symbols)) {
6016 FFI_G(symbols) = pemalloc(sizeof(HashTable), FFI_G(persistent));
6017 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));
6018 }
6019 sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
6020 if (sym) {
6021 zend_ffi_parser_error("Redeclaration of \"%.*s\" at line %d", name_len, name, FFI_G(line));
6022 } else {
6023 sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6024 sym->kind = ZEND_FFI_SYM_CONST;
6025 sym->type = (zend_ffi_type*)sym_type;
6026 sym->value = value;
6027 zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6028 }
6029 }
6030 /* }}} */
6031
6032 void zend_ffi_make_struct_type(zend_ffi_dcl *dcl) /* {{{ */
6033 {
6034 zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6035 type->kind = ZEND_FFI_TYPE_STRUCT;
6036 type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_STRUCT_ATTRS);
6037 type->size = 0;
6038 type->align = dcl->align > 1 ? dcl->align : 1;
6039 if (dcl->flags & ZEND_FFI_DCL_UNION) {
6040 type->attr |= ZEND_FFI_ATTR_UNION;
6041 }
6042 dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6043 type->record.tag_name = NULL;
6044 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));
6045 dcl->attr &= ~ZEND_FFI_STRUCT_ATTRS;
6046 dcl->align = 0;
6047 }
6048 /* }}} */
6049
6050 static zend_result zend_ffi_validate_prev_field_type(zend_ffi_type *struct_type) /* {{{ */
6051 {
6052 if (zend_hash_num_elements(&struct_type->record.fields) > 0) {
6053 zend_ffi_field *field = NULL;
6054
6055 ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&struct_type->record.fields, field) {
6056 break;
6057 } ZEND_HASH_FOREACH_END();
6058 if (ZEND_FFI_TYPE(field->type)->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY) {
6059 zend_ffi_throw_parser_error("Flexible array member not at end of struct at line %d", FFI_G(line));
6060 return FAILURE;
6061 }
6062 }
6063 return SUCCESS;
6064 }
6065 /* }}} */
6066
6067 static zend_result zend_ffi_validate_field_type(zend_ffi_type *type, zend_ffi_type *struct_type) /* {{{ */
6068 {
6069 if (type == struct_type) {
6070 zend_ffi_throw_parser_error("Struct/union can't contain an instance of itself at line %d", FFI_G(line));
6071 return FAILURE;
6072 } else if (zend_ffi_validate_var_type(type, 1) == FAILURE) {
6073 return FAILURE;
6074 } else if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6075 if (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY) {
6076 zend_ffi_throw_parser_error("Flexible array member in union at line %d", FFI_G(line));
6077 return FAILURE;
6078 }
6079 }
6080 return zend_ffi_validate_prev_field_type(struct_type);
6081 }
6082 /* }}} */
6083
6084 void zend_ffi_add_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl) /* {{{ */
6085 {
6086 zend_ffi_field *field;
6087 zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
6088 zend_ffi_type *field_type;
6089
6090 ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6091 zend_ffi_finalize_type(field_dcl);
6092 field_type = ZEND_FFI_TYPE(field_dcl->type);
6093 if (zend_ffi_validate_field_type(field_type, struct_type) == FAILURE) {
6094 zend_ffi_cleanup_dcl(field_dcl);
6095 LONGJMP(FFI_G(bailout), FAILURE);
6096 }
6097
6098 field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
6099 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6100 struct_type->align = MAX(struct_type->align, MAX(field_type->align, field_dcl->align));
6101 }
6102 if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6103 field->offset = 0;
6104 struct_type->size = MAX(struct_type->size, field_type->size);
6105 } else {
6106 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6107 uint32_t field_align = MAX(field_type->align, field_dcl->align);
6108 struct_type->size = ((struct_type->size + (field_align - 1)) / field_align) * field_align;
6109 }
6110 field->offset = struct_type->size;
6111 struct_type->size += field_type->size;
6112 }
6113 field->type = field_dcl->type;
6114 field->is_const = (bool)(field_dcl->attr & ZEND_FFI_ATTR_CONST);
6115 field->is_nested = 0;
6116 field->first_bit = 0;
6117 field->bits = 0;
6118 field_dcl->type = field_type; /* reset "owned" flag */
6119
6120 if (!zend_hash_str_add_ptr(&struct_type->record.fields, name, name_len, field)) {
6121 zend_ffi_type_dtor(field->type);
6122 pefree(field, FFI_G(persistent));
6123 zend_ffi_parser_error("Duplicate field name \"%.*s\" at line %d", name_len, name, FFI_G(line));
6124 }
6125 }
6126 /* }}} */
6127
6128 void zend_ffi_add_anonymous_field(zend_ffi_dcl *struct_dcl, zend_ffi_dcl *field_dcl) /* {{{ */
6129 {
6130 zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
6131 zend_ffi_type *field_type;
6132 zend_ffi_field *field;
6133 zend_string *key;
6134
6135 ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6136 zend_ffi_finalize_type(field_dcl);
6137 field_type = ZEND_FFI_TYPE(field_dcl->type);
6138 if (field_type->kind != ZEND_FFI_TYPE_STRUCT) {
6139 zend_ffi_cleanup_dcl(field_dcl);
6140 zend_ffi_parser_error("Declaration does not declare anything at line %d", FFI_G(line));
6141 return;
6142 }
6143
6144 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6145 struct_type->align = MAX(struct_type->align, MAX(field_type->align, field_dcl->align));
6146 }
6147 if (!(struct_type->attr & ZEND_FFI_ATTR_UNION)) {
6148 if (zend_ffi_validate_prev_field_type(struct_type) == FAILURE) {
6149 zend_ffi_cleanup_dcl(field_dcl);
6150 LONGJMP(FFI_G(bailout), FAILURE);
6151 }
6152 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6153 uint32_t field_align = MAX(field_type->align, field_dcl->align);
6154 struct_type->size = ((struct_type->size + (field_align - 1)) / field_align) * field_align;
6155 }
6156 }
6157
6158 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&field_type->record.fields, key, field) {
6159 zend_ffi_field *new_field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
6160
6161 if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6162 new_field->offset = field->offset;
6163 } else {
6164 new_field->offset = struct_type->size + field->offset;
6165 }
6166 new_field->type = field->type;
6167 new_field->is_const = field->is_const;
6168 new_field->is_nested = 1;
6169 new_field->first_bit = field->first_bit;
6170 new_field->bits = field->bits;
6171 field->type = ZEND_FFI_TYPE(field->type); /* reset "owned" flag */
6172
6173 if (key) {
6174 if (!zend_hash_add_ptr(&struct_type->record.fields, key, new_field)) {
6175 zend_ffi_type_dtor(new_field->type);
6176 pefree(new_field, FFI_G(persistent));
6177 zend_ffi_parser_error("Duplicate field name \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
6178 return;
6179 }
6180 } else {
6181 zend_hash_next_index_insert_ptr(&struct_type->record.fields, field);
6182 }
6183 } ZEND_HASH_FOREACH_END();
6184
6185 if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6186 struct_type->size = MAX(struct_type->size, field_type->size);
6187 } else {
6188 struct_type->size += field_type->size;
6189 }
6190
6191 zend_ffi_type_dtor(field_dcl->type);
6192 field_dcl->type = NULL;
6193 }
6194 /* }}} */
6195
6196 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) /* {{{ */
6197 {
6198 zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
6199 zend_ffi_type *field_type;
6200 zend_ffi_field *field;
6201
6202 ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6203 zend_ffi_finalize_type(field_dcl);
6204 field_type = ZEND_FFI_TYPE(field_dcl->type);
6205 if (zend_ffi_validate_field_type(field_type, struct_type) == FAILURE) {
6206 zend_ffi_cleanup_dcl(field_dcl);
6207 LONGJMP(FFI_G(bailout), FAILURE);
6208 }
6209
6210 if (field_type->kind < ZEND_FFI_TYPE_UINT8 || field_type->kind > ZEND_FFI_TYPE_BOOL) {
6211 zend_ffi_cleanup_dcl(field_dcl);
6212 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));
6213 }
6214
6215 if (bits->kind == ZEND_FFI_VAL_INT32 || bits->kind == ZEND_FFI_VAL_INT64) {
6216 if (bits->i64 < 0) {
6217 zend_ffi_cleanup_dcl(field_dcl);
6218 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));
6219 } else if (bits->i64 == 0) {
6220 zend_ffi_cleanup_dcl(field_dcl);
6221 if (name) {
6222 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));
6223 }
6224 return;
6225 } else if (bits->i64 > field_type->size * 8) {
6226 zend_ffi_cleanup_dcl(field_dcl);
6227 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));
6228 }
6229 } else if (bits->kind == ZEND_FFI_VAL_UINT32 || bits->kind == ZEND_FFI_VAL_UINT64) {
6230 if (bits->u64 == 0) {
6231 zend_ffi_cleanup_dcl(field_dcl);
6232 if (name) {
6233 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));
6234 }
6235 return;
6236 } else if (bits->u64 > field_type->size * 8) {
6237 zend_ffi_cleanup_dcl(field_dcl);
6238 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));
6239 }
6240 } else {
6241 zend_ffi_cleanup_dcl(field_dcl);
6242 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));
6243 }
6244
6245 field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
6246 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED)) {
6247 struct_type->align = MAX(struct_type->align, sizeof(uint32_t));
6248 }
6249 if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6250 field->offset = 0;
6251 field->first_bit = 0;
6252 field->bits = bits->u64;
6253 if (struct_type->attr & ZEND_FFI_ATTR_PACKED) {
6254 struct_type->size = MAX(struct_type->size, (bits->u64 + 7) / 8);
6255 } else {
6256 struct_type->size = MAX(struct_type->size, ((bits->u64 + 31) / 32) * 4);
6257 }
6258 } else {
6259 zend_ffi_field *prev_field = NULL;
6260
6261 if (zend_hash_num_elements(&struct_type->record.fields) > 0) {
6262 ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&struct_type->record.fields, prev_field) {
6263 break;
6264 } ZEND_HASH_FOREACH_END();
6265 }
6266 if (prev_field && prev_field->bits) {
6267 field->offset = prev_field->offset;
6268 field->first_bit = prev_field->first_bit + prev_field->bits;
6269 field->bits = bits->u64;
6270 } else {
6271 field->offset = struct_type->size;
6272 field->first_bit = 0;
6273 field->bits = bits->u64;
6274 }
6275 if (struct_type->attr & ZEND_FFI_ATTR_PACKED) {
6276 struct_type->size = field->offset + ((field->first_bit + field->bits) + 7) / 8;
6277 } else {
6278 struct_type->size = field->offset + (((field->first_bit + field->bits) + 31) / 32) * 4;
6279 }
6280 }
6281 field->type = field_dcl->type;
6282 field->is_const = (bool)(field_dcl->attr & ZEND_FFI_ATTR_CONST);
6283 field->is_nested = 0;
6284 field_dcl->type = field_type; /* reset "owned" flag */
6285
6286 if (name) {
6287 if (!zend_hash_str_add_ptr(&struct_type->record.fields, name, name_len, field)) {
6288 zend_ffi_type_dtor(field->type);
6289 pefree(field, FFI_G(persistent));
6290 zend_ffi_parser_error("Duplicate field name \"%.*s\" at line %d", name_len, name, FFI_G(line));
6291 }
6292 } else {
6293 zend_hash_next_index_insert_ptr(&struct_type->record.fields, field);
6294 }
6295 }
6296 /* }}} */
6297
6298 void zend_ffi_adjust_struct_size(zend_ffi_dcl *dcl) /* {{{ */
6299 {
6300 zend_ffi_type *struct_type = ZEND_FFI_TYPE(dcl->type);
6301
6302 ZEND_ASSERT(struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6303 if (dcl->align > struct_type->align) {
6304 struct_type->align = dcl->align;
6305 }
6306 if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED)) {
6307 struct_type->size = ((struct_type->size + (struct_type->align - 1)) / struct_type->align) * struct_type->align;
6308 }
6309 dcl->align = 0;
6310 }
6311 /* }}} */
6312
6313 void zend_ffi_make_pointer_type(zend_ffi_dcl *dcl) /* {{{ */
6314 {
6315 zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6316 type->kind = ZEND_FFI_TYPE_POINTER;
6317 type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_POINTER_ATTRS);
6318 type->size = sizeof(void*);
6319 type->align = _Alignof(void*);
6320 zend_ffi_finalize_type(dcl);
6321 if (zend_ffi_validate_vla(ZEND_FFI_TYPE(dcl->type)) == FAILURE) {
6322 zend_ffi_cleanup_dcl(dcl);
6323 LONGJMP(FFI_G(bailout), FAILURE);
6324 }
6325 type->pointer.type = dcl->type;
6326 dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6327 dcl->flags &= ~ZEND_FFI_DCL_TYPE_QUALIFIERS;
6328 dcl->attr &= ~ZEND_FFI_POINTER_ATTRS;
6329 dcl->align = 0;
6330 }
6331 /* }}} */
6332
6333 static zend_result zend_ffi_validate_array_element_type(zend_ffi_type *type) /* {{{ */
6334 {
6335 if (type->kind == ZEND_FFI_TYPE_FUNC) {
6336 zend_ffi_throw_parser_error("Array of functions is not allowed at line %d", FFI_G(line));
6337 return FAILURE;
6338 } else if (type->kind == ZEND_FFI_TYPE_ARRAY && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
6339 zend_ffi_throw_parser_error("Only the leftmost array can be undimensioned at line %d", FFI_G(line));
6340 return FAILURE;
6341 }
6342 return zend_ffi_validate_type(type, 0, 1);
6343 }
6344 /* }}} */
6345
6346 void zend_ffi_make_array_type(zend_ffi_dcl *dcl, zend_ffi_val *len) /* {{{ */
6347 {
6348 int length = 0;
6349 zend_ffi_type *element_type;
6350 zend_ffi_type *type;
6351
6352 zend_ffi_finalize_type(dcl);
6353 element_type = ZEND_FFI_TYPE(dcl->type);
6354
6355 if (len->kind == ZEND_FFI_VAL_EMPTY) {
6356 length = 0;
6357 } else if (len->kind == ZEND_FFI_VAL_UINT32 || len->kind == ZEND_FFI_VAL_UINT64) {
6358 length = len->u64;
6359 } else if (len->kind == ZEND_FFI_VAL_INT32 || len->kind == ZEND_FFI_VAL_INT64) {
6360 length = len->i64;
6361 } else if (len->kind == ZEND_FFI_VAL_CHAR) {
6362 length = len->ch;
6363 } else {
6364 zend_ffi_cleanup_dcl(dcl);
6365 zend_ffi_parser_error("Unsupported array index type at line %d", FFI_G(line));
6366 return;
6367 }
6368 if (length < 0) {
6369 zend_ffi_cleanup_dcl(dcl);
6370 zend_ffi_parser_error("Negative array index at line %d", FFI_G(line));
6371 return;
6372 }
6373
6374 if (zend_ffi_validate_array_element_type(element_type) == FAILURE) {
6375 zend_ffi_cleanup_dcl(dcl);
6376 LONGJMP(FFI_G(bailout), FAILURE);
6377 }
6378
6379 type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6380 type->kind = ZEND_FFI_TYPE_ARRAY;
6381 type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_ARRAY_ATTRS);
6382 type->size = length * element_type->size;
6383 type->align = element_type->align;
6384 type->array.type = dcl->type;
6385 type->array.length = length;
6386 dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6387 dcl->flags &= ~ZEND_FFI_DCL_TYPE_QUALIFIERS;
6388 dcl->attr &= ~ZEND_FFI_ARRAY_ATTRS;
6389 dcl->align = 0;
6390 }
6391 /* }}} */
6392
6393 static zend_result zend_ffi_validate_func_ret_type(zend_ffi_type *type) /* {{{ */
6394 {
6395 if (type->kind == ZEND_FFI_TYPE_FUNC) {
6396 zend_ffi_throw_parser_error("Function returning function is not allowed at line %d", FFI_G(line));
6397 return FAILURE;
6398 } else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
6399 zend_ffi_throw_parser_error("Function returning array is not allowed at line %d", FFI_G(line));
6400 return FAILURE;
6401 }
6402 return zend_ffi_validate_incomplete_type(type, 1, 0);
6403 }
6404 /* }}} */
6405
6406 void zend_ffi_make_func_type(zend_ffi_dcl *dcl, HashTable *args, zend_ffi_dcl *nested_dcl) /* {{{ */
6407 {
6408 zend_ffi_type *type;
6409 zend_ffi_type *ret_type;
6410
6411 zend_ffi_finalize_type(dcl);
6412 ret_type = ZEND_FFI_TYPE(dcl->type);
6413
6414 if (args) {
6415 int no_args = 0;
6416 zend_ffi_type *arg_type;
6417
6418 ZEND_HASH_PACKED_FOREACH_PTR(args, arg_type) {
6419 arg_type = ZEND_FFI_TYPE(arg_type);
6420 if (arg_type->kind == ZEND_FFI_TYPE_VOID) {
6421 if (zend_hash_num_elements(args) != 1) {
6422 zend_ffi_cleanup_dcl(nested_dcl);
6423 zend_ffi_cleanup_dcl(dcl);
6424 zend_hash_destroy(args);
6425 pefree(args, FFI_G(persistent));
6426 zend_ffi_parser_error("void type is not allowed at line %d", FFI_G(line));
6427 return;
6428 } else {
6429 no_args = 1;
6430 }
6431 }
6432 } ZEND_HASH_FOREACH_END();
6433 if (no_args) {
6434 zend_hash_destroy(args);
6435 pefree(args, FFI_G(persistent));
6436 args = NULL;
6437 }
6438 }
6439
6440 #ifdef HAVE_FFI_VECTORCALL_PARTIAL
6441 if (dcl->abi == ZEND_FFI_ABI_VECTORCALL && args) {
6442 zend_ulong i;
6443 zend_ffi_type *arg_type;
6444
6445 ZEND_HASH_PACKED_FOREACH_KEY_PTR(args, i, arg_type) {
6446 arg_type = ZEND_FFI_TYPE(arg_type);
6447 # ifdef _WIN64
6448 if (i >= 4 && i <= 5 && (arg_type->kind == ZEND_FFI_TYPE_FLOAT || arg_type->kind == ZEND_FFI_TYPE_DOUBLE)) {
6449 # else
6450 if (i < 6 && (arg_type->kind == ZEND_FFI_TYPE_FLOAT || arg_type->kind == ZEND_FFI_TYPE_DOUBLE)) {
6451 # endif
6452 zend_ffi_cleanup_dcl(nested_dcl);
6453 zend_ffi_cleanup_dcl(dcl);
6454 zend_hash_destroy(args);
6455 pefree(args, FFI_G(persistent));
6456 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));
6457 return;
6458 }
6459 } ZEND_HASH_FOREACH_END();
6460 }
6461 #endif
6462
6463 if (zend_ffi_validate_func_ret_type(ret_type) == FAILURE) {
6464 zend_ffi_cleanup_dcl(nested_dcl);
6465 zend_ffi_cleanup_dcl(dcl);
6466 if (args) {
6467 zend_hash_destroy(args);
6468 pefree(args, FFI_G(persistent));
6469 }
6470 LONGJMP(FFI_G(bailout), FAILURE);
6471 }
6472
6473 type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6474 type->kind = ZEND_FFI_TYPE_FUNC;
6475 type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_FUNC_ATTRS);
6476 type->size = sizeof(void*);
6477 type->align = 1;
6478 type->func.ret_type = dcl->type;
6479 switch (dcl->abi) {
6480 case ZEND_FFI_ABI_DEFAULT:
6481 case ZEND_FFI_ABI_CDECL:
6482 type->func.abi = FFI_DEFAULT_ABI;
6483 break;
6484 #ifdef HAVE_FFI_FASTCALL
6485 case ZEND_FFI_ABI_FASTCALL:
6486 type->func.abi = FFI_FASTCALL;
6487 break;
6488 #endif
6489 #ifdef HAVE_FFI_THISCALL
6490 case ZEND_FFI_ABI_THISCALL:
6491 type->func.abi = FFI_THISCALL;
6492 break;
6493 #endif
6494 #ifdef HAVE_FFI_STDCALL
6495 case ZEND_FFI_ABI_STDCALL:
6496 type->func.abi = FFI_STDCALL;
6497 break;
6498 #endif
6499 #ifdef HAVE_FFI_PASCAL
6500 case ZEND_FFI_ABI_PASCAL:
6501 type->func.abi = FFI_PASCAL;
6502 break;
6503 #endif
6504 #ifdef HAVE_FFI_REGISTER
6505 case ZEND_FFI_ABI_REGISTER:
6506 type->func.abi = FFI_REGISTER;
6507 break;
6508 #endif
6509 #ifdef HAVE_FFI_MS_CDECL
6510 case ZEND_FFI_ABI_MS:
6511 type->func.abi = FFI_MS_CDECL;
6512 break;
6513 #endif
6514 #ifdef HAVE_FFI_SYSV
6515 case ZEND_FFI_ABI_SYSV:
6516 type->func.abi = FFI_SYSV;
6517 break;
6518 #endif
6519 #ifdef HAVE_FFI_VECTORCALL_PARTIAL
6520 case ZEND_FFI_ABI_VECTORCALL:
6521 type->func.abi = FFI_VECTORCALL_PARTIAL;
6522 break;
6523 #endif
6524 default:
6525 type->func.abi = FFI_DEFAULT_ABI;
6526 zend_ffi_cleanup_dcl(nested_dcl);
6527 if (args) {
6528 zend_hash_destroy(args);
6529 pefree(args, FFI_G(persistent));
6530 }
6531 type->func.args = NULL;
6532 _zend_ffi_type_dtor(type);
6533 zend_ffi_parser_error("Unsupported calling convention line %d", FFI_G(line));
6534 break;
6535 }
6536 type->func.args = args;
6537 dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6538 dcl->attr &= ~ZEND_FFI_FUNC_ATTRS;
6539 dcl->align = 0;
6540 dcl->abi = 0;
6541 }
6542 /* }}} */
6543
6544 void zend_ffi_add_arg(HashTable **args, const char *name, size_t name_len, zend_ffi_dcl *arg_dcl) /* {{{ */
6545 {
6546 zend_ffi_type *type;
6547
6548 if (!*args) {
6549 *args = pemalloc(sizeof(HashTable), FFI_G(persistent));
6550 zend_hash_init(*args, 0, NULL, zend_ffi_type_hash_dtor, FFI_G(persistent));
6551 }
6552 zend_ffi_finalize_type(arg_dcl);
6553 type = ZEND_FFI_TYPE(arg_dcl->type);
6554 if (type->kind == ZEND_FFI_TYPE_ARRAY) {
6555 if (ZEND_FFI_TYPE_IS_OWNED(arg_dcl->type)) {
6556 type->kind = ZEND_FFI_TYPE_POINTER;
6557 type->size = sizeof(void*);
6558 } else {
6559 zend_ffi_type *new_type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6560 new_type->kind = ZEND_FFI_TYPE_POINTER;
6561 new_type->attr = FFI_G(default_type_attr) | (type->attr & ZEND_FFI_POINTER_ATTRS);
6562 new_type->size = sizeof(void*);
6563 new_type->align = _Alignof(void*);
6564 new_type->pointer.type = ZEND_FFI_TYPE(type->array.type);
6565 arg_dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
6566 }
6567 } else if (type->kind == ZEND_FFI_TYPE_FUNC) {
6568 zend_ffi_type *new_type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6569 new_type->kind = ZEND_FFI_TYPE_POINTER;
6570 new_type->attr = FFI_G(default_type_attr);
6571 new_type->size = sizeof(void*);
6572 new_type->align = _Alignof(void*);
6573 new_type->pointer.type = arg_dcl->type;
6574 arg_dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
6575 }
6576 if (zend_ffi_validate_incomplete_type(type, 1, 1) == FAILURE) {
6577 zend_ffi_cleanup_dcl(arg_dcl);
6578 zend_hash_destroy(*args);
6579 pefree(*args, FFI_G(persistent));
6580 *args = NULL;
6581 LONGJMP(FFI_G(bailout), FAILURE);
6582 }
6583 zend_hash_next_index_insert_ptr(*args, (void*)arg_dcl->type);
6584 }
6585 /* }}} */
6586
6587 void zend_ffi_declare(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* {{{ */
6588 {
6589 zend_ffi_symbol *sym;
6590
6591 if (!FFI_G(symbols)) {
6592 FFI_G(symbols) = pemalloc(sizeof(HashTable), FFI_G(persistent));
6593 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));
6594 }
6595 zend_ffi_finalize_type(dcl);
6596 sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
6597 if (sym) {
6598 if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_TYPEDEF
6599 && sym->kind == ZEND_FFI_SYM_TYPE
6600 && zend_ffi_is_same_type(ZEND_FFI_TYPE(sym->type), ZEND_FFI_TYPE(dcl->type))
6601 && sym->is_const == (bool)(dcl->attr & ZEND_FFI_ATTR_CONST)) {
6602 /* allowed redeclaration */
6603 zend_ffi_type_dtor(dcl->type);
6604 return;
6605 } else if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0
6606 || (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN) {
6607 zend_ffi_type *type = ZEND_FFI_TYPE(dcl->type);
6608
6609 if (type->kind == ZEND_FFI_TYPE_FUNC) {
6610 if (sym->kind == ZEND_FFI_SYM_FUNC
6611 && zend_ffi_same_types(ZEND_FFI_TYPE(sym->type), type)) {
6612 /* allowed redeclaration */
6613 zend_ffi_type_dtor(dcl->type);
6614 return;
6615 }
6616 } else {
6617 if (sym->kind == ZEND_FFI_SYM_VAR
6618 && zend_ffi_is_same_type(ZEND_FFI_TYPE(sym->type), type)
6619 && sym->is_const == (bool)(dcl->attr & ZEND_FFI_ATTR_CONST)) {
6620 /* allowed redeclaration */
6621 zend_ffi_type_dtor(dcl->type);
6622 return;
6623 }
6624 }
6625 }
6626 zend_ffi_parser_error("Redeclaration of \"%.*s\" at line %d", name_len, name, FFI_G(line));
6627 } else {
6628 if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_TYPEDEF) {
6629 if (zend_ffi_validate_vla(ZEND_FFI_TYPE(dcl->type)) == FAILURE) {
6630 zend_ffi_cleanup_dcl(dcl);
6631 LONGJMP(FFI_G(bailout), FAILURE);
6632 }
6633 if (dcl->align && dcl->align > ZEND_FFI_TYPE(dcl->type)->align) {
6634 if (ZEND_FFI_TYPE_IS_OWNED(dcl->type)) {
6635 ZEND_FFI_TYPE(dcl->type)->align = dcl->align;
6636 } else {
6637 zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6638
6639 memcpy(type, ZEND_FFI_TYPE(dcl->type), sizeof(zend_ffi_type));
6640 type->attr |= FFI_G(default_type_attr);
6641 type->align = dcl->align;
6642 dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6643 }
6644 }
6645 sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6646 sym->kind = ZEND_FFI_SYM_TYPE;
6647 sym->type = dcl->type;
6648 sym->is_const = (bool)(dcl->attr & ZEND_FFI_ATTR_CONST);
6649 dcl->type = ZEND_FFI_TYPE(dcl->type); /* reset "owned" flag */
6650 zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6651 } else {
6652 zend_ffi_type *type;
6653
6654 type = ZEND_FFI_TYPE(dcl->type);
6655 if (zend_ffi_validate_type(type, (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN, 1) == FAILURE) {
6656 zend_ffi_cleanup_dcl(dcl);
6657 LONGJMP(FFI_G(bailout), FAILURE);
6658 }
6659 if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0 ||
6660 (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN) {
6661 sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6662 sym->kind = (type->kind == ZEND_FFI_TYPE_FUNC) ? ZEND_FFI_SYM_FUNC : ZEND_FFI_SYM_VAR;
6663 sym->type = dcl->type;
6664 sym->is_const = (bool)(dcl->attr & ZEND_FFI_ATTR_CONST);
6665 dcl->type = type; /* reset "owned" flag */
6666 zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6667 } else {
6668 /* useless declaration */
6669 zend_ffi_type_dtor(dcl->type);
6670 }
6671 }
6672 }
6673 }
6674 /* }}} */
6675
6676 void zend_ffi_declare_tag(const char *name, size_t name_len, zend_ffi_dcl *dcl, bool incomplete) /* {{{ */
6677 {
6678 zend_ffi_tag *tag;
6679 zend_ffi_type *type;
6680
6681 if (!FFI_G(tags)) {
6682 FFI_G(tags) = pemalloc(sizeof(HashTable), FFI_G(persistent));
6683 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));
6684 }
6685 tag = zend_hash_str_find_ptr(FFI_G(tags), name, name_len);
6686 if (tag) {
6687 zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
6688
6689 if (dcl->flags & ZEND_FFI_DCL_STRUCT) {
6690 if (tag->kind != ZEND_FFI_TAG_STRUCT) {
6691 zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6692 return;
6693 } else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6694 zend_ffi_parser_error("Redefinition of \"struct %.*s\" at line %d", name_len, name, FFI_G(line));
6695 return;
6696 }
6697 } else if (dcl->flags & ZEND_FFI_DCL_UNION) {
6698 if (tag->kind != ZEND_FFI_TAG_UNION) {
6699 zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6700 return;
6701 } else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6702 zend_ffi_parser_error("Redefinition of \"union %.*s\" at line %d", name_len, name, FFI_G(line));
6703 return;
6704 }
6705 } else if (dcl->flags & ZEND_FFI_DCL_ENUM) {
6706 if (tag->kind != ZEND_FFI_TAG_ENUM) {
6707 zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6708 return;
6709 } else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6710 zend_ffi_parser_error("Redefinition of \"enum %.*s\" at line %d", name_len, name, FFI_G(line));
6711 return;
6712 }
6713 } else {
6714 ZEND_UNREACHABLE();
6715 return;
6716 }
6717 dcl->type = type;
6718 if (!incomplete) {
6719 type->attr &= ~ZEND_FFI_ATTR_INCOMPLETE_TAG;
6720 }
6721 } else {
6722 zend_ffi_tag *tag = pemalloc(sizeof(zend_ffi_tag), FFI_G(persistent));
6723 zend_string *tag_name = zend_string_init(name, name_len, FFI_G(persistent));
6724
6725 if (dcl->flags & ZEND_FFI_DCL_STRUCT) {
6726 tag->kind = ZEND_FFI_TAG_STRUCT;
6727 zend_ffi_make_struct_type(dcl);
6728 type = ZEND_FFI_TYPE(dcl->type);
6729 type->record.tag_name = zend_string_copy(tag_name);
6730 } else if (dcl->flags & ZEND_FFI_DCL_UNION) {
6731 tag->kind = ZEND_FFI_TAG_UNION;
6732 zend_ffi_make_struct_type(dcl);
6733 type = ZEND_FFI_TYPE(dcl->type);
6734 type->record.tag_name = zend_string_copy(tag_name);
6735 } else if (dcl->flags & ZEND_FFI_DCL_ENUM) {
6736 tag->kind = ZEND_FFI_TAG_ENUM;
6737 zend_ffi_make_enum_type(dcl);
6738 type = ZEND_FFI_TYPE(dcl->type);
6739 type->enumeration.tag_name = zend_string_copy(tag_name);
6740 } else {
6741 ZEND_UNREACHABLE();
6742 }
6743 tag->type = ZEND_FFI_TYPE_MAKE_OWNED(dcl->type);
6744 dcl->type = ZEND_FFI_TYPE(dcl->type);
6745 if (incomplete) {
6746 dcl->type->attr |= ZEND_FFI_ATTR_INCOMPLETE_TAG;
6747 }
6748 zend_hash_add_new_ptr(FFI_G(tags), tag_name, tag);
6749 zend_string_release(tag_name);
6750 }
6751 }
6752 /* }}} */
6753
6754 void zend_ffi_set_abi(zend_ffi_dcl *dcl, uint16_t abi) /* {{{ */
6755 {
6756 if (dcl->abi != ZEND_FFI_ABI_DEFAULT) {
6757 zend_ffi_parser_error("Multiple calling convention specifiers at line %d", FFI_G(line));
6758 } else {
6759 dcl->abi = abi;
6760 }
6761 }
6762 /* }}} */
6763
6764 #define SIMPLE_ATTRIBUTES(_) \
6765 _(cdecl) \
6766 _(fastcall) \
6767 _(thiscall) \
6768 _(stdcall) \
6769 _(ms_abi) \
6770 _(sysv_abi) \
6771 _(vectorcall) \
6772 _(aligned) \
6773 _(packed) \
6774 _(ms_struct) \
6775 _(gcc_struct) \
6776 _(const) \
6777 _(malloc) \
6778 _(deprecated) \
6779 _(nothrow) \
6780 _(leaf) \
6781 _(pure) \
6782 _(noreturn) \
6783 _(warn_unused_result)
6784
6785 #define ATTR_ID(name) attr_ ## name,
6786 #define ATTR_NAME(name) {sizeof(#name)-1, #name},
6787
6788 void zend_ffi_add_attribute(zend_ffi_dcl *dcl, const char *name, size_t name_len) /* {{{ */
6789 {
6790 enum {
6791 SIMPLE_ATTRIBUTES(ATTR_ID)
6792 attr_unsupported
6793 };
6794 static const struct {
6795 size_t len;
6796 const char * const name;
6797 } names[] = {
6798 SIMPLE_ATTRIBUTES(ATTR_NAME)
6799 {0, NULL}
6800 };
6801 int id;
6802
6803 if (name_len > 4
6804 && name[0] == '_'
6805 && name[1] == '_'
6806 && name[name_len-2] == '_'
6807 && name[name_len-1] == '_') {
6808 name += 2;
6809 name_len -= 4;
6810 }
6811 for (id = 0; names[id].len != 0; id++) {
6812 if (name_len == names[id].len) {
6813 if (memcmp(name, names[id].name, name_len) == 0) {
6814 break;
6815 }
6816 }
6817 }
6818 switch (id) {
6819 case attr_cdecl:
6820 zend_ffi_set_abi(dcl, ZEND_FFI_ABI_CDECL);
6821 break;
6822 case attr_fastcall:
6823 zend_ffi_set_abi(dcl, ZEND_FFI_ABI_FASTCALL);
6824 break;
6825 case attr_thiscall:
6826 zend_ffi_set_abi(dcl, ZEND_FFI_ABI_THISCALL);
6827 break;
6828 case attr_stdcall:
6829 zend_ffi_set_abi(dcl, ZEND_FFI_ABI_STDCALL);
6830 break;
6831 case attr_ms_abi:
6832 zend_ffi_set_abi(dcl, ZEND_FFI_ABI_MS);
6833 break;
6834 case attr_sysv_abi:
6835 zend_ffi_set_abi(dcl, ZEND_FFI_ABI_SYSV);
6836 break;
6837 case attr_vectorcall:
6838 zend_ffi_set_abi(dcl, ZEND_FFI_ABI_VECTORCALL);
6839 break;
6840 case attr_aligned:
6841 dcl->align = __BIGGEST_ALIGNMENT__;
6842 break;
6843 case attr_packed:
6844 dcl->attr |= ZEND_FFI_ATTR_PACKED;
6845 break;
6846 case attr_ms_struct:
6847 dcl->attr |= ZEND_FFI_ATTR_MS_STRUCT;
6848 break;
6849 case attr_gcc_struct:
6850 dcl->attr |= ZEND_FFI_ATTR_GCC_STRUCT;
6851 break;
6852 case attr_unsupported:
6853 zend_ffi_parser_error("Unsupported attribute \"%.*s\" at line %d", name_len, name, FFI_G(line));
6854 break;
6855 default:
6856 /* ignore */
6857 break;
6858 }
6859 }
6860 /* }}} */
6861
6862 #define VALUE_ATTRIBUTES(_) \
6863 _(regparam) \
6864 _(aligned) \
6865 _(mode) \
6866 _(nonnull) \
6867 _(alloc_size) \
6868 _(format) \
6869 _(deprecated)
6870
6871 void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, int n, zend_ffi_val *val) /* {{{ */
6872 {
6873 enum {
6874 VALUE_ATTRIBUTES(ATTR_ID)
6875 attr_unsupported
6876 };
6877 static const struct {
6878 size_t len;
6879 const char * const name;
6880 } names[] = {
6881 VALUE_ATTRIBUTES(ATTR_NAME)
6882 {0, NULL}
6883 };
6884 int id;
6885
6886 if (name_len > 4
6887 && name[0] == '_'
6888 && name[1] == '_'
6889 && name[name_len-2] == '_'
6890 && name[name_len-1] == '_') {
6891 name += 2;
6892 name_len -= 4;
6893 }
6894 for (id = 0; names[id].len != 0; id++) {
6895 if (name_len == names[id].len) {
6896 if (memcmp(name, names[id].name, name_len) == 0) {
6897 break;
6898 }
6899 }
6900 }
6901 switch (id) {
6902 case attr_regparam:
6903 if (n == 0
6904 && (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
6905 && val->i64 == 3) {
6906 zend_ffi_set_abi(dcl, ZEND_FFI_ABI_REGISTER);
6907 } else {
6908 zend_ffi_parser_error("Incorrect \"regparam\" value at line %d", FFI_G(line));
6909 }
6910 break;
6911 case attr_aligned:
6912 if (n == 0
6913 && (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
6914 && val->i64 > 0 && val->i64 <= 0x80000000 && (val->i64 & (val->i64 - 1)) == 0) {
6915 dcl->align = val->i64;
6916 } else {
6917 zend_ffi_parser_error("Incorrect \"alignment\" value at line %d", FFI_G(line));
6918 }
6919 break;
6920 case attr_mode:
6921 if (n == 0
6922 && (val->kind == ZEND_FFI_VAL_NAME)) {
6923 const char *str = val->str;
6924 size_t len = val->len;
6925 if (len > 4
6926 && str[0] == '_'
6927 && str[1] == '_'
6928 && str[len-2] == '_'
6929 && str[len-1] == '_') {
6930 str += 2;
6931 len -= 4;
6932 }
6933 // TODO: Add support for vector type 'VnXX' ???
6934 if (len == 2) {
6935 if (str[1] == 'I') {
6936 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))) {
6937 /* inappropriate type */
6938 } else if (str[0] == 'Q') {
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_CHAR;
6941 break;
6942 } else if (str[0] == 'H') {
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_SHORT;
6945 break;
6946 } else if (str[0] == 'S') {
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 dcl->flags |= ZEND_FFI_DCL_INT;
6949 break;
6950 } else if (str[0] == 'D') {
6951 dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
6952 if (sizeof(long) == 8) {
6953 dcl->flags |= ZEND_FFI_DCL_LONG;
6954 } else {
6955 dcl->flags |= ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG;
6956 }
6957 break;
6958 }
6959 } else if (str[1] == 'F') {
6960 if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE))) {
6961 /* inappropriate type */
6962 } else if (str[0] == 'S') {
6963 dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
6964 dcl->flags |= ZEND_FFI_DCL_FLOAT;
6965 break;
6966 } else if (str[0] == 'D') {
6967 dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
6968 dcl->flags |= ZEND_FFI_DCL_DOUBLE;
6969 break;
6970 }
6971 }
6972 }
6973 }
6974 zend_ffi_parser_error("Unsupported \"mode\" value at line %d", FFI_G(line));
6975 // TODO: ???
6976 case attr_unsupported:
6977 zend_ffi_parser_error("Unsupported attribute \"%.*s\" at line %d", name_len, name, FFI_G(line));
6978 break;
6979 default:
6980 /* ignore */
6981 break;
6982 }
6983 }
6984 /* }}} */
6985
6986 void zend_ffi_add_msvc_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */
6987 {
6988 if (name_len == sizeof("align")-1 && memcmp(name, "align", sizeof("align")-1) == 0) {
6989 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)
6990 && val->i64 > 0 && val->i64 <= 0x80000000 && (val->i64 & (val->i64 - 1)) == 0) {
6991 dcl->align = val->i64;
6992 } else {
6993 zend_ffi_parser_error("Incorrect \"alignment\" value at line %d", FFI_G(line));
6994 }
6995 } else {
6996 /* ignore */
6997 }
6998 }
6999 /* }}} */
7000
7001 static zend_result zend_ffi_nested_type(zend_ffi_type *type, zend_ffi_type *nested_type) /* {{{ */
7002 {
7003 nested_type = ZEND_FFI_TYPE(nested_type);
7004 switch (nested_type->kind) {
7005 case ZEND_FFI_TYPE_POINTER:
7006 /* "char" is used as a terminator of nested declaration */
7007 if (nested_type->pointer.type == &zend_ffi_type_char) {
7008 nested_type->pointer.type = type;
7009 return zend_ffi_validate_vla(ZEND_FFI_TYPE(type));
7010 } else {
7011 return zend_ffi_nested_type(type, nested_type->pointer.type);
7012 }
7013 break;
7014 case ZEND_FFI_TYPE_ARRAY:
7015 /* "char" is used as a terminator of nested declaration */
7016 if (nested_type->array.type == &zend_ffi_type_char) {
7017 nested_type->array.type = type;
7018 if (zend_ffi_validate_array_element_type(ZEND_FFI_TYPE(type)) == FAILURE) {
7019 return FAILURE;
7020 }
7021 } else {
7022 if (zend_ffi_nested_type(type, nested_type->array.type) != SUCCESS) {
7023 return FAILURE;
7024 }
7025 }
7026 nested_type->size = nested_type->array.length * ZEND_FFI_TYPE(nested_type->array.type)->size;
7027 nested_type->align = ZEND_FFI_TYPE(nested_type->array.type)->align;
7028 return SUCCESS;
7029 break;
7030 case ZEND_FFI_TYPE_FUNC:
7031 /* "char" is used as a terminator of nested declaration */
7032 if (nested_type->func.ret_type == &zend_ffi_type_char) {
7033 nested_type->func.ret_type = type;
7034 return zend_ffi_validate_func_ret_type(ZEND_FFI_TYPE(type));
7035 } else {
7036 return zend_ffi_nested_type(type, nested_type->func.ret_type);
7037 }
7038 break;
7039 default:
7040 ZEND_UNREACHABLE();
7041 }
7042 }
7043 /* }}} */
7044
7045 void zend_ffi_nested_declaration(zend_ffi_dcl *dcl, zend_ffi_dcl *nested_dcl) /* {{{ */
7046 {
7047 /* "char" is used as a terminator of nested declaration */
7048 zend_ffi_finalize_type(dcl);
7049 if (!nested_dcl->type || nested_dcl->type == &zend_ffi_type_char) {
7050 nested_dcl->type = dcl->type;
7051 } else {
7052 if (zend_ffi_nested_type(dcl->type, nested_dcl->type) == FAILURE) {
7053 zend_ffi_cleanup_dcl(nested_dcl);
7054 LONGJMP(FFI_G(bailout), FAILURE);
7055 }
7056 }
7057 dcl->type = nested_dcl->type;
7058 }
7059 /* }}} */
7060
7061 void zend_ffi_align_as_type(zend_ffi_dcl *dcl, zend_ffi_dcl *align_dcl) /* {{{ */
7062 {
7063 zend_ffi_finalize_type(align_dcl);
7064 dcl->align = MAX(align_dcl->align, ZEND_FFI_TYPE(align_dcl->type)->align);
7065 }
7066 /* }}} */
7067
7068 void zend_ffi_align_as_val(zend_ffi_dcl *dcl, zend_ffi_val *align_val) /* {{{ */
7069 {
7070 switch (align_val->kind) {
7071 case ZEND_FFI_VAL_INT32:
7072 case ZEND_FFI_VAL_UINT32:
7073 dcl->align = zend_ffi_type_uint32.align;
7074 break;
7075 case ZEND_FFI_VAL_INT64:
7076 case ZEND_FFI_VAL_UINT64:
7077 dcl->align = zend_ffi_type_uint64.align;
7078 break;
7079 case ZEND_FFI_VAL_FLOAT:
7080 dcl->align = zend_ffi_type_float.align;
7081 break;
7082 case ZEND_FFI_VAL_DOUBLE:
7083 dcl->align = zend_ffi_type_double.align;
7084 break;
7085 #ifdef HAVE_LONG_DOUBLE
7086 case ZEND_FFI_VAL_LONG_DOUBLE:
7087 dcl->align = zend_ffi_type_long_double.align;
7088 break;
7089 #endif
7090 case ZEND_FFI_VAL_CHAR:
7091 case ZEND_FFI_VAL_STRING:
7092 dcl->align = zend_ffi_type_char.align;
7093 break;
7094 default:
7095 break;
7096 }
7097 }
7098 /* }}} */
7099
7100 #define zend_ffi_expr_bool(val) do { \
7101 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7102 val->kind = ZEND_FFI_VAL_INT32; \
7103 val->i64 = !!val->u64; \
7104 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7105 val->kind = ZEND_FFI_VAL_INT32; \
7106 val->i64 = !!val->i64; \
7107 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7108 val->kind = ZEND_FFI_VAL_INT32; \
7109 val->i64 = !!val->d; \
7110 } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7111 val->kind = ZEND_FFI_VAL_INT32; \
7112 val->i64 = !!val->ch; \
7113 } else { \
7114 val->kind = ZEND_FFI_VAL_ERROR; \
7115 } \
7116 } while (0)
7117
7118 #define zend_ffi_expr_math(val, op2, OP) do { \
7119 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7120 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7121 val->kind = MAX(val->kind, op2->kind); \
7122 val->u64 = val->u64 OP op2->u64; \
7123 } else if (op2->kind == ZEND_FFI_VAL_INT32) { \
7124 val->u64 = val->u64 OP op2->i64; \
7125 } else if (op2->kind == ZEND_FFI_VAL_INT64) { \
7126 val->u64 = val->u64 OP op2->i64; \
7127 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7128 val->kind = op2->kind; \
7129 val->d = (zend_ffi_double)val->u64 OP op2->d; \
7130 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7131 val->u64 = val->u64 OP op2->ch; \
7132 } else { \
7133 val->kind = ZEND_FFI_VAL_ERROR; \
7134 } \
7135 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7136 if (op2->kind == ZEND_FFI_VAL_UINT32) { \
7137 val->i64 = val->i64 OP op2->u64; \
7138 } else if (op2->kind == ZEND_FFI_VAL_UINT64) { \
7139 val->i64 = val->i64 OP op2->u64; \
7140 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7141 val->kind = MAX(val->kind, op2->kind); \
7142 val->i64 = val->i64 OP op2->i64; \
7143 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7144 val->kind = op2->kind; \
7145 val->d = (zend_ffi_double)val->i64 OP op2->d; \
7146 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7147 val->i64 = val->i64 OP op2->ch; \
7148 } else { \
7149 val->kind = ZEND_FFI_VAL_ERROR; \
7150 } \
7151 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7152 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7153 val->d = val->d OP (zend_ffi_double)op2->u64; \
7154 } else if (op2->kind == ZEND_FFI_VAL_INT32 ||op2->kind == ZEND_FFI_VAL_INT64) { \
7155 val->d = val->d OP (zend_ffi_double)op2->i64; \
7156 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7157 val->kind = MAX(val->kind, op2->kind); \
7158 val->d = val->d OP op2->d; \
7159 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7160 val->d = val->d OP (zend_ffi_double)op2->ch; \
7161 } else { \
7162 val->kind = ZEND_FFI_VAL_ERROR; \
7163 } \
7164 } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7165 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7166 val->kind = op2->kind; \
7167 val->u64 = val->ch OP op2->u64; \
7168 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7169 val->kind = ZEND_FFI_VAL_INT64; \
7170 val->i64 = val->ch OP op2->i64; \
7171 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7172 val->kind = op2->kind; \
7173 val->d = (zend_ffi_double)val->ch OP op2->d; \
7174 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7175 val->ch = val->ch OP op2->ch; \
7176 } else { \
7177 val->kind = ZEND_FFI_VAL_ERROR; \
7178 } \
7179 } else { \
7180 val->kind = ZEND_FFI_VAL_ERROR; \
7181 } \
7182 } while (0)
7183
7184 #define zend_ffi_expr_int_math(val, op2, OP) do { \
7185 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7186 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7187 val->kind = MAX(val->kind, op2->kind); \
7188 val->u64 = val->u64 OP op2->u64; \
7189 } else if (op2->kind == ZEND_FFI_VAL_INT32) { \
7190 val->u64 = val->u64 OP op2->i64; \
7191 } else if (op2->kind == ZEND_FFI_VAL_INT64) { \
7192 val->u64 = val->u64 OP op2->i64; \
7193 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7194 val->u64 = val->u64 OP (uint64_t)op2->d; \
7195 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7196 val->u64 = val->u64 OP op2->ch; \
7197 } else { \
7198 val->kind = ZEND_FFI_VAL_ERROR; \
7199 } \
7200 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7201 if (op2->kind == ZEND_FFI_VAL_UINT32) { \
7202 val->i64 = val->i64 OP op2->u64; \
7203 } else if (op2->kind == ZEND_FFI_VAL_UINT64) { \
7204 val->i64 = val->i64 OP op2->u64; \
7205 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7206 val->kind = MAX(val->kind, op2->kind); \
7207 val->i64 = val->i64 OP op2->i64; \
7208 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7209 val->u64 = val->u64 OP (int64_t)op2->d; \
7210 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7211 val->i64 = val->i64 OP op2->ch; \
7212 } else { \
7213 val->kind = ZEND_FFI_VAL_ERROR; \
7214 } \
7215 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7216 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7217 val->kind = op2->kind; \
7218 val->u64 = (uint64_t)val->d OP op2->u64; \
7219 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7220 val->kind = op2->kind; \
7221 val->i64 = (int64_t)val->d OP op2->i64; \
7222 } else { \
7223 val->kind = ZEND_FFI_VAL_ERROR; \
7224 } \
7225 } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7226 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7227 val->kind = op2->kind; \
7228 val->u64 = (uint64_t)val->ch OP op2->u64; \
7229 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7230 val->kind = op2->kind; \
7231 val->i64 = (int64_t)val->ch OP op2->u64; \
7232 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7233 val->ch = val->ch OP op2->ch; \
7234 } else { \
7235 val->kind = ZEND_FFI_VAL_ERROR; \
7236 } \
7237 } else { \
7238 val->kind = ZEND_FFI_VAL_ERROR; \
7239 } \
7240 } while (0)
7241
7242 #define zend_ffi_expr_cmp(val, op2, OP) do { \
7243 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7244 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7245 val->kind = ZEND_FFI_VAL_INT32; \
7246 val->i64 = val->u64 OP op2->u64; \
7247 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7248 val->kind = ZEND_FFI_VAL_INT32; \
7249 val->i64 = val->u64 OP op2->u64; /*signed/unsigned */ \
7250 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7251 val->kind = ZEND_FFI_VAL_INT32; \
7252 val->i64 = (zend_ffi_double)val->u64 OP op2->d; \
7253 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7254 val->kind = ZEND_FFI_VAL_INT32; \
7255 val->i64 = val->u64 OP op2->d; \
7256 } else { \
7257 val->kind = ZEND_FFI_VAL_ERROR; \
7258 } \
7259 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7260 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7261 val->kind = ZEND_FFI_VAL_INT32; \
7262 val->i64 = val->i64 OP op2->i64; /* signed/unsigned */ \
7263 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7264 val->kind = ZEND_FFI_VAL_INT32; \
7265 val->i64 = val->i64 OP op2->i64; \
7266 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7267 val->kind = ZEND_FFI_VAL_INT32; \
7268 val->i64 = (zend_ffi_double)val->i64 OP op2->d; \
7269 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7270 val->kind = ZEND_FFI_VAL_INT32; \
7271 val->i64 = val->i64 OP op2->ch; \
7272 } else { \
7273 val->kind = ZEND_FFI_VAL_ERROR; \
7274 } \
7275 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7276 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7277 val->kind = ZEND_FFI_VAL_INT32; \
7278 val->i64 = val->d OP (zend_ffi_double)op2->u64; \
7279 } else if (op2->kind == ZEND_FFI_VAL_INT32 ||op2->kind == ZEND_FFI_VAL_INT64) { \
7280 val->kind = ZEND_FFI_VAL_INT32; \
7281 val->i64 = val->d OP (zend_ffi_double)op2->i64; \
7282 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7283 val->kind = ZEND_FFI_VAL_INT32; \
7284 val->i64 = val->d OP op2->d; \
7285 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7286 val->kind = ZEND_FFI_VAL_INT32; \
7287 val->i64 = val->d OP (zend_ffi_double)op2->ch; \
7288 } else { \
7289 val->kind = ZEND_FFI_VAL_ERROR; \
7290 } \
7291 } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7292 if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7293 val->kind = ZEND_FFI_VAL_INT32; \
7294 val->i64 = val->ch OP op2->i64; /* signed/unsigned */ \
7295 } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7296 val->kind = ZEND_FFI_VAL_INT32; \
7297 val->i64 = val->ch OP op2->i64; \
7298 } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7299 val->kind = ZEND_FFI_VAL_INT32; \
7300 val->i64 = (zend_ffi_double)val->ch OP op2->d; \
7301 } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7302 val->kind = ZEND_FFI_VAL_INT32; \
7303 val->i64 = val->ch OP op2->ch; \
7304 } else { \
7305 val->kind = ZEND_FFI_VAL_ERROR; \
7306 } \
7307 } else { \
7308 val->kind = ZEND_FFI_VAL_ERROR; \
7309 } \
7310 } while (0)
7311
7312 void zend_ffi_expr_conditional(zend_ffi_val *val, zend_ffi_val *op2, zend_ffi_val *op3) /* {{{ */
7313 {
7314 zend_ffi_expr_bool(val);
7315 if (val->kind == ZEND_FFI_VAL_INT32) {
7316 if (val->i64) {
7317 *val = *op2;
7318 } else {
7319 *val = *op3;
7320 }
7321 }
7322 }
7323 /* }}} */
7324
7325 void zend_ffi_expr_bool_or(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7326 {
7327 zend_ffi_expr_bool(val);
7328 zend_ffi_expr_bool(op2);
7329 if (val->kind == ZEND_FFI_VAL_INT32 && op2->kind == ZEND_FFI_VAL_INT32) {
7330 val->i64 = val->i64 || op2->i64;
7331 } else {
7332 val->kind = ZEND_FFI_VAL_ERROR;
7333 }
7334 }
7335 /* }}} */
7336
7337 void zend_ffi_expr_bool_and(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7338 {
7339 zend_ffi_expr_bool(val);
7340 zend_ffi_expr_bool(op2);
7341 if (val->kind == ZEND_FFI_VAL_INT32 && op2->kind == ZEND_FFI_VAL_INT32) {
7342 val->i64 = val->i64 && op2->i64;
7343 } else {
7344 val->kind = ZEND_FFI_VAL_ERROR;
7345 }
7346 }
7347 /* }}} */
7348
7349 void zend_ffi_expr_bw_or(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7350 {
7351 zend_ffi_expr_int_math(val, op2, |);
7352 }
7353 /* }}} */
7354
7355 void zend_ffi_expr_bw_xor(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7356 {
7357 zend_ffi_expr_int_math(val, op2, ^);
7358 }
7359 /* }}} */
7360
7361 void zend_ffi_expr_bw_and(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7362 {
7363 zend_ffi_expr_int_math(val, op2, &);
7364 }
7365 /* }}} */
7366
7367 void zend_ffi_expr_is_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7368 {
7369 zend_ffi_expr_cmp(val, op2, ==);
7370 }
7371 /* }}} */
7372
7373 void zend_ffi_expr_is_not_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7374 {
7375 zend_ffi_expr_cmp(val, op2, !=);
7376 }
7377 /* }}} */
7378
7379 void zend_ffi_expr_is_less(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7380 {
7381 zend_ffi_expr_cmp(val, op2, <);
7382 }
7383 /* }}} */
7384
7385 void zend_ffi_expr_is_greater(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7386 {
7387 zend_ffi_expr_cmp(val, op2, >);
7388 }
7389 /* }}} */
7390
7391 void zend_ffi_expr_is_less_or_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7392 {
7393 zend_ffi_expr_cmp(val, op2, <=);
7394 }
7395 /* }}} */
7396
7397 void zend_ffi_expr_is_greater_or_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7398 {
7399 zend_ffi_expr_cmp(val, op2, >=);
7400 }
7401 /* }}} */
7402
7403 void zend_ffi_expr_shift_left(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7404 {
7405 zend_ffi_expr_int_math(val, op2, <<);
7406 }
7407 /* }}} */
7408
7409 void zend_ffi_expr_shift_right(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7410 {
7411 zend_ffi_expr_int_math(val, op2, >>);
7412 }
7413 /* }}} */
7414
7415 void zend_ffi_expr_add(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7416 {
7417 zend_ffi_expr_math(val, op2, +);
7418 }
7419 /* }}} */
7420
7421 void zend_ffi_expr_sub(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7422 {
7423 zend_ffi_expr_math(val, op2, -);
7424 }
7425 /* }}} */
7426
7427 void zend_ffi_expr_mul(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7428 {
7429 zend_ffi_expr_math(val, op2, *);
7430 }
7431 /* }}} */
7432
7433 void zend_ffi_expr_div(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7434 {
7435 zend_ffi_expr_math(val, op2, /);
7436 }
7437 /* }}} */
7438
7439 void zend_ffi_expr_mod(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7440 {
7441 zend_ffi_expr_int_math(val, op2, %); // ???
7442 }
7443 /* }}} */
7444
7445 void zend_ffi_expr_cast(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
7446 {
7447 zend_ffi_finalize_type(dcl);
7448 switch (ZEND_FFI_TYPE(dcl->type)->kind) {
7449 case ZEND_FFI_TYPE_FLOAT:
7450 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7451 val->kind = ZEND_FFI_VAL_FLOAT;
7452 val->d = val->u64;
7453 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7454 val->kind = ZEND_FFI_VAL_FLOAT;
7455 val->d = val->i64;
7456 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7457 val->kind = ZEND_FFI_VAL_FLOAT;
7458 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7459 val->kind = ZEND_FFI_VAL_FLOAT;
7460 val->d = val->ch;
7461 } else {
7462 val->kind = ZEND_FFI_VAL_ERROR;
7463 }
7464 break;
7465 case ZEND_FFI_TYPE_DOUBLE:
7466 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7467 val->kind = ZEND_FFI_VAL_DOUBLE;
7468 val->d = val->u64;
7469 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7470 val->kind = ZEND_FFI_VAL_DOUBLE;
7471 val->d = val->i64;
7472 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7473 val->kind = ZEND_FFI_VAL_DOUBLE;
7474 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7475 val->kind = ZEND_FFI_VAL_DOUBLE;
7476 val->d = val->ch;
7477 } else {
7478 val->kind = ZEND_FFI_VAL_ERROR;
7479 }
7480 break;
7481 #ifdef HAVE_LONG_DOUBLE
7482 case ZEND_FFI_TYPE_LONGDOUBLE:
7483 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7484 val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7485 val->d = val->u64;
7486 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7487 val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7488 val->d = val->i64;
7489 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7490 val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7491 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7492 val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7493 val->d = val->ch;
7494 } else {
7495 val->kind = ZEND_FFI_VAL_ERROR;
7496 }
7497 break;
7498 #endif
7499 case ZEND_FFI_TYPE_UINT8:
7500 case ZEND_FFI_TYPE_UINT16:
7501 case ZEND_FFI_TYPE_UINT32:
7502 case ZEND_FFI_TYPE_BOOL:
7503 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) {
7504 val->kind = ZEND_FFI_VAL_UINT32;
7505 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7506 val->kind = ZEND_FFI_VAL_UINT32;
7507 val->u64 = val->d;
7508 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7509 val->kind = ZEND_FFI_VAL_UINT32;
7510 val->u64 = val->ch;
7511 } else {
7512 val->kind = ZEND_FFI_VAL_ERROR;
7513 }
7514 break;
7515 case ZEND_FFI_TYPE_SINT8:
7516 case ZEND_FFI_TYPE_SINT16:
7517 case ZEND_FFI_TYPE_SINT32:
7518 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) {
7519 val->kind = ZEND_FFI_VAL_INT32;
7520 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7521 val->kind = ZEND_FFI_VAL_INT32;
7522 val->i64 = val->d;
7523 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7524 val->kind = ZEND_FFI_VAL_INT32;
7525 val->i64 = val->ch;
7526 } else {
7527 val->kind = ZEND_FFI_VAL_ERROR;
7528 }
7529 break;
7530 case ZEND_FFI_TYPE_UINT64:
7531 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) {
7532 val->kind = ZEND_FFI_VAL_UINT64;
7533 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7534 val->kind = ZEND_FFI_VAL_UINT64;
7535 val->u64 = val->d;
7536 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7537 val->kind = ZEND_FFI_VAL_UINT64;
7538 val->u64 = val->ch;
7539 } else {
7540 val->kind = ZEND_FFI_VAL_ERROR;
7541 }
7542 break;
7543 case ZEND_FFI_TYPE_SINT64:
7544 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7545 val->kind = ZEND_FFI_VAL_CHAR;
7546 val->ch = val->u64;
7547 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7548 val->kind = ZEND_FFI_VAL_CHAR;
7549 val->ch = val->i64;
7550 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7551 val->kind = ZEND_FFI_VAL_CHAR;
7552 val->ch = val->d;
7553 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7554 } else {
7555 val->kind = ZEND_FFI_VAL_ERROR;
7556 }
7557 break;
7558 case ZEND_FFI_TYPE_CHAR:
7559 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) {
7560 val->kind = ZEND_FFI_VAL_UINT32;
7561 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7562 val->kind = ZEND_FFI_VAL_UINT32;
7563 val->u64 = val->d;
7564 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7565 val->kind = ZEND_FFI_VAL_UINT32;
7566 val->u64 = val->ch;
7567 } else {
7568 val->kind = ZEND_FFI_VAL_ERROR;
7569 }
7570 break;
7571 default:
7572 val->kind = ZEND_FFI_VAL_ERROR;
7573 break;
7574 }
7575 zend_ffi_type_dtor(dcl->type);
7576 }
7577 /* }}} */
7578
7579 void zend_ffi_expr_plus(zend_ffi_val *val) /* {{{ */
7580 {
7581 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7582 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7583 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7584 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7585 } else {
7586 val->kind = ZEND_FFI_VAL_ERROR;
7587 }
7588 }
7589 /* }}} */
7590
7591 void zend_ffi_expr_neg(zend_ffi_val *val) /* {{{ */
7592 {
7593 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7594 val->u64 = -val->u64;
7595 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7596 val->i64 = -val->i64;
7597 } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7598 val->d = -val->d;
7599 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7600 val->ch = -val->ch;
7601 } else {
7602 val->kind = ZEND_FFI_VAL_ERROR;
7603 }
7604 }
7605 /* }}} */
7606
7607 void zend_ffi_expr_bw_not(zend_ffi_val *val) /* {{{ */
7608 {
7609 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7610 val->u64 = ~val->u64;
7611 } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7612 val->i64 = ~val->i64;
7613 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7614 val->ch = ~val->ch;
7615 } else {
7616 val->kind = ZEND_FFI_VAL_ERROR;
7617 }
7618 }
7619 /* }}} */
7620
7621 void zend_ffi_expr_bool_not(zend_ffi_val *val) /* {{{ */
7622 {
7623 zend_ffi_expr_bool(val);
7624 if (val->kind == ZEND_FFI_VAL_INT32) {
7625 val->i64 = !val->i64;
7626 }
7627 }
7628 /* }}} */
7629
7630 void zend_ffi_expr_sizeof_val(zend_ffi_val *val) /* {{{ */
7631 {
7632 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT32) {
7633 val->kind = ZEND_FFI_VAL_UINT32;
7634 val->u64 = zend_ffi_type_uint32.size;
7635 } else if (val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT64) {
7636 val->kind = ZEND_FFI_VAL_UINT32;
7637 val->u64 = zend_ffi_type_uint64.size;
7638 } else if (val->kind == ZEND_FFI_VAL_FLOAT) {
7639 val->kind = ZEND_FFI_VAL_UINT32;
7640 val->u64 = zend_ffi_type_float.size;
7641 } else if (val->kind == ZEND_FFI_VAL_DOUBLE) {
7642 val->kind = ZEND_FFI_VAL_UINT32;
7643 val->u64 = zend_ffi_type_double.size;
7644 } else if (val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7645 val->kind = ZEND_FFI_VAL_UINT32;
7646 #ifdef _WIN32
7647 val->u64 = zend_ffi_type_double.size;
7648 #else
7649 val->u64 = zend_ffi_type_long_double.size;
7650 #endif
7651 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7652 val->kind = ZEND_FFI_VAL_UINT32;
7653 val->u64 = zend_ffi_type_char.size;
7654 } else if (val->kind == ZEND_FFI_VAL_STRING) {
7655 if (memchr(val->str, '\\', val->len)) {
7656 // TODO: support for escape sequences ???
7657 val->kind = ZEND_FFI_VAL_ERROR;
7658 } else {
7659 val->kind = ZEND_FFI_VAL_UINT32;
7660 val->u64 = val->len + 1;
7661 }
7662 } else {
7663 val->kind = ZEND_FFI_VAL_ERROR;
7664 }
7665 }
7666 /* }}} */
7667
7668 void zend_ffi_expr_sizeof_type(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
7669 {
7670 zend_ffi_type *type;
7671
7672 zend_ffi_finalize_type(dcl);
7673 type = ZEND_FFI_TYPE(dcl->type);
7674 val->kind = (type->size > 0xffffffff) ? ZEND_FFI_VAL_UINT64 : ZEND_FFI_VAL_UINT32;
7675 val->u64 = type->size;
7676 zend_ffi_type_dtor(dcl->type);
7677 }
7678 /* }}} */
7679
7680 void zend_ffi_expr_alignof_val(zend_ffi_val *val) /* {{{ */
7681 {
7682 if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT32) {
7683 val->kind = ZEND_FFI_VAL_UINT32;
7684 val->u64 = zend_ffi_type_uint32.align;
7685 } else if (val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT64) {
7686 val->kind = ZEND_FFI_VAL_UINT32;
7687 val->u64 = zend_ffi_type_uint64.align;
7688 } else if (val->kind == ZEND_FFI_VAL_FLOAT) {
7689 val->kind = ZEND_FFI_VAL_UINT32;
7690 val->u64 = zend_ffi_type_float.align;
7691 } else if (val->kind == ZEND_FFI_VAL_DOUBLE) {
7692 val->kind = ZEND_FFI_VAL_UINT32;
7693 val->u64 = zend_ffi_type_double.align;
7694 #ifdef HAVE_LONG_DOUBLE
7695 } else if (val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7696 val->kind = ZEND_FFI_VAL_UINT32;
7697 val->u64 = zend_ffi_type_long_double.align;
7698 #endif
7699 } else if (val->kind == ZEND_FFI_VAL_CHAR) {
7700 val->kind = ZEND_FFI_VAL_UINT32;
7701 val->u64 = zend_ffi_type_char.size;
7702 } else if (val->kind == ZEND_FFI_VAL_STRING) {
7703 val->kind = ZEND_FFI_VAL_UINT32;
7704 val->u64 = _Alignof(char*);
7705 } else {
7706 val->kind = ZEND_FFI_VAL_ERROR;
7707 }
7708 }
7709 /* }}} */
7710
7711 void zend_ffi_expr_alignof_type(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
7712 {
7713 zend_ffi_finalize_type(dcl);
7714 val->kind = ZEND_FFI_VAL_UINT32;
7715 val->u64 = ZEND_FFI_TYPE(dcl->type)->align;
7716 zend_ffi_type_dtor(dcl->type);
7717 }
7718 /* }}} */
7719
7720 void zend_ffi_val_number(zend_ffi_val *val, int base, const char *str, size_t str_len) /* {{{ */
7721 {
7722 int u = 0;
7723 int l = 0;
7724
7725 if (str[str_len-1] == 'u' || str[str_len-1] == 'U') {
7726 u = 1;
7727 if (str[str_len-2] == 'l' || str[str_len-2] == 'L') {
7728 l = 1;
7729 if (str[str_len-3] == 'l' || str[str_len-3] == 'L') {
7730 l = 2;
7731 }
7732 }
7733 } else if (str[str_len-1] == 'l' || str[str_len-1] == 'L') {
7734 l = 1;
7735 if (str[str_len-2] == 'l' || str[str_len-2] == 'L') {
7736 l = 2;
7737 if (str[str_len-3] == 'u' || str[str_len-3] == 'U') {
7738 u = 1;
7739 }
7740 } else if (str[str_len-2] == 'u' || str[str_len-2] == 'U') {
7741 u = 1;
7742 }
7743 }
7744 if (u) {
7745 val->u64 = strtoull(str, NULL, base);
7746 if (l == 0) {
7747 val->kind = ZEND_FFI_VAL_UINT32;
7748 } else if (l == 1) {
7749 val->kind = (sizeof(long) == 4) ? ZEND_FFI_VAL_UINT32 : ZEND_FFI_VAL_UINT64;
7750 } else if (l == 2) {
7751 val->kind = ZEND_FFI_VAL_UINT64;
7752 }
7753 } else {
7754 val->i64 = strtoll(str, NULL, base);
7755 if (l == 0) {
7756 val->kind = ZEND_FFI_VAL_INT32;
7757 } else if (l == 1) {
7758 val->kind = (sizeof(long) == 4) ? ZEND_FFI_VAL_INT32 : ZEND_FFI_VAL_INT64;
7759 } else if (l == 2) {
7760 val->kind = ZEND_FFI_VAL_INT64;
7761 }
7762 }
7763 }
7764 /* }}} */
7765
7766 void zend_ffi_val_float_number(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7767 {
7768 val->d = strtold(str, NULL);
7769 if (str[str_len-1] == 'f' || str[str_len-1] == 'F') {
7770 val->kind = ZEND_FFI_VAL_FLOAT;
7771 } else if (str[str_len-1] == 'l' || str[str_len-1] == 'L') {
7772 val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7773 } else {
7774 val->kind = ZEND_FFI_VAL_DOUBLE;
7775 }
7776 }
7777 /* }}} */
7778
7779 void zend_ffi_val_string(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7780 {
7781 if (str[0] != '\"') {
7782 val->kind = ZEND_FFI_VAL_ERROR;
7783 } else {
7784 val->kind = ZEND_FFI_VAL_STRING;
7785 val->str = str + 1;
7786 val->len = str_len - 2;
7787 }
7788 }
7789 /* }}} */
7790
7791 void zend_ffi_val_character(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7792 {
7793 int n;
7794
7795 if (str[0] != '\'') {
7796 val->kind = ZEND_FFI_VAL_ERROR;
7797 } else {
7798 val->kind = ZEND_FFI_VAL_CHAR;
7799 if (str_len == 3) {
7800 val->ch = str[1];
7801 } else if (str[1] == '\\') {
7802 if (str[2] == 'a') {
7803 } else if (str[2] == 'b' && str_len == 4) {
7804 val->ch = '\b';
7805 } else if (str[2] == 'f' && str_len == 4) {
7806 val->ch = '\f';
7807 } else if (str[2] == 'n' && str_len == 4) {
7808 val->ch = '\n';
7809 } else if (str[2] == 'r' && str_len == 4) {
7810 val->ch = '\r';
7811 } else if (str[2] == 't' && str_len == 4) {
7812 val->ch = '\t';
7813 } else if (str[2] == 'v' && str_len == 4) {
7814 val->ch = '\v';
7815 } else if (str[2] >= '0' && str[2] <= '7') {
7816 n = str[2] - '0';
7817 if (str[3] >= '0' && str[3] <= '7') {
7818 n = n * 8 + (str[3] - '0');
7819 if ((str[4] >= '0' && str[4] <= '7') && str_len == 6) {
7820 n = n * 8 + (str[4] - '0');
7821 } else if (str_len != 5) {
7822 val->kind = ZEND_FFI_VAL_ERROR;
7823 }
7824 } else if (str_len != 4) {
7825 val->kind = ZEND_FFI_VAL_ERROR;
7826 }
7827 if (n <= 0xff) {
7828 val->ch = n;
7829 } else {
7830 val->kind = ZEND_FFI_VAL_ERROR;
7831 }
7832 } else if (str[2] == 'x') {
7833 if (str[3] >= '0' && str[3] <= '9') {
7834 n = str[3] - '0';
7835 } else if (str[3] >= 'A' && str[3] <= 'F') {
7836 n = str[3] - 'A';
7837 } else if (str[3] >= 'a' && str[3] <= 'f') {
7838 n = str[3] - 'a';
7839 } else {
7840 val->kind = ZEND_FFI_VAL_ERROR;
7841 return;
7842 }
7843 if ((str[4] >= '0' && str[4] <= '9') && str_len == 6) {
7844 n = n * 16 + (str[4] - '0');
7845 } else if ((str[4] >= 'A' && str[4] <= 'F') && str_len == 6) {
7846 n = n * 16 + (str[4] - 'A');
7847 } else if ((str[4] >= 'a' && str[4] <= 'f') && str_len == 6) {
7848 n = n * 16 + (str[4] - 'a');
7849 } else if (str_len != 5) {
7850 val->kind = ZEND_FFI_VAL_ERROR;
7851 return;
7852 }
7853 val->ch = n;
7854 } else if (str_len == 4) {
7855 val->ch = str[2];
7856 } else {
7857 val->kind = ZEND_FFI_VAL_ERROR;
7858 }
7859 } else {
7860 val->kind = ZEND_FFI_VAL_ERROR;
7861 }
7862 }
7863 }
7864 /* }}} */
7865