separar - ¿Por qué strcpy desencadena una falla de segmentación con variables globales?
variables estaticas (8)
Así que tengo un código C:
#include <stdio.h>
#include <string.h>
/* putting one of the "char*"s here causes a segfault */
void main() {
char* path = "/temp";
char* temp;
strcpy(temp, path);
}
Esto compila, ejecuta y se comporta como se ve. Sin embargo, si uno o ambos punteros de caracteres se declaran como variables globales, strcpy produce un error de segmentación. ¿Por qué pasó esto? Evidentemente, hay un error en mi comprensión del alcance.
Como se mencionó anteriormente, olvidaste asignar espacio para la temperatura. Prefiero strdup
a malloc+strcpy
. Hace lo que quieres hacer.
Como se menciona en otros carteles, la raíz del problema es que la temperatura no está inicializada. Cuando se declara como una variable automática en la pila, contendrá la basura que se encuentre en esa ubicación de memoria. Aparentemente para el compilador + CPU + sistema operativo que está ejecutando, la basura en esa ubicación es un puntero válido. El strcpy "tiene éxito" en que no segfault, pero en realidad copió una cadena a una ubicación arbitraria en otro lugar de la memoria. Este tipo de problema de corrupción en la memoria genera temor en los corazones de los programadores de C en todas partes, ya que es extraordinariamente difícil de depurar.
Cuando mueve la declaración de variables temp al alcance global, se coloca en la sección BSS y se pone a cero automáticamente. Los intentos de desreferencia * temp luego dan como resultado una segfault.
Cuando mueve la ruta * al ámbito global, * la temperatura sube una ubicación en la pila. La basura en esa ubicación aparentemente no es un puntero válido, por lo que desreferenciar * temp da como resultado una segfault.
Invoca un comportamiento indefinido, ya que no está inicializando la variable de temp
. Apunta a una ubicación aleatoria en la memoria, por lo que su programa puede funcionar, pero lo más probable es segfault. Necesita que su cadena de destino sea una matriz, o que apunte a la memoria dinámica:
// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, 256, path);
// Or, use dynamic memory
char *temp = (char *)malloc(256);
strncpy(temp, 256, path);
Además, use strncpy()
lugar de strcpy()
para evitar saturaciones de búfer.
La parte importante a tener en cuenta:
El destino de la cadena de destino debe ser lo suficientemente grande para recibir la copia.
En su situación, la temperatura no tiene memoria asignada para copiar.
Copiado de la página man de strcpy:
DESCRIPTION
The strcpy() function copies the string pointed to by src (including
the terminating ''/0'' character) to the array pointed to by dest. The
strings may not overlap, and the destination string dest must be large
enough to receive the copy.
La variable de temperatura no apunta a ningún almacenamiento (memoria) y no está inicializada.
si la temperatura es declarada como char temp[32];
entonces el código funcionaría sin importar dónde se declare. Sin embargo, existen otros problemas para declarar la temperatura con un tamaño fijo como ese, pero esa es una pregunta para otro día.
Ahora, ¿por qué falla cuando se declara de forma global y no localmente? Suerte...
Cuando se declara localmente, el valor de la temperatura viene del valor que pueda haber en la pila en ese momento. Es una suerte que apunta a una dirección que no causa un bloqueo. Sin embargo, está destruyendo la memoria utilizada por otra persona.
Cuando se declaran globalmente, en la mayoría de los procesadores, estas variables se almacenarán en segmentos de datos que utilizarán cero demandas de páginas. Así, char *temp
aparece como si hubiera sido declarado char *temp=0
.
Me gustaría volver a escribir el primer fragmento de Adam como
// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, sizeof(temp), path);
temp[sizeof(temp)-1] = ''/0'';
De esa manera usted:
1. don''t have magic numbers laced through the code, and
2. you guarantee that your string is null terminated.
El segundo punto es la pérdida del último carácter de su cadena de origen si tiene> = 256 caracteres.
No, esto no funciona independientemente de las variables, simplemente se ve como lo hizo porque tienes (no) suerte. Debe asignar espacio para almacenar el contenido de la cadena, en lugar de dejar la variable sin inicializar.
Las variables no inicializadas en la pila apuntan a ubicaciones de memoria prácticamente aleatorias. Si estas direcciones resultan ser válidas, su código pisoteará todo lo que haya allí, pero no obtendrá un error (pero puede generar errores desagradables relacionados con la corrupción de la memoria en cualquier parte de su código).
Los globales fallan consistentemente porque generalmente se establecen en patrones específicos que apuntan a la memoria no asignada. Intentar desreferenciarlos le da un segfault inmediatamente (lo cual es mejor, dejarlo para más tarde hace que el error sea muy difícil de rastrear).
Olvidaste asignar e inicializar la temperatura:
temp = (char *)malloc(TEMP_SIZE);
Solo asegúrate de que TEMP_SIZE sea lo suficientemente grande. También puede calcular esto en tiempo de ejecución, luego asegúrese de que el tamaño sea suficiente (debe ser al menos Strlen (ruta))