This appears to be a bug and the .NET team is tracking it.  It's
considered a relative corner case so it may not be a high priority fix.

Here's some research that Vladimir did on this.

<snip>

There is a bug/'deadlock issue'. There is a mechanism to release the
lock if an exception is thrown inside a synchronized method, so if the
commented out code below in 'foo' is used instead of the current body of
'foo' there is no deadlock. But if you do modify the 'this' pointer the
second thread deadlocks, regardless of if 'foo' throws an exception or
not.

 
////////////////////////////
.assembly extern mscorlib {}
.assembly test {}
.class private auto ansi beforefieldinit Test
       extends [mscorlib]System.Object
{
  .method public hidebysig newslot virtual
          instance void  foo() cil managed synchronized
  {
    ldnull
    starg 0
    //newobj     instance void ['mscorlib']System.Exception::.ctor()
    //throw
    //ldstr      "After throw"
    //call       void ['mscorlib']System.Console::WriteLine(string)
    ret
  }
 
  .method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    .locals init (class Test V_1, class
[mscorlib]System.Threading.Thread V_2)
    .try {
      newobj     instance void Test::.ctor()
      stloc.0
      ldloc.0
      callvirt   instance void Test::foo()
      leave.s   SecondCall
    }
    catch ['mscorlib']System.Exception 
    {
        pop
        ldstr      "Inside catch"
        call       void ['mscorlib']System.Console::WriteLine(string)
        leave.s   SecondCall
    }  // end handler
SecondCall:
    .try {
        ldloc.0
        ldftn   instance void Test::foo()
        newobj  instance void
[mscorlib]System.Threading.ThreadStart::.ctor(object, native int)
        newobj     instance void
[mscorlib]System.Threading.Thread::.ctor(class
[mscorlib]System.Threading.ThreadStart)
        stloc.1
        ldloc.1
        callvirt   instance void
[mscorlib]System.Threading.Thread::Start()
        ldloc.1
        callvirt   instance void
[mscorlib]System.Threading.Thread::Join()
        leave.s    EndIL
      }
      catch ['mscorlib']System.Exception 
      {  
        pop
        ldstr      "Inside catch2"
        call       void ['mscorlib']System.Console::WriteLine(string)
        leave.s    EndIL
      }  // end handler
EndIL:
    ret
  }

  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }
}
////////////////////////////
</snip>

This posting is provided "AS IS" with no warranties, and confers no
rights.

-----Original Message-----
From: Jeroen Frijters [mailto:[EMAIL PROTECTED]] 
Sent: Wednesday, June 12, 2002 9:29 AM
To: [EMAIL PROTECTED]
Subject: Bug?


The code below throws an exception:

Unhandled Exception: System.ArgumentNullException: Value cannot be null.
   at System.Threading.Monitor.Exit(Object obj)
   at Test.foo()
   at Test.Main()

Is this correct behavior? I understand why it is happening, but from my
reading of the spec, this behavior is incorrect.

BTW, the commercial implementation behaves the same (although the
Monitor.Exit line is missing from the stack trace, so I guess it inlines
that).

Regards,
Jeroen

//////////////////// start /////////////////////

.assembly extern mscorlib {}
.assembly test {}

.class private auto ansi beforefieldinit Test
       extends [mscorlib]System.Object
{
  .method public hidebysig newslot virtual
          instance void  foo() cil managed synchronized
  {
    ldnull
    starg 0
    ret
  }

  .method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    newobj     instance void Test::.ctor()
    callvirt   instance void Test::foo()
    ret
  }

  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }
}

//////////////////// end /////////////////////

Reply via email to