Segmentation fault when working with relations in a loop

When working with relationships via alias inside a loop, I get a segmentation fault error.

I have two models (simplified example):

class Person 
{
    public $id;
    public $company_id;
    public $address_id;

    public function initialize()
    {
        $this->hasOne('address_id', Address::class, 'id', [
            'alias' => 'Address'
        ]);
    }

    public static function fetchByCompanyId(int $companyId): array
    {
        $builder = DI::getDefault()->getModelsManager()->createBuilder()
            ->columns(['person.*, address.*'])
            ->from(['person' => Person::class])
            ->leftJoin(Address::class, 'person.address_id = address.id', 'address')
            ->where('person.company_id = :companyId:');

        $resultSet = $builder->getQuery()->execute(['companyId' => $companyId]);

        $persons = [];
        foreach ($resultSet as $row) {
            $person = $row['person'];
            $address = $row['address'];
            $person->Address = $address->id === null ? null : $address;

            $persons[] = $person;
        }

        return $persons;
    }
}
class Address 
{
    public $id;
}

Here is a sample function that produces segmentation fault:

class DebugController extends Controller
{
    public function index(): string
    {
        $companyIds = [1, 2];
        foreach ($companyIds as $companyId) {
            $persons = Person::fetchByCompanyId($companyId);
            foreach ($persons as $person) {
                echo $person->id . " + " . $person->Address->id;
            }
        }

        return 'OK';
    }
}

If I remove an element from $companyIds and leave only one (so foreach loops once), function works without an error. However, if there are multiple loops, it throws a segmentation fault error when called: [core:notice] [pid 1] AH00052: child pid 27 exit signal Segmentation fault (11)

My questions are:

  1. I am setting the relationship manually like so $person->Address = $address->id === null ? null : $address; because I don't want to make an additional DB call to fetch the relationship. Is this the correct way to do this or is there another way?
  2. If 1) is correct, what causes segmentation fault?
  3. Is this a bug or am I doing something I should't be doing?

Possibly worth mentioning: If I add this call after each Person::fetchByCompanyId, it works fine in all cases:

$this->modelsManager->__destruct();

However, I don't like this solution since it doesn't reuse modelsManager, but destroys and creates a new one on each loop.

Also, if I'd do a basic Person:find() + $person->Address, everything would work, but it would make a new DB query for each alias call and I don't want that.

Any help/insight is appreciated, thanks!

Additional info:

PHP 7.4
Phalcon 4.0.5
Running inside a docker


7.8k

i feel its because of the relation alias name ( i'm only guessing at this point )

i know you main goal for this statement $person->Address = $address->id === null ? null : $address; is not make the query when $person->Address is needed

try by using a another property name to pin point the issue

for example:

$person->someAddress = $address->id === null ? null : $address;

As far as I'm concerned, segmentation faults are never your fault - they're indiciative of an error in Phalcon. I'd recommend filing a bug report on GitHub.



1.1k
edited 13d ago

i feel its because of the relation alias name ( i'm only guessing at this point )

i know you main goal for this statement $person->Address = $address->id === null ? null : $address; is not make the query when $person->Address is needed

try by using a another property name to pin point the issue

for example:

$person->someAddress = $address->id === null ? null : $address;

Hm you're right, changing the alias to something different fixed it in the above example. It seems like the alias is clashing with the model name (this should perhaps be documentated as a note).

However, the above code is a sample of a bigger code I'm actually working on, and in that code there's an additional step between a controller and the model, and it's a service.

So after changing the alias like you suggested (from Address to someAddress), the code above works, but if I additionally change the code to:

class DebugController extends Controller
{
    public function index(): string
    {
        $companyIds = [1, 2];
        foreach ($companyIds as $companyId) {

            // the original call is now encapsulated in a service method
            // which returns a single ?Person object
            $person = PersonService::fetchFirst($companyId);

            if ($person !== null) {
                echo $person->id . " + " . $person->someAddress->id;
            }
        }

        return 'OK';
    }
}

Where PersonService is:

class PersonService extends Injectable
{
    public static function fetchFirst(int $companyId): ?Person
    {
       // the same method as from previous code, but encapsulated in a service
        $persons = Person::fetchByCompanyId($companyId);

        if (count($persons) === 0) {
            return null;
        }

        return $persons[0];
    }
}

(Please don't mind the logic of the fetching, it's just for testing purposes).

Now if I execute the same code above, it throws the segfault error again, even with the updated alias name: [core:notice] [pid 1] AH00052: child pid 29 exit signal Segmentation fault (11)



7.8k

Dylan Anderson is probably right.

if its your code it should produce a php error but you can try using different versions of phalcon, php or both



1.1k

Alright, thanks! I submitted the issue here.