我想写一个c程序,可以分析PHP脚本出于各种原因。我需要从PHP核心库中调用token_get_all,但我正在为此苦苦挣扎。我已经静态编译php7主分支,并将其链接到我的程序。我会发布几个代码片段,因为我已经尝试了很多方法来调用这个函数,并且一直运行在一种或另一种类型的错误中。从c程序调用token_get_all
这个片断得到,当我执行它最远:
int main(void)
{
zval function_name, params[1], return_value, param;
ZVAL_NEW_STR(&function_name, zend_string_init("token_get_all", strlen("token_get_all"), 1));
printf("Got here\n");
ZVAL_NEW_STR(¶ms[0], zend_string_init("<?php $x = 1;", strlen("<?php $x = 1;"), 1));
int ret;
printf("Calling function\n");
ret = call_user_function(CG(function_table), NULL, &function_name, &return_value, 1, params TSRMLS_CC);
printf("%i", ret);
}
当它到达call_user_function,它出现segfaults。 Valgrind输出:
==11451== 1 errors in context 1 of 1:
==11451== Invalid read of size 8
==11451== at 0x40268C: parse_php (parser.c:73)
==11451== by 0x402730: parse_php_file (parser.c:95)
==11451== by 0x4029B2: main (parse-script-main.c:14)
==11451== Address 0x0 is not stack'd, malloc'd or (recently) free'd
parser.c:73是call_user_function的行。
我会发布这个以及,虽然它可能是一个单独的问题。如果我改变了我初始化函数名或独立参数的方式,那么我会用不同的段错误结束。试想一下:
int main(void)
{
zval function_name, params[1], return_value, param;
ZVAL_STRING(&function_name, "token_get_all");
printf("Got here\n");
ZVAL_NEW_STR(¶ms[0], zend_string_init("<?php $x = 1;", strlen("<?php $x = 1;"), 1));
int ret;
printf("Calling function\n");
ret = call_user_function(CG(function_table), NULL, &function_name, &return_value, 1, params TSRMLS_CC);
printf("%i", ret);
}
这给了我一个段错误的ZVAL_STRING行:
==11481== 1 errors in context 1 of 1:
==11481== Invalid read of size 8
==11481== at 0x407DF5: _emalloc (zend_alloc.c:2376)
==11481== by 0x402559: zend_string_alloc (zend_string.h:121)
==11481== by 0x4025C2: zend_string_init (zend_string.h:157)
==11481== by 0x402639: parse_php (parser.c:65)
==11481== by 0x402747: parse_php_file (parser.c:95)
==11481== by 0x4029C9: main (parse-script-main.c:14)
==11481== Address 0x0 is not stack'd, malloc'd or (recently) free'd
最后,这里是我的编译器/连接命令:
gcc -g -D_GNU_SOURCE -Iinclude -I/usr/local/include/php -I/usr/local/include/php/Zend -I/usr/local/include/php/include -I/usr/local/include/php/main -I/usr/local/include/php/ext -I/usr/local/include/php/sapi -I/usr/local/include/php/TSRM -c /path/to/parser.c -o obj/Debug/include/parser.o
g++ -Linclude -L/usr/lib/x86_64-linux-gnu -L/usr/local/lib -o bin/Debug/parse-script obj/Debug/include/parser.o obj/Debug/include/project.o obj/Debug/include/utils.o obj/Debug/parse-script-main.o -lphp7 -ldl -lc -lpthread -lgcc
我知道生成的目标文件唐不符合上面的代码。在上面的例子中,我将问题函数封装在“int main(void)”中。