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