Domanda

Quindi ho del codice 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);
}

Questo compila, gira e si comporta come sembra. Tuttavia, se uno o entrambi i puntatori carattere vengono dichiarati come variabile globale, strcpy si traduce in un errore di segmentazione. Perché succede? Evidentemente c'è un errore nella mia comprensione dell'ambito.

È stato utile?

Soluzione

Come menzionato da altri manifesti, la radice del problema è che la temp non è inizializzata. Quando viene dichiarata come variabile automatica nello stack, conterrà qualunque rifiuto si trovi in ??quella posizione di memoria. Apparentemente per il compilatore + CPU + SO che stai eseguendo, la spazzatura in quella posizione è un puntatore valido. Lo strcpy "riesce" a " in quanto non segfault, ma in realtà ha copiato una stringa in una posizione arbitraria altrove nella memoria. Questo tipo di problema di corruzione della memoria colpisce la paura nei cuori dei programmatori C di tutto il mondo poiché è straordinariamente difficile eseguire il debug.

Quando si sposta la dichiarazione della variabile temporanea in ambito globale, questa viene inserita nella sezione BSS e automaticamente azzerata. I tentativi di dereference * temp si traducono in un segfault.

Quando si sposta * il percorso in ambito globale, * temp si sposta in alto di una posizione nello stack. La spazzatura in quella posizione apparentemente non è un puntatore valido, e quindi la dereferenziazione * temp si traduce in un segfault.

Altri suggerimenti

La variabile temp non punta a nessuna memoria (memoria) ed è non inizializzata.

se temp è dichiarato come char temp [32]; il codice funzionerebbe indipendentemente da dove viene dichiarato. Tuttavia, ci sono altri problemi nel dichiarare temp con una dimensione fissa come quella, ma questa è una domanda per un altro giorno.

Ora, perché si blocca quando viene dichiarato a livello globale e non localmente. Luck ...

Se dichiarato localmente, il valore di temp proviene da qualsiasi valore mai presente nello stack in quel momento. È una fortuna che punta a un indirizzo che non causa un arresto anomalo. Tuttavia, si tratta di eliminare la memoria utilizzata da qualcun altro.

Se dichiarate a livello globale, sulla maggior parte dei processori queste variabili verranno archiviate in segmenti di dati che utilizzeranno le pagine zero della domanda. Pertanto char * temp appare come se fosse stato dichiarato char * temp = 0 .

Hai dimenticato di allocare e inizializzare temp:

temp = (char *)malloc(TEMP_SIZE);

Assicurati solo che TEMP_SIZE sia abbastanza grande. Puoi anche calcolarlo in fase di esecuzione, quindi assicurati che la dimensione sia sufficiente (dovrebbe essere almeno strlen (percorso))

Come accennato in precedenza, hai dimenticato di allocare spazio per temp. Preferisco strdup a malloc + strcpy . Fa quello che vuoi fare.

No - questo non funziona a prescindere dalle variabili - sembra proprio che sia stato perché sei (non) fortunato. È necessario allocare spazio per archiviare il contenuto della stringa, anziché lasciare la variabile non inizializzata.

Le variabili non inizializzate nello stack indicheranno posizioni della memoria praticamente casuali. Se questi indirizzi sono validi, il tuo codice calpesterà tutto ciò che era lì, ma non otterrai un errore (ma potresti ottenere cattivi bug relativi alla corruzione della memoria altrove nel tuo codice).

I globali falliscono costantemente perché di solito vengono impostati su schemi specifici che puntano alla memoria non mappata. Tentare di dereferenziarsi ti dà immediatamente un segfault (il che è meglio - lasciarlo in un secondo momento rende il bug molto difficile da rintracciare).

Vorrei riscrivere il primo frammento di Adam come

// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, sizeof(temp), path);
temp[sizeof(temp)-1] = '\0';

In questo modo:

1. don't have magic numbers laced through the code, and
2. you guarantee that your string is null terminated.

Il secondo punto è la perdita dell'ultimo carattere della stringa di origine se è lunga > = 256 caratteri.

La parte importante da notare:
dest stringa di destinazione deve essere abbastanza grande per ricevere la copia.
Nella tua situazione, temp non ha memoria allocata per la copia in.

Copiato dalla pagina man di 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.

Stai invocando un comportamento indefinito, poiché non stai inizializzando la variabile temp . Indica una posizione casuale nella memoria, quindi il programma potrebbe funzionare, ma molto probabilmente sarà segfault. È necessario che la stringa di destinazione sia un array o che punti alla memoria dinamica:

// 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);

Inoltre, usa strncpy () invece di strcpy () per evitare sovraccarichi del buffer.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top