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