Skip to content
This repository has been archived by the owner on Sep 14, 2018. It is now read-only.

Hard crash with copy.copy() copying proxy object #1192

Open
pekkaklarck opened this issue Apr 9, 2015 · 2 comments
Open

Hard crash with copy.copy() copying proxy object #1192

pekkaklarck opened this issue Apr 9, 2015 · 2 comments

Comments

@pekkaklarck
Copy link

The following example crashes IronPython 2.7.5 for good. I first get a dialog telling "IronPython Console has stopped working" and after closing it "Process is terminated due to StackOverflowException." is printed to the command prompt.

import copy

class Proxy(object):

    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, attr):
        return getattr(self.obj, attr)

class Object(object):
    attr = 1

copy.copy(Proxy(Object()))
@pekkaklarck
Copy link
Author

A workaround for this problem is creating a custom __copy__ method. For example this works fine:

import copy

class Proxy(object):

    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, attr):
        return getattr(self.obj, attr)

    def __copy__(self):
        return Proxy(copy.copy(self.obj))

class Object(object):
    attr = 1

copy.copy(Proxy(Object()))

pekkaklarck added a commit to robotframework/robotframework that referenced this issue Apr 10, 2015
Creating custom __copy__ required small changes to how embedded args
objects are created. Also made all attributes needed only by embedded
args private to avoid masking attributes by proxied handler objects.

This is related to #1818 and the IronPython bug is
IronLanguages/main#1192
@kunom
Copy link
Contributor

kunom commented May 9, 2015

The underlying issue is that a call to hasattr(clone, '__setstate__') leads to an infinite loop in Proxy.__getattr__ since the clone instance does not (yet) have an obj member.

CPython has identical behaviour, but somehow stops recursion without crashing after a nesting level of 331 (in my case).

In any case, the current implementation of the Proxy class seems to be suboptimal at least with regard to the copy module.

Test code:

o = Proxy(Object())

reductor = getattr(o, "__reduce_ex__", None)
print "reductor =", reductor
info = reductor(2)
print "info =", info
callable, args = info[:2]
print "callable, args =", callable, args
y = callable(*args)
print "inst =", y
hasattr(y, '__setstate__')

Output:

reductor = <built-in method __reduce_ex__ of Proxy object at 0x000000000000002B>
info = (<built-in function __newobj__>, (<class '__main__.Proxy'>,), {'obj': <Object object at 0x000000000000002C>}, None, None)
callable, args = <built-in function __newobj__> (<class '__main__.Proxy'>,)
inst = <Proxy object at 0x000000000000002D>

Process is terminated due to StackOverflowException.

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

No branches or pull requests

4 participants