VB.NET: Async method state machine "losing" locals - Release only (Async/Await + Try/Finally + For) #9001
Labels
Area-Compilers
Bug
Resolution-Duplicate
The described behavior is tracked in another issue
Tenet-Compatibility
Violation of forwards/backwards compatibility in a design-time piece.
Verification Not Required
I've come across a very strange
NullReferenceException
issue which only manifests itself when building in Release configuration (with Advanced Compile Options -> Enable optimizations enabled).This occurs in
Async
methods (bothTask
-returning andAsync Sub
) which have aTry/Finally
block where theTry
contains aFor
loop, which in turn contains anAwait
statement. When a local variable pointing to a reference type instance is declared before such aTry/Finally
and accessed inside theFinally
, an "impossible"NullReferenceException
is thrown.Here is a complete Console application demonstrating the issue when built with VS2015 (targeting .NET4.5, Release):
Analysis
Looking at the Release binary with ILDASM, the compiler-generated
VB$StateMachine_1_TestAsync
is missing the following field definition:Here are the relevant bits of
MoveNext
IL in Debug (works fine):VS Release (throws):
The above works fine if the
Await
completes synchronously, but if not - the local is uninitialized afterAwait
, hence theNullReferenceException
.Environment
The above has been reproduced using:
Addendum
If
obj
isIDisposable
, you can replaceTry/Finally
with aUsing
statement and then the problem is even worse due to the null check auto-inserted by the compiler before theobj.Dispose
call, meaning thatNullReferenceException
is never thrown -Dispose
simply doesn't get called, i.e.The text was updated successfully, but these errors were encountered: