Grave bug encontrado em conversão de String->Double em PHP aparece na JVM

41 respostas
Paulo_Silveira

Um simples e novo bug foi recém descoberto em todas as versões do Java. Um double d = Double.parseDouble(“2.2250738585072012e-308”); (o menor double possível) entra em loop infinito, assim como no PHP.

Ou mesmo se você escrever um código java com double d = 2.2250738585072012e-308; o compilador vai utilizar o Double.parseDouble internamente, fazendo o compilador travar em loop infinito.

Isso obviamente afeta JRuby, Scala, Clojure, etc. Pode ser também um ataque a formuários web que recebem parâmetros e convertem diretamente para Double, o que sempre pareceu ser uma operação segura.

Mais informações:
http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/

Testei na JVM do Mac e o mesmo ocorre. O código “que ofende” :slight_smile: é esse aqui:
http://google.com/codesearch/p?hl=en#lM3pwaU8RUc/src/share/classes/sun/misc/FloatingDecimal.java&q=parseDouble&l=1476

Não há respostas da Oracle até o momento. Agradecimentos ao @rlucindo

41 Respostas

zoren

Se colar essa linha no netbeans ele trava.

Mas eu não vi esse bug com o:

e ainda dá um valor direfente.

só agora que eu vi, tem o MIN_NORMAL, mas o valor é bem próximo, mas ainda não é esse.

Double.MIN_NORMAL = 2.2250738585072014E-308; Double.MIN_VALUE = 4.9E-324

sergiolopes

O bug é só no parseDouble. Se você usa a constante diretamente não há chamada ao parseDouble.

zoren

Sergio Lopes:
O bug é só no parseDouble. Se você usa a constante diretamente não há chamada ao parseDouble.

Mas os valores não são os mesmos.

Só próximos.

Paulo_Silveira

é um antes do Double.MIN_NORMAL, algo assim.

Faça algo como System.out.printf("%.20e", Double.MIN_NORMAL);

Mas qual valor ele representa exatamente não é relevante para o bug. A fragilidade é qualquer um que converta diretamente de uma String da web para double, esta sucetivel a isso. Exemplo Double.parseDouble(req.getParameter(“valor”));

danilomunoz

O meu eclipse tbm deu deadlock, mas é só dar stop nos processos de compilação.

Marky.Vasconcelos

Travou o eclipse também.

danilomunoz

Ops … melhor não fazerem no eclipse não …
tive que editar o código por fora (notepad) e remover a linha … pq não conseguia mais salvar pelo eclipse …

encheu um pouco o saco aqui … travou bem feio … rs.

Até mais,

Jose111

Aqui o eclipse travou também… mas acredito que foi porque eu usei esta forma:

Try to compile this program; the compiler will hang:

class compilehang {
public static void main(String[] args) {
  double d = 2.2250738585072012e-308;
  System.out.println("Value: " + d);
 }
}

Entao fica preso na compilação… brincadeira legal para fazer com estagiário :twisted: :lol:

M

No php a coisa é mais feia entao pelo o cast ser automático?

Diabo_Loiro

mto louco o cara que descobriu isso… quem vai usar um double dessa forma hehe

kkkkkk

Kanin_Dragon

Ai sim fomos surpreendidos novamente.!

Marky.Vasconcelos

danilomunoz:
Ops … melhor não fazerem no eclipse não …
tive que editar o código por fora (notepad) e remover a linha … pq não conseguia mais salvar pelo eclipse …

encheu um pouco o saco aqui … travou bem feio … rs.

Até mais,

Tive que fazer isso também.

Cuidado.

Diabo_Loiro

show de bola esse bug.

drigo.angelo

Então #comofaz agora? toda vez que tiver uma entrada de um valor double do usuário vou ter que validar??

G

Quem tiver um tempo vago e der uma pesquisada tem uma série de bugs milenares no bugtrack da Sun.

Tem um do JDK Logging que, inverte o System.out e o System.err, e já está fazendo seu 8º aniversário: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4827381

emmanuelrock

drigo cuidado para não validar com parseDouble() kkkkk…

B

Paulo Silveira:
Um simples e novo bug foi recém descoberto em todas as versões do Java. Um double d = Double.parseDouble(“2.2250738585072012e-308”); (o menor double possível) entra em loop infinito, assim como no PHP.

