Olivier Olivier - 28 days ago 16
C# Question

Null key entry in a dictionary

I'm facing a troubling situation.

I've got a dictionary which holds a null key entry...

null key in dictionary

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):

enter image description here

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:

private fields

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

edit

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);

Answer

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);

Where 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.