Segurança e Condições de Corrida
Outra área de preocupação é o potencial de falhas de segurança exploradas pelas condições de corrida. Há várias maneiras pelas quais isso pode acontecer. Os subtópicos a seguir descrevem algumas das principais armadilhas que o desenvolvedor deve evitar.
Condições de Corrida no Método de Eliminação
Se o método Dispose de uma classe (para obter mais informações, consulte Garbage Collection) não estiver sincronizado, é possível que o código de limpeza dentro de Dispose possa ser executado mais de uma vez, conforme mostrado no exemplo a seguir.
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;
}
}
Como essa implementação Dispose não está sincronizada, é possível Cleanup
ser chamado primeiro por um thread e, em seguida, um segundo thread antes _myObj
é definido como null. Se isso é uma preocupação de segurança depende do que acontece quando o Cleanup
código é executado. Um grande problema com implementações Dispose não sincronizadas envolve o uso de identificadores de recursos, como arquivos. O descarte inadequado pode fazer com que o identificador errado seja usado, o que muitas vezes leva a vulnerabilidades de segurança.
Condições de Corrida em Construtores
Em alguns aplicativos, pode ser possível que outros threads acessem membros de classe antes que seus construtores de classe tenham sido completamente executados. Você deve revisar todos os construtores de classe para certificar-se de que não há problemas de segurança, se isso acontecer, ou sincronizar threads, se necessário.
Condições de corrida com objetos armazenados em cache
O código que armazena em cache informações de segurança ou usa a segurança de acesso ao código A operação Assert também pode ser vulnerável a condições de corrida se outras partes da classe não estiverem adequadamente sincronizadas, conforme mostrado no exemplo a seguir.
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();
}
}
Se houver outros caminhos que DoOtherWork
podem ser chamados de outro thread com o mesmo objeto, um chamador não confiável pode passar por uma demanda.
Se o seu código armazenar informações de segurança em cache, certifique-se de que o analisa para esta vulnerabilidade.
Condições de Corrida em Finalizadores
As condições de corrida também podem ocorrer em um objeto que faz referência a um recurso estático ou não gerenciado que ele libera em seu finalizador. Se vários objetos compartilharem um recurso que é manipulado no finalizador de uma classe, os objetos devem sincronizar todo o acesso a esse recurso.