lunes, 6 de julio de 2015

Guarreando con los límites de un array

Como no puede ser de otra forma, en el día a día, por muchos años que lleve uno desarrollando, siempre nos encontramos con el típico error latoso provocado por acceder fuera de los límites de memoria de una estructura de datos. Algunos lenguajes son totalmente permisivos y no avisan, otros sacan "warning" y siguen adelante, otros mueren ante estas situaciones. Me entró el otro día la curiosidad de ver cómo reaccionan diferentes lenguajes antes estos errores, así que me preparé unas líneas de código triviales en diferentes lenguajes para comprobarlo. Se trata de acceder fuera de los límites de un array. En Perl:
#!/usr/bin/perl
use strict;
my @input = ("This", "is", "an", "array");
my $max = 4;
for (my $x=0; $x<=$max; $x++) {
printf("Index: %d // Value: %sn", $x, $input[$x]);
}
printf "Goodbye, I'm Perl!n";

En PHP:
<?php
$input = array("This", "is", "an", "array");
$max = 4;
for ($x=0; $x<=$max; $x++) {
echo sprintf("Index: %d // Value: %sn", $x, $input[$x]);
}
echo "Goodbye, I'm PHP!n";

En Python:
#!/usr/bin/env python

input = ["This", "is", "an", "array"];
max = 4;
for x in range(max+1):
print "Index: %d // Value: %s" % (x, input[x]);
print "Goodbye, I'm Python";

En C:
#include 

int main() {
char *input[] = {"This", "is", "an", "array"};
int max = 4;
for (int x=0; x<=max; x++) {
printf("Index: %d // Value: %sn", x, input[x]);
}
printf("Goodbye, I'm C!n");

}

En Java:
class out {
public static void main(String[] args) {
String[] input = {"This", "is", "an", "array"};
int max = 4;
for (int x=0; x<=max; x++) {
System.out.printf("Index: %d // Value: %sn", x, input[x]);
}
System.out.println("Goodbye, I'm Java");
}
}

En Pascal:
program Out;
Uses sysutils;

Var
max : Integer = 4;
x : Integer;
input : Array [0..3] of string[20] = ('This', 'is', 'an', 'array');
begin
for x := 0 to max do
begin
Writeln('Index: ' + IntToStr(x) + ' // Value: ' + input[x]);
end;
end.

He ignorado deliberadamente los modismos de cada lenguaje para hacer algo similar en todos (jamás recorrería una lista en Python de esta forma). Al ejecutarlo, es curioso ver cómo reacciona cada lenguaje en cada plataforma. Por ejemplo, en un MacOSX:




Veamos en un Linux:



Es curioso el comportamiento de la versión en C. En Mac OSX devuelve un valor sin fallar (accede a un área de memoria que no le pertenece) y en Linux hace un "segfault". La línea de compilación es la misma en ambos casos: gcc -std=c99 -o outc out.c, pero el ejecutable resultante no se comporta igual. Tendría que mirarlo más a fondo ;)