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;
}
È stato utile?

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 da malloc()?


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 chiamate printf / 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:

  1. malloc(3) restituisce void * 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 prototipare gcc può essere abbastanza serio. Alcuni ambienti a 64 bit non supportano realmente l'amplificatore K &; R C. :-)
  2. A proposito di avvisi, assicurati di attivarli tutti. Con -Wall puoi accenderne la maggior parte con <=>.
  3. Non stai verificando il valore di ritorno di <=> per un errore.
  4. Utilizza un debugger di memoria come Electric Fence . Ci sono molte scelte, vedi il mio link.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top