En informática , el alias describe una situación en la que se puede acceder a una ubicación de datos en la memoria a través de diferentes nombres simbólicos en el programa. Por lo tanto, modificar los datos a través de un nombre modifica implícitamente los valores asociados con todos los nombres con alias, lo que puede no ser esperado por el programador. Como resultado, el aliasing hace que sea particularmente difícil comprender, analizar y optimizar programas. Los analizadores de alias tienen como objetivo generar y calcular información útil para comprender el alias en los programas.
Por ejemplo, la mayoría de las implementaciones del lenguaje de programación C no realizan la verificación de los límites de la matriz . Luego se puede explotar la implementación del lenguaje de programación por parte del compilador y las convenciones del lenguaje ensamblador de la arquitectura de la computadora , para lograr efectos de alias escribiendo fuera de la matriz (un tipo de desbordamiento del búfer ). Esto invoca un comportamiento indefinido según la especificación del lenguaje C; sin embargo, muchas implementaciones de C mostrarán los efectos de alias descritos aquí.
Si se crea una matriz en la pila , con una variable dispuesta en la memoria directamente al lado de esa matriz , se podría indexar fuera de la matriz y cambiar directamente la variable cambiando el elemento relevante de la matriz. Por ejemplo, si hay una int
matriz de tamaño 2 (para este ejemplo, llámela arr
), junto a otra int
variable (llámela i
), arr[2]
(es decir, el tercer elemento) se le asignará un alias i
si son adyacentes en la memoria.
# incluir <stdio.h> int principal () { int arreglo [ 2 ] = { 1 , 2 }; int yo = 10 ; /* Escribe más allá del final de arr. El comportamiento indefinido en C estándar se escribirá en i en algunas implementaciones. */ arreglo [ 2 ] = 20 ; printf ( "elemento 0: %d \t " , arreglo [ 0 ]); // genera 1 printf ( "elemento 1: %d \t " , arr [ 1 ]); // genera 2 printf ( "elemento 2: %d \t " , arr [ 2 ]); // genera 20, si se produjo un alias printf ( "i: %d \t\t " , i ); // también podría generar 20, no 10, debido al alias, pero el compilador podría tener i almacenado en un registro e imprimir 10 /* el tamaño del arreglo sigue siendo 2. */ printf ( "tamaño del arreglo: %lu \n " , ( largo ) ( tamaño de ( arr ) / tamaño de ( int ))); }
Esto es posible en algunas implementaciones de C porque una matriz es un bloque de memoria contigua y los elementos de la matriz simplemente están referenciados por desplazamientos de la dirección del comienzo de ese bloque multiplicada por el tamaño de un solo elemento. Dado que C no tiene límites de verificación, es posible indexar y direccionar fuera de la matriz. Tenga en cuenta que el comportamiento de alias antes mencionado es un comportamiento indefinido . Algunas implementaciones pueden dejar espacio entre matrices y variables en la pila, por ejemplo, para alinear variables con ubicaciones de memoria que son múltiplos del tamaño de palabra nativo de la arquitectura . El estándar C generalmente no especifica cómo se deben distribuir los datos en la memoria. (ISO/IEC 9899:1999, sección 6.2.6.1).
No es erróneo que un compilador omita los efectos de alias para los accesos que quedan fuera de los límites de una matriz.
Otra variedad de alias puede ocurrir en cualquier idioma que pueda hacer referencia a una ubicación en la memoria con más de un nombre (por ejemplo, con punteros ). Este es un problema común con funciones que aceptan argumentos de puntero, y su tolerancia (o la falta de ella) al alias debe documentarse cuidadosamente, particularmente para funciones que realizan manipulaciones complejas en áreas de memoria que se les pasan.
En algunos casos, puede ser deseable un comportamiento de alias controlado (es decir, un comportamiento de alias que se especifica, a diferencia del que permite el diseño de memoria en C). Es una práctica común en Fortran . El lenguaje de programación Perl especifica, en algunas construcciones, un comportamiento de alias, como en los bucles. Esto permite modificar ciertas estructuras de datos directamente con menos código. Por ejemplo,foreach
mi @array = ( 1 , 2 , 3 ); foreach my $element ( @array ) { # Incrementa $element, modificando así automáticamente # @array, ya que $element tiene un ''alias'' # para cada uno de los elementos de @array por turno. $elemento ++ ; } imprimir "@matriz\n" ;
imprimirá "2 3 4" como resultado. Si uno quisiera evitar los efectos de alias, podría copiar el contenido de la variable de índice en otra y cambiar la copia.
Los optimizadores a menudo tienen que hacer suposiciones conservadoras sobre las variables cuando es posible el alias. Por ejemplo, conocer el valor de una variable (como x
5) normalmente permite ciertas optimizaciones (como la propagación constante ). Sin embargo, el compilador no puede utilizar esta información después de una asignación a otra variable (por ejemplo, en C, *y = 10
) porque podría ser *y
un alias de x
. Este podría ser el caso después de una tarea como y = &x
. Como efecto de esta asignación a *y
, el valor de x
también cambiaría, por lo que propagar la información que x
es 5 a las declaraciones siguientes *y = 10
sería potencialmente incorrecto (si *y
de hecho es un alias de x
). Sin embargo, si hay información sobre punteros, el proceso de propagación constante podría generar una consulta como: ¿puede x
ser un alias de *y
? Entonces, si la respuesta es no, x = 5
se podrá propagar de forma segura.
Otra optimización afectada por el alias es la reordenación del código. Si el compilador decide que x
no tiene el alias de *y
, entonces el código que usa o cambia el valor de x
se puede mover antes de la asignación *y = 10
, si esto mejoraría la programación o permitiría realizar más optimizaciones de bucle .
Para permitir tales optimizaciones de manera predecible, el estándar ISO para el lenguaje de programación C (incluida su edición más reciente C99 , consulte la sección 6.5, párrafo 7) especifica que es ilegal (con algunas excepciones) acceder a la misma ubicación de memoria utilizando punteros de diferentes tipos. Por lo tanto, un compilador puede suponer que dichos punteros no tienen alias. Esta regla, conocida como regla de alias estricta , a veces permite aumentos impresionantes en el rendimiento, [1] pero se sabe que rompe algún código que de otro modo sería válido. Varios proyectos de software violan intencionalmente esta parte del estándar C99. Por ejemplo, Python 2.x lo hizo para implementar el recuento de referencias , [2] y requirió cambios en las estructuras de objetos básicas en Python 3 para permitir esta optimización. El kernel de Linux hace esto porque el alias estricto causa problemas con la optimización del código en línea. [3] En tales casos, cuando se compila con gcc-fno-strict-aliasing
, se invoca la opción para evitar optimizaciones no deseadas que podrían generar código inesperado.
El término alias también se utiliza para describir la situación en la que, debido a una elección de diseño de hardware o a una falla del hardware, uno o más de los bits de dirección disponibles no se utilizan en el proceso de selección de memoria. [4] Esto puede ser una decisión de diseño si hay más bits de dirección disponibles de los necesarios para admitir los dispositivos de memoria instalados. En una falla, uno o más bits de dirección pueden estar en cortocircuito o pueden ser forzados a tierra (0 lógico) o al voltaje de suministro (1 lógico).
Para este ejemplo, supongamos un diseño de memoria con 8 ubicaciones, que requiere solo 3 líneas de dirección (o bits ), ya que 2 · 3 = 8). Los bits de dirección (llamados A2 a A0) se decodifican para seleccionar ubicaciones de memoria únicas de la siguiente manera, en forma de contador binario estándar :
En la tabla anterior, cada una de las 8 combinaciones únicas de bits de dirección selecciona una ubicación de memoria diferente. Sin embargo, si un bit de dirección (digamos A2) fuera puesto en cortocircuito a tierra, la tabla se modificaría de la siguiente manera:
En este caso, siendo A2 siempre cero, las primeras cuatro ubicaciones de memoria se duplican y aparecen nuevamente como las segundas cuatro. Las ubicaciones de memoria 4 a 7 se han vuelto inaccesibles.
Si este cambio se produjera en un bit de dirección diferente, los resultados de la decodificación serían diferentes, pero en general el efecto sería el mismo: la pérdida de un único bit de dirección corta el espacio de memoria disponible a la mitad, con la consiguiente duplicación (aliasing) del bit de dirección. espacio restante.