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