Pergunta

Qual é a prática mais eficaz para prevenir estouro aritmético e estouro negativo?

Alguns exemplos que vêm à mente são:

  • testes baseados em intervalos de entrada válidos
  • validação usando métodos formais
  • uso de invariantes
  • detecção em tempo de execução usando recursos de linguagem ou bibliotecas (isso não impede)
Foi útil?

Solução

Uma possibilidade é usar uma linguagem que tenha números inteiros de tamanho arbitrário que nunca estourem/estourem.

Caso contrário, se isso é algo que realmente o preocupa e se sua linguagem permitir, escreva uma classe wrapper que atue como um número inteiro, mas verifique se há estouro em cada operação.Você pode até fazer com que ele verifique as compilações de depuração e deixe as coisas otimizadas para as compilações de lançamento.Em uma linguagem como C++, você poderia fazer isso e se comportaria quase exatamente como um número inteiro para compilações de lançamento, mas para compilações de depuração você obteria verificação completa em tempo de execução.

class CheckedInt
{
private: 
    int Value;

public:
    // Constructor
    CheckedInt(int src) : Value(src) {}

    // Conversions back to int
    operator int&() { return Value; }
    operator const int &() const { return Value; }

    // Operators
    CheckedInt operator+(CheckedInt rhs) const
    {
        if (rhs.Value < 0 && rhs.Value + Value > Value)
            throw OverflowException();
        if (rhs.Value > 0 && rhs.Value + Value < Value)
            throw OverflowException();
        return CheckedInt(rhs.Value + Value);
    }

    // Lots more operators...
};

Editar:

Acontece que alguém está já fazendo isso para C++ - a implementação atual está focada no Visual Studio, mas parece que eles também estão recebendo suporte para o gcc.

Outras dicas

Eu escrevo muito código de teste para verificar o intervalo/validade do meu código.Isso tende a capturar a maioria desses tipos de situações - e definitivamente me ajuda a escrever um código mais à prova de balas.

Use números de ponto flutuante de alta precisão como um longo duplo.

Acho que está faltando uma opção muito importante na sua lista:escolha a linguagem de programação certa para o trabalho.Existem muitas linguagens de programação que não apresentam esses problemas, porque não possuem números inteiros de tamanho fixo.

Há considerações mais importantes ao escolher qual idioma usar do que o tamanho do número inteiro.Basta verificar sua entrada se não souber se o valor está dentro dos limites ou usar o tratamento de exceções se o caso for extremamente raro.

Um wrapper que verifica inconsistências fará sentido em muitos casos.Se uma operação aditiva (ou seja, adição ou multiplicação) em dois ou mais números inteiros resultar em um valor menor que os operandos, então você sabe que algo deu errado.Cada operação aditiva deve ser seguida por,

if (sum < operand1 || sum < operand2)
    omg_error();

Da mesma forma, qualquer operação que deva logicamente resultar em um valor menor deve ser verificada para ver se foi incorporada acidentalmente.

Você investigou o uso de métodos formais para verificar seu código e provar que ele está livre de overflows?Uma técnica de métodos formais conhecida como interpretação abstrata pode verificar a robustez do seu software para provar que ele não sofrerá overflow, underflow, divisão por zero, overflow ou outro erro de tempo de execução semelhante.É uma técnica matemática que analisa exaustivamente o seu software.A técnica foi iniciada por Patrick Cousot na década de 1970.Foi usado com sucesso para diagnosticar uma condição de transbordamento no foguete Arian 5, onde um transbordamento causou a destruição do veículo lançador.O estouro foi causado durante a conversão de um número de ponto flutuante em um número inteiro.Você pode encontrar mais informações sobre esta técnica aqui e também em Wikipédia.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top