Integer Overflow Explicado: O Bug que Derruba
Integer overflow e um dos bugs mais antigos da computacao e continua derrubando sistemas criticos ate hoje. De Ariane 5 ao Gangnam Style, entenda como numeros que transbordam
Em 1996, um foguete de US$ 7 bilhoes explodiu 37 segundos apos o lancamento porque um numero nao cabia dentro de uma variavel. O Ariane 5 foi destruido por integer overflow. Parece brincadeira, mas e exatamente o que aconteceu.
Integer overflow e um daqueles bugs que todo programador ja ouviu falar, poucos realmente entendem a fundo, e quase ninguem testa direito. Neste artigo vou destrinchar tudo: o que e, como funciona em cada linguagem, e os casos historicos onde esse bug causou estrago de verdade.
Se voce quer entender a historia completa do Ariane 5, tem um artigo detalhado aqui: A Historia Nao Contada do Desastre do Ariane 5. Mas aqui vou focar no mecanismo tecnico por tras do desastre.
Como Computadores Guardam Numeros
Antes de falar de overflow, precisa entender como inteiros funcionam em memoria. Computadores guardam tudo em bits: zeros e uns. Um inteiro de 8 bits pode representar 256 valores diferentes (2^8).
Para inteiros sem sinal (unsigned), esses 256 valores vao de 0 a 255. Para inteiros com sinal (signed), metade fica para negativos: -128 a 127. E aqui esta a pegadinha.
O sistema de complemento de dois
Computadores usam um sistema chamado complemento de dois para representar negativos. No bit mais significativo (o da esquerda), 0 significa positivo e 1 significa negativo. O numero 127 em binario de 8 bits e 01111111. Se voce somar 1 a isso, fica 10000000. Sabe qual numero esse padrao representa? -128.
A logica do overflow
Integer Overflow Explicado: O Bug que Derruba. Integer overflow e um dos bugs mais antigos da computacao e continua derrubando sistemas criticos ate hoje. De Ariane 5 ao Gangnam Style, entenda como numeros que transbordam destroem software real.
Isso nao e bug do hardware. E matematica binaria funcionando exatamente como foi projetada. O problema e quando o software nao espera por esse comportamento.
O Ariane 5: Um int16 que Nao Deveria Existir Ali
O sistema de navegacao inercial do Ariane 5 foi reaproveitado do Ariane 4. Funciona, comprovado, por que reescrever? Mas o Ariane 5 era mais rapido. Muito mais rapido.
Uma variavel chamada BH (velocidade horizontal relativa) era representada como float de 64 bits. Quando o software tentou converter esse valor para int16 para transmissao, o numero era 32768. Maior que o maximo de um int16 (32767). Overflow.
-- Ada (pseudocodigo do sistema de navegacao)
declare
BH_float : Float64 := 32768.0; -- velocidade horizontal
BH_int : Integer16; -- int16 maximo = 32767
begin
BH_int := Integer16(BH_float); -- BOOM: Constraint_Error
-- No sistema original do Ariane 4, esse valor nunca
-- passava de 32767. No Ariane 5, passava.
end;O software nao tinha protecao para esse caso porque no Ariane 4 esse valor nunca excedia o limite. Ninguem imaginou que um foguete mais potente quebraria uma variavel.
A cadeia de falhas
O overflow gerou uma excecao. O sistema de navegacao, sem tratamento para aquela excecao especifica, desligou. O sistema de backup entrou em acao. Mas o backup rodava o mesmo software com o mesmo bug. O segundo sistema tambem falhou. Sem navegacao, o foguete comeou a girar fora de controle. O sistema de autodestruicao ativou. US$ 7 bilhoes viram uma nuvem de fumaca sobre a Guiana Francesa.
Outros Casos Historicos de Overflow
O Ariane 5 e o mais dramatico, mas integer overflow aparece em lugares que voce nem imagina.
Pac-Man: o nivel 256
O classico Pac-Man guarda o numero do nivel em um byte unsigned (uint8). Maximo: 255. Quando o nivel chega em 256, o byte transborda para 0. O codigo que renderiza o mapa usa esse numero diretamente para calcular posicoes. Com 0, metade da tela fica com lixo de memoria, misturando numeros de fase, letras e graficos corrompidos. O nivel 256 e literalmente injogavel.
Gangnam Style quebrou o YouTube
Em 2014, o contador de visualizacoes do YouTube usava int32 com sinal. Limite: 2.147.483.647 views. Gangnam Style estava quebrando esse limite em tempo real. O Google atualizou o contador para int64 as pressas, mas por algumas horas o numero ficou negativo no codigo interno.
Boeing 787: reboot obrigatorio a cada 248 dias
Em 2015, a FAA emitiu uma diretiva sobre o Boeing 787 Dreamliner. Os geradores de energia perdiam potencia se ficassem ligados por mais de 248 dias continuos. A causa: um contador interno de 32 bits contando centesimos de segundo. Em 248 dias, o contador atingia 2^31 e fazia overflow. A solucao temporaria foi rebotar o aviao antes de 248 dias.
248 dias em milissegundos
248 dias x 24 horas x 60 minutos x 60 segundos x 100 centesimos = 2.143.814.400
Limite do int32 com sinal: 2.147.483.647
Diferenca: apenas 3.669.247 centesimos de segundo (aprox. 10 horas)
Um aviao comercial fica ligado por semanas sem reboot. Era questao de tempo.
Y2K: o overflow de data
Y2K tecnicamente nao e integer overflow classico, mas e o mesmo conceito: guardar ano em 2 digitos (0-99) e esperar que o computador entenda que '00' vem depois de '99'. O mundo gastou US$ 300 bilhoes para corrigir isso antes de 2000.
Como Overflow Acontece em Cada Linguagem
Cada linguagem trata overflow de um jeito. E importante saber o comportamento da sua linguagem especifica.
C e C++: comportamento indefinido
#include <stdio.h>
#include <limits.h>
int main() {
int x = INT_MAX; // 2147483647
printf("%d\n", x); // 2147483647
printf("%d\n", x + 1); // Comportamento INDEFINIDO em C
// Na pratica, na maioria dos compiladores: -2147483648
// Mas o compilador pode fazer qualquer coisa, incluindo
// otimizacoes que removem codigo baseado na suposicao
// de que overflow nunca acontece.
unsigned int y = UINT_MAX; // 4294967295
printf("%u\n", y + 1); // 0 - wrap-around definido para unsigned
return 0;
}A diferenca entre signed e unsigned em C e critica: overflow de unsigned e comportamento definido (wrap-around). Overflow de signed e comportamento indefinido. O compilador pode fazer literalmente o que quiser, incluindo remover loops inteiros que ele julgar 'impossíveis' por assumir que overflow nao ocorre.
Java: wrap-around silencioso
public class OverflowDemo {
public static void main(String[] args) {
int max = Integer.MAX_VALUE; // 2147483647
System.out.println(max); // 2147483647
System.out.println(max + 1); // -2147483648 - sem excecao!
// Problema classico: calcular media de dois inteiros
int a = 2_000_000_000;
int b = 2_000_000_000;
int media_errada = (a + b) / 2; // a + b causa overflow!
int media_certa = a + (b - a) / 2; // correto
System.out.println("Media errada: " + media_errada); // negativo!
System.out.println("Media certa: " + media_certa); // 2000000000
}
}Java nao lanca excecao em overflow de inteiros. O valor simplesmente faz wrap-around. Isso e especialmente perigoso porque parece que esta funcionando.
JavaScript: sem inteiros de verdade
// JavaScript usa float64 para todos os numeros por padrao
// Inteiros sao representados exatamente ate 2^53
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992 (igual!)
// Para inteiros grandes, use BigInt
const grande = BigInt(Number.MAX_SAFE_INTEGER) + 2n;
console.log(grande); // 9007199254740993n - correto!
// Typed Arrays tem overflow classico
const arr = new Int8Array(1);
arr[0] = 127;
console.log(arr[0]); // 127
arr[0] = 128;
console.log(arr[0]); // -128 - overflow!Rust: panic em debug, wrap em release
fn main() {
let x: i32 = i32::MAX; // 2147483647
// Em modo debug: thread 'main' panicked at 'attempt to add with overflow'
// Em modo release: wrap-around silencioso (como C unsigned)
// let overflow = x + 1; // panic em debug!
// Rust oferece metodos explicitos para cada comportamento:
println!("{:?}", x.checked_add(1)); // None - overflow detectado
println!("{:?}", x.saturating_add(1)); // 2147483647 - fica no maximo
println!("{:?}", x.wrapping_add(1)); // -2147483648 - wrap explicito
println!("{:?}", x.overflowing_add(1)); // (-2147483648, true) - valor + flag
}Rust e a linguagem mais honesta sobre overflow: em debug, o programa crasha ao inves de silenciosamente produzir valor errado. Em producao, voce escolhe o comportamento que quer de forma explicita.
Python e a Excecao da Regra
Python faz algo que a maioria das linguagens nao faz: inteiros crescem automaticamente. Um int em Python pode ter qualquer tamanho, limitado apenas pela RAM disponivel.
# Python: sem overflow de inteiros nativos
x = 2**63 # 9223372036854775808
print(x) # funciona perfeitamente
x = 2**1000 # numero astronomico
print(x) # Python calcula sem problema
# Mas... numpy e ctypes tem overflow classico!
import numpy as np
a = np.int8(127)
print(a + 1) # -128 - overflow classico!Python parece resolver o problema, mas tem custo: operacoes com inteiros grandes sao muito mais lentas que operacoes nativas de 64 bits. Por isso numpy usa tipos fixos, e ai o overflow volta.
Como Prevenir Integer Overflow
Conhecer o problema e metade do caminho. A outra metade e saber quando e como se proteger.
- Escolha o tipo certo para o dado: se um valor pode passar de 2 bilhoes, use int64 desde o inicio. Nao espere o bug aparecer em producao.
- Valide inputs no limite do sistema: nunca confie em valores externos. Se um usuario pode enviar um numero, valide o range antes de operar.
- Cuidado com calculos intermediarios: (a + b) / 2 pode causar overflow mesmo que a e b individualmente sejam validos. Use a + (b - a) / 2.
- Use funcoes de verificacao quando necessario: checked_add em Rust, Math.addExact em Java, ou implementacoes manuais em C.
- Ative warnings de overflow no compilador: GCC tem -ftrapv para detectar overflow de inteiros com sinal em runtime.
- Teste com valores no limite: sempre inclua testes com INT_MAX, INT_MIN e valores proximo a esses limites.
- Documente suposicoes sobre ranges: se uma variavel so pode ter valores de 0 a 1000, documente isso e adicione assertions.
Tecnica: safe arithmetic em C
#include <limits.h>
#include <stdbool.h>
// Adicao segura que detecta overflow
bool safe_add(int a, int b, int *result) {
if (b > 0 && a > INT_MAX - b) return false; // overflow positivo
if (b < 0 && a < INT_MIN - b) return false; // overflow negativo
*result = a + b;
return true;
}
int main() {
int result;
if (!safe_add(INT_MAX, 1, &result)) {
printf("Overflow detectado! Operacao abortada.\n");
} else {
printf("Resultado: %d\n", result);
}
return 0;
}Quando overflow e intencional
Nem todo overflow e bug. Checksums, hash functions e geradores de numeros pseudoaleatorios frequentemente dependem de wrap-around intencional. A diferenca e documentacao e intencionalidade: use tipos unsigned quando wrap-around e o comportamento esperado, e documente claramente que o overflow e proposital.
Ferramentas para Detectar Overflow
Detectar overflow manualmente em bases de codigo grandes e impossivel. Felizmente existem ferramentas para isso.
- AddressSanitizer + UBSan (C/C++): compile com -fsanitize=undefined,address para detectar overflow em tempo de execucao durante testes.
- Valgrind Memcheck: detecta varios tipos de comportamento indefinido incluindo overflow em C/C++.
- Coverity e CodeSonar: analise estatica comercial que encontra overflows sem executar o codigo.
- Infer (Facebook/Meta): analise estatica open-source para C, Java e Objective-C.
- KLEE: execucao simbolica que explora automaticamente caminhos de codigo em busca de overflows.
- Miri (Rust): interpreta codigo Rust para detectar comportamento indefinido mesmo em modo release.
Para projetos criticos como os da NASA, onde integer overflow pode custar vidas e bilhoes, a abordagem e usar multiplas ferramentas em camadas: analise estatica no CI, sanitizers em testes, e revisao manual em codigo de seguranca.
O desastre do Ariane 5 aconteceu porque ninguem testou o sistema com os valores reais do novo foguete. Uma simples verificacao de range teria evitado tudo. Da pra aprender muito sobre engenharia de software com esses casos historicos, e o artigo sobre o desastre do Ariane 5 mergulha fundo em todas as decisoes que levaram ao fracasso.
Resumo: O que Lembrar Sobre Integer Overflow
Integer overflow e simples de entender mas facil de ignorar. Os casos historicos mostram que o custo de ignorar pode ser catastrofico.
Checklist Final
- Inteiros tem limites fixos que dependem do tamanho do tipo (8, 16, 32, 64 bits)
- Overflow comportamento varia por linguagem: panic em Rust debug, wrap silencioso em Java, UB em C signed
- Ariane 5, Pac-Man nivel 256, Boeing 787, Gangnam Style: todos vitimas de overflow
- Escolher o tipo certo desde o inicio e a prevencao mais simples
- Calculos intermediarios podem causar overflow mesmo que os valores finais caibam no tipo
- Use ferramentas de analise estatica e sanitizers em projetos criticos
- Python evita o problema com inteiros de precisao arbitraria, mas numpy e ctypes tem overflow classico
Perguntas frequentes
O que e integer overflow?
Integer overflow acontece quando uma operacao matematica produz um resultado maior do que o tipo de dado consegue armazenar. Em vez de dar erro, o numero 'transborda' e vira um valor incorreto, geralmente negativo ou zero.
Integer overflow causa crash no programa?
Depende da linguagem. Em C e C++, overflow em inteiros com sinal e comportamento indefinido e pode crashar ou gerar valores errados silenciosamente. Em Java, o overflow acontece silenciosamente com wrap-around. Em Rust, o programa entra em panic no modo debug.
Como prevenir integer overflow no dia a dia?
Use tipos de dados adequados ao problema (int64 para valores grandes), valide inputs antes de operar, use bibliotecas de aritmetica segura quando necessario, e em linguagens como Rust habilite overflow checks em producao.
Como Computadores Guardam Numeros
Antes de falar de overflow, precisa entender como inteiros funcionam em memoria. Computadores guardam tudo em bits: zeros e uns. Um inteiro de 8 bits pode representar 256 valores diferentes (2^8). Para inteiros sem sinal (unsigned), esses 256 valores vao de 0 a 255. Para inteiros com sinal (signed), metade fica para negativos: -128 a 127. E aqui esta a pegadinha. Computadores usam um sistema chamado complemento de dois para representar negativos. No bit mais significativo (o da esquerda), 0 significa positivo e 1 significa negativo. O numero 127 em binario de 8 bits e 01111111. Se voce somar 1 a isso, fica 10000000. Sabe qual numero esse padrao representa? -128.
Como Overflow Acontece em Cada Linguagem
Cada linguagem trata overflow de um jeito. E importante saber o comportamento da sua linguagem especifica. A diferenca entre signed e unsigned em C e critica: overflow de unsigned e comportamento definido (wrap-around). Overflow de signed e comportamento indefinido. O compilador pode fazer literalmente o que quiser, incluindo remover loops inteiros que ele julgar 'impossíveis' por assumir que overflow nao ocorre. Java nao lanca excecao em overflow de inteiros. O valor simplesmente faz wrap-around. Isso e especialmente perigoso porque parece que esta funcionando.
Como Prevenir Integer Overflow
Conhecer o problema e metade do caminho. A outra metade e saber quando e como se proteger.