runtime: Returning an object initialized with a using {} block results in null on Linux but works on Windows

Debugging my server sample I found that on Linux if you return the object defined with a using {} block of code it will result in null from the caller. However this works on Windows. Not sure which resulting behavior is correct from a language / platform point of view but wanted to call out the discrepancy between the runtime on Linux vs Windows.

Example code that works on Windows, but results in a null object on Linux:

        /// <summary>
        /// Creates a ECDsa instance with the specified curve
        /// </summary>
        /// <param name="Curve">ECCurve value</param>
        /// <returns>ECDsa instance</returns>
        public static ECDsa Create(ECCurve Curve)
        {
            using (var ecdsa = ECDsa.Create(Curve))
            {
                return ecdsa;
            }
        }

To fix this on Linux you need to remove the using variable to avoid the null.

        /// <summary>
        /// Creates a ECDsa instance with the specified curve
        /// </summary>
        /// <param name="Curve">ECCurve value</param>
        /// <returns>ECDsa instance</returns>
        public static ECDsa Create(ECCurve Curve)
        {
                return ECDsa.Create(Curve);
        }

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 15 (11 by maintainers)

Most upvoted comments

As far as I can tell, the core issue was correctly identified by @jnm2: You’re using a disposed object. When you do that, there is no guarantee that it will work, which is why you’re getting an exception on Linux. Though you should not get NullReferenceException, the right exception kind would be ObjectDisposedException. It works on Windows, because Windows has a completely different implementation, where ExportParameters still works after Dispose().

Note that you’re never getting a null object in your code, the NullReferenceException is thrown from the implementation of ExportParameters.

What I think should be done:

  1. Consider whether ExportParameters should work on Linux even after the object has been disposed, to make it more consistent with Windows.

    My opinion is that this is not worth doing. If the user uses a disposed object, they have a bug and throwing an exception is okay in that case.

    If it’s decided that this still should not work, the code should still be changed, to ensure it throws ObjectDisposedException, not NullReferenceException.

  2. Consider whether ExportParameters should be changed on Windows to throw if the object has been disposed, to make it more consistent with Linux.

    This would be a breaking change. And even though it’s only breaking code that is incorrect, it’s probably not worth changing.


For the record, the code in question is:

“Consider whether ExportParameters should work on Linux even after the object has been disposed”. If you make this change you will have introduced a security vulnerability because the object must actually be disposed.

The bug on Windows is that Dispose put the object into a state that looked like no key had been generated again, so ExportParameters actually caused a new key to be generated, then exported (keys aren’t generated by the ctor, so that Import isn’t wasteful). It’s not that Dispose did nothing, or kept the key/keyref alive too long.

That said, the fix will be that both implementations should be throwing an ObjectDisposedException, not one doing accidental state reset and the other throwing a NullReferenceException.

            using (var ecdsa = ECDsa.Create(Curve))
            {
                return ecdsa;
            }

Why are you returning a disposed object?

You’d still not return a disposed object because disposed objects should not be interacted with.