Skip to content

Conversation

@gnat42
Copy link
Contributor

@gnat42 gnat42 commented Jan 7, 2021

Initial support for PHP 8.0.

// is incorrect in their view. another place to put this may be
// hiding it behind the fname
_argv[_argc + 1].type = reinterpret_cast<zend_type>(this);
// _argv[_argc + 1].type = reinterpret_cast<zend_type>(this);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't solve this - I don't know what functionality breaks by not fixing it. Its related to the zend_type becoming a struct

#if PHP_VERSION_ID < 80000
info->return_reference = false;
info->_is_variadic = false;
info->type = ZEND_TYPE_ENCODE((int)_return, true);
Copy link
Contributor Author

@gnat42 gnat42 Jan 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there needs to be a similar line for PHP 8 or not ?

Meaning - I'm wondering if info->type needs some default initialization or not

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was running into various SIGSEV's with functions that utilised pass by reference.

__strchrnul (s=0x202c6e6f69746169 <error: Cannot access memory at address 0x202c6e6f69746169>, c=c@entry=124) at src/string/strchrnul.c:19
19	src/string/strchrnul.c: No such file or directory.
(gdb) backtrace
#0  __strchrnul (s=0x202c6e6f69746169 <error: Cannot access memory at address 0x202c6e6f69746169>, c=c@entry=124) at src/string/strchrnul.c:19
#1  0x00007fee50a5f4f4 in strchr (s=<optimized out>, c=124) at src/string/strchr.c:5
#2  0x000055d31751a242 in zend_register_functions ()
#3  0x000055d31751a7aa in ?? ()
#4  0x00007fee4fed96e5 in Php::ClassImpl::initialize (this=0x7fee5020b7f0, base=0x7fee4f93bcd0, prefix=...) at zend/classimpl.cpp:1457

The following fixed it:

#if PHP_VERSION_ID >= 80000
    info->type = (zend_type) ZEND_TYPE_INIT_CODE((int)_return, true, 0);
#endif

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!, I've added it to my PR/patch.

Comment on lines +1532 to +1537
int retval = 0;
zend_string *tmp_str;
tmp_str = zend_string_init(key, size, 0);
retval = has_property(Z_OBJ_P(_val), tmp_str, 0, nullptr);
zend_string_release(tmp_str);
return retval;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can probably happen with some way of getting a pointer to the key or something like that but I couldn't find the appropriate PHP macro for it

@gnat42 gnat42 mentioned this pull request Jan 8, 2021
Copy link

@stmboyd stmboyd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left a few comments that should help get this to compile again. However, I feel like having #if all over the place is unwise, and it would be better to do it once at the top of the file with a using statement.

@gnat42 gnat42 force-pushed the php80 branch 7 times, most recently from 20f2061 to 831c386 Compare January 14, 2021 17:46
@Dringho
Copy link

Dringho commented Sep 7, 2021

Hi @gnat42 . I tried to compile a class using your code but at runtime is failing with the following error

php -a
PHP Fatal error:  Method RA_Matrix::__construct() cannot declare a return type in Unknown on line 0

The class I have implemented is the following

class RA_Matrix : public Php::Base
{
private:

public:
    /**
     *  Internal value
     */
    mat _value;

    /**
     *  c++ constructor
     */
    RA_Matrix() = default;
    RA_Matrix(int rows,int cols) : _value(rows,cols) {}
    RA_Matrix(mat value) : _value(value) {}

    /**
     *  c++ destructor
     */
    virtual ~RA_Matrix() = default;

    /**
     *  php "constructor"
     *  @param  params
     */
    void __construct(Php::Parameters &params)
    {
        if (!params.empty()){
            if (params.size()==2){
                if (params[0].isNumeric() && params[1].isNumeric()){
                    _value = mat ((int)params[0],(int)params[1]);
                }
                else{
                    cout << "RA_Matrix 2 Parametros Invalidos"<< endl;
                }
            }
            else{
                if (params.size()==1){
                    if (params[0].isArray()){
                        //llega como vector de vectors desde PHP, ver como "comprobarlo"
                        std::vector<std::vector<double>> B=params[0];
                        int rows = B.size();
                        int cols=B[0].size();
                        _value =zeros<mat>(rows,cols);
                        for (int i=0; i<rows; i++){
                            rowvec fila(B[i]);
                            _value.row(i)=fila;
                        }
                        //_value.print();
                    }
                    else{
                        cout << "RA_Matrix Parametro Invalido"<< endl;
                    }
                }
                else{
                    cout << "RA_Matrix Numero de Parametros Invalidos"<< endl;
                }
            }
        }
        else _value = mat();
    }
}

Do you have any ideas what could be the problem? This worked alright in PHP 7.3

@gnat42
Copy link
Contributor Author

gnat42 commented Sep 7, 2021

hello @Dringho if you look at #469 @axelusarov submitted a change/fix for this specific issue - I just haven't had a time to update my PR with their fix.

@Dringho
Copy link

Dringho commented Sep 7, 2021

