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.