Skip to content

PHP Extension - Segmentation fault if message constructor is not called. #19978

@FabioBatSilva

Description

@FabioBatSilva

We are trying to migrate an application from the PHP Protobuf implementation to the C extension.

A few tests are using the prophecy to mock objects during tests.
and prophecy ends up creating a proxy that looks something like this :

class P5
    extends \UserProfile\V1alpha\Account
    implements \Prophecy\Doubler\DoubleInterface, \Prophecy\Prophecy\ProphecySubjectInterface, \Prophecy\Doubler\Generator\ReflectionInterface
{
    private $objectProphecyClosure;

    public  function __construct( $data = NULL) {
        if (0 < func_num_args()) {
            call_user_func_array(array('parent', '__construct'), func_get_args());
        }
    }

    public  function setProphecy(\Prophecy\Prophecy\ProphecyInterface $prophecy) {
        if (null === $this->objectProphecyClosure) {
            $this->objectProphecyClosure = static function () use ($prophecy) {
                return $prophecy;
            };
        }
    }

    public  function getProphecy() {
        return \call_user_func($this->objectProphecyClosure);
    }
}

Since the parent constructor is not always called it seems the message never properly initialized and the field lookup fails when get_field is called.

NOTE: This is a common pattern in many php frameworks.
And it is debatable weather or not this should be mocked/proxied but the behaviour is inconsistent between the two implementations and I believe no condition should trigger a seg fault.


What version of protobuf and what language are you using?
Version: main
Language: php
OS: Linux

What did you do?

<?php
# proxy_test.php

require_once('../vendor/autoload.php');
require_once('test_util.php');

use Foo\TestMessage;

class TestMessageProxy extends TestMessage
{
    private $foo;

    public  function __construct($data = NULL) {
        if (0 < func_num_args()) {
            parent::__construct($data);
        }
    }

    public function setFoo($foo) {
        $this->foo = $foo;
    }

    public function getFoo() {
        return $this->foo;
    }
}


$p = new TestMessageProxy();

$p->setFoo('bar');

assert('bar' === $p->getFoo());
# Compile the extension 
./php/tests/compile_extension.sh

# Run script
php -d display_errors=on -dextension=../ext/google/protobuf/modules/protobuf.so proxy_test.php

What did you expect to see

No error

What did you see instead?

Segmentation fault (core dumped)

gdb

in get_field (msg=0x7ffff2bfb6c0, msg=0x7ffff2bfb6c0, member=<optimized out>)
    at /tmp/pear/temp/protobuf/message.c:92

bt
#0  0x00007ffff3fb7836 in get_field (msg=0x7ffff280cd20, msg=0x7ffff280cd20, member=<optimized out>)
    at /tmp/pear/temp/protobuf/message.c:92
#1  Message_read_property (obj=0x7ffff280cd20, member=0x7ffff3705a80, type=<optimized out>, cache_slot=0x7fffec4e8e98, 
    rv=0x7ffff4817c80) at /tmp/pear/temp/protobuf/message.c:312
#2  0x00005555559dc082 in execute_ex ()
#3  0x000055555563c839 in ?? ()

Metadata

Metadata

Assignees

Labels

untriagedauto added to all issues by default when created.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions