Description
Description
We’re seeing this issue when we try to migrate our solution from .NET 6 to .NET 8.
Once we got the code compiling and running, our application freezes. I guess something changed from .NET 6 to .NET 8 that isn’t apparent.
After some digging around, this is what I've found.
We have some 3rd party objects that implement IDispose
. The 3rd party objects seems to do a lock (this) {}
in their Dispose
and it is out of our control.
Now when we instantiate an instance of this object inside a using {}
block, the code hangs at the closing scope.
key.Down() returns a new instance of SegmentKey
(as far as I can tell from VS decompilation) with some vendor bookkeeping logic.
If we remove the using
block, the GC thread will freeze (eventually) – I’m assuming that it’s also hitting the lock.
This is what our code looks like when it freezes:
public static bool HasSubkey(this SegmentKey key, string name)
{
using (SegmentKey subkey = key.Down(name, false))
{
try
{
return subkey.Name() == name;
}
catch { }
} // freezes here
return false;
}
This is what the SegmentKey’s (3rd party) Dispose looks like from VS decompilation:
public override void Dispose()
{
lock (this) // debugger says that we freeze here
{
.
.
.
}
}
Looking into this, I peeked around the memory and cross referenced with documentation on how CLR objects work (https://mycodingplace.wordpress.com/2018/01/10/object-header-get-complicated/). I see this:
If my understanding is correct, that value of 0x0100007f
indicates that our object is BIT_SBLK_SPIN_LOCK
’ed.
I thought maybe the vendor is doing something silly, so I experimented with a plain C# object. It too had BIT_SBLK_SPIN_LOCK
(among other bits set).
If I try to lock o, then the thread freezes – even if I do so directly after allocation:
public static bool HasSubkey(this SegmentKey key, string name)
{
System.Object o = new System.Object();
lock (o) { } // freezes on lock
using (SegmentKey subkey = key.Down(name, false))
{
try
{
return subkey.Name() == name;
}
catch { }
}
return false;
}
I don't think threads are involved. This is all happening on the main thread. It seems like the main thread is deadlocking itself.
For me, this is 100% reproducible on .NET 8. It always happens on the 4th call to HasSubKey
(which I determined by counting breakpoint hits).
I tried clearing out the bin/ directory and forcing a clean rebuild. Didn't help.
I’ve also tried the clrgc
trick from this post: https://maoni0.medium.com/is-the-regression-in-gc-or-something-else-38f10018dd21 (which I discovered after reading through #95191). I was successfully able to load clrgc, but it didn’t have any noticeable effect on preventing the freeze.
Reproduction Steps
not sure if I can provide a sandboxed repro steps
Expected behavior
a newly instantiated object isn't locked
Actual behavior
a newly instantiated object is locked
Regression?
No response
Known Workarounds
No response
Configuration
Windows 11 x64
trying to migrate .NET 6 -> 8
Other information
Not sure if this is useful, I think if you try to do Monitor.TryLock()
on this object, the function never returns -- and the thread deadlocks as well
Metadata
Metadata
Assignees
Type
Projects
Status