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