В чем причина этого OutOfMemoryException для конструктора Mutex?

Я получаю System.OutOfMemoryException в этой строке кода:

mutex2 = new Mutex(true, "Name2");

Вот стек:

{"Exception of type 'System.OutOfMemoryException' was thrown."}
 at Microsoft.Win32.Win32Native.CreateMutex(SECURITY_ATTRIBUTES lpSecurityAttributes, Boolean initialOwner, String name)
 at System.Threading.Mutex.CreateMutexHandle(Boolean initiallyOwned, String name, SECURITY_ATTRIBUTES securityAttribute, SafeWaitHandle& mutexHandle)
 at System.Threading.Mutex.MutexTryCodeHelper.MutexTryCode(Object userData)
 at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
 at System.Threading.Mutex.CreateMutexWithGuaranteedCleanup(Boolean initiallyOwned, String name, Boolean& createdNew, SECURITY_ATTRIBUTES secAttrs)
 at System.Threading.Mutex..ctor(Boolean initiallyOwned, String name, Boolean& createdNew, MutexSecurity mutexSecurity)
 at System.Threading.Mutex..ctor(Boolean initiallyOwned, String name)
 at Foo.FooDefinitions.FooManager.FooForm.FooForm_Load(Object sender, EventArgs e) in c:\tfs\DWS\TRUNK\DEV\FooDefinitions\FooManager\FooForm.cs:line 92

Это произойдет только тогда, когда я использую олицетворение. Без олицетворения (работает на моей обычной учетной записи Windows) он будет работать нормально. Выдача олицетворения выглядит примерно так:

if (!NativeMethods.LogonUser(userName, domainName, password, 2, 0, ref this._tokenHandle)) // [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
 {
 throw new Win32Exception(Marshal.GetLastWin32Error());
 }
 this._impersonatedUser = new WindowsIdentity(this._tokenHandle).Impersonate();

РЕДАКТИРОВАТЬ. Я просто создаю автоматические тесты для устаревшего кода. Я бы удалил использование мьютексов, если мог. В настоящее время я изучаю SecurityCriticalAttribute в конструкторе Mutex.

EDIT2. Вот полный пример кода:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.ComponentModel;
using System.Net;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Threading;
namespace ReinierDG.MutexTesting
{
 [TestClass]
 public class MutexTest
 {
 [TestMethod]
 public void CreateMutexUnderImpersonation()
 {
 var credentials = new NetworkCredential("testagent", "secretpassword");
 var tokenHandle = new IntPtr();
 if (!NativeMethods.LogonUser(credentials.UserName, credentials.Domain, credentials.Password, 2, 0, ref tokenHandle))
 {
 throw new Win32Exception(Marshal.GetLastWin32Error());
 }
 var impersonatedUser = new WindowsIdentity(tokenHandle).Impersonate();
 // this will run indefinately or untill memory is full with 1 cpu core at 100%
 var mutex = new Mutex(true, "test");
 }
 internal static class NativeMethods
 {
 [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
 internal static extern bool LogonUser([MarshalAs(UnmanagedType.LPWStr)]string lpszUsername, [MarshalAs(UnmanagedType.LPWStr)]string lpszDomain, [MarshalAs(UnmanagedType.LPWStr)]string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
 }
 }
}
2 ответа

Вы можете использовать LOGON32_LOGON_NEW_CREDENTIALS (9) как LogonType и LOGON32_PROVIDER_WINNT50 (3) как LogonProvider, это будет успешным. Я думаю об этом авторитете.

Когда вы отлаживаете его в своем коде, вы можете найти его в бесконечном цикле , mutexHandle = Win32Native.CreateMutex(securityAttribute, initiallyOwned, name); не удалось с ERROR_ACCESS_DENIED. Он будет запускать Win32Native.OpenMutex(Win32Native.MUTEX_MODIFY_STATE | Win32Native.SYNCHRONIZE, false, name);, но также не удалось выполнить ERROR_FILE_NOT_FOUND


// this will run indefinately or untill memory is full

Ну, это будет одно объяснение. Мы должны будем предположить, что комментарий просто не соответствует коду. Наиболее очевидная проблема заключается в том, что вы не опубликовали трассировку стека, которая достаточно уместна для ошибки и не поможет вам диагностировать основную проблему. Я могу только сообщать подсказки, чтобы довести вас до следующего этапа.

Слишком легко предположить, что сработала функция CreateMutex(). Это, однако, не так, отказ этой функции winapi сообщается по-разному, вы увидите __Error.WinIOError() обратно в трассировку стека. И код ошибки будет другим, вы получите ошибку 1450, ERROR_NO_SYSTEM_RESOURCES, "Недостаточно системных ресурсов для завершения запрошенной службы".

На самом деле CLR выбрасывает исключение. Или, другими словами, это pinvoke marshaller не удался. Это значительно усложняет диагностику, существует очень большое количество мест в очень большом количестве кода, где он может бросать OOM. Часто приходится выделять неуправляемую память для выполнения задания pinvoke, если это не удается, вы получаете OOM-kaboom. Много способов, которые могут произойти, внутреннего неуправляемого разлома кучи, конечно, достаточно. Ваше объявление LogonUser() pinvoke технически неверно (CharSet.Auto!= UnmanagedType.LPWStr), но недостаточно для объяснения этой проблемы.

Вам нужно приблизиться к корню исключения и потребовать включения неуправляемого отладчика. Для VS2015 используйте "Проект" > "Свойства" > вкладка "Отладка" > отметьте флажок "Включить отладку собственного кода". Вам потребуется отладочные символы для CLR, чтобы понять трассировку стека. Используйте "Инструменты" > "Параметры" > "Отладка" > "Символы" > отметьте "Microsoft Symbol Server". Вам нужно сделать остановку отладчика в случае исключения с первым шансом, использовать Debug > Windows > Exception Settings > tick "Win32 Exceptions".

Теперь вы узнаете намного больше, вы можете опубликовать гораздо более качественную трассировку стека в своем вопросе. Тем не менее, вероятность того, что это даст пользователям SO, или кристально чистую диагностику, которая показывает, как эта ошибка может быть объяснена олицетворением, далека. Вызов с помощью поддержки Microsoft будет разумным, однако им нужно будет узнать намного больше о том, как именно настроена учетная запись "testagent". Имейте в виду, что такие учетные записи часто преднамеренно искалечены, чтобы гарантировать, что модульные тесты не могут требовать слишком много системных ресурсов.

licensed under cc by-sa 3.0 with attribution.