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