• Publicidad

Revolución en Perl v5.18 (hashes)

Novedades y noticias acerca de todo lo relacionado a Perl.

Revolución en Perl v5.18 (hashes)

Notapor explorer » 2012-12-10 15:42 @696

Desde hace unas semanas, la gente que se dedica a crear las nuevas versiones del intérprete de Perl (los Perl 5 Porters), decidieron cambiar el algoritmo de los hashes, más bien, en el orden de la creación de los pares clave/valor.

Los hash en Perl v5 ya se ordenaban de forma aleatoria, por un tema que tiene que ver con asuntos de seguridad: los hash se pueden usar para temas de claves/autenticación, y en esos casos es vital que nadie, desde fuera del programa, pueda adivinar el orden de creación de esos pares.

Pero ahora han añadido un elemento de seguridad más: el orden de creación de los hashes será diferente en cada ejecución del programa.

Entonces, ya que sabíamos que en nuestros programas no debíamos confiar en el orden de los pares clave/valor, ahora se junta la dificultad que tampoco debemos confiarnos en que en cada ejecución del programa, las claves y valores son devueltos siempre en el mismo orden.

A partir de Perl v5.17.6 se han empezado a recibir mensajes de error en muchos módulos de CPAN, precisamente por ese "pequeño" detalle.

Un ejemplo. Supongamos el siguiente trozo de código:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $ops   = join "|", map quotemeta, keys %hash;
  2. my $regex = qr/^($ops)?($rest_of_regex)/;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


¿Se ve el problema? La expresión regular con una alternativa viene derivada de las claves de un hash. Al principio, parece que no es importante el orden de los miembros en la alternancia... excepto cuando un miembro es un prefijo de otro, y en ese caso el primero gana. Por ejemplo, buscando por "absurdo" con qr/^(a|ab|abc)?(.*)/ no es lo mismo que hacerlo con qr/^(abc|ab|a)?(.*)/: en un caso, $1 contendrá 'a', y en el otro caso, 'ab'.

Esto está provocando un revuelo tremendo en muchos autores de módulos, que tienen que revisar sus códigos, para evitar estos problemas. En la mayor parte de los casos, se puede resolver sacando las claves (y/o valores) en un determinado orden, con sort() o cualquier otro método de ordenación.

Como se indica en perlsec, desde la versión v5.8.1 (año 2003), Perl nunca ha garantizado ninguna ordenación de las claves de un hash, y de hecho la ordenación ha cambiado varias veces a lo largo de la historia. El problema es que muchos desarrolladores inadvertidamente acaban confiando en la ordenación por defecto de los hash, o en un aleatorio, pero orden constante, simplemente porque el ese orden funcionaba en su máquina. Vamos... un error difícil de cazar...

Ejemplo. Supongamos el siguiente programa Perl de una línea:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. perl -E 'local $,=q[, ]; $hash{$_} = $_ for 1..15; say keys %hash'
  2. 6, 11, 3, 7, 9, 12, 2, 15, 14, 8, 1, 4, 13, 10, 5
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


¿Qué sucede si el código añade una decimosexta clave y, entonces, como si corrigiéramos un error, la volvemos a quitar? Siguen estando quince claves, las mismas claves que antes, pero, estarán en el mismo orden, ¿no? Pues no:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. perl -E 'local $,=q[, ]; $hash{$_}=$_ for 1..15; $hash{16}=16; delete $hash{16}; say keys %hash'
  2. 11, 7, 2, 1, 13, 6, 3, 9, 12, 14, 15, 8, 4, 10, 5
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Esto sucede siempre, como cuando reutilizamos una variable hash:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     sub init { ( 1=>1, 2=>2, 3=>3, 4=>4, 5=>5 ) }
  2.  
  3.     my %hash = init();
  4.     say "original: " . join ', ' => keys %hash;
  5.     $hash{$_} = $_ for 6..100;
  6.  
  7.     %hash = init(); # recupera los valores originales
  8.     say "original? " . join ', ' => keys %hash;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Esto es lo que se obtiene en un antiguo Perl v5.14.3:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
    original: 4, 1, 3, 2, 5
    original? 2, 1, 3, 4, 5
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Como se ve, esto es un problema real y puede acechar en cualquier código nuestro. El parche que se ha puesto en los Perl de desarrollo (ahora v5.17) es mostrar este comportamiento de una forma más explícita. Esto es bueno, porque aparte de añadir una protección extra en temas de seguridad, mostrará código erróneo de forma más fácil. Si ejecutamos el código anterior con la versión v5.17.6 obtendremos un orden de las claves diferente en cada ejecución:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. perl -E 'local $,=q[, ]; $hash{$_} = $_ for 1..15; say keys %hash'
  2. 1, 5, 15, 12, 6, 4, 10, 9, 3, 13, 7, 14, 11, 2, 8
  3. perl -E 'local $,=q[, ]; $hash{$_} = $_ for 1..15; say keys %hash'
  4. 5, 11, 7, 3, 15, 6, 12, 2, 13, 9, 8, 14, 10, 1, 4
  5. perl -E 'local $,=q[, ]; $hash{$_} = $_ for 1..15; say keys %hash'
  6. 2, 15, 14, 13, 5, 1, 9, 10, 3, 11, 6, 8, 12, 4, 7
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Así que ya sabéis: hay que repasar nuestro código, sobre todo cuando usemos las funciones keys(), values() y each().


JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Publicidad

Volver a Noticias de Perl

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 4 invitados