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