Overflow

De Viquipèdia
Dreceres ràpides: navegació, cerca

L'Overflow és l'efecte que es produeix quan un nombre sobrepassa un cert rang de valors o unes característiques numèriques.

En informàtica i programació, un desbordament de buffer (prové de l'anglès, buffer overflow o buffer overrun) és un error de software que es produeix quan es copia una quantitat de dades a una àrea que no és suficientment gran per contenir-les, sobreescrivint d'aquesta manera altres zones de memòria. Això és degut generalment a una errada de programació. La conseqüència d'escriure en una zona de memòria imprevista pot donar resultats impredictibles. Existeixen zones de memòria protegides per el sistema operatiu i si es produeix una escriptura fora d'una zona de memòria protegida es produirà una excepció. Sota certes condicions, això es pot arribar a utilitzar per a fins malintencionats.

Per exemple, volem realitzar una operació matemàtica amb dos nombres expressats en binari de 8 bits, i el resultat el guardarem en un buffer de 8 bits. Si el resultat de l'operació és un nombre binari de 9 bits, el buffer no el pot emmagatzemar completament i, per tant, perdrem informació. Aquest bit de més que tenim n'anomenem carry.

Dins del camp de la informàtica, existeixen diferents tipus d'overflow que encara avui dia són impredictibles i difícils de solucionar. Tenim un molt conegut, l'aritmètic overflow que es genera en sumar dos nombres i sortir un tercer amb una mida més gran del que s'esperava (exemple anterior, tot i que s'hi pot trobar en molts altres operacions). També hi trobem el stack overflow o desbordament de pila, que es produeix quan un programa o un procés de l'ordinador realitza masses crides a subrutines i col·lapsa la pila. I per últim, el més general, el buffer overflow, que és el més comú, i es produeix quan les dades entrants (d'un programa o subrutina) excedeixen la mida del buffer i provoca una pèrdua d'informació.

Mètodes de control de desbordament[modifica | modifica el codi]

  1. Disseny: mitjançant la selecció correcta de tipus de dades, tant en longitud com amb signe o sense.
  2. Evitar: la comprovació d'operands per endavant, és possible garantir que el resultat mai serà més gran que el que es pot emmagatzemar.
  3. Manipulació: Si es preveu que pugui passar i quan es produeixi un desbordament poden ser detectats i tractats per altres processos. Exemple: és possible sumar dos nombres de dos bytes utilitzant sumes byte a byte: primer els bytes baixos s'afegeixen a continuació, llavors es sumen els bytes alts, si s'ha produït overflow al sumar els bytes alts s'hauria de sumar 1 al següent byte. Les CPUs tenen generalment una forma de detectar això per donar suport a la suma de nombre més grans que la mida registre, típicament usant un flag indicador d'aquest estat.
  4. Propagació: si un valor és massa gran per a ser emmagatzemat se li pot assignar un valor especial que indica que s'ha produït un sobreeiximent i després tenir totes les operacions successives retornar aquest valor de l'indicador. Això és útil perquè el problema es pugui comprovar al final d'un càlcul al llarg d'una sèrie de comptes de després de cada pas. Aquest cas és controlat en càlculs de coma flotant de maquinari anomenat FPU.
  5. Ignora: Aquest és l'enfocament més comú, però dóna resultats incorrectes i pot suposar un perill. De fet, el principal problema de l'overflow és que el sistema operatiu agafi aquest mètode per tractar-ho. Ignorar aquest problema deriva en errors de lectura de memòria, d'escriptura, i fins i tot (és un cas molt conegut) pot bloquejar el sistema. Per això, cal estudiar com tractar l'overflow per tal de no ignorar el problema mai si és possible.

Exemples d'overflow[modifica | modifica el codi]

Les operacions de suma i resta són independents de la interpretació que realitzem dels nombres, ja que alguns overflows poden ser-ho i alguns no. Primer realitzarem les operacions i després interpretarem els resultats segons el tipus de dades.

010010 + 110011 = 1000101

  • Nombres naturals: Aquesta operació produeix overflow, ja que hi ha carry.
  • Nombres enters: No hi ha overflow, la suma de dos nombres de diferent signe mai produeix overflow.

110001 - 111000 = 1111001

  • Nombres naturals: Aquesta operació produeix underflow, ja que hi ha carry a la resta.
  • Nombres enters: No hi ha overflow, la resta de dos nombres del mateix signe mai produeix overflow.

010101 + 010000 = 100101

  • Nombres naturals: Aquesta operació no produeix overflow, ja que no hi ha carry.
  • Nombres enters: Hi ha overflow, la suma de dos nombres positius produeix un nombre negatiu com a resultat.

Usos de l'overflow[modifica | modifica el codi]

A part dels inconvenient que comporta, és possible utilitzar aquest efecte a favor, sobretot en termes de comptadors numèrics i temporals. Els flags o banderes d'overflow són molt útils si cal programar una tasca o interrupció interna del sistema operatiu de manera repetitiva i sense dependre d'un hardware o software gaire complex. Un simple comptador que augmenti el seu valor quan es produeixi un estat en concret pot avisar-nos al cap d'un cert nombre de repeticions (imaginem-nos una màquina que compti peces).

Tractament d'overflow en llenguatges de programació[modifica | modifica el codi]

Normalment els llenguatges de programació com per exemple Java o Python no donen una eina per controlar els errors produïts per l'overflow, per tant és problema del programador fer un bon disseny i saber quin tipus de variable es necessitarà per la seva aplicació. Tot i així es poden fer solucions més o menys elegants. Una solució senzilla és comprovar que el resultat de, per exemple, una multiplicació és correcte comprovant si la divisió pel mateix nombre dóna el mateix resultat que el nombre anterior. Exemple en java d'un overflow i el seu control:

public class Overflow
{
    public static void main(String[] args)
   {
        int h=2;
        int c;
        //Bucle infinit fins que doni overflow
        for(;;)
        {
            //Anem multiplicant per dos fins que el resultat no capiga en un tipus "enter"
            c=h*2;
            if(c/2==h)
            //Si la multiplicació ha sigut correcta, la divisió pel mateix nombre que la multiplicació ha
            //ha de donar el mateix nombre que teníem
            {
                System.out.println(h);
                h=c;
            }
            else
            {
                System.out.println("OVERFLOW  "+h);
                System.exit(-1);
            }
        }
    }
}

Molts altres llenguatges de programació estan dotats de control en temps d'execució i en alguns casos també de control en temps de compilació, cas en el qual s'envia un avís o es genera una excepció quan C o C++ podrien sobreescriure dades i continuar executant instruccions fins que s'obtenen resultats erronis. Exemples d'aquests llenguatges poden ser Ada, Eiffel, Lisp, Modula-2, Smalltalk, Objective Caml i derivats com Cyclone i D. El bytecode dels entorns Java i .NET també requereixen comprovacions de límits en tots els vectors. Gairebé tots els llenguatges interpretats protegeixen contra els buffer overflows.