Question

J'ai besoin d'aide, car cela me déroute dans mon programme C

J'ai 2 chaînes (base et chemin)

BASE: /home/steve/cps730
PATH: /page2.html

C’est ainsi que printf lit avant d’appeler un sprintf pour joindre son contenu. voici le bloc de code

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

Maintenant, pouvez-vous expliquer le retour de l'instruction 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

parce que cela ne le comprend pas du tout.

** J'ai ajouté 9000 dans l'instruction malloc pour empêcher le programme de planter (car la taille de la chaîne est évidemment plus grande que 31 octets.

Sortie complète

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 ................... Tout le code qui utilise ces variables

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;
}
Était-ce utile?

La solution

Vous appelez readPage avec un pointeur non valide path - il pointe dans la mémoire précédemment allouée avec le pointeur method, qui est libéré juste avant l'appel de malloc. Le prochain <=> peut réutiliser cette mémoire et alors tout peut arriver ...

Autres conseils

Eh bien, cela ne peut évidemment pas arriver: -)

Je suppose que votre tas est déjà horriblement corrompu.

Je regarderais les valeurs de pointeur réelles utilisées par filepath, input et base. Je me demande si vous constaterez que cette entrée est très proche de filepath?

Je voudrais aussi voir comment le chemin de fichier, la base, etc. ont été créés à l'origine, pourriez-vous avoir un buffer surchargé là-bas?

Essayez ce code:

#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;
}

Si cela ne pose pas de problème, il doit y avoir un problème ailleurs dans le code. C’est ainsi que des comportements indéfinis peuvent parfois se manifester (déranger le fonctionnement d’un code non lié).

(Au fait, je n'ai pas ajouté +1 aux deux appels strlen, car la chaîne concaténée aura toujours un seul terminateur nul.)

Étant donné que la BASE_DIR valeur se répète, filepath ou input chevauche probablement la sprintf mémoire.

Assurez-vous que <=> et <=> disposent réellement de mémoire.

Un premier essai consiste simplement à créer une copie locale de <=> et <=> avant d'appeler <=>.

Aaah - le frisson de la poursuite alors que la question se modifie pendant que nous essayons de résoudre le problème!

Le code actuel ressemble à:

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);
    }
    ...

Question: s’il s’applique sur un serveur Web, est-il prudent d’utiliser la fonction thread-unsafe strtok()? Je vais supposer "oui, c'est sûr", même si je ne suis pas totalement convaincu. Avez-vous imprimé la chaîne header? Avez-vous imprimé la valeur de path? Aviez-vous vraiment l'intention de divulguer le malloc() + strcpy() alloué? Saviez-vous que la séquence BASE_DIR ne copie pas input dans filepath?

La version d'origine du code s'est terminée par:

 printf("\n\nPATH: %s\n\n", filepath);

D'où la réponse partielle suggérée dans l'original:

  

Vous formatez en sprintf(); vous imprimez à partir de malloc()?

Quelle est la probabilité que (char *) pointe vers une mémoire déjà libérée? Lorsque vous allouez la mémoire, il se peut que rien ne se passe dans la zone quasi-aléatoire que <=> désignait auparavant. Une autre possibilité pourrait être que <=> soit un pointeur sur une variable locale dans une fonction renvoyée - ainsi, il pointe vers un emplacement aléatoire de la pile qui est réutilisé par un autre code, tel que <=>.

J'ai également mentionné dans un commentaire que vous pourriez probablement avoir besoin de vous assurer que <=> est déclaré et d'en vérifier la valeur de retour. Le transtypage <=> n'est pas obligatoire en C (il l'est en C ++) et beaucoup préfèrent ne pas l'inclure si le code est strictement C et non bilingue en C et C ++.

Ce code fonctionne pour moi:

#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);
}

Cela produit des lignes vides superflues plus:

Alloc: 31
BASE: /home/steve/cps730
PATH: /page2.html
PATH: /page2.html
PATH: /home/steve/cps730/page2.html

Le moyen le plus simple de comprendre ce qui se passe est de suivre l'exécution dans un débogueur (éventuellement en traçant le code d'assembly).

Quelques suppositions sur ce qui pourrait se passer:

  • corruption de mémoire provoquée par un autre thread (semble improbable si elle est facilement répétable)
  • segment de mémoire corrompu (semble également improbable, car vous videz les 2 chaînes de composant après l'appel malloc())
  • comme mentionné par Jonathan Leffler dans un commentaire, il se peut qu'il manque un en-tête (peut-être stdio.h) et le compilateur génère la séquence de nettoyage de pile / appel incorrecte pour les appels printf / sprintf. Je m'attendrais à ce que vous voyiez des avertissements concernant la compilation si tel était le cas - ceux dont vous devriez prendre note.

Quel compilateur / cible utilisez-vous?

Pour le faire correctement, je changerais le code en:

/* 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;
}

Suggestions

Il n'y a évidemment aucun problème avec le programme. Mise à jour: eh bien, il y a quelque chose d'évident maintenant. Pour la première heure, seules quelques lignes ont été postées et elles ne présentaient aucun bogue grave. ) Vous devrez en poster plus. Voici quelques idées:

  1. malloc(3) renvoie void * il ne devrait donc pas être nécessaire de le lancer. Si vous recevez un avertissement, cela signifie probablement que vous n'avez pas inclus <stdlib.h>. Si vous ne l'êtes pas, vous devriez. (Par exemple, sur un système 64 bits, le prototypage gcc peut être assez sérieux. Certains environnements 64 bits ne prennent pas vraiment en charge K & Amp; R C.: -)
  2. En parlant d’avertissements, assurez-vous de les activer tous. Avec -Wall vous pouvez activer la plupart d’entre eux avec <=>.
  3. Vous ne recherchez pas d'erreur dans la valeur de retour de <=>.
  4. Utiliser un débogueur de mémoire comme Clôture électrique . Il y a beaucoup de choix, voir mon lien.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top