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