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)
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 beObjectDisposedException. It works on Windows, because Windows has a completely different implementation, whereExportParametersstill works afterDispose().Note that you’re never getting a null object in your code, the
NullReferenceExceptionis thrown from the implementation ofExportParameters.What I think should be done:
Consider whether
ExportParametersshould 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, notNullReferenceException.Consider whether
ExportParametersshould 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:
ECDsaImplementation.ECDsaOpenSsl.Dispose,ECOpenSsl.FreeKey,ECDsaImplementation.ECDsaOpenSsl.ExportParametersECDsaImplementation.ECDsaCng.ExportParametersThe 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.
Why are you returning a disposed object?
You’d still not return a disposed object because disposed objects should not be interacted with.