hello @Dringho if you look at #469 @axelusarov submitted a change/fix for this specific issue - I just haven't had a time to update my PR with their fix.

I added that fix and my class extension compiled and worked :) thank you very much both.

@gnat42
Copy link
Contributor Author

gnat42 commented Sep 11, 2021

hello @Dringho and @axelusarov I've pushed a new version of the PR that includes the change. If you can make sure it works for you that would be helpful.

@edhelas
Copy link

edhelas commented Apr 7, 2022

I have a crash when trying to execute my code based on this branch

Program received signal SIGSEGV, Segmentation fault.
__strchr_avx2 () at ../sysdeps/x86_64/multiarch/strchr-avx2.S:61
61	../sysdeps/x86_64/multiarch/strchr-avx2.S: Aucun fichier ou dossier de ce type.
(gdb) bt
#0  __strchr_avx2 () at ../sysdeps/x86_64/multiarch/strchr-avx2.S:61
#1  0x00005555558317ca in zend_register_functions ()
#2  0x0000555555831ce4 in  ()
#3  0x00007ffff2735c44 in Php::ClassImpl::initialize(Php::ClassBase*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (this=0x555555c41090, base=0x555555b7f850, prefix="")
    at zend/classimpl.cpp:1457
#4  0x00007ffff273d42c in operator()(std::string const&, Php::ClassBase&) const
    (__closure=0x7fffffffc9e0, prefix="", c=warning: RTTI symbol not found for class 'Php::Class<PhpLinphoneAuth>'
...) at zend/extensionimpl.cpp:380
#5  0x00007ffff273e557 in std::__invoke_impl<void, Php::ExtensionImpl::initialize(int)::<lambda(const string&, Php::ClassBase&)>&, const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, Php::ClassBase&>(std::__invoke_other, struct {...} &) (__f=...) at /usr/include/c++/11/bits/invoke.h:61
#6  0x00007ffff273e250 in std::__invoke_r<void, Php::ExtensionImpl::initialize(int)::<lambda(const string&, Php::ClassBase&)>&, const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, Php::ClassBase&>(struct {...} &) (__fn=...) at /usr/include/c++/11/bits/invoke.h:154
#7  0x00007ffff273ddfb in std::_Function_handler<void(const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, Php::ClassBase&), Php::ExtensionImpl::initialize(int)::<lambda(const string&, Php::ClassBase&)> >::_M_invoke(const std::_Any_data &, const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > &, Php::ClassBase &) (__functor=..., __args#0="", __args#1=warning: RTTI symbol not found for class 'Php::Class<PhpLinphoneAuth>'
...) at /usr/include/c++/11/bits/std_function.h:290
#8  0x00007ffff274a041 in std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Php::ClassBase&)>::operator()(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Php::ClassBase&) const (this=0x7fffffffc9e0, __args#0="", __args#1=warning: RTTI symbol not found for class 'Php::Class<PhpLinphoneAuth>'
...)
    at /usr/include/c++/11/bits/std_function.h:590
#9  0x00007ffff27481fe in Php::Namespace::classes(std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Php::ClassBase&)> const&)
    (this=0x7ffff2984480 <get_module::extension>, callback=...) at zend/namespace.cpp:148
#10 0x00007ffff273d65b in Php::ExtensionImpl::initialize(int) (this=0x555555c40f10, module_number=51)
    at zend/extensionimpl.cpp:377
#11 0x00007ffff273cc58 in Php::ExtensionImpl::processStartup(int, int) (type=1, module_number=51)
--Type <RET> for more, q to quit, c to continue without paging--
    at zend/extensionimpl.cpp:123
#12 0x00005555558302d8 in zend_startup_module_ex ()
#13 0x000055555583036c in  ()
#14 0x000055555583dd72 in zend_hash_apply ()
#15 0x00005555557c8093 in php_module_startup ()
#16 0x000055555590f8cd in  ()
#17 0x0000555555675ec4 in  ()
#18 0x00007ffff76337fd in __libc_start_main (main=
    0x555555675d40, argc=1, argv=0x7fffffffe148, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe138) at ../csu/libc-start.c:332
#19 0x000055555567628a in _start ()

Not sure where the cause is.

@edhelas
Copy link

edhelas commented Apr 11, 2022

Si it seems that it is related to the JIT feature added in PHP8, I'm trying to disable the AVX optimizations using opcache.jit=0255 but it doesn't seems to work.

@alitoufighi
Copy link

Are there any intentions to merge this?

