jso0 / runsharp

Automatically exported from code.google.com/p/runsharp
MIT License
2 stars 0 forks source link

KeyNotFoundException in CacheEntry's finalizer #25

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
A weird, random thing happened to me today: cache[t] threw KeyNotFoundException 
in CacheEntry's finalizer, where t was typeof(Int64).

~CacheEntry()
{
    lock (cache)
    {
        if (cache[t].Target == this || cache[t].Target == null)
            cache.Remove(t);
    }
}

I thought of a way this bug could be triggered:

(1) Someone calls GetCacheEntry(Int64), which locks the cache
(2) The finalizer for the CacheEntry of Int64 starts and cannot acquire the 
lock, so it enters a wait state
(3) GetCacheEntry can't find Int64 in the cache so it creates a new CacheEntry 
for it
(4) GetCacheEntry releases the lock and the finalizer of CacheEntry acquires it
(5) Int64 is removed from the cache, but a second CacheEntry for Int64 still 
exists
(6) The finalizer of the second CacheEntry is called at some later time, which 
causes the KeyNotFoundException.

Workaround (not sure if it's perfectly safe): ~CacheEntry should use 
cache.TryGetValue instead.

Original issue reported on code.google.com by qwertie...@gmail.com on 5 Jan 2011 at 12:52

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
Ack. There is a mistake in how I described step 3 (should be: the 
WeakReference.Target is null), and I just realized my theory is wrong because 
of how ~CacheEntry is written. So I really don't know what's going on :O

Original comment by qwertie...@gmail.com on 5 Jan 2011 at 12:56

GoogleCodeExporter commented 9 years ago
I ran into this today (took down our IIS process):

Application: w3wp.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Collections.Generic.KeyNotFoundException
Stack:
   at TriAxis.RunSharp.TypeInfo+CacheEntry.Finalize()

Any clue on what could be wrong?

Original comment by T...@aimproductions.be on 9 Dec 2013 at 8:28

GoogleCodeExporter commented 9 years ago
Hi,

this issue has already been reported and fixed in the source quite some time 
ago (Issue 12 and 21, 
https://code.google.com/p/runsharp/source/detail?r=046d87743a5eb71dfe60e6d9afbba
e4af623ac48)

A bit of detail about what's (most likely) happening:
1. a cache entry for type T is garbage collected and goes to the finalizer queue
2. before the actual finalizer runs, TypeInfo for the same type T is requested 
again - this creates a new instance and updates the cache dictionary
3. one more collection occurs before the finalizer runs (maybe because the 
finalizer thread is waiting for a lock on cache, but this doesn't really matter)
4. at this point, there are two CacheEntry objects waiting for finalization and 
the WeakReference in the cache is already invalid (thus Target == null)
5. the first finalizer runs and removes the WeakReference from the cache, even 
though it was the reference actually created by the second CacheEntry
6. the second finalizer runs and down we go...

However, as I've said, this has been fixed years ago. In general, I recommend 
using the tip of the source tree - it contains a few fixes over the 0.1.2 
release, and is more or less what was to become 0.2 if I ever found the time to 
write some docs.

Also, I'm quite surprised to find out that people are actually using it :) 
Unfortunately, I've lost control of the project (because I've deleted the 
owning google account quite some time ago) and in reality, I don't have the 
time required to maintain it properly. So please, if anyone watching this finds 
the library useful and feels like maintaining it, go ahead, fork it and move it 
somewhere else or try to persuade Google to transfer ownership or something...

Best Regards,
Stefan

Original comment by si...@triaxis.sk on 9 Dec 2013 at 7:54