SHARED
, o que permite acesso de leitura e gravação.
results = query.execute(Database.SHARED);
results = query.execute(); //missing query mode
ActionForms
são vulneráveis à manipulação de ClassLoader.String
pode levar à perda de dados.String
, não fica claro o que acontecerá com os dados que estiverem fora do conjunto de caracteres aplicável. Isso pode provocar perda de dados ou uma diminuição no nível de segurança quando dados binários são necessários para assegurar que medidas de segurança adequadas sejam seguidas.
...
FileInputStream fis = new FileInputStream(myFile);
byte[] byteArr = byte[BUFSIZE];
...
int count = fis.read(byteArr);
...
String fileString = new String(byteArr);
String fileSHA256Hex = DigestUtils.sha256Hex(fileString);
// use fileSHA256Hex to validate file
...
BUFSIZE
, desde que as informações em myFile
sejam codificadas da mesma maneira que o conjunto de caracteres padrão. Porém, se uma codificação diferente estiver em uso, ou se o arquivo for binário, haverá perda de informações. Isso por sua vez fará com que o hash SHA resultante seja menos confiável e pode implicar que colisões podem ser provocadas com muito mais facilidade, especialmente se os dados fora do conjunto de caracteres padrão forem representados pelo mesmo valor, como um ponto de interrogação.notify()
for chamado.notify()
.notifyJob()
chama notify()
.
public synchronized notifyJob() {
flag = true;
notify();
}
...
public synchronized waitForSomething() {
while(!flag) {
try {
wait();
}
catch (InterruptedException e)
{
...
}
}
...
}
wait()
, mas é possível que notify()
notifique um thread diferente do pretendido.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();
System.gc()
às vezes parece fazer com que o problema desapareça.System.gc()
é a coisa errada a se fazer. Na verdade, chamar System.gc()
pode causar problemas de desempenho isso for feito com demasiada frequência.run()
de um thread em vez de chamar start()
.run()
de um objeto Thread
é um bug. O programador pretendia iniciar um novo thread de controle, mas acidentalmente chamou run()
no lugar de start()
e, portanto, o método run()
será executado no thread de controle do chamador.run()
em vez de start()
.
Thread thr = new Thread() {
public void run() {
...
}
};
thr.run();
stop()
de um thread, possivelmente deixando vazar recursos.stop()
de um objeto Thread
é um bug. O programador pretendia parar a execução de um thread, mas não sabia que esta não é uma maneira adequada de fazer isso. A função stop()
dentro de Thread
causa uma exceção ThreadDeath
em qualquer lugar dentro do objeto Thread
, provavelmente deixando objetos em um estado inconsistente e possivelmente deixando vazar recursos. Como essa API é inerentemente insegura, seu uso foi preterido há muito tempo.Thread.stop()
.
...
public static void main(String[] args){
...
Thread thr = new Thread() {
public void run() {
...
}
};
...
thr.start();
...
thr.stop();
...
}
clone()
, mas não implementa a interface Cloneable
.Cloneable
, pois ela implementa um método denominado clone()
. No entanto, a classe não implementa a interface Cloneable
, e o método clone()
não se comportará corretamente.clone()
para essa chamada resultará em uma CloneNotSupportedException.
public class Kibitzer {
public Object clone() throws CloneNotSupportedException {
...
}
}
Equals()
é chamado em um objeto que não implementa Equals()
.Equals()
em uma classe (ou qualquer superclasse/interface) que não implemente Equals()
explicitamente resulta em uma chamada para o método Equals()
herdada de System.Object
. Em vez de comparar campos membros de objetos ou outras propriedades, o Object.Equals()
compara duas instâncias de objeto para ver se elas são iguais. Embora existam usos legítimos de Object.Equals()
, muitas vezes isso é uma indicação de um código com bug.
public class AccountGroup
{
private int gid;
public int Gid
{
get { return gid; }
set { gid = value; }
}
}
...
public class CompareGroup
{
public bool compareGroups(AccountGroup group1, AccountGroup group2)
{
return group1.Equals(group2); //Equals() is not implemented in AccountGroup
}
}
equals()
é chamado em um objeto que não implementa equals()
.equals()
em uma classe (ou qualquer superclasse/interface) que não implemente equals()
explicitamente resulta em uma chamada para o método equals()
herdada de java.lang.Object
. Em vez de comparar campos membros de objetos ou outras propriedades, o Object.equals()
compara duas instâncias de objeto para ver se elas são iguais. Embora existam usos legítimos de Object.equals()
, muitas vezes isso é uma indicação de um código com bug.
public class AccountGroup
{
private int gid;
public int getGid()
{
return gid;
}
public void setGid(int newGid)
{
gid = newGid;
}
}
...
public class CompareGroup
{
public boolean compareGroups(AccountGroup group1, AccountGroup group2)
{
return group1.equals(group2); //equals() is not implemented in AccountGroup
}
}
clone()
na classe chama uma função que pode ser substituída.clone()
chama uma função substituível, ela pode fazer com que o clone seja deixado em um estado parcialmente inicializado ou se torne corrompido.clone()
a seguir chama um método que pode ser substituído.
...
class User implements Cloneable {
private String username;
private boolean valid;
public Object clone() throws CloneNotSupportedException {
final User clone = (User) super.clone();
clone.doSomething();
return clone;
}
public void doSomething(){
...
}
}
doSomething()
e a sua classe delimitadora não são final
, significa que a função pode ser substituída, o que pode deixar o objeto clone
clonado em um estado parcialmente inicializado, capaz de provocar erros, se não estiver trabalhando em torno da lógica de uma forma inesperada.equals()
pode resultar em um comportamento inesperado.equals()
da primitiva encaixotada deve ser chamado em vez dos operadores ==
e !=
. A Especificação Java declara o seguinte sobre conversões de encaixotamento: Boolean
ou Byte
), apenas uma faixa de valores será armazenada em cache ou memorizada. Para um subconjunto de valores, o uso de ==
ou !=
retornará o valor correto. Para todos os outros valores fora desse subconjunto, isso retornará o resultado da comparação dos endereços de objetos.
...
Integer mask0 = 100;
Integer mask1 = 100;
...
if (file0.readWriteAllPerms){
mask0 = 777;
}
if (file1.readWriteAllPerms){
mask1 = 777;
}
...
if (mask0 == mask1){
//assume file0 and file1 have same permissions
...
}
...
Example 1
usa primitivas encaixotadas Integer
para tentar comparar dois valores int
. Se mask0
e mask1
forem ambos iguais a 100
, mask0 == mask1
retornará true
. No entanto, quando mask0
e mask1
forem ambos iguais a 777
, mask0 == maske1
agora retornará false
, pois esses valores não estão dentro do intervalo de valores armazenados em cache para essas primitivas encaixotadas.NaN
é sempre um erro.NaN
, ela é sempre avaliada como false
, exceto para o operador !=
, que sempre é avaliado como true
, já que NaN
não está ordenado.NaN
.
...
if (result == Double.NaN){
//something went wrong
throw new RuntimeException("Something went wrong, NaN found");
}
...
result
não é NaN
, mas o uso do operador ==
com NaN
sempre resulta em um valor de false
, e, portanto, essa verificação nunca lançará a exceção.this
antes que o objeto seja totalmente inicializado, o que, por sua vez, pode provocar uma vulnerabilidade.
...
class User {
private String username;
private boolean valid;
public User(String username, String password){
this.username = username;
this.valid = validateUser(username, password);
}
public boolean validateUser(String username, String password){
//validate user is real and can authenticate
...
}
public final boolean isValid(){
return valid;
}
}
validateUser
e a classe não são final
, isso significa que elas podem ser substituídas e, dessa forma, inicializar uma variável para a subclasse que substitui essa função possibilitaria o desvio da funcionalidade validateUser
. Por exemplo:
...
class Attacker extends User{
public Attacker(String username, String password){
super(username, password);
}
public boolean validateUser(String username, String password){
return true;
}
}
...
class MainClass{
public static void main(String[] args){
User hacker = new Attacker("Evil", "Hacker");
if (hacker.isValid()){
System.out.println("Attack successful!");
}else{
System.out.println("Attack failed");
}
}
}
Example 1
imprime "Attack successful!", uma vez que a classe Attacker
substitui a função validateUser()
que é chamada a partir do construtor da superclasse User
, e o Java primeiro examinará a subclasse em busca de funções chamadas a partir desse construtor.
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].inputReader
é confiável com base em seu nome de classe. Se um invasor puder fornecer uma implementação de inputReader
que executa comandos mal-intencionados, esse código não poderá diferenciar as versões bem-intencionadas das mal-intencionadas do objeto.
if (inputReader.GetType().FullName == "CompanyX.Transaction.Monetary")
{
processTransaction(inputReader);
}
inputReader
é confiável com base em seu nome de classe. Se um invasor puder fornecer uma implementação de inputReader
que executa comandos mal-intencionados, esse código não poderá diferenciar as versões bem-intencionadas das mal-intencionadas do objeto.
if (inputReader.getClass().getName().equals("com.example.TrustedClass")) {
input = inputReader.getInput();
...
}
inputReader
é confiável com base em seu nome de classe. Se um invasor puder fornecer uma implementação de inputReader
que executa comandos mal-intencionados, esse código não poderá diferenciar as versões bem-intencionadas das mal-intencionadas do objeto.
if (inputReader::class.qualifiedName == "com.example.TrustedClass") {
input = inputReader.getInput()
...
}
finalize()
deve chamar super.finalize()
.finalize()
chamar super.finalize()
[1].super.finalize()
.
protected void finalize() {
discardNative();
}
equals()
, e não com ==
ou !=
.==
ou !=
para comparar a igualdade de duas strings, o que compara a igualdade de dois objetos, e não seus valores. São boas as chances de que as duas referências nunca serão iguais.
if (args[0] == STRING_CONSTANT) {
logger.info("miracle");
}
==
e !=
apenas se comportarão conforme esperado quando forem usados para comparar strings contidas em objetos que são iguais. A maneira mais comum de isso acontecer é internalizando as strings, processo pelo qual elas são adicionadas a um pool de objetos mantidos pela classe String
. Após a internalização de uma string, todas as suas aplicações usarão o mesmo objeto, e os operadores de igualdade terão o comportamento esperado. Todos os literais de string e constantes com valores de string são internalizados automaticamente. Outras strings podem ser internalizadas manualmente chamando String.intern()
, o que retornará uma instância canônica da string atual, criando uma se necessário.