En informática , una variable no inicializada es aquella que se declara pero no se le asigna un valor definido antes de su uso. Tendrá algún valor, pero no uno predecible. Por lo tanto, se trata de un error de programación y una causa común de fallos en el software.
Ejemplo del lenguaje C
Una suposición común entre los programadores novatos es que todas las variables se inicializan con un valor conocido, como cero, al declararlas. Si bien esto es cierto para muchos lenguajes, no lo es para todos, lo que aumenta la posibilidad de errores. Lenguajes como C utilizan la pila para las variables, y el conjunto de variables asignadas a una subrutina se conoce como marco de pila . Aunque el ordenador reserva el espacio necesario para el marco de pila, suele hacerlo simplemente ajustando el valor del puntero de pila , sin modificar el estado de la memoria (normalmente por motivos de eficiencia). Por lo tanto, el contenido de esa memoria en ese momento aparecerá como los valores iniciales de las variables que ocupan esas direcciones.
Aquí tienes un ejemplo sencillo en C:
void count ( void ) { int k ; for ( int i = 0 ; i < 10 ; i ++ ) { k = k + 1 ; } printf ( "%d" , k ); }El valor final de kno está definido. La respuesta de que debe ser 10 presupone que comenzó en cero, lo cual puede ser cierto o no. Nótese que en el ejemplo, la variable ise inicializa a cero mediante la primera cláusula de la forinstrucción.
Otro ejemplo puede ser cuando se trata de estructuras . En el fragmento de código a continuación, tenemos una struct studentque contiene algunas variables que describen la información sobre un estudiante. La función registerStudentfiltra contenido de memoria porque no logra inicializar completamente los miembros de struct Student newStudent. Si observamos más de cerca, al principio, age, semestery studentNumberse inicializan. Pero la inicialización de los miembros firstNamey lastNamees incorrecta. Esto se debe a que si la longitud de firstNamey lastNamelos arreglos de caracteres es menor que 16 bytes, durante strcpy, [ 1 ] no logramos inicializar completamente los 16 bytes de memoria reservados para cada uno de estos miembros. Por lo tanto, después de memcpy()pasar la estructura resultante a output, [ 2 ] filtramos algo de memoria de pila al llamador.
#include <stdio.h> #include <string.h>typedef struct { char firstName [ 16 ]; char lastName [ 16 ]; unsigned int studentNumber ; unsigned int age ; unsigned int semester ; float gpa ; } Estudiante ;int registerStudent ( Student * output , int age , char * firstName , char * lastName ) { // Si alguno de estos punteros es NULL, devuelve -1. if ( ! output || ! first_name || ! last_name ) { fprintf ( stderr , "¡Error! Algún parámetro es NULL. \n " ); return -1 ; }// Nos aseguramos de que la longitud de las cadenas sea menor a 16 bytes (incluido el byte nulo) // para evitar desbordamientos if ( strlen ( firstName ) > 15 || strlen ( lastName ) > 15 ) { fprintf ( stderr , "firstName y lastName no pueden tener más de 16 caracteres! \n " ); return -1 ; }// Inicializando los miembros Estudiante nuevoEstudiante { . número_estudiante = obtenerNuevoNúmeroEstudiante () . edad = edad ; . semestre = 1 ; . promedio = 4.0f ; } strcpy ( nuevoEstudiante . nombre , nombre ); strcpy ( nuevoEstudiante . apellido , apellido );// Copiando el resultado a la salida memcpy ( salida , & newStudent , sizeof ( Estudiante )); return 0 ; }En cualquier caso, incluso cuando una variable se inicializa implícitamente a un valor predeterminado como 0, este no suele ser el valor correcto . Inicializado no significa correcto si el valor es uno predeterminado. (Sin embargo, la inicialización predeterminada a NULL (o nullptrdesde C23 o en C++ ) es una práctica correcta para punteros y matrices de punteros, ya que los invalida antes de que se inicialicen realmente a su valor correcto). En C, las variables con duración de almacenamiento estática que no se inicializan explícitamente se inicializan a cero (o NULL, para punteros). [ 3 ]
Las variables no inicializadas no solo son una causa frecuente de errores, sino que este tipo de error es particularmente grave porque puede no ser reproducible: por ejemplo, una variable puede permanecer sin inicializar solo en alguna rama del programa. En algunos casos, los programas con variables no inicializadas incluso pueden pasar las pruebas de software .
Impactos
Las variables no inicializadas son vulnerabilidades graves, ya que pueden explotarse para filtrar memoria arbitraria, sobrescribir memoria arbitrariamente o lograr la ejecución de código, según el caso. Al explotar un software que utiliza la aleatorización del espacio de direcciones (ASLR), a menudo es necesario conocer la dirección base del software en memoria. Explotar una variable no inicializada de forma que obligue al software a filtrar un puntero de su espacio de direcciones puede utilizarse para eludir ASLR.
Uso en idiomas
Las variables no inicializadas representan un problema particular en lenguajes como el lenguaje ensamblador , C y C++ , diseñados para la programación de sistemas . El desarrollo de estos lenguajes se basó en una filosofía de diseño donde los conflictos entre rendimiento y seguridad generalmente se resolvían a favor del rendimiento. El programador era responsable de estar al tanto de problemas peligrosos como las variables no inicializadas.
En otros lenguajes, las variables a menudo se inicializan con valores conocidos cuando se crean. Algunos ejemplos son:
- VHDL inicializa todas las variables estándar con un valor especial 'U'. Se utiliza en simulación, para depuración, para que el usuario sepa cuándo los valores iniciales, a través de la lógica multivaluada , afectan la salida.
- Java no tiene variables sin inicializar. Los campos de clases y objetos que no tienen un inicializador explícito y los elementos de los arreglos se inicializan automáticamente con el valor predeterminado para su tipo ( para
falsetodos los tipos numéricos, para todos los tipos de referencia). [ 4 ] Las variables locales en Java deben asignarse definitivamente a antes de acceder a ellas, o es un error de compilación.boolean0null - Python inicializa las variables locales a
NULL(distintas deNone) y genera una excepciónUnboundLocalErrorcuando se accede a dicha variable antes de ser (re)inicializada a un valor válido. - D inicializa todas las variables a menos que el programador especifique explícitamente lo contrario.
Incluso en lenguajes donde se permiten variables no inicializadas, muchos compiladores intentarán identificar el uso de variables no inicializadas y reportarlas como errores de compilación . Algunos lenguajes ayudan en esta tarea ofreciendo construcciones para manejar la inicialización de variables; por ejemplo, C# tiene una variante especial de parámetros de llamada por referencia a subrutinas (especificados como en lugar del habitual ), que afirma que la variable puede estar sin inicializar al entrar, pero se inicializará posteriormente.outref
Véase también
Referencias
- ↑ strcpy
- ↑ memcpy()
- ↑ "ISO/IEC 9899:TC3 (Estándar C actual)" (PDF) . 7 de septiembre de 2007. pág. 126. Consultado el 26 de septiembre de 2008 .Sección 6.7.8, párrafo 10.
- ↑ "Especificación del lenguaje Java: 4.12.5 Valores iniciales de las variables" . Sun Microsystems . Consultado el 18 de octubre de 2008 .
Lecturas adicionales
- "CWE-457 Uso de variables no inicializadas" .
- Errores de software
- Variable (informática)