Domanda
Ho bisogno di aiuto con questo, poiché mi confonde nel mio programma C
Ho 2 stringhe (base e percorso)
BASE: /home/steve/cps730
PATH: /page2.html
ecco come legge printf subito prima di chiamare uno sprintf per unire insieme i loro contenuti.ecco il blocco di codice
int memory_alloc = strlen(filepath)+1;
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc+9000);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s",BASE_DIR,filepath); // :(
printf("\n\nPATH: %s\n\n",input);
Ora, puoi spiegare come ritorna l'istruzione printf finale
PATH: e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/stev
perché non lo capisce affatto.
** Ho aggiunto 9000 nell'istruzione malloc per evitare il crash del programma (poiché la dimensione della stringa è ovviamente maggiore di 31 byte.
Uscita completa
Alloc: 31
BASE: /home/steve/cps730
PATH: /page2.html
PATH: /home/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/stev
Sending:
HTTP/1.0 404 Not Found
Date: Sat, 12 Sep 2009 19:01:53 GMT
Connection: close
EDIT...................Tutto il codice che utilizza queste variabili
const char *BASE_DIR = "/home/steve/cps730";
char* handleHeader(char *header){
//Method given by browser (will only take GET, POST, and HEAD)
char *method;
method = (char*)malloc(strlen(header)+1);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
path = (char*)malloc(strlen(BASE_DIR)+1+12);
strcpy(path,"/index.html");
}
free(method);
return readPage(path);
}
else if(!strcmp(method,"POST")){
}
else if(!strcmp(method,"HEAD")){
}
else{
strcat(contents,"HTTP/1.1 501 Not Implemented\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Connection: close\n\n");
}
free(method);
}
//Return the contents of an HTML file
char* readPage(char* filepath){
int memory_alloc = strlen(filepath)+1;
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc+9000);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s\0",BASE_DIR,filepath);
printf("\n\nPATH: %s\n\n",input);
FILE *file;
file = fopen(input, "r");
char temp[255];
strcat(contents,"");
if(file){
strcat(contents, "HTTP/1.1 200 OK\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Content-Type: text/html; charset=utf-8\n");
strcat(contents, "Connection: close\n\n");
//Read the requested file line by line
while(fgets(temp, 255, file)!=NULL) {
strcat(contents, temp);
}
}
else{
strcat(contents, "HTTP/1.0 404 Not Found\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Connection: close\n\n");
}
return contents;
}
Soluzione
Chiami readPage
con un puntatore non valido path
: punta nella memoria precedentemente allocata con il puntatore method
, che viene liberato prima della chiamata in malloc
. Il prossimo <=> può riutilizzare questa memoria e quindi tutto può succedere ...
Altri suggerimenti
Beh, chiaramente questo non può accadere :-)
La mia ipotesi è che il tuo heap sia già orribilmente corrotto.
Vorrei esaminare i valori effettivi del puntatore utilizzati da filepath, input e base.Mi chiedo se scoprirai che l'input è molto vicino al percorso del file?
Vorrei anche esaminare come sono stati originariamente creati il percorso file, la base ecc., potresti avere un buffer overrun lì?
Prova questo codice:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
const char* BASE_DIR = "/home/steve/cps730";
const char* filepath = "/page2.html";
int memory_alloc = strlen(filepath);
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s",BASE_DIR,filepath); // :(
printf("\n\nPATH: %s\n\n",input);
return 0;
}
Se questo non ha un problema, allora ci deve essere qualcosa di sbagliato altrove nel codice. È così che a volte può manifestarsi un comportamento indefinito (incasinare il funzionamento del codice non correlato).
(A proposito, non ho aggiunto +1 ad entrambe le chiamate strlen, poiché la stringa concatenata avrà ancora un solo terminatore null.)
Poiché il valore BASE_DIR
si ripete da solo, filepath
o input
probabilmente si sovrappone alla sprintf
memoria.
Assicurati che sia <=> che <=> abbiano realmente allocato memoria.
Un primo tentativo è semplicemente fare una copia locale di <=> e <=> prima di chiamare <=>.
Aaah - il brivido dell'inseguimento mentre la domanda si trasforma mentre stiamo cercando di risolvere il problema!
Il codice attuale è simile a:
const char *BASE_DIR = "/home/steve/cps730";
//Handles the header sent by the browser
char* handleHeader(char *header){
//Method given by browser (will only take GET, POST, and HEAD)
char *method;
method = (char*)malloc(strlen(header)+1);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
path = (char*)malloc(strlen(BASE_DIR)+1+12);
strcpy(path,"/index.html");
}
free(method);
return readPage(path);
}
...
Domanda: se è in esecuzione in un server Web, è sicuro utilizzare la funzione thread-unssafe strtok()
? Presumo 'Sì, è sicuro', anche se non sono del tutto convinto. Hai stampato la header
stringa? Hai stampato il valore di path
? Hai davvero intenzione di perdere l'allocato malloc() + strcpy()
? Ti sei reso conto che la BASE_DIR
sequenza non copia input
in filepath
?
La versione originale del codice è terminata con:
printf("\n\nPATH: %s\n\n", filepath);
Da qui la risposta parziale suggerita originale:
Formatta in
sprintf()
; stampi damalloc()
?
Qual è la possibilità che (char *)
punti alla memoria già rilasciata? Quando assegni la memoria, potresti ricevere qualsiasi cosa accada nell'area quasi casuale a cui <=> puntava. Un'altra possibilità potrebbe essere che <=> sia un puntatore a una variabile locale in una funzione che è tornata - quindi punta a un punto casuale nello stack che viene riutilizzato da altri codici, come <=>.
Ho anche menzionato in un commento che potrebbe essere necessario assicurarsi che <=> sia dichiarato e verificarne il valore di ritorno. Il cast "<=>" non è obbligatorio in C (è in C ++) e molti preferiscono non includere il cast se il codice è rigorosamente C e non bilingue in C e C ++.
Questo codice funziona per me:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
const char *BASE_DIR = "/home/steve/cps730";
const char *filepath = "/page2.html";
int memory_alloc = strlen(filepath) + 1;
memory_alloc += strlen(BASE_DIR) + 1;
printf("\n\nAlloc: %d", memory_alloc);
char *input = (char*)malloc(memory_alloc + 9000);
printf("\n\nBASE: %s\nPATH: %s\n\n", BASE_DIR, filepath);
sprintf(input, "%s%s", BASE_DIR, filepath);
printf("\n\nPATH: %s\n\n", filepath);
printf("\n\nPATH: %s\n\n", input);
return(0);
}
Produce righe vuote estranee più:
Alloc: 31
BASE: /home/steve/cps730
PATH: /page2.html
PATH: /page2.html
PATH: /home/steve/cps730/page2.html
Il modo più semplice per capire cosa sta succedendo è di rintracciare l'esecuzione in un debugger (eventualmente cadere per tracciare il codice assembly).
Alcune ipotesi su cosa potrebbe succedere:
- danneggiamento della memoria da parte di un altro thread (sembra improbabile se questo è facilmente ripetibile)
- heap corrotto (sembra anche improbabile, dato che si scaricano le 2 stringhe del componente dopo la
malloc()
chiamata) - come menzionato da Jonathan Leffler in un commento, potresti non avere un'intestazione (forse
stdio.h
) e il compilatore sta generando una sequenza di pulizia chiamata / stack errata per le chiamateprintf
/sprintf
. Mi aspetto che vedresti alcuni avvisi in fase di compilazione se questo fosse il caso, di cui dovresti prendere nota.
Quale compilatore / destinazione stai usando?
Per farlo correttamente, cambierei il codice in:
/* CHANGED: allocate additional space for "index.html" */
method = (char*)malloc(strlen(header)+1+10);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
/* CHANGED: don't allocate new memory, use previously allocated */
strcpy(path,"/index.html");
}
/* CHANGED: call function first and free memory _after_ the call */
char *result = readPage(path);
free(method);
return result;
}
Suggerimenti
Ovviamente non c'è nulla di sbagliato nel programma. ( Aggiornamento: bene, ora c'è qualcosa di ovvio. Per la prima ora sono state pubblicate solo poche righe e non hanno avuto bug gravi. ) Dovrai postarne di più. Ecco alcune idee:
-
malloc(3)
restituiscevoid *
quindi non dovrebbe essere necessario lanciarlo. Se ricevi un avviso, molto probabilmente significa che non hai incluso<stdlib.h>
. Se non lo sei, dovresti. (Ad esempio, su un sistema a 64 bit, non prototiparegcc
può essere abbastanza serio. Alcuni ambienti a 64 bit non supportano realmente l'amplificatore K &; R C. :-) - A proposito di avvisi, assicurati di attivarli tutti. Con
-Wall
puoi accenderne la maggior parte con <=>. - Non stai verificando il valore di ritorno di <=> per un errore.
- Utilizza un debugger di memoria come Electric Fence . Ci sono molte scelte, vedi il mio link.