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