Home > Enterprise >  Mutex .ctor inexplicably throws System.UnauthorizedAccessException when given a GUID-like name
Mutex .ctor inexplicably throws System.UnauthorizedAccessException when given a GUID-like name

Time:07-10

I have an ASP.NET app, built for .NET 4.7.2 and running on a variety of Windows servers under IIS, which all use the same App Pool configuration.

I was recently informed about a surprising crashing bug on one of the servers that are running the app. Upon examining the Windows Event Log entries, I saw a stack trace, which pointed to a System.UnauthorizedAccessException being thrown by a System.Threading.Mutex .ctor. The error message was this:

Access to the path '00000000-0000-0000-0000-000000000000' is denied.

This was somewhat surprising, because the code path in question had been routinely handling mutexes with GUID names without any problem for years now. But I did determine that up to until recently, they were all actual GUIDs. Due to a recent code change, there is now also the possibility that the string value of Guid.Empty can be used as a mutex name.

Naturally, I assumed that there is something about the 00000000-0000-0000-0000-000000000000 GUID that Windows OS doesn't like. Maybe it's reserved or something, I thought to myself.

So I, without much further thought, naively arranged things so that a fixed replacement GUID value was going to be used as mutex name instead of Guid.Empty.

Again, to my surprise, a couple of days later I received report about another crashing bug at the exact same place in code! And the error message from Windows Event Log clearly stated the new replacement value, which proved that my naive conclusion was wrong.

I then devised the following test, expecting a crash that would be observable on my machine, under debugger:

// Random GUID name.
var random = new Mutex(false, Guid.NewGuid().ToString());
random.WaitOne();
random.ReleaseMutex();
random.Dispose();

// Empty GUID name.
var zero = new Mutex(false, Guid.Empty.ToString());
zero.WaitOne();
zero.ReleaseMutex();
zero.Dispose();

// Prefixed GUID name.
var adorned = new Mutex(false, "SomePrefix-"   Guid.NewGuid().ToString());
adorned.WaitOne();
adorned.ReleaseMutex();
adorned.Dispose();

As expected, all three cases worked properly under debugger. I haven't yet had the chance to test these cases on the actual server where my ASP.NET app is crashing, because... well, because procedure. I'll get there in the next day or so.

The question I'm trying to answer in the mean time is: why wouldn't these values possibly work on one specific server? Is it a configuration issue? Rights issue? Something about the GUID substrings? Or is it something else entirely?

CodePudding user response:

It turned out that there was indeed a name clash on the server that was running my ASP.NET app. It was another copy of the app which was installed alongside the first and used occasionally for testing different configurations before deploying them to the actual production instance. Doh! Thanks @Hans Kesting for the great hint!

That is why basically any commonly shared GUID value as mutex name (such as '00000000-0000-0000-0000-000000000000', as well as the fixed replacement I tried) could cause this problem. Which is exactly what was observed.

At first, I was tempted to introduce an app-unique prefix to patch the issue, but in the end, I decided to follow @Charlieface's hint, and came up with a different method of synchronization that doesn't involve mutexes, but rather a custom ConcurrentDictionary<string, SemaphoreSlim> repository.

  • Related