Open atvise opened 7 years ago
This also happens with PHP 7.0.17
Do you happen to have a small test case which reproduces the issue?
Yes here you go:
#include <phpcpp/phpcpp.h>
extern "C" {
__declspec(dllexport) void* get_module()
{
static Php::Extension myExtension("php_my_test", "1.0");
static bool extensionAdded = false;
if (!extensionAdded)
{
extensionAdded = true;
myExtension.onRequest([]()
{
Php::eval("echo 'Hello World!';");
});
}
return myExtension;
}
}
Confirmed.
Program received signal SIGSEGV, Segmentation fault.
0x00007fffed400e94 in Php::ExecuteState::ExecuteState (this=0x7fffffffc370, no_extensions=0) at zend/executestate.h:55
55 _return_value = EG(current_execute_data)->return_value;
(gdb) bt
#0 0x00007fffed400e94 in Php::ExecuteState::ExecuteState (this=0x7fffffffc370, no_extensions=0) at zend/executestate.h:55
#1 0x00007fffed401120 in Php::Opcodes::execute (this=0x5555569d5fd0) at zend/opcodes.h:76
#2 0x00007fffed4006ec in Php::Script::execute (this=0x7fffffffc430) at zend/script.cpp:85
#3 0x00007fffed3feaa3 in Php::eval (phpCode=0x7fffed6655da "echo 'Hello World!';") at zend/eval.cpp:27
#4 0x00007fffed66506e in get_module::{lambda()#1}::operator()() const () from ./test.so
#5 0x00007fffed6652fa in std::_Function_handler<void (), get_module::{lambda()#1}>::_M_invoke(std::_Any_data const&) () from ./test.so
#6 0x00007fffed3f6498 in std::function<void ()>::operator()() const (this=0x55555686dfc0) at /usr/include/c++/6/functional:2136
#7 0x00007fffed3f39da in Php::ExtensionImpl::processRequest (type=1, module_number=49) at zend/extensionimpl.cpp:152
#8 0x0000555555da13cb in zend_activate_modules () at /tmp/php-build/source/7.0.17/Zend/zend_API.c:2541
#9 0x0000555555ccd595 in php_request_startup () at /tmp/php-build/source/7.0.17/main/main.c:1627
#10 0x0000555555e6e3fc in do_cli (argc=6, argv=0x5555567f9ff0) at /tmp/php-build/source/7.0.17/sapi/cli/php_cli.c:948
#11 0x0000555555e6faa3 in main (argc=6, argv=0x5555567f9ff0) at /tmp/php-build/source/7.0.17/sapi/cli/php_cli.c:1347
The issue is that you are trying to execute PHP code before executor data are set up.
This will work:
#include <phpcpp.h>
static void testfunc()
{
Php::eval("echo 'Hello World!';");
}
extern "C" {
void* get_module()
{
static Php::Extension myExtension("php_my_test", "1.0");
myExtension.add<testfunc>("testfunc");
return myExtension;
}
}
php -n -dextension_dir=. -dextension=test.so -r 'testfunc();'
If you absolutely must call PHP code during request startup but before the executor is initialized, you will have to use Zend API:
#include <phpcpp.h>
#include <cstring>
#include <Zend/zend.h>
#include <Zend/zend_compile.h>
#include <Zend/zend_execute.h>
extern "C" {
void* get_module()
{
static Php::Extension myExtension("php_my_test", "1.0");
static bool extensionAdded = false;
if (!extensionAdded)
{
extensionAdded = true;
myExtension.onRequest([]()
{
char code[] = "echo \"Hello, world!\\n\";";
char* desc = zend_make_compiled_string_description("eval'd code");
zend_eval_stringl_ex(code, std::strlen(code), nullptr, desc, 1);
efree(desc);
});
}
return myExtension;
}
}
Simple wrapper function:
void runPhpCode(const std::string& code)
{
char* desc = zend_make_compiled_string_description("eval'd code");
zend_eval_stringl_ex(const_cast<char*>(code.c_str()), code.size(), nullptr, desc, 1);
efree(desc);
}
@sjinks Thank you very much for your effort and help !! I'm very appreciating it! But I'm wondering why this is not working with Php::eval() because this all worked in the legacy version of PHP-CPP and PHP 5.6 :(
Don't get me wrong your code works great but doesn't it make the existing implementation of PHP-CPP obsolete ? I think we should somehow get it running again with the PHP-CPP eval implementation but I'm lacking in knowlege how PHP is working in that way :(
Php::eval
still works, the only issue is that it should not be called from onRequest()
callback (RINIT happens before the script to run is parsed).
onRequest
/RINIT
is usually used to initialize some data structures etc, not to run the code.
Php::eval
tries to save executor's state (see ExecuteState::ExecuteState()
), rebuild the active symbol table (see Opcodes::execute()
) — this is what zend_eval_stringl()
does not do. I am not sure, probably that code was copied from PHP5, or maybe it tried to generalize include/require/eval cases.
As my underestanding of this library everything will be initialized after onStartup Callback a mentioned in the documentation:
"The startup callback is called when the Zend engine has loaded your extension and all functions and classes in it were registered. If you want to initialize additional variables in your extension before the functions are going to get called, you can use the onStartup() function and register a callback to run this initialization code.
After the Zend engine is initialized, it is ready to process requests. In the example above we used the onRequest() method to register a callback that is called in front of each request"
And as I mentioned before the same function Php::eval() (with nearly exact the same implementation behind) worked with PHP 5.6 and PHP-CPP Lagacy in the onRequest() method.
Hi,
Sorry to bump this post, but @sjinks i'm trying to use your solution, but can't get it to work. I've downloaded php source to import zend libraries, but with no sucess to compile. I keep getting this error:
~/.../Examples/Extension >>> make ±[●●][master]
g++ -Wall -c -O2 -std=c++11 -fpic -o extension.o extension.cpp
In file included from php7/Zend/zend_types.h:27,
from php7/Zend/zend.h:29,
from extension.cpp:4:
php7/Zend/zend_portability.h:45:11: fatal error: zend_config.h: Arquivo ou diretório inexistente
# include <zend_config.h>
^~~~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:127: extension.o] Error 1
Could you please help me?
g++ $(php-config --includes) -Wall -c -O2 -std=c++11 -fpic -o extension.o extension.cpp
@sjinks hi,I used your way but it turned to error in linking process:
g++ -I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM -I/usr/include/php/Zend -I/usr/include/php/ext -I/usr/include/php/ext/date/lib -Wall -c -O2 -std=c++11 -fpic -o main.o main.cpp
g++ -shared -o imagecpp.so main.o -I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM -I/usr/include/php/Zend -I/usr/include/php/ext -I/usr/include/php/ext/date/lib -lphpcpp
Undefined symbols for architecture x86_64:
"_zend_eval_stringl_ex", referenced from:
std::__1::__function::__func<get_module::$_0, std::__1::allocator<get_module::$_0>, void ()>::operator()() in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [imagecpp.so] Error 1
Could you please help me?
You need to link against libphp as well. Add smth like -lphp7
to your link command.
@sjinks it seems that there donnot exists such library
@sjinks solved by adding -undefined dynamic_lookup
because I use Mac OS X
Hi,
i've compiled the latest version of PHP-CPP (a5ca2f39c43b3bc67f62f73863a5c0c8beb45b2e) with PHP 7.1.3 (64bit) on Win10 (64bit) VS2015. When I call the function Php::eval(phpContent) -> I get following error
script.cpp (Line 85) -> opcodes.h (Line 76) -> ExecuteState execState(0) 0xC0000005: Access violation reading location 0x0000000000000010
Can you verify this problem ?
Thank you very much for your help in advance!
Greetings, atvise