You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@logging.apache.org by "Matt Grimwade (Jira)" <ji...@apache.org> on 2020/03/13 09:31:00 UTC

[jira] [Created] (LOG4NET-646) RendererMap not threadsafe (IndexOutOfRangeException)

Matt Grimwade created LOG4NET-646:
-------------------------------------

             Summary: RendererMap not threadsafe (IndexOutOfRangeException)
                 Key: LOG4NET-646
                 URL: https://issues.apache.org/jira/browse/LOG4NET-646
             Project: Log4net
          Issue Type: Bug
          Components: Core
    Affects Versions: 2.0.8
            Reporter: Matt Grimwade


Concurrent calls to code such as
{code}
loggerRepository.RendererMap.FindAndRender(new { Foo = "bar" });
{code}
occasionally fail with
{code}
System.IndexOutOfRangeException: Index was outside the bounds of the array.
    at System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add)
    at log4net.ObjectRenderer.RendererMap.Get(Type type)
    at log4net.ObjectRenderer.RendererMap.FindAndRender(Object obj, TextWriter writer)
{code}

Once this has occured, further calls to RendererMap throw. This causes total failure of the logging system.

This appears to be because log4net.ObjectRenderer.RendererMap is not thread-safe. Internally it holds two Hashtables, {{m_map}} and {{m_cache}}. The first uses a synchronized wrapper and the second does not.

From https://docs.microsoft.com/en-us/dotnet/api/system.collections.hashtable?view=netframework-4.8:
{quote}
Hashtable is thread safe for use by multiple reader threads and a single writing thread. It is thread safe for multi-thread use when only one of the threads perform write (update) operations, which allows for lock-free reads provided that the writers are serialized to the Hashtable. To support multiple writers all operations on the Hashtable must be done through the wrapper returned by the Synchronized(Hashtable) method, provided that there are no threads reading the Hashtable object.
{quote}

So when two threads attempt to mutate the cache concurrently its internal state is corrupted.

A solution (at least for .NET Framework 4.0 onwards) might be to replace both with a ConcurrentDictionary<Type, IObjectRenderer> accessed via its GetOrAdd method.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)