Status: Accepted
Owner: ----
Labels: Type-Defect Priority-High Core

New issue 3130 by [email protected]: Unpickling a Symbol with protocol 2 corrupts the cache
http://code.google.com/p/sympy/issues/detail?id=3130

Here's a minimal demo of the problem:

In [1]: import pickle

In [2]: pickle.loads(pickle.dumps(Symbol('a', even=True), 2))
Out[2]: a

In [3]: Symbol('a').is_even
Out[3]: True

Let's replay the scene in slow-motion:

* First, while instantiating a1 = Symbol('a', even=True), the cache system stores something like cache[Symbol, ('a',), {'even': True}] = a1. No problem here.
* Then, dumps(a1) is effectively equivalent to:
    args = a1.__getnewargs__()
    state = a1.__getstate__()
Here, args is just (a1.name,) == ('a',) while state is equal to what a1.__dict__ would be if there were no __slots__ declarations.
* Then, the loads() call does effectively:
    a2 = Symbol(*args)
    a2.__setstate__(state)
The instantiation of a2 puts cache[Symbol, ('a',), {}] = a2 in the cache, but then __setstate__ copies over the attributes of a1 into a2, including its _assumptions dict, which causes a2.is_even == True. * And finally, the last call to Symbol('a') finds that there is already a cached entry for cache[Symbol, ('a',), {}] and returns a2 directly.

I don't know how we should fix this mess, but I think that pickling shouldn't rely on __slots__ (it serialises too much) and that the cache shouldn't store the name of the Symbol since that doesn't save any processing.


--
You received this message because you are subscribed to the Google Groups 
"sympy-issues" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sympy-issues?hl=en.

Reply via email to