Seudonimización (informática)

En informática, seudonimizar 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 seudonimizaciones, lo que puede no ser esperado por el programador. Como resultado, seudonimizar hace que sea particularmente difícil comprender, analizar y optimizar los programas. Los analizadores de seudonimización tienen la intención de crear y calcular información útil para comprender la seudonimización en los programas.

Ejemplos

Desbordamiento de búfer

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 aprovechar 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 seudonimización escribiendo fuera de la matriz (un tipo de desbordamiento de búfer ). Esto desata un comportamiento indefinido de acuerdo con la especificación del lenguaje C; sin embargo, muchas implementaciones del C mostrarán los efectos de seudonimización 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 de matriz relevante. Por ejemplo, si hay una matriz int de tamaño 2 (para este ejemplo, llámela arr ), junto a otra variable int (llámela i ), arr[2] (es decir, el tercer elemento) tendría un alias i si son adyacentes en la memoria.

# include <stdio.h>

int main()
{
  int arr[2] = { 1, 2 };
  int i=10;

  /* Write beyond the end of arr. Undefined behaviour in standard C, will write to i in some implementations. */
  arr[2] = 20;

  printf("element 0: %d \t", arr[0]); // outputs 1
  printf("element 1: %d \t", arr[1]); // outputs 2
  printf("element 2: %d \t", arr[2]); // outputs 20, if aliasing occurred
  printf("i: %d \t\t", i); // might also output 20, not 10, because of aliasing, but the compiler might have i stored in a register and print 10
  /* arr size is still 2. */
  printf("arr size: %lu \n", (long) (sizeof(arr) / sizeof(int)));
}

Esto es posible en algunas implementaciones del C porque una matriz es un bloque de memoria contigua, y los elementos de la matriz simplemente se referencian mediante compensaciones 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, es posible verificar, indexar y direccionar fuera de la matriz. Tenga en cuenta que el comportamiento de seudonimización antes mencionado es un comportamiento indefinido . Algunas implementaciones pueden dejar espacio entre matrices y variables en la pila, por ejemplo, para alinear variables en ubicaciones de memoria que son un múltiplo del tamaño de palabra nativo de la arquitectura. El estándar C generalmente no especifica cómo se distribuirán los datos en la memoria. (ISO/IEC 9899:1999, sección 6.2.6.1).

No es un error que un compilador omita los efectos de seudonimización para los accesos que se encuentran fuera de los límites de una matriz.

Punteros con seudonimización

Otra variedad de seudonimización 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 ). Vea el ejemplo de C del algoritmo de intercambio XOR que es una función; asume que los dos punteros que se le pasan son distintos, pero si son iguales (o alias entre sí), la función falla. Este es un problema común con las funciones que aceptan argumentos de puntero, y su tolerancia (o la falta de ella) para la seudonimización debe documentarse cuidadosamente, particularmente para las funciones que realizan manipulaciones complejas en las áreas de memoria que se les pasan.

Seudonimización especificado

El comportamiento de la seudonimización controlada puede ser deseable en algunos casos (es decir, el comportamiento de la seudonimización que se especifica, a diferencia del habilitado por 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, el comportamiento de creación de seudonimización, como en los bucles foreach . Esto permite que ciertas estructuras de datos se modifiquen directamente con menos código. Por ejemplo,

my @array = (1, 2, 3);

foreach my $element (@array) {
    # Increment $element, thus automatically
    # modifying @array, since $element is ''aliased''
    # to each of @array's elements in turn.
    $element++;
}

print "@array \n";

imprimirá "2 3 4" como resultado. Si uno quisiera omitir los efectos de seudonimización, podría copiar el contenido de la variable de índice en otra y cambiar la copia.

Conflictos con la optimización

Los optimizadores a menudo tienen que hacer suposiciones conservadoras sobre las variables cuando es posible crear seudonimizaciones. Por ejemplo, conocer el valor de una variable (como x es 5) normalmente permite ciertas optimizaciones (como la propagación constante ). Sin embargo, el compilador no puede usar esta información después de una asignación a otra variable (por ejemplo, en C, *y = 10 ) porque podría ser que *y sea un alias de x . Este podría ser el caso después de una asignación 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 de que x es 5 a las declaraciones que siguen *y = 10 sería potencialmente incorrecto (si *y es de hecho un alias de x ). Sin embargo, si hay información sobre punteros, el proceso de propagación constante podría hacer una consulta como: ¿puede x ser un alias de *y ? Entonces, si la respuesta es no, x = 5 se puede propagar con seguridad.

Otra optimización afectada por la creación de seudonimizaciones es el reordenamiento del código. Si el compilador decide que x no tiene un alias *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 mejora la programación o permite realizar más optimizaciones de bucle .

Para habilitar dichas optimizaciones de manera predecible, el estándar ISO para el lenguaje de programación C (incluida su edición C99 más reciente, 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 seudoniminaciones. Esta regla, conocida como la regla de seudonimización 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 conteo de referencias,[2] y requirió cambios en las estructuras de objetos básicos en Python 3 para habilitar esta optimización. El kernel de Linux hace esto porque la seudonimización estricta causa problemas con la optimización del código en línea.[3] En tales casos, cuando se compila con gcc, se invoca la opción -fno-strict-aliasing para evitar optimizaciones no deseadas que podrían generar código inesperado.

Seudonimización de hardware

El término seudonimización también se usa para describir la situación en la que, debido a una elección de diseño de hardware o una falla de hardware, uno o más de los bits de dirección disponibles no se usan en el proceso de selección de memoria.[4] Esta 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 caso de falla, uno o más bits de dirección pueden cortocircuitarse, o pueden forzarse a tierra (0 lógico) o al voltaje de suministro (1 lógico).

Ejemplo

Para este ejemplo, asumiendo un diseño de memoria con 8 ubicaciones, requiriendo solo 3 líneas de dirección (o bits ) ya que 2 3 = 8). Los bits de dirección (denominados A2 a A0) se decodifican para seleccionar ubicaciones de memoria únicas de la siguiente manera, en forma de contador binario estándar:

A2 A1 A0 Ubicación de la memoria
0 0 0 0
0 0 1 1
0 1 0 2
0 1 1 3
1 0 0 4
1 0 1 5
1 1 0 6
1 1 1 7

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 (por ejemplo, A2) se cortocircuitara a tierra, la tabla se modificaría de la siguiente manera:

A2 A1 A0 Ubicación de la memoria
0 0 0 0
0 0 1 1
0 1 0 2
0 1 1 3
0 0 0 0
0 0 1 1
0 1 0 2
0 1 1 3

En este caso, con A2 siempre siendo 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 ocurriera 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 solo bit de dirección reduce el espacio de memoria disponible a la mitad, con la consiguiente duplicación (seudonimización) del espacio restante.

Véase también

  • Anti-seudonimización
  • Seudonimización para usos de la palabra cuando se aplica al procesamiento de señales, incluidos los gráficos por computadora

Referencias

  1. Mike Acton (1 de junio de 2006). «Understanding Strict Aliasing».
  2. Neil Schemenauer (17 de julio de 2003). «ANSI strict aliasing and Python».
  3. Linus Torvalds (26 de febrero de 2003). «Re: Invalid compilation without -fno-strict-aliasing».
  4. Michael Barr (27 de julio de 2012). «Software Based Memory Testing».
Este artículo ha sido escrito por Wikipedia. El texto está disponible bajo la licencia Creative Commons - Atribución - CompartirIgual. Pueden aplicarse cláusulas adicionales a los archivos multimedia.