#else
if ((int)_return) {
info->type = (zend_type)ZEND_TYPE_INIT_CODE((int)_return, true, 0);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type needs to be initialized for void functions as well. Otherwise the uninitialized value is used and can lead to early segfaults.

I was able to solve this with

else {
        info->type = (zend_type)ZEND_TYPE_INIT_NONE(0);
}
``

@gnat42
Copy link
Contributor Author

gnat42 commented Aug 29, 2022

@edhelas Interestingly I have that same crash on PHP 8.1.9 when compiled against Fedora 36, but don't have the crash when running against PHP 8.1.9 on CentOS 7... I'm investigating. Have you found a solution?

@edhelas
Copy link

edhelas commented Aug 29, 2022

@gnat42 We choose to move to another solution regarding our needs. I might try again but not anytime soon. Sorry.

@gnat42
Copy link
Contributor Author

gnat42 commented Aug 29, 2022

Ah ok, well in the in-between messaging, I can say that I fixed the crash for my extension by applying the change @flaviozavan suggested. So I will add that to my patch/PR

@gnat42
Copy link
Contributor Author

gnat42 commented Sep 7, 2022

One more bit of information for people using this patch. Reflection is broken with these changes. For example with the following simple extension

#include <phpcpp.h>

/**
 *  Counter class that can be used for counting
 */
class Counter : public Php::Base
{
private:
    /**
     *  The initial value
     *  @var    int
     */
    int _value = 0;

public:
    /**
     *  C++ constructor and destructor
     */
    Counter() = default;
    virtual ~Counter() = default;

    /**
     *  Update methods to increment or decrement the counter
     *  Both methods return the NEW value of the counter
     *  @return int
     */
    Php::Value increment() { return ++_value; }
    Php::Value decrement() { return --_value; }

    /**
     *  Method to retrieve the current counter value
     *  @return int
     */
    Php::Value value() const { return _value; }

    Php::Value test(Php::Parameters &params) {
       return _value;
    }
};

/**
 *  tell the compiler that the get_module is a pure C function
 */
extern "C" {

    /**
     *  Function that is called by PHP right after the PHP process
     *  has started, and that returns an address of an internal PHP
     *  strucure with all the details and features of your extension
     *
     *  @return void*   a pointer to an address that is understood by PHP
     */
    PHPCPP_EXPORT void *get_module() 
    {
        // static(!) Php::Extension object that should stay in memory
        // for the entire duration of the process (that's why it's static)
        static Php::Extension extension("gnat", "1.0");

	Php::Namespace myNamespace("Counter");

        Php::Class<Counter> counter("Counter");
        counter.method<&Counter::increment> ("increment");
        counter.method<&Counter::decrement> ("decrement");
        counter.method<&Counter::value>     ("value");

	counter.method<&Counter::test>("test", Php::Public, { 
            Php::ByVal("date", "\\DateTime", true, false),
            Php::ByRef("date2", "\\DateTime", true, false),
            Php::ByVal("something", Php::Type::Numeric),
            Php::ByVal("something2", Php::Type::Array),
            Php::ByVal("output", Php::Type::String),
            Php::ByVal("dpi", Php::Type::Numeric,false)
        });

	myNamespace.add(counter);

	extension.add(myNamespace);

        // return the extension
        return extension;
    }
}

and the following php

<?php

use \Counter\Counter;

$refClass = new ReflectionClass(Counter::class);
echo Counter::class."\n";
foreach ($refClass->getMethods() as $method) {
    echo "\n\nMethod: " . $method->getName() . "\n";
    foreach ($method->getParameters() as $parameter) {
        echo "\tParameter: " . $parameter->getName() . "\n";
        $type = $parameter->getType();
        if (!$type) {
	        echo "\tType: null type\n";
	        continue;
	    }

        echo "\tType: " . $type->getName() . "\n";
	    echo "\t\tBuiltIn: ".($type->isBuiltIn() ? 'Y':'N')."\n";
	    echo "\t\tAllowNull: ".($type->allowsNull() ? 'Y':'N')."\n";
    }
}

return;

The output is as follows on PHP 8.x.

// snip....
Method: test
        Parameter: ?\DateTime
        Type: object
                BuiltIn: Y
                AllowNull: Y
        Parameter: ?\DateTime
        Type: object
                BuiltIn: Y
                AllowNull: Y
        Parameter: something
        Type: int
                BuiltIn: Y
                AllowNull: N
        Parameter: something2
        Type: array
                BuiltIn: Y
                AllowNull: N
        Parameter: output
        Type: string
                BuiltIn: Y
                AllowNull: N
        Parameter: dpi
        Type: int
                BuiltIn: Y
                AllowNull: N

On php 7.x the is Parameter: date, type ?\DateTime... I'm trying to find out what's going on but everything I've seen so far is correct.

Anyone with suggestions would be appreciated.

@gnat42
Copy link
Contributor Author

gnat42 commented Sep 8, 2022

This latest push (Sep 8) fixes the issue.

@gnat42
Copy link
Contributor Author

gnat42 commented Oct 8, 2022

the latest push incorporated the PR by @rtio that fixes a function signature difference between PHP 7.4 and 8.0. Since I'm squashing all fixes to my patches I just wanted to make sure some credit/attribution was made.

@carlos-granados
Copy link

This has been merged into a maintained fork here: fast-debug#8

@EmielBruijntjes EmielBruijntjes merged commit 4494f1a into CopernicaMarketingSoftware:master Nov 6, 2023
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

Successfully merging this pull request may close these issues.