impressionante, mas pelo jeito esse bug já tinha sido reportado desde o final de 2009:

https://bugs.openjdk.java.net/show_bug.cgi?id=100119

acho que eles não tinham pensado nessa possibilidade que vc citou de alguém fazer ataque via formularios.

Luiz_Henrique_Coura

No PHP esse bug já foi corrigido nas versões 5.3.5 e 5.2.17:

http://www.php.net/archive/2011.php#id2011-01-06-1

Luiz

Paulo_Silveira

bobmoe:

impressionante, mas pelo jeito esse bug já tinha sido reportado desde o final de 2009:

https://bugs.openjdk.java.net/show_bug.cgi?id=100119

acho que eles não tinham pensado nessa possibilidade que vc citou de alguém fazer ataque via formularios.

Bem observado Roberto! Acho que é interessante voce postar essa referencia la no post da noticia!

victorwss

Esse bug é realmente estranho. Mas há bugs piores.

Em 2007 eu submeti esse bug:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6531725

No entanto, se você clicar neste link aí em cima, verá que ele não funciona. Quando a Oracle comprou a Sun, vários bugs cadastrados “misteriosamente” sumiram.

Bem, que eu saiba ele não foi consertado até hoje (na época a sun recusou o bug como sendo algo “não importante”). Trata-se do seguinte:

Throwable a = new Throwable();
Throwable b = new Throwable(a);
a.initCause(b);
a.printStackTrace(); // Loop infinito!

Imagina o que acontece se um hacker serializa a exceção para o servidor e o servidor faz o log dela?

Adelar

victorwss:
Esse bug é realmente estranho. Mas há bugs piores.

Em 2007 eu submeti esse bug:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6531725

No entanto, se você clicar neste link aí em cima, verá que ele não funciona. Quando a Oracle comprou a Sun, vários bugs cadastrados “misteriosamente” sumiram.

Bem, que eu saiba ele não foi consertado até hoje (na época a sun recusou o bug como sendo algo “não importante”). Trata-se do seguinte:

Throwable a = new Throwable();
Throwable b = new Throwable(a);
a.initCause(b);
a.printStackTrace(); // Loop infinito!

Imagina o que acontece se um hacker serializa a exceção para o servidor e o servidor faz o log dela?


Se o cadastro sumiu quer dizer que foi corrigido :twisted:

victorwss

Adelar:
victorwss:
Esse bug é realmente estranho. Mas há bugs piores.

Em 2007 eu submeti esse bug:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6531725

No entanto, se você clicar neste link aí em cima, verá que ele não funciona. Quando a Oracle comprou a Sun, vários bugs cadastrados “misteriosamente” sumiram.

Bem, que eu saiba ele não foi consertado até hoje (na época a sun recusou o bug como sendo algo “não importante”). Trata-se do seguinte:

Throwable a = new Throwable();
Throwable b = new Throwable(a);
a.initCause(b);
a.printStackTrace(); // Loop infinito!

Imagina o que acontece se um hacker serializa a exceção para o servidor e o servidor faz o log dela?


Se o cadastro sumiu quer dizer que foi corrigido :twisted:

Bem, acabei de testar aqui (Java Hotspot Client VM, versão 1.6.0_22) para ver o que acontecia. Deu um StackOverflowError após ele gerar centenas de linhas de stacktrace repetido. Menos pior do que um loop infinito, mas ainda assim uma ferramenta muito útil para alguém atacar um servidor. :twisted:

Adelar

victorwss:

Bem, acabei de testar aqui (Java Hotspot Client VM, versão 1.6.0_22) para ver o que acontecia. Deu um StackOverflowError após ele gerar centenas de linhas de stacktrace repetido. Menos pior do que um loop infinito, mas ainda assim uma ferramenta muito útil para alguém atacar um servidor. :twisted:

Aí sim heim… bem melhor kkkkkk
Nem me impressiono tanto… quando mexia com C tinha coisa bem pior :smiley:

namor

Deve ficar melhor ainda assim:

while(true){ double d = 2.2250738585072012e-308; System.out.println("Value: " + d); }

hahahahaha

Adelar

namor:
Deve ficar melhor ainda assim:

while(true){ double d = 2.2250738585072012e-308; System.out.println("Value: " + d); }

hahahahaha


Uma versão customizada… daí caso corrijam o problema lançando uma exceção ainda vai entrar em loop infinito :twisted:

