2016-04-13 53 views
5

Durante il test di un'applicazione, ho eseguito uno strano comportamento. Alcuni test utilizzano la rappresentazione per eseguire codice come utente diverso, ma si bloccano sempre, non vengono mai completati.La creazione di mutex si blocca durante l'utilizzo della rappresentazione

Dopo alcune indagini, il problema è stato ridotto all'uso di mutex. Inizialmente, abbiamo utilizzato il nostro codice di rappresentazione basato sullo MSDN documentation, ma anche quando si utilizza il SimpleImpersonation library il problema rimane ancora. Ecco un esempio minimo per riprodurre il problema:

using (Impersonation.LogonUser(DOMAIN, USER, PASSWORD, LogonType.Interactive)) 
{ 
    Console.WriteLine("Impersonated"); 
    bool mine; 
    using (new Mutex(true, "Mutex", out mine)) 
    { 
     if (!mine) 
      throw new Exception("Couldn't get mutex"); 
     Console.WriteLine("Got mutex"); 
    } 
} 

Console.WriteLine("Finished"); 

Questo non finisce mai, si è bloccato sulla linea con la creazione mutex. Lo documentation afferma che deve generare un'eccezione o restituire qualcosa, ma non menziona il blocco.

Alcune altre osservazioni, che potrebbe o non potrebbe essere correlati:

  • se "Rappresenta" l'utente corrente, restituisce immediatamente
  • se corriamo l'effettiva applicazione e avviare un'altra istanza come utente diverso, tutto funziona come previsto

Probabilmente c'è qualcosa in corso con le risorse di sistema sottostanti, ma non siamo riusciti a capirlo. Come fare questo lavoro?

UPDATE: Come per il commento di Hans, ho provato a disattivare Windows Defender, non è stato d'aiuto. Ecco uno stacktrace del luogo in cui è appeso:

[email protected]() 
    [email protected]() 
    mscorlib.ni.dll!719c1867() 
    [Frames below may be incorrect and/or missing, native debugger attempting to walk managed call stack] 
    mscorlib.ni.dll!719c1852() 
    [Managed to Native Transition] 
    mscorlib.dll!System.Threading.Mutex.CreateMutexHandle(bool initiallyOwned, string name, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES securityAttribute, out Microsoft.Win32.SafeHandles.SafeWaitHandle mutexHandle) 
     mscorlib.dll!System.Threading.Mutex.MutexTryCodeHelper.MutexTryCode(object userData) 
    [Native to Managed Transition] 
    [Managed to Native Transition] 
    mscorlib.dll!System.Threading.Mutex.CreateMutexWithGuaranteedCleanup(bool initiallyOwned, string name, out bool createdNew, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES secAttrs) 
    mscorlib.dll!System.Threading.Mutex.Mutex(bool initiallyOwned, string name, out bool createdNew, System.Security.AccessControl.MutexSecurity mutexSecurity) 
    mscorlib.dll!System.Threading.Mutex.Mutex(bool initiallyOwned, string name, out bool createdNew)  
    MutexImpersonationTest.exe!MutexImpersonationTest.Program.Main(string[] args) Line 16 
+0

Molto strano. FWIW, se non si ottiene una buona risposta, una soluzione alternativa sarebbe dimenticare le classi .net e utilizzare P/Invoke per chiamare direttamente l'API Win32. –

risposta

6

Sembra che il codice di acquisire un mutex è conficcato in un ciclo infinito, e nel mio test, è agganciare un core al 100% entro la chiamata a new Mutex(...).

Il motivo per questo sembra essere che il codice framework prima tenta di chiamare il Win32 CreateMutex, se non riesce con un errore "Accesso negato", tenta invece di chiamare OpenMutex. Se la chiamata OpenMutex fallisce con un errore che indica che il mutex non esiste, ripete di nuovo l'intero processo e quindi si blocca in un ciclo infinito se il mutex non esiste.

Secondo il CreateMutex documentation, questo è essenzialmente l'approccio corretto, ma non sembra spiegare il caso in cui l'iniziale CreateMutex esito negativo con un accesso negato questo è non a causa di autorizzazioni per un mutex esistente.

Una cosa che sembrava funzionare quando ho provato era prefisso il nome mutex con "Global \", si spera che questa soluzione sia adatta per voi.

+0

I mutex globali possono essere creati in questo modo, ma limitano le istanze in tutte le sessioni utente, il che è un drastico cambiamento nel comportamento ... –

+0

Nice catch, il codice while (true) [è qui] (http: // referenceource. microsoft.com/#mscorlib/system/threading/mutex.cs,9faa5b5e2b4c8f31). –

+1

@ MártonMolnár Se vuoi un mutex specifico per sessione, sembra che tu abbia un paio di opzioni: potresti creare il mutex * prima * di impersonare e impostare le autorizzazioni su di esso per permettere all'utente che impersona ad accedervi, o usare il " Prefisso globale \ ", ma incorporare l'ID di sessione (' Processo.GetCurrentProcess(). SessionId') nel nome del mutex, creando così un mutex "per sessione" nello spazio dei nomi globale. – Iridium