2016-08-08 52 views
4

Ich erhalte eine System.OutOfMemoryException auf dieser Codezeile:Was ist die Ursache für diese OutOfMemoryException beim Mutex-Konstruktor?

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

Hier ist die Stacktrace:

{"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 

Es tritt nur dann auf, wenn ich den Identitätswechsel verwenden. Ohne Identitätswechsel (läuft auf meinem normalen Windows-Account) läuft es gut. Der Identitätswechsel ist so etwas wie dieses:

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(); 

EDIT: Nur um eloborate, ich schaffe automatisierte Tests auf Legacy-Code. Ich hätte die Verwendung von Mutexen entfernt, wenn ich könnte. Ich untersuche gerade die SecurityCriticalAttribute auf dem Mutex-Konstruktor.

EDIT2: Hier ist ein vollständiges Beispiel des Codes:

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); 
     } 
    } 
} 
+4

[hier] (http://referencesource.microsoft.com/#mscorlib/system/threading/mutex.cs,434) ist die Quelle. Es zeigt "CreateMutex" in einem 'while (true)'; Vielleicht hast du einen Endlosschleife Bug gefunden? – Quantic

+2

Code Ihrer 'FooForm.FooForm_Load' Methode – giammin

+0

aber vor allem: Sind Sie sicher, dass Sie einen Mutex brauchen? in einem Formular laden Ereignis ??? – giammin

Antwort

7
// this will run indefinately or untill memory is full 

Nun, das wäre eine Erklärung. Wir müssen davon ausgehen, dass der Kommentar nicht mit dem Code übereinstimmt. Das offensichtlichste Problem hier ist, dass Sie keinen Stack-Trace gepostet haben, der relevant genug für den Fehler ist und Ihnen nicht hilft, das zugrunde liegende Problem zu diagnostizieren. Ich kann nur Hinweise veröffentlichen, um Sie zur nächsten Stufe zu bringen.

Es ist zu einfach anzunehmen, dass CreateMutex() fehlgeschlagen ist. Das ist jedoch nicht der Fall, ein Fehler dieser winapi-Funktion wird anders gemeldet, Sie würden __Error.WinIOError() zurück im Stack-Trace sehen. Und der Fehlercode wäre anders, Sie erhalten den Fehler 1450, ERROR_NO_SYSTEM_RESOURCES, "Es sind nicht genügend Systemressourcen vorhanden, um den angeforderten Dienst auszuführen".

Es ist in der Tat die CLR, die die Ausnahme ausgelöst hat. Oder mit anderen Worten, es ist die Pinvoke Marshaller, die fehlgeschlagen ist. Das erschwert die Diagnose erheblich, da es sehr viele Stellen in der sehr großen Menge Code gibt, wo es OOM werfen kann. Es muss oft nicht gemanagter Speicher zugewiesen werden, um den Pinvoke-Job zu erledigen. Wenn dies fehlschlägt, dann erhalten Sie den OOM-kaboom. Viele Möglichkeiten, die passieren können, interne unmanaged Heap Korruption ist sicherlich genug. Ihre LogonUser() -Pinvoke-Deklaration ist technisch falsch (CharSet.Auto! = UnmanagedType.LPWStr), aber nicht falsch genug, um dieses Problem zu erklären.

Sie müssen näher an den Stamm der Ausnahme herantreten, und dazu muss der nicht verwaltete Debugger aktiviert werden. Verwenden Sie für VS2015 Projekt> Eigenschaften> Registerkarte Debugging> aktivieren Sie das Kontrollkästchen Debuggen von systemeigenem Code aktivieren. Sie benötigen Debugging-Symbole für die CLR, um den Stack-Trace zu verstehen. Verwenden Sie Extras> Optionen> Debugging> Symbole> kreuzen Sie "Microsoft Symbol Server" an. Sie müssen den Debugger bei der Ausnahme der ersten Chance stoppen, verwenden Sie Debug> Windows> Exception Settings> Häkchen "Win32 Exceptions".

Sie werden jetzt viel mehr wissen, können Sie eine viel bessere Stack-Trace in Ihrer Frage buchen. Dennoch ist die Wahrscheinlichkeit, dass dies SO-Benutzern oder Ihnen eine kristallklare Diagnose liefert, die zeigt, wie dieses Missgeschick mit einem Identitätswechsel erklärt werden kann, gering. Die Hilfe von Microsoft Support zu verwenden wäre klug, sie müssen jedoch viel mehr darüber wissen, wie genau dieses "testagent" Konto konfiguriert ist. Denken Sie daran, dass solche Konten oft absichtlich verkrüppelt werden, um sicherzustellen, dass Komponententests nicht zu viele Systemressourcen erfordern können.

1

Sie können die LOGON32_LOGON_NEW_CREDENTIALS (9) als LogonType und LOGON32_PROVIDER_WINNT50 (3) als LogonProvider verwenden, es wird erfolgreich.Ich denke, es geht um die authority.

Wenn Sie es in Ihrem Code debuggen, können Sie es in der unendlichen loop finden kann, konnte der mutexHandle = Win32Native.CreateMutex(securityAttribute, initiallyOwned, name); mit ERROR_ACCESS_DENIED. Es läuft Win32Native.OpenMutex(Win32Native.MUTEX_MODIFY_STATE | Win32Native.SYNCHRONIZE, false, name);, aber es scheiterte auch mit ERROR_FILE_NOT_FOUND