php - Calling token_get_all from c program -
i'm trying write c program can analyse php scripts various reasons. need call token_get_all php core library, i'm struggling mightily it. i've compiled php7 master branch statically , linked program. i'll post couple of code snippets i've tried many ways of calling function , keep running errors of 1 type or another.
this snippet gets farthest when execute it:
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); }
when gets call_user_function, segfaults. valgrind output:
==11451== 1 errors in context 1 of 1: ==11451== invalid read of size 8 ==11451== @ 0x40268c: parse_php (parser.c:73) ==11451== 0x402730: parse_php_file (parser.c:95) ==11451== 0x4029b2: main (parse-script-main.c:14) ==11451== address 0x0 not stack'd, malloc'd or (recently) free'd
parser.c:73 line of call_user_function.
i'll post well, though may separate question. if change way initialize function_name or lone parameter wind different segfault. consider this:
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); }
this gives me segfault on zval_string line:
==11481== 1 errors in context 1 of 1: ==11481== invalid read of size 8 ==11481== @ 0x407df5: _emalloc (zend_alloc.c:2376) ==11481== 0x402559: zend_string_alloc (zend_string.h:121) ==11481== 0x4025c2: zend_string_init (zend_string.h:157) ==11481== 0x402639: parse_php (parser.c:65) ==11481== 0x402747: parse_php_file (parser.c:95) ==11481== 0x4029c9: main (parse-script-main.c:14) ==11481== address 0x0 not stack'd, malloc'd or (recently) free'd
finally, here's compiler/linker commands:
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
i know generated object files don't match code above. wrapped problem function in "int main(void)" in examples above.
okay, managed past this. i'll post findings here. basically, of information find when search on topic (at least me) related writing php extensions, not linking php c app , calling of internal functions. here's working me:
main.c:
#include <stdio.h> #include <stdlib.h> #include <sapi/embed/php_embed.h> #include "parser.h" int main(int, char *[]); int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stdout, "usage: parse-script <php-file>\n"); exit(0); } php_embed_start_block(argc, argv); parse_php_file(argv[1]); php_embed_end_block(); return 0; }
parser.c:
#include <stdio.h> #include "utils.h" #include "php.h" int parse_php(char *code) { zval function_name; zval return_value; int param_count = 1; zval code_param; zval *params[1]; zval_stringl(params[0], code, strlen(code), 0); init_zval(function_name); zval_string(&function_name, "token_get_all", 0); tsrmls_fetch(); if (call_user_function(cg(function_table), (zval **)null, &function_name, &return_value, 1, params tsrmls_cc) == success) { zend_print_zval_r(&return_value, 0); } else { fprintf(stderr, "error parsing php code.\n"); } printf("done\n"); } int parse_php_file(char *file_name) { char *code; code = read_file(file_name); if (code == null) { fprintf(stderr, "could not read file: %s\n", file_name); return 0; } parse_php(code); }
the key seems php_embed_start_block() , php_embed_end_block(). wrapping main code in 2 statements made start working properly. save headaches down road :)
Comments
Post a Comment