Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access violation on eval PHP code #320

Open
atvise opened this issue Apr 3, 2017 · 15 comments
Open

Access violation on eval PHP code #320

atvise opened this issue Apr 3, 2017 · 15 comments

Comments

@atvise
Copy link
Contributor

atvise commented Apr 3, 2017

Hi,

i've compiled the latest version of PHP-CPP (a5ca2f3) 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

@atvise
Copy link
Contributor Author

atvise commented Apr 11, 2017

This also happens with PHP 7.0.17

@sjinks
Copy link
Contributor

sjinks commented Apr 11, 2017

Do you happen to have a small test case which reproduces the issue?

@atvise
Copy link
Contributor Author

atvise commented Apr 11, 2017

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;
  }
}

@sjinks
Copy link
Contributor

sjinks commented Apr 11, 2017

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

@sjinks
Copy link
Contributor

sjinks commented Apr 11, 2017

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();'

@sjinks
Copy link
Contributor

sjinks commented Apr 11, 2017

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);
}

@atvise
Copy link
Contributor Author

atvise commented Apr 12, 2017

@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 :(

@sjinks
Copy link
Contributor

sjinks commented Apr 12, 2017

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.

@atvise
Copy link
Contributor Author

atvise commented Apr 13, 2017

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.

@rodriguescr
Copy link

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?

@sjinks
Copy link
Contributor

sjinks commented Oct 16, 2018

g++ $(php-config --includes) -Wall -c -O2 -std=c++11 -fpic -o extension.o extension.cpp

@imagemlt
Copy link

@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?

@sjinks
Copy link
Contributor

sjinks commented Mar 10, 2019

You need to link against libphp as well. Add smth like -lphp7 to your link command.

@imagemlt
Copy link

@sjinks it seems that there donnot exists such library

@imagemlt
Copy link

imagemlt commented Mar 11, 2019

@sjinks solved by adding -undefined dynamic_lookup because I use Mac OS X

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants