#14471: Exception KeyError: in WeakValueDictionary remove ignored
---------------------------+------------------------------------------------
       Reporter:  vbraun   |         Owner:  rlm      
           Type:  defect   |        Status:  new      
       Priority:  major    |     Milestone:  sage-5.10
      Component:  memleak  |    Resolution:           
       Keywords:           |   Work issues:           
Report Upstream:  N/A      |     Reviewers:           
        Authors:           |     Merged in:           
   Dependencies:           |      Stopgaps:           
---------------------------+------------------------------------------------

Comment (by nbruin):

 Replying to [comment:7 vbraun]:
 > Fair enough, but even after I catch the !KeyError the `wr.key in
 self.data.keys()` is still `True`. So the `self.data` dict is in a weird
 place for sure.

 That is weird, and sounds to me like `self.data` is indeed corrupted.
 Given that key/value pairs are stored together in a dictionary, it's very
 hard for this to be true too. Caching the result from data.keys wouldn't
 make sense at all, so I don't think python will be doing that. Perhaps
 check that something like `wr.key in self.data` or
 `self.data.__contains__(wr.key)` returns true and/or if
 `value=self.data[wr.key]` succeeds (and what kind of value you get back:
 whether it's `wr`)

 That might give you some indication of what exactly is wrong with the
 entry and hence where the problem might be coming from.

 One thing your traceback is confirming:
  - There is no GC going on, so callbacks are happening when you think they
 should.
  - Hence there's also not a circular data structure directly involved
  - Things are happening during cleanup, so these callbacks are probably
 indeed happening on a dict that will be deleted too. It's still bad they
 don't properly execute, of course, but we've seen before that order in
 cleanup can sometimes lead to subtle problems (i.e., whether things are
 stored in a cdef attribute or in a conventional dict).

 One possible scenario:
  - self.data is in the process of being cleared. The dict is actually
 emptied then before any entries are decreffed (to prevent dict reshaping
 during deallocation).
  - One of the weakreffed values also occurs as a key in the dict (and
 that's the only strong ref)
  - decreffing that key causes the callback, but the callback finds a dict
 that is now empty, so of course we get a key error.

 Your diagnosis that `wr.key in self.data` is still true is not consistent
 with that, but the scenario indeed leads to ignored keyerrors:

 {{{
 import weakref

 class A(object):
   def __init__(self,n):
     self.n=n
   def __repr__(self):
     return "A(%d)"%self.n

 def mess(n):
   D=weakref.WeakValueDictionary()
   L=[A(i) for i in range(n)]
   for i in range(n-1):
       j=(i+10)%n
       D[L[i]]=L[j]
   return D

 D=mess(10000)
 D.clear()
 }}}

 (how many you ignored keyerrors you get depends a bit on memory layout
 etc.)

 This is definitely a bug in the python library. The problem is that
 `remove` does check if the dict still exists (via the weakref, which is
 mainly to ensure that presence of callbacks doesn't extend the life of the
 dict), but doesn't check if the dict is otherwise in a funny state, such
 as "in the process of a `clear`".

-- 
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/14471#comment:9>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to