Zend:如何在 PHP 7 中正确销毁自定义对象?
Zend: How to correctly destruct a custom object in PHP 7?
我正在学习 PHP 扩展编写,以便使一些旧的扩展与 PHP 7.
一起工作
我试图修改 http://devzone.zend.com/1435/wrapping-c-classes-in-a-php-extension/ 的示例扩展,但它在破坏自定义对象时一直导致段错误。所有其他功能都正常工作。 (在我的代码中 Car 被 BDict 替换了。)
这是我的代码:
#define Z_BDICT_OBJ_P(zv) php_bdict_object_fetch_object(Z_OBJ_P(zv))
zend_object_handlers bdict_object_handlers;
typedef struct _bdict_object {
BDict *bdict_data;
zend_object std;
} bdict_object;
zend_class_entry *bdict_ce;
static void bdict_free_storage(zend_object *object TSRMLS_DC)
{
bdict_object *intern = (bdict_object *)object;
// ***Both the following two lines will cause segfault***
delete intern->bdict_data;
zend_object_std_dtor(&intern->std TSRMLS_CC);
}
zend_object * bdict_object_new(zend_class_entry *ce TSRMLS_DC)
{
bdict_object *intern = (bdict_object *)ecalloc(1,
sizeof(bdict_object) +
zend_object_properties_size(ce));
zend_object_std_init(&intern->std, ce TSRMLS_CC);
object_properties_init(&intern->std, ce);
intern->std.handlers = &bdict_object_handlers;
return &intern->std;
}
static inline bdict_object * php_bdict_object_fetch_object(zend_object *obj)
{
return (bdict_object *)((char *)obj - XtOffsetOf(bdict_object, std));
}
PHP_METHOD(BDict, __construct)
{
long maxGear;
BDict *bdict = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &maxGear) == FAILURE) {
RETURN_NULL();
}
bdict = new BDict(maxGear);
bdict_object *intern = Z_BDICT_OBJ_P(getThis());
intern->bdict_data = bdict;
}
PHP_MINIT_FUNCTION(bencode)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "BDict", bdict_methods);
bdict_ce = zend_register_internal_class(&ce TSRMLS_CC);
bdict_ce->create_object = bdict_object_new;
memcpy(&bdict_object_handlers,
zend_get_std_object_handlers(), sizeof(zend_object_handlers));
bdict_object_handlers.offset = XtOffsetOf(bdict_object, std);
bdict_object_handlers.free_obj = bdict_free_storage;
return SUCCESS;
}
通过改变两行的顺序并执行$dict = new BDict(10); unset($dict);
,我设法得到了他们两行的错误信息。
/***** delete intern->bdict_data; *****/
Starting program: /opt/php-7.0.1/bin/php test.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
__GI___libc_free (mem=0xc002180800000001) at malloc.c:2933
/***** zend_object_std_dtor(&intern->std TSRMLS_CC); *****/
Starting program: /opt/php-7.0.1/bin/php test.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x0000000000a45890 in zend_object_std_dtor (object=0x7ffff4001c90) at /home/frederick/php-7.0.1/Zend/zend_objects.c:59
59 if (EXPECTED(!(GC_FLAGS(object->properties) & IS_ARRAY_IMMUTABLE))) {
我是 PHP 扩展的新手,现在我真的很困惑。非常感谢任何帮助,谢谢。
更新
我注意到 bdict_free_storage()
中转换后对象实际上发生了变化,这显然是错误的,但我不知道如何修复它。
这是调试日志。可以看到bdict_free_storage()
里面的intern
和object
的数据完全不一样,BDict的地址是错误的
(gdb) b bencode.cc:20 // bdict_free_storage(): bdict_object *intern = (bdict_object *)object;
Breakpoint 1 at 0x7ffff36de608: file /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc, line 20.
(gdb) b bencode.cc:54 // PHP_METHOD(BDict, __construct): intern->bdict_data = bdict;
Breakpoint 2 at 0x7ffff36de77e: file /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc, line 54.
(gdb) r
Starting program: /opt/php-7.0.1/bin/php test.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 2, zim_BDict___construct (execute_data=0x7ffff40140d0, return_value=0x7ffff40140b0) at /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc:54
54 intern->bdict_data = bdict;
(gdb) n
55 }
(gdb) p intern->bdict_data
= (BDict *) 0x150c530
(gdb) c
Continuing.
Breakpoint 1, bdict_free_storage (object=0x7ffff4001c88) at /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc:20
20 bdict_object *intern = (bdict_object *)object;
(gdb) n
21 zend_object_std_dtor(&intern->std TSRMLS_CC);
(gdb) p *object // type = 8 means IS_OBJECT
= {gc = {refcount = 1, u = {v = {type = 8 '\b', flags = 24 '0', gc_info = 49154}, type_info = 3221362696}}, handle = 1, ce = 0x14fe6e0,
handlers = 0x7ffff38e0300 <bdict_object_handlers>, properties = 0x0, properties_table = {{value = {lval = 48, dval = 2.3715151000379834e-322, counted = 0x30, str = 0x30, arr = 0x30,
obj = 0x30, res = 0x30, ref = 0x30, ast = 0x30, zv = 0x30, ptr = 0x30, ce = 0x30, func = 0x30, ww = {w1 = 48, w2 = 0}}, u1 = {v = {type = 232 '0', type_flags = 237 '5',
const_flags = 109 'm', reserved = 243 '3'}, type_info = 4084067816}, u2 = {var_flags = 32767, next = 32767, cache_slot = 32767, lineno = 32767, num_args = 32767,
fe_pos = 32767, fe_iter_idx = 32767}}}}
(gdb) p *intern // type = 0 means IS_UNDEF, all other data are also different
= {bdict_data = 0xc002180800000001, std = {gc = {refcount = 1, u = {v = {type = 0 '[=13=]0', flags = 0 '[=13=]0', gc_info = 0}, type_info = 0}}, handle = 22013664,
ce = 0x7ffff38e0300 <bdict_object_handlers>, handlers = 0x0, properties = 0x30, properties_table = {{value = {lval = 140737277455848, dval = 6.9533453880162249e-310,
counted = 0x7ffff36dede8, str = 0x7ffff36dede8, arr = 0x7ffff36dede8, obj = 0x7ffff36dede8, res = 0x7ffff36dede8, ref = 0x7ffff36dede8, ast = 0x7ffff36dede8, zv = 0x7ffff36dede8,
ptr = 0x7ffff36dede8, ce = 0x7ffff36dede8, func = 0x7ffff36dede8, ww = {w1 = 4084067816, w2 = 32767}}, u1 = {v = {type = 0 '[=13=]0', type_flags = 131 '3',
const_flags = 3 '[=13=]3', reserved = 1 '[=13=]1'}, type_info = 17007360}, u2 = {var_flags = 0, next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0}}}}}
我发现其他一些人在使用
static void bdict_free_storage(void *object TSRMLS_DC)
而不是
static void bdict_free_storage(zend_object *object TSRMLS_DC)
我试过了,但它给了我一个编译时错误。
/home/frederick/php-7.0.1/ext/php-bencode/bencode.cc: In function ‘int zm_startup_bencode(int, int)’:
/home/frederick/php-7.0.1/ext/php-bencode/bencode.cc:131:36: error: invalid conversion from ‘void (*)(void*)’ to ‘zend_object_free_obj_t {aka void (*)(_zend_object*)}’ [-fpermissive]
bdict_object_handlers.free_obj = bdict_free_storage;
将"zend_object_handlers bdict_object_handlers;"更改为"zend_object_handlers bdict_object_handlers = std_object_handlers;"可以解决这个问题,因为你没有初始化结构。
"bdict_free_storage"中的参数必须通过其偏移
您可以试试:
bdict_object *intern = (bdict_object *) ((char *) object - XtOffsetOf(bdict_object, std));
我正在学习 PHP 扩展编写,以便使一些旧的扩展与 PHP 7.
一起工作我试图修改 http://devzone.zend.com/1435/wrapping-c-classes-in-a-php-extension/ 的示例扩展,但它在破坏自定义对象时一直导致段错误。所有其他功能都正常工作。 (在我的代码中 Car 被 BDict 替换了。)
这是我的代码:
#define Z_BDICT_OBJ_P(zv) php_bdict_object_fetch_object(Z_OBJ_P(zv))
zend_object_handlers bdict_object_handlers;
typedef struct _bdict_object {
BDict *bdict_data;
zend_object std;
} bdict_object;
zend_class_entry *bdict_ce;
static void bdict_free_storage(zend_object *object TSRMLS_DC)
{
bdict_object *intern = (bdict_object *)object;
// ***Both the following two lines will cause segfault***
delete intern->bdict_data;
zend_object_std_dtor(&intern->std TSRMLS_CC);
}
zend_object * bdict_object_new(zend_class_entry *ce TSRMLS_DC)
{
bdict_object *intern = (bdict_object *)ecalloc(1,
sizeof(bdict_object) +
zend_object_properties_size(ce));
zend_object_std_init(&intern->std, ce TSRMLS_CC);
object_properties_init(&intern->std, ce);
intern->std.handlers = &bdict_object_handlers;
return &intern->std;
}
static inline bdict_object * php_bdict_object_fetch_object(zend_object *obj)
{
return (bdict_object *)((char *)obj - XtOffsetOf(bdict_object, std));
}
PHP_METHOD(BDict, __construct)
{
long maxGear;
BDict *bdict = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &maxGear) == FAILURE) {
RETURN_NULL();
}
bdict = new BDict(maxGear);
bdict_object *intern = Z_BDICT_OBJ_P(getThis());
intern->bdict_data = bdict;
}
PHP_MINIT_FUNCTION(bencode)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "BDict", bdict_methods);
bdict_ce = zend_register_internal_class(&ce TSRMLS_CC);
bdict_ce->create_object = bdict_object_new;
memcpy(&bdict_object_handlers,
zend_get_std_object_handlers(), sizeof(zend_object_handlers));
bdict_object_handlers.offset = XtOffsetOf(bdict_object, std);
bdict_object_handlers.free_obj = bdict_free_storage;
return SUCCESS;
}
通过改变两行的顺序并执行$dict = new BDict(10); unset($dict);
,我设法得到了他们两行的错误信息。
/***** delete intern->bdict_data; *****/
Starting program: /opt/php-7.0.1/bin/php test.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
__GI___libc_free (mem=0xc002180800000001) at malloc.c:2933
/***** zend_object_std_dtor(&intern->std TSRMLS_CC); *****/
Starting program: /opt/php-7.0.1/bin/php test.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x0000000000a45890 in zend_object_std_dtor (object=0x7ffff4001c90) at /home/frederick/php-7.0.1/Zend/zend_objects.c:59
59 if (EXPECTED(!(GC_FLAGS(object->properties) & IS_ARRAY_IMMUTABLE))) {
我是 PHP 扩展的新手,现在我真的很困惑。非常感谢任何帮助,谢谢。
更新
我注意到 bdict_free_storage()
中转换后对象实际上发生了变化,这显然是错误的,但我不知道如何修复它。
这是调试日志。可以看到bdict_free_storage()
里面的intern
和object
的数据完全不一样,BDict的地址是错误的
(gdb) b bencode.cc:20 // bdict_free_storage(): bdict_object *intern = (bdict_object *)object;
Breakpoint 1 at 0x7ffff36de608: file /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc, line 20.
(gdb) b bencode.cc:54 // PHP_METHOD(BDict, __construct): intern->bdict_data = bdict;
Breakpoint 2 at 0x7ffff36de77e: file /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc, line 54.
(gdb) r
Starting program: /opt/php-7.0.1/bin/php test.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 2, zim_BDict___construct (execute_data=0x7ffff40140d0, return_value=0x7ffff40140b0) at /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc:54
54 intern->bdict_data = bdict;
(gdb) n
55 }
(gdb) p intern->bdict_data
= (BDict *) 0x150c530
(gdb) c
Continuing.
Breakpoint 1, bdict_free_storage (object=0x7ffff4001c88) at /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc:20
20 bdict_object *intern = (bdict_object *)object;
(gdb) n
21 zend_object_std_dtor(&intern->std TSRMLS_CC);
(gdb) p *object // type = 8 means IS_OBJECT
= {gc = {refcount = 1, u = {v = {type = 8 '\b', flags = 24 '0', gc_info = 49154}, type_info = 3221362696}}, handle = 1, ce = 0x14fe6e0,
handlers = 0x7ffff38e0300 <bdict_object_handlers>, properties = 0x0, properties_table = {{value = {lval = 48, dval = 2.3715151000379834e-322, counted = 0x30, str = 0x30, arr = 0x30,
obj = 0x30, res = 0x30, ref = 0x30, ast = 0x30, zv = 0x30, ptr = 0x30, ce = 0x30, func = 0x30, ww = {w1 = 48, w2 = 0}}, u1 = {v = {type = 232 '0', type_flags = 237 '5',
const_flags = 109 'm', reserved = 243 '3'}, type_info = 4084067816}, u2 = {var_flags = 32767, next = 32767, cache_slot = 32767, lineno = 32767, num_args = 32767,
fe_pos = 32767, fe_iter_idx = 32767}}}}
(gdb) p *intern // type = 0 means IS_UNDEF, all other data are also different
= {bdict_data = 0xc002180800000001, std = {gc = {refcount = 1, u = {v = {type = 0 '[=13=]0', flags = 0 '[=13=]0', gc_info = 0}, type_info = 0}}, handle = 22013664,
ce = 0x7ffff38e0300 <bdict_object_handlers>, handlers = 0x0, properties = 0x30, properties_table = {{value = {lval = 140737277455848, dval = 6.9533453880162249e-310,
counted = 0x7ffff36dede8, str = 0x7ffff36dede8, arr = 0x7ffff36dede8, obj = 0x7ffff36dede8, res = 0x7ffff36dede8, ref = 0x7ffff36dede8, ast = 0x7ffff36dede8, zv = 0x7ffff36dede8,
ptr = 0x7ffff36dede8, ce = 0x7ffff36dede8, func = 0x7ffff36dede8, ww = {w1 = 4084067816, w2 = 32767}}, u1 = {v = {type = 0 '[=13=]0', type_flags = 131 '3',
const_flags = 3 '[=13=]3', reserved = 1 '[=13=]1'}, type_info = 17007360}, u2 = {var_flags = 0, next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0}}}}}
我发现其他一些人在使用
static void bdict_free_storage(void *object TSRMLS_DC)
而不是
static void bdict_free_storage(zend_object *object TSRMLS_DC)
我试过了,但它给了我一个编译时错误。
/home/frederick/php-7.0.1/ext/php-bencode/bencode.cc: In function ‘int zm_startup_bencode(int, int)’:
/home/frederick/php-7.0.1/ext/php-bencode/bencode.cc:131:36: error: invalid conversion from ‘void (*)(void*)’ to ‘zend_object_free_obj_t {aka void (*)(_zend_object*)}’ [-fpermissive]
bdict_object_handlers.free_obj = bdict_free_storage;
将"zend_object_handlers bdict_object_handlers;"更改为"zend_object_handlers bdict_object_handlers = std_object_handlers;"可以解决这个问题,因为你没有初始化结构。
"bdict_free_storage"中的参数必须通过其偏移
您可以试试:
bdict_object *intern = (bdict_object *) ((char *) object - XtOffsetOf(bdict_object, std));