I'm facing a troubling situation.
I've got a dictionary which holds a null key entry...
This happens from time to time in my iis application, which then freezes when a lookup is performed on this dictionary (100% cpu, infinite loop):
Sources of FindEntry method (both uncompiled or reference sources) are pretty clear:
1) Having a null key in a dictionary is NOT possible
2) The infinite loop is pretty obvious given my dictionary private field:
Any idea on happens to me ?
ps: I do not have any funny thing installed like ryujit or custom .net build.
Just a regular iisexpress running under .Net 4.5
As requested (i should have precised): I'm not doing anything funny with this dictionary either.
Only one usage:
if (!readers.TryGetValue(type, out ret))
readers[type] = ret = GetReaderOfTMethod.MakeGenericMethod(type).Invoke(this,null);
If this dictionary isn't restricted to a single thread (created within a method and used there, but stored statically) then I'd expect this to happen.
Dictionary is written, like any other code, with assumptions about what can have previously happened to it. These assumptions don't consider simultaneous calls so e.g. it's assumed that if the dictionary is being resized, that the resize won't happen again until that resize is finished, that only one attempt will be made to set a given value at a time, and so on.
Don't guard against this, and two calls can put the dictionary into a state that its coders didn't consider and then things that don't make sense can happen, like having a null key even though null keys aren't allowed.
If such simultaneous use isn't going to be common (and it would seem it won't), then guard every access with a lock:
lock(lockObj) if (!readers.TryGetValue(type, out ret)) readers[type] = ret = GetReaderOfTMethod.MakeGenericMethod(type).Invoke(this,null);
lockObj is an object at the same scope as
readers which is used to lock all access to it. (Likely
readers would work well as the lock object itself here, but when that is and isn't a good idea is another topic in itself).
If there are any other uses of
reader they should also be locked using the same lock object*.
If such simultaneous use is going be common then a concurrent dictionary that is designed to tolerate such uses would be better (
ConcurrentDictionary in the framework, or my
ThreadsafeDictionary will both work). These tend to be less efficient generally, but more efficient above a certain level of concurrent uses.
*Actually, if both the key and value type of the dictionary are reference types, the implementation of
Dictionary is such that you should be okay only locking on writes, but there's no guarantee of that, so I wouldn't advise risking it.