PHP扩展-带有PHP版本编译的Segfault
我已经写了一个PHP扩展,现在我真的很奇怪 如果我通过PHP扩展-带有PHP版本编译的Segfault,php,c++,c,segmentation-fault,php-extension,Php,C++,C,Segmentation Fault,Php Extension,我已经写了一个PHP扩展,现在我真的很奇怪 如果我通过php test.php或phpce->name), ZSTR_LEN(对象)->ce->name) 这也是防撞的 此外,您还使函数的开头变得复杂: char*ini_ns_key=estrdup(“bencode.namespace”); zend_bool ini_ns=zend_ini_long(ini_ns_键,strlen(ini_ns_键),0); efree(ini键) 应该这样写: zend_long ini_ns_long=
php test.php
或php
运行测试脚本是可以的,但是如果我在交互模式下输入完全相同的命令(php-a
),则会出现segfault
46 char *_class_name = (char *)emalloc(_class_name_len);
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x000055555578f664 in _emalloc ()
首先,我认为从Launchpad复制PHP二进制文件可能会有一些问题,我编译了自己的一个。configure命令是。/configure'--前缀=/opt/php7 dbg'--使用gd'--使用mysqli'--使用readline'--使用curl'
。(优化器参数为-O2
)
我又遇到了完全相同的问题,但这次我可以更进一步
46 char *_class_name = (char *)emalloc(_class_name_len);
(gdb) s
_emalloc (size=4) at /home/frederick/Programming/C/php-7.0.6/Zend/zend_alloc.c:2439
2439 {
(gdb) n
2442 if (UNEXPECTED(AG(mm_heap)->use_custom_heap)) {
(gdb) n
2450 return zend_mm_alloc_heap(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
(gdb) s
zend_mm_alloc_heap (size=4, heap=0x7fffef000040) at /home/frederick/Programming/C/php-7.0.6/Zend/zend_alloc.c:1365
1365 if (size <= ZEND_MM_MAX_SMALL_SIZE) {
(gdb) n
1366 ptr = zend_mm_alloc_small(heap, size, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
(gdb) s
zend_mm_small_size_to_bin (size=4) at /home/frederick/Programming/C/php-7.0.6/Zend/zend_alloc.c:1211
1211 if (size <= 64) {
(gdb) n
1213 return (size - !!size) >> 3;
(gdb) s
zend_mm_alloc_heap (size=<optimised out>, heap=0x7fffef000040) at /home/frederick/Programming/C/php-7.0.6/Zend/zend_alloc.c:1366
1366 ptr = zend_mm_alloc_small(heap, size, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
(gdb) s
zend_mm_alloc_small (bin_num=<optimised out>, size=<optimised out>, heap=0x7fffef000040) at /home/frederick/Programming/C/php-7.0.6/Zend/zend_alloc.c:1286
1286 size_t size = heap->size + bin_data_size[bin_num];
(gdb) n
1287 size_t peak = MAX(heap->peak, size);
(gdb) n
1288 heap->size = size;
(gdb) n
1289 heap->peak = peak;
(gdb) n
1293 if (EXPECTED(heap->free_slot[bin_num] != NULL)) {
(gdb) n
1295 heap->free_slot[bin_num] = p->next_free_slot;
(gdb) p bin_num
$1 = <optimised out>
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
zend_mm_alloc_small (bin_num=<optimised out>, size=<optimised out>, heap=0x7fffef000040) at /home/frederick/Programming/C/php-7.0.6/Zend/zend_alloc.c:1295
1295 heap->free_slot[bin_num] = p->next_free_slot;
然后我知道是哪条线路产生了SEGFULT,我想解决这个问题。因此,我立即编译了一个PHP调试版本(configure命令:'./configure'.-prefix=/opt/php7 dbg'.-with-gd'.-with-mysqli'.-with-readline'.-with-curl'.-enable debug'
,优化器:-O0
)
但是,在基于相同代码的调试构建中,segfault就消失了
我不是一个经验丰富的C/C++开发人员,这是我第一次遇到这样的问题。请帮忙,非常感谢
更新
看来这个问题是由一个愚蠢的错误引起的。导致SEG故障的线路应
char *_class_name = (char *)emalloc(_class_name_len + 1);
as C字符串应以“\0”结尾
但是为什么调试版本可以呢?我猜您的程序在
strcpy
处崩溃,emalloc
行只是崩溃前的最后一行。这里确实有一个错误,需要向emalloc添加+1,因为字符串末尾有0字节
但你把事情弄得太复杂了。因为你使用C++,你可以用一行替换所有的从sisivit到EFELE(包括它们)的行:
std::string class_name(ZSTR_VAL(Z_OBJ_p(object)->ce->name),
ZSTR_LEN(对象)->ce->name)代码>
这也是防撞的
此外,您还使函数的开头变得复杂:
char*ini_ns_key=estrdup(“bencode.namespace”);
zend_bool ini_ns=zend_ini_long(ini_ns_键,strlen(ini_ns_键),0);
efree(ini键)代码>
应该这样写:
zend_long ini_ns_long=zend_ini_long(“bencode.namespace”),strlen(“bencode.namespace”),0;
bool ini_ns=(ini_ns_long!=0)代码>我猜您的程序在strcpy
处崩溃,emalloc
行只是崩溃前的最后一行。这里确实有一个错误,需要向emalloc添加+1,因为字符串末尾有0字节
但你把事情弄得太复杂了。因为你使用C++,你可以用一行替换所有的从sisivit到EFELE(包括它们)的行:
std::string class_name(ZSTR_VAL(Z_OBJ_p(object)->ce->name),
ZSTR_LEN(对象)->ce->name)代码>
这也是防撞的
此外,您还使函数的开头变得复杂:
char*ini_ns_key=estrdup(“bencode.namespace”);
zend_bool ini_ns=zend_ini_long(ini_ns_键,strlen(ini_ns_键),0);
efree(ini键)代码>
应该这样写:
zend_long ini_ns_long=zend_ini_long(“bencode.namespace”),strlen(“bencode.namespace”),0;
bool ini_ns=(ini_ns_long!=0)代码>很有趣。昨晚我看了一会儿,没有发现任何惊人的错误。我仍然不相信你的解决方案真的解决了这个问题。据我所知,emalloc
不知道它正在为字符串分配空间,需要为'\0'
分配空间。这是一个奇怪的事实,它的seg断层。根据我的经验,打开优化会暴露出在关闭优化时没有发现的问题。我敢打赌,在调用emalloc
时,您的代码中有一些UB未显示,并且出于任何原因,它会暴露出来。zend\u
函数是您的吗?什么是zval?宏是什么?@yano谢谢你的回答!这些宏大多来自PHP,PHP通过#define emalloc(size)_emalloc((size)ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
定义了自己的emalloc
。更重要的是,PHPemalloc
将根据许多因素(无论是调试,还是在Windows下,或者使用clang等)表现不同。这相当复杂,我不确定问题从何而来。也许你需要PHP的源代码,呃,我对PHP
一无所知。这是您发布的唯一的c++
调用的c++
函数,还是从其他c++
调用的未发布代码?感谢您指出php
有一个emalloc
函数,我想知道为什么您的gdb
进入emalloc
看起来与c
版本完全不同:@yano它只是整个扩展的一部分。仅供参考,您可以在PHP中的第2400行找到emalloc
。昨晚我看了一会儿,没有发现任何惊人的错误。我仍然不相信你的解决方案真的解决了这个问题。据我所知,emalloc
不知道它正在为字符串分配空间,需要为'\0'
分配空间。这是一个奇怪的事实,它的seg断层。根据我的经验,打开优化会暴露出在关闭优化时没有发现的问题。我敢打赌,在调用emalloc
时,您的代码中有一些UB未显示,并且出于任何原因,它会暴露出来。zend\u
函数是您的吗?什么是zval?宏是什么?@yano谢谢你的回答!这些宏大多来自PHP,PHP通过#define emalloc(size)_emalloc((size)ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
定义了自己的emalloc
。更重要的是,PHPemalloc
的行为将因具体情况而有所不同
char *_class_name = (char *)emalloc(_class_name_len + 1);