Zabezpieczenia i sytuacja wyścigu

Innym obszarem zainteresowania jest potencjał otworów bezpieczeństwa wykorzystywanych przez warunki wyścigowe. Istnieje kilka sposobów, na które może się to zdarzyć. Podtopy, które są zgodne z opisem niektórych głównych pułapek, których deweloper musi unikać.

Warunki wyścigu w metodzie Dispose

Jeśli metoda Dispose klasy (aby uzyskać więcej informacji, zobacz Odzyskiwanie pamięci) nie jest zsynchronizowana, istnieje możliwość, że kod oczyszczania wewnątrz funkcji Dispose można uruchomić więcej niż raz, jak pokazano w poniższym przykładzie.

Sub Dispose()  
    If Not (myObj Is Nothing) Then  
       Cleanup(myObj)  
       myObj = Nothing  
    End If  
End Sub  
void Dispose()
{  
    if (myObj != null)
    {  
        Cleanup(myObj);  
        myObj = null;  
    }  
}  

Ponieważ ta implementacja Dispose nie jest zsynchronizowana, można Cleanup wywołać ją przez pierwszy wątek, a następnie drugi wątek przed _myObj ustawieniem wartości null. To, czy jest to kwestia zabezpieczeń, zależy od tego, co się stanie po uruchomieniu Cleanup kodu. Głównym problemem z implementacjami unsynchronized Dispose jest użycie dojść do zasobów, takich jak pliki. Niewłaściwe usuwanie może spowodować niewłaściwe wykorzystanie uchwytu, co często prowadzi do luk w zabezpieczeniach.

Warunki wyścigu w konstruktorach

W niektórych aplikacjach może być możliwe, aby inne wątki miały dostęp do składowych klas, zanim konstruktory klas zostaną całkowicie uruchomione. Należy przejrzeć wszystkie konstruktory klas, aby upewnić się, że w razie potrzeby nie ma problemów z zabezpieczeniami lub zsynchronizować wątki.

Warunki wyścigu z buforowanymi obiektami

Kod, który buforuje informacje o zabezpieczeniach lub używa operacji potwierdzenia zabezpieczeń dostępu do kodu, może być również narażony na warunki wyścigu, jeśli inne części klasy nie są odpowiednio zsynchronizowane, jak pokazano w poniższym przykładzie.

Sub SomeSecureFunction()  
    If SomeDemandPasses() Then  
        fCallersOk = True  
        DoOtherWork()  
        fCallersOk = False  
    End If  
End Sub  
  
Sub DoOtherWork()  
    If fCallersOK Then  
        DoSomethingTrusted()  
    Else  
        DemandSomething()  
        DoSomethingTrusted()  
    End If  
End Sub  
void SomeSecureFunction()
{  
    if (SomeDemandPasses())
    {  
        fCallersOk = true;  
        DoOtherWork();  
        fCallersOk = false;  
    }  
}  
void DoOtherWork()
{  
    if (fCallersOK)
    {  
        DoSomethingTrusted();  
    }  
    else
    {  
        DemandSomething();  
        DoSomethingTrusted();  
    }  
}  

Jeśli istnieją inne ścieżki do DoOtherWork tego, które można wywołać z innego wątku z tym samym obiektem, niezaufany obiekt wywołujący może przesunąć żądanie.

Jeśli kod buforuje informacje o zabezpieczeniach, upewnij się, że przejrzysz je pod kątem tej luki w zabezpieczeniach.

Warunki wyścigu w finalizatorach

Warunki wyścigu mogą również wystąpić w obiekcie, który odwołuje się do statycznego lub niezarządzanego zasobu, który następnie zwalnia w finalizatorze. Jeśli wiele obiektów współużytkuje zasób, który jest manipulowany w finalizatorze klasy, obiekty muszą synchronizować cały dostęp do tego zasobu.

Zobacz też