HttpSessionState
pode prejudicar a confiabilidade do aplicativo.HttpSessionState
, seus atributos e quaisquer objetos aos quais eles fazem referência. Esse modelo limita o estado da sessão ativa que pode ser acomodado pela memória do sistema de uma única máquina. Para ampliar a capacidade além dessas limitações, os servidores são frequentemente configurados para informações de estado de sessão persistentes, o que expande a capacidade e também permite a replicação através de várias máquinas a fim de melhorar o desempenho global. Para persistir o estado de sua sessão, o servidor deve serializar o objeto HttpSessionState
, o que requer que todos os objetos nele armazenados sejam serializáveis.[Serializable]
. Além disso, se o objeto exigir métodos de serialização personalizados, ele também deverá implementar a interface ISerializable
.
public class DataGlob {
String GlobName;
String GlobValue;
public void AddToSession(HttpSessionState session) {
session["glob"] = this;
}
}
sleep()
enquanto um bloqueio é mantido pode causar perda de desempenho e provocar um deadlock.sleep()
enquanto um bloqueio é mantido pode fazer com que todos os outros threads aguardem a liberação desse recurso, o que pode resultar na piora do desempenho e em um deadlock.sleep()
enquanto mantém um bloqueio.
ReentrantLock rl = new ReentrantLock();
...
rl.lock();
Thread.sleep(500);
...
rl.unlock();
if (fitz == null) {
synchronized (this) {
if (fitz == null) {
fitz = new Fitzer();
}
}
}
return fitz;
Fitzer()
sempre seja alocado, mas não quer pagar o custo de sincronização cada vez que esse código é chamado. Essa expressão idiomática é conhecida como bloqueio duplamente verificado.Fitzer()
podem ser alocados. Consulte a declaração "O bloqueio duplamente verificado está quebrado" para obter mais detalhes [1].pthread_mutex_unlock()
antes que a execução de outro thread possa começar. Se o thread de sinalização não conseguir desbloquear o mutex, a chamada pthread_cond_wait()
no segundo thread não será retornada, e o thread não será executado.pthread_cond_signal()
, mas não consegue desbloquear esse mutex no qual o outro thread está aguardando.
...
pthread_mutex_lock(&count_mutex);
// Signal waiting thread
pthread_cond_signal(&count_threshold_cv);
...
...
if (tmpnam_r(filename)){
FILE* tmp = fopen(filename,"wb+");
while((recv(sock,recvbuf,DATA_SIZE, 0) > 0)&&(amt!=0))
amt = fwrite(recvbuf,1,DATA_SIZE,tmp);
}
...
tmpnam()
, tempnam()
, mktemp()
e seus equivalentes em C ++ prefaciados com um _
(sublinhado), bem como a função GetTempFileName()
da API do Windows. Esse grupo de funções é afetado por uma condição de corrida subjacente no nome do arquivo escolhido. Embora as funções garantam que o nome do arquivo é exclusivo no momento em que é selecionado, não existe nenhum mecanismo para impedir que outro processo ou um invasor crie um arquivo com o mesmo nome após essa seleção, mas antes de o aplicativo tentar abri-lo. Além do risco de uma colisão legítima causada por outra chamada para a mesma função, há uma alta probabilidade de que um invasor seja capaz de criar uma colisão mal-intencionada, pois os nomes de arquivos gerados por essas funções não são suficientemente aleatórios a ponto de os tornar difíceis de adivinhar.open()
usando os sinalizadores O_CREAT
e O_EXCL
ou para CreateFile()
usando o atributo CREATE_NEW
, o que falhará se o arquivo já existir, impedindo assim os tipos de ataques descritos anteriormente. No entanto, se um invasor for capaz de prever com precisão uma sequência de nomes de arquivos temporários, o aplicativo poderá ser impedido de abrir o armazenamento temporário necessário, causando um ataque de negação de serviço (DoS). Considerando a pequena quantidade de aleatoriedade usada na seleção dos nomes de arquivos gerados por essas funções, não é difícil elaborar esse tipo de ataque.tmpfile()
e seus equivalentes em C++ prefaciados com um _
(sublinhado), bem como a função mkstemp()
da Biblioteca C, que apresenta um comportamento um pouco melhor.tmpfile()
constroem um nome de arquivo exclusivo e abrem esse arquivo da mesma maneira que fopen()
faria se os sinalizadores "wb+"
fossem transmitidos, ou seja, como um arquivo binário no modo de leitura/gravação. Se o arquivo já existir, tmpfile()
vai truncá-lo no tamanho zero, possivelmente em uma tentativa de acalmar as preocupações de segurança mencionadas anteriormente a respeito da condição de corrida existente entre a seleção de um nome de arquivo supostamente exclusivo e a subsequente abertura do arquivo selecionado. No entanto, esse comportamento claramente não resolve os problemas de segurança da função. Em primeiro lugar, um invasor pode criar o arquivo previamente com permissões brandas de acesso que provavelmente serão mantidas pelo arquivo aberto por tmpfile()
. Além disso, em sistemas baseados no Unix, se o invasor criar o arquivo previamente como um link para outro arquivo importante, o aplicativo poderá usar suas permissões possivelmente elevadas para truncar esse arquivo, provocando danos em nome do invasor. Por fim, se tmpfile()
criar um novo arquivo, as permissões de acesso aplicadas a esse arquivo vão variar de um sistema operacional para outro, o que pode deixar os dados do aplicativo vulneráveis mesmo que um invasor não seja capaz de prever com antecedência o nome do arquivo a ser usado.mkstemp()
é uma forma razoavelmente segura de criar arquivos temporários. Essa função tentará criar e abrir um arquivo exclusivo com base em um modelo de nome de arquivo fornecido pelo usuário, combinado com uma série de caracteres aleatoriamente gerados. Se ela não conseguir criar esse arquivo, falhará e retornará -1
. Em sistemas modernos, o arquivo é aberto com o uso do modo 0600
, o que significa que o arquivo ficará protegido contra adulteração, a menos que o usuário altere explicitamente suas permissões de acesso. No entanto, mkstemp()
ainda sofre com o uso de nomes de arquivos previsíveis e poderá deixar um aplicativo vulnerável a ataques de negação de serviço se um invasor provocar a falha de mkstemp()
ao prever e criar previamente os nomes de arquivo a serem utilizados.
...
try:
tmp_filename = os.tempnam()
tmp_file = open(tmp_filename, 'w')
data = s.recv(4096)
while True:
more = s.recv(4096)
tmp_file.write(more)
if not more:
break
except socket.timeout:
errMsg = "Connection timed-out while connecting"
self.logger.exception(errMsg)
raise Exception
...
open()
usando os sinalizadores os.O_CREAT
e os.O_EXCL
, que falharão se o arquivo já existir e, portanto, evitarão os tipos de ataques anteriormente descritos. No entanto, se um invasor for capaz de prever com precisão uma sequência de nomes de arquivos temporários, o aplicativo poderá ser impedido de abrir o armazenamento temporário necessário, causando um ataque de negação de serviço (DoS). Considerando a pequena quantidade de aleatoriedade usada na seleção dos nomes de arquivos gerados por essas funções, não é difícil elaborar esse tipo de ataque.tmpfile()
.tmpfile()
constroem um nome de arquivo exclusivo e abrem esse arquivo da mesma maneira que open()
faria se os sinalizadores "wb+"
fossem transmitidos, ou seja, como um arquivo binário no modo de leitura/gravação. Se o arquivo já existir, tmpfile()
vai truncá-lo no tamanho zero, possivelmente em uma tentativa de acalmar as preocupações de segurança mencionadas anteriormente a respeito da condição de corrida existente entre a seleção de um nome de arquivo supostamente exclusivo e a subsequente abertura do arquivo selecionado. No entanto, esse comportamento claramente não resolve os problemas de segurança da função. Em primeiro lugar, um invasor pode criar o arquivo previamente com permissões brandas de acesso que provavelmente serão mantidas pelo arquivo aberto por tmpfile()
. Além disso, em sistemas baseados no Unix, se o invasor criar o arquivo previamente como um link para outro arquivo importante, o aplicativo poderá usar suas permissões possivelmente elevadas para truncar esse arquivo, provocando danos em nome do invasor. Por fim, se tmpfile()
criar um novo arquivo, as permissões de acesso aplicadas a esse arquivo vão variar de um sistema operacional para outro, o que pode deixar os dados do aplicativo vulneráveis mesmo que um invasor não seja capaz de prever com antecedência o nome do arquivo a ser usado.
...
HttpSession sesssion = request.getSession(true);
sesssion.setMaxInactiveInterval(-1);
...
HttpSession
pode prejudicar a confiabilidade do aplicativo.HttpSession
em várias JVMs de forma que, se uma JVM se tornar indisponível, outra poderá entrar e tomar o seu lugar sem interromper o fluxo do aplicativo.Serializable
.
public class DataGlob {
String globName;
String globValue;
public void addToSession(HttpSession session) {
session.setAttribute("glob", this);
}
}
...
EXEC CICS
INGNORE CONDITION ERROR
END-EXEC.
...
doExchange()
.
try {
doExchange();
}
catch (RareException e) {
// this can never happen
}
RareException
fosse lançado, o programa continuaria sendo executado como se nada incomum tivesse ocorrido. O programa não registra nenhuma evidência indicando a situação especial, potencialmente frustrando qualquer tentativa posterior de explicar o comportamento do programa.DoExchange()
.
try {
DoExchange();
}
catch (RareException e) {
// this can never happen
}
RareException
tivesse que ser lançada alguma vez, o programa continuaria a ser executado como se nada incomum tivesse ocorrido. O programa não registra nenhuma evidência que indique a situação especial, possivelmente frustrando qualquer tentativa posterior de explicar o comportamento do programa.doExchange()
.
try {
doExchange();
}
catch (RareException e) {
// this can never happen
}
RareException
tivesse que ser lançada alguma vez, o programa continuaria a ser executado como se nada incomum tivesse ocorrido. O programa não registra nenhuma evidência que indique a situação especial, possivelmente frustrando qualquer tentativa posterior de explicar o comportamento do programa.doExchange()
.
try {
doExchange();
}
catch (exception $e) {
// this can never happen
}
RareException
tivesse que ser lançada alguma vez, o programa continuaria a ser executado como se nada incomum tivesse ocorrido. O programa não registra nenhuma evidência que indique a situação especial, possivelmente frustrando qualquer tentativa posterior de explicar o comportamento do programa.open()
.
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except:
# This will never happen
pass
RareException
tivesse que ser lançada alguma vez, o programa continuaria a ser executado como se nada incomum tivesse ocorrido. O programa não registra nenhuma evidência que indique a situação especial, possivelmente frustrando qualquer tentativa posterior de explicar o comportamento do programa.
PROCEDURE do_it_all
IS
BEGIN
BEGIN
INSERT INTO table1 VALUES(...);
COMMIT;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
END do_it_all;
Exception
, pode obscurecer exceções que merecem tratamento especial ou que não devem ser detectadas a essa altura no programa. A captura uma exceção excessivamente ampla destrói em essência a finalidade de exceções .NET com tipo definido, podendo tornar-se um procedimento particularmente perigoso se o programa crescer e começar a lançar novos tipos de exceções. Os novos tipos de exceção não receberão nenhuma atenção.
try {
DoExchange();
}
catch (IOException e) {
logger.Error("DoExchange failed", e);
}
catch (FormatException e) {
logger.Error("DoExchange failed", e);
}
catch (TimeoutException e) {
logger.Error("DoExchange failed", e);
}
try {
DoExchange();
}
catch (Exception e) {
logger.Error("DoExchange failed", e);
}
DoExchange()
for modificado de forma a lançar um novo tipo de exceção que deve ser tratado de maneira diferente, o bloco "catch" amplo impedirá que o compilador aponte a situação. Além disso, o novo bloco "catch" também passará a lidar com exceções dos tipos ApplicationException
e NullReferenceException
, o que não é a intenção do programador.Exception
, pode obscurecer exceções que merecem tratamento especial ou que não devem ser detectadas a essa altura no programa. A captura uma exceção excessivamente ampla destrói em essência a finalidade de exceções de Java com tipo definido, podendo tornar-se um procedimento particularmente perigoso se o programa crescer e começar a lançar novos tipos de exceções. Os novos tipos de exceção não receberão nenhuma atenção.
try {
doExchange();
}
catch (IOException e) {
logger.error("doExchange failed", e);
}
catch (InvocationTargetException e) {
logger.error("doExchange failed", e);
}
catch (SQLException e) {
logger.error("doExchange failed", e);
}
try {
doExchange();
}
catch (Exception e) {
logger.error("doExchange failed", e);
}
doExchange()
for modificado de forma a lançar um novo tipo de exceção que deve ser tratado de maneira diferente, o bloco "catch" amplo impedirá que o compilador aponte a situação. Além disso, o novo bloco "catch" também passará a lidar com exceções derivadas de RuntimeException
, como ClassCastException
e NullPointerException
, o que não é a intenção do programador.Exception
ou Throwable
dificulta o trabalho de tratamento de erros e recuperação por parte dos chamadores. O mecanismo de exceção do Java está configurado para facilitar a tarefa dos chamadores de antecipar o que pode dar errado e escrever um código para lidar com cada circunstância excepcional específica. Declarar que um método lança uma forma genérica de exceção derrota esse sistema.
public void doExchange()
throws IOException, InvocationTargetException,
SQLException {
...
}
public void doExchange()
throws Exception {
...
}
doExchange()
introduz um novo tipo de exceção que deve ser tratado de forma diferente do que exceções anteriores, não haverá nenhuma maneira simples de fazer cumprir essa exigência.NullPointerException
é uma prática imprópria.NullPointerException
em três circunstâncias:NullPointerException
para sinalizar uma condição de erro.NullPointerException
por engano.
try {
mysteryMethod();
}
catch (NullPointerException npe) {
}
NullReferenceException
é uma prática imprópria.NullReferenceException
em três circunstâncias:NullReferenceException
para sinalizar uma condição de erro.NullReferenceException
por engano.
try {
MysteryMethod();
}
catch (NullReferenceException npe) {
}
finally
fará com que exceções sejam perdidas.finally
fará com que qualquer exceção que possa ser lançada no bloco "try" seja descartada.MagicException
lançada pela segunda chamada para doMagic
com true
transmitido para ela nunca será entregue para o chamador. A instrução de retorno dentro do bloco finally
fará com que a exceção seja descartada.
public class MagicTrick {
public static class MagicException extends Exception { }
public static void main(String[] args) {
System.out.println("Watch as this magical code makes an " +
"exception disappear before your very eyes!");
System.out.println("First, the kind of exception handling " +
"you're used to:");
try {
doMagic(false);
} catch (MagicException e) {
// An exception will be caught here
e.printStackTrace();
}
System.out.println("Now, the magic:");
try {
doMagic(true);
} catch (MagicException e) {
// No exception caught here, the finally block ate it
e.printStackTrace();
}
System.out.println("tada!");
}
public static void doMagic(boolean returnFromFinally)
throws MagicException {
try {
throw new MagicException();
}
finally {
if (returnFromFinally) {
return;
}
}
}
}
finally
fará com que exceções sejam perdidas.finally
fará com que qualquer exceção que possa ser lançada no bloco "try" seja descartada.exception
lançada pela segunda chamada para doMagic
com True
transmitido para ela nunca será entregue para o chamador. A instrução de retorno dentro do bloco finally
fará com que a exceção seja descartada."disappear before your very eyes!" . PHP_EOL;
echo "First, the kind of exception handling " .
"you're used to:" . PHP_EOL;
try {
doMagic(False);
} catch (exception $e) {
// An exception will be caught here
echo $e->getMessage();
}
echo "Now, the magic:" . PHP_EOL;
try {
doMagic(True);
} catch (exception $e) {
// No exception caught here, the finally block ate it
echo $e->getMessage();
}
echo "Tada!" . PHP_EOL;
function doMagic($returnFromFinally) {
try {
throw new Exception("Magic Exception" . PHP_EOL);
}
finally {
if ($returnFromFinally) {
return;
}
}
}
?>
ThreadDeath
não for lançado novamente, o thread em questão não poderá realmente ser desativado.ThreadDeath
só devem ser capturados se um aplicativos precisar de uma limpeza depois de ter sido finalizado de forma assíncrona. Se um erro ThreadDeath
for capturado, é importante que ele seja novamente lançado para que o thread realmente seja desativado. O objetivo de lançar ThreadDeath
é interromper um thread. Se ThreadDeath
for engolido, ele poderá impedir que um thread seja interrompido e resultar em um comportamento inesperado, pois, quem quer que tenha lançado ThreadDeath
originalmente, espera que o thread seja interrompido.ThreadDeath
, mas não volta a lançá-lo.
try
{
//some code
}
catch(ThreadDeath td)
{
//clean up code
}
throw
dentro de um bloco finally
rompe a progressão lógica via try-catch-finally
.finally
são sempre executados depois de seus blocos try-catch
correspondentes e são frequentemente utilizados para liberar recursos alocados, como identificadores de arquivos ou cursores de banco de dados. Lançar uma exceção em um bloco finally
pode ignorar o código de limpeza crítico, pois a execução normal do programa será interrompida.stmt.close()
é ignorada quando a FileNotFoundException
é lançada.
public void processTransaction(Connection conn) throws FileNotFoundException
{
FileInputStream fis = null;
Statement stmt = null;
try
{
stmt = conn.createStatement();
fis = new FileInputStream("badFile.txt");
...
}
catch (FileNotFoundException fe)
{
log("File not found.");
}
catch (SQLException se)
{
//handle error
}
finally
{
if (fis == null)
{
throw new FileNotFoundException();
}
if (stmt != null)
{
try
{
stmt.close();
}
catch (SQLException e)
{
log(e);
}
}
}
}