public void bug(){ try{ while(true){ double d = Double.parseDouble("2.2250738585072012e-308"); } } catch(Exception e){ bug(); } }

peczenyj

Não acontece com Ruby \o/

mas e o jruby? :cry:

peerless

No minimo a Sun não utilizava testes de cobertura :twisted:

Alexandre_Saudate

BigDecimal é seu amigo.

[]´s

dmitsuo

Pessoal, só a título de aprendizado com relação a esse bug, se houvessem testes unitários automatizados utilizando as condições de fronteira (valores mínimos, máximos e imediatamente anteriores e posteriores) isso não poderia ter sido evitado? Esse bug pode ser considerado uma prova de que a Sun não utiliza/utilizou testes unitários automatizados em sua base de código?

Diabo_Loiro

Se eu fosse malvado eu diria.

"Mandem este codigo por email para os amigos mais queridos testarem.

Comitem um metodo com esse codigo so para ver se cai o servidor "

Mais como sou bonzinho eu digo.

Use bigdecimal, para evitar problemas.

rs kkk

andreiribas

dmitsuo:
Pessoal, só a título de aprendizado com relação a esse bug, se houvessem testes unitários automatizados utilizando as condições de fronteira (valores mínimos, máximos e imediatamente anteriores e posteriores) isso não poderia ter sido evitado? Esse bug pode ser considerado uma prova de que a Sun não utiliza/utilizou testes unitários automatizados em sua base de código?

Teoricamente esse tipo de erro deveria ter sido capturado no TCK, que é o teste de compatibilidade da plataforma Java, mas aparentemente os caras não testavam o código mesmo.

Imagina só, um erro tão bobo demorou mais de 15 anos para ser descoberto (desconsiderando o bugtraq da sun claro :).

eduveks

Affff!!!

Passei um calafrio danado agora… só de ver isto passou pela minha cabeça todos os sites q fiz, mas ainda bem que pelo q eu recordo não há nenhum parametro do tipo double, integers/ids há as pancadas como é óbvio, só falta algum ID estar sendo validado com o parseDouble… ai eu corto os pulsos!!!

Bem, se os servidores começarem a dar problemas já sei q poderá ser disto…

Aqui no guj esta tudo seguro? :twisted:

O q vai ter de neguinho tentando travar os sites em Java por ai…

Espero q os meus queridos colegas fanáticos em .Net não venham me encher o sako com isto! Se bem que o .Net tb tem bugs arcáicos não resolvidos, mas não imaginava q o Java estivesse assim tb, eu pelo menos acho que nunca encontrei um bug, é q na verdade até posso ter encontrado um ou outro e pensado q o problema era do código… :stuck_out_tongue:

M

Um bug realmente existe, mas existe também um problema de interpretação matemática. O código abaixo roda normalmente e o parser também funciona, observer o comentário que coloquei no código.

Eu recomendo relamente validar e usar o BigDecimal para tratar formularios web, pois o caso acima realmente não evita um ataque ao server se vc estiver usando o parse double para valores científicos.

Testei no Netbean 6.9.1 e funciona normalmente como a saida abaixo. RECOMENDO NAO TENTAR DEPURAR O CODIGO ABAIXO, POIS VAI TRAVAR O IDE.

X: 2.2250738585072014E-308
Y1: 2.2250738585072014E-308
Y2: 2.2250738585072014E-308
Z: double MIN_NORMAL: 2.2250738585072014E-308
B: 2.2250738585072012E-308
W: 0.0

/**
             *  Atencao nas casas decimais a direita do ponto,
             *  a declaracao abaixo, 22250738585072014E-324, equivale extamente
             *  ao numero 2.225073858507201E-308, mas observe que
             *  2.2250738585072012 eh diferente de 22250738585072012.
             *  O motivo eh a limitacao do expoente -308, sendo que com
             *  2.2250738585072012 temos 16 casas apos o ponto, logo extrapola
             *  o limite do double.
             *  Exemplo para 2.50e-5 e 250e-7 que sao o mesmo numero
             *  0.0000250
             */
            double x = 22250738585072014E-324;
            System.out.println("X: " + x);
            String v = String.valueOf(x);
            // o parser ocorre sem problemas, pois a representacao esta no limite
            // do couble.
            double y = Double.parseDouble(v);
            System.out.println("Y1: " + y);

            // aqui tambem ocorre normalmente pois ainda esta no limite do double
            y = Double.parseDouble("22250738585072014E-324");
            System.out.println("Y2: " + y);

            double z = Double.MIN_NORMAL;
            System.out.println("Z: double MIN_NORMAL: " + z);
            // operacao ocorre normalmente
            double w = x - y;

            /**
             * convesrao sem problema feita pelo BigDecimal
             */
            BigDecimal b = new BigDecimal("2.2250738585072012e-308");
            System.out.println("B: " + b);
            /**
             * A T E N C A O
             * a chamada abaixo vai dar problema pois nao ha como
             * representar o numero acima em double.
             */
            //System.out.println("B: " + b.doubleValue());

            System.out.println("W: " + w);

