Skip to content

Possible infinite recursion when relinking model members #651

@rileyjmurray

Description

@rileyjmurray

Affecting pyGSTi 0.9.14.1 (develop), and probably also the penultimate release of 0.9.13.

Here's a minimal snippet that can always reproduce the issue.

from copy import deepcopy
from pygsti.modelpacks import smq1Q_XYI
tm = smq1Q_XYI.target_model('full TP')
op = tm.operations[()]
deepcopy(op)  # infinite recursion in DenseOperatorInterface.__getattr__

I encountered this issue just when copying lists of ExplicitOpModels: ExplicitOpModel.copy() triggers calls to ModelMember.copy(), which triggers calls to copy.deepcopy() on ModelMember objects. As copy.deepcopy()'s magic starts to recurse back up, we end up calling ExplicitOpModel.__setstate__(), which triggers calls to the ModelMember.relink_parent, which tries to evaluate the expression self._parent (as an accessor, not a setter). Depending on the context, this can trigger calls to custom __getattr__ functions that inadvertently break (with an infinite recursion) when '_parent' in self.__dict__ is False.

Here's a corrected implementation for ModelMember.relink_parent:

    def relink_parent(self, parent):
        for subm in self.submembers():
            subm.relink_parent(parent)    
        if '_parent' in self.__dict__:
            if self._parent is parent:
                return  # OK to relink multiple times
            assert(self._parent is None), "Cannot relink parent: current parent is not None!"
        self._parent = parent  # assume no dependent objects

Interestingly, the possibility of infinite recursion was noted in the implementation of DenseOperatorInterface.__getattr__.

Image

Metadata

Metadata

Assignees

Labels

bugA bug or regressionfixed but not in release yetBug has been fixed, but isn't in an official release yet (just exists on a development branch)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions