V3083. Unsafe invocation of event, NullReferenceException is possible. Consider assigning event to a local variable before invoking it.


The analyzer detected a potentially unsafe call to an event handler that may result in NullReferenceException. Consider the following example:

public event EventHandler MyEvent;
void OnMyEvent(EventArgs e)
{
    if (MyEvent != null)
        MyEvent(this, e);
}

In this code, the 'MyEvent' field is tested for null, and then the corresponding event is invoked. The null check helps to prevent an exception if there are no event subscribers at the moment when the event is invoked (in this case, MyEvent will be null).

Suppose, however, there is one subscriber to the 'MyEvent' event. Then, at the moment between the null check and the call to the event handler by the 'MyEvent()' invocation, the subscriber may unsubscribe from the event - for example on a different thread:

MyEvent -= OnMyEventHandler;

Now, if the 'OnMyEventHandler' handler was the only subscriber to 'MyEvent' event, the 'MyEvent' field will have a null value, but because in our hypothetical example the null check has already executed on another thread where the event is to be invoked, the line 'MyEvent()' will be executed. This situation will cause a NullReferenceException.

Therefore, a null check alone is not enough to ensure safe event invocation. There are many ways to avoid the potential error described above. Let's see what these ways are.

The first solution is to create a temporary local variable to store a reference to event handlers of our event:

public event EventHandler MyEvent;
void OnMyEvent(EventArgs e)
{
    EventHandler handler = MyEvent;
    if (handler != null)
        handler(this, e);
}

This solution will allow calling event handlers without raising the exception. Even if the event subscriber gets unsubscribed at the point between testing 'handler' for null and invoking it, as in our first example, the 'handler' variable will still be storing the reference to the original handler, and this handler will be invoked correctly despite the fact that the 'MyEvent' event no longer contains this handler.

Another way to avoid the error is to assign an empty handler, with an anonymous method or lambda expression, to the event field at its initialization:

public event EventHandler MyEvent = (sender, args) => {};

This solution guarantees that the 'MyEvent' field will never have a null value, as such anonymous method cannot be unsubscribed (unless it's stored in a separate variable, of course). It also enables us to do without a null check before invoking the event.

Finally, starting with C# version 6.0 (Visual Studio 2015), you can use the '?.' operator to ensure safe event invocation:

MyEvent?.Invoke(this, e);

According to Common Weakness Enumeration, potential errors found by using this diagnostic are classified as CWE-367.

You can look at examples of errors detected by the V3083 diagnostic.


Bugs Found

Checked Projects
346
Collected Errors
13 188