Abraços, Maximilian.

peczenyj

pesquisei este numero e travei o google.

galera, foi mal :confused:

sergiolopes

Foi corrigido no OpenJDK: http://hg.openjdk.java.net/jdk7/tl/jdk/rev/82c8c54ac1d5

A Oracle também já lançou updates pro JDK deles e um patch manual pra quem quiser aplicar. Fizeram um post dando umas desculpinhas pra não terem corrigido antes, já que o bug existe desde 2001:

http://blogs.oracle.com/henrik/2011/02/double_trouble_-_fixing_a_java_security_issue.html

Felagund

peczenyj:
Não acontece com Ruby \o/

mas e o jruby? :cry:

Segundo o Sr. Nutter

o JRuby é a primeira linguagem da JVM livre do BUG :stuck_out_tongue:

luistiagos

victorwss:
Esse bug é realmente estranho. Mas há bugs piores.

Em 2007 eu submeti esse bug:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6531725

No entanto, se você clicar neste link aí em cima, verá que ele não funciona. Quando a Oracle comprou a Sun, vários bugs cadastrados “misteriosamente” sumiram.

Bem, que eu saiba ele não foi consertado até hoje (na época a sun recusou o bug como sendo algo “não importante”). Trata-se do seguinte:

Throwable a = new Throwable();
Throwable b = new Throwable(a);
a.initCause(b);
a.printStackTrace(); // Loop infinito!

Imagina o que acontece se um hacker serializa a exceção para o servidor e o servidor faz o log dela?

O que vc estava tentando fazer para descobrir isto? :shock: :shock: :shock:

peerless

luistiagos:
victorwss:
Esse bug é realmente estranho. Mas há bugs piores.

Em 2007 eu submeti esse bug:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6531725

No entanto, se você clicar neste link aí em cima, verá que ele não funciona. Quando a Oracle comprou a Sun, vários bugs cadastrados “misteriosamente” sumiram.

Bem, que eu saiba ele não foi consertado até hoje (na época a sun recusou o bug como sendo algo “não importante”). Trata-se do seguinte:

Throwable a = new Throwable();
Throwable b = new Throwable(a);
a.initCause(b);
a.printStackTrace(); // Loop infinito!

Imagina o que acontece se um hacker serializa a exceção para o servidor e o servidor faz o log dela?

O que vc estava tentando fazer para descobrir isto? :shock: :shock: :shock:

Ele estava tentando descobrir o que a JVM faz quando uma exceção culpa a outra!

luistiagos

peerless:

Ele estava tentando descobrir o que a JVM faz quando uma exceção culpa a outra!

então estava só brincando… agora ta explicado o porque a sun recusou… pela própria natureza do negocio isto iria estourar a pilha,
é a mesma coisa que vc colocar 2 espelhos um refletindo o outro e querer que só um deles reflita e o outro não…

victorwss

Cara, tem alguns anos desde que achei este bug, não lembro o que eu estava fazendo.
Eu acho que eu estava usando o initCause em exceções que não recebiam a causa pelo construtor. Mas troquei alguma variável sem querer e saiu isso.

E embora este problema possa parecer ser supérfluo e sem importância, na verdade constitui-se em uma falha de segurança, pois um usuário mal-intencionado pode serializar estas exceções para um servidor. Assim como o bug do Double.parseFloat poderia parecer supérfluo porque nenhum usuário inocente digitaria um valor daquele, há o problema de que alguém mal-intencionado com certeza faria.

WellingtonRamos

Não use Double :twisted:

Criado 1 de fevereiro de 2011
Ultima resposta 1 de fev. de 2011
Respostas 41
Participantes 27