Вопрос

Мне нужна помощь с этим, так как это сбивает меня с толку в моей программе на C.

У меня есть 2 строки (база и путь)

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

вот как читается printf перед тем, как я вызываю sprintf, чтобы объединить их содержимое.вот блок кода

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

Теперь можете ли вы объяснить, как последний оператор printf возвращает результат?

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

потому что он вообще этого не понимает.

** Я добавил 9000 в оператор malloc, чтобы предотвратить сбой программы (поскольку размер строки явно превышает 31 байт.

Полный вывод

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

РЕДАКТИРОВАТЬ...................Весь код, использующий эти переменные

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;
}
Это было полезно?

Решение

Вы вызываете readPage с неверным указателем path - он указывает на память, ранее выделенную указателем method, которая освобождается непосредственно перед вызовом malloc. Следующий <=> может повторно использовать эту память, и тогда может произойти все что угодно ...

Другие советы

Ну, ясно, что этого не может быть: -)

Я предполагаю, что ваша куча уже ужасно испорчена.

Я бы посмотрел на фактические значения указателя, используемые filepath, input и base. Интересно, вы обнаружите, что ввод очень близок к filepath?

Я бы также посмотрел, как изначально создавался путь к файлу, база и т. д. Не могли бы вы переполнить буфер там?

Попробуйте этот код:

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

Если с этим нет проблем, то где-то в коде должно быть что-то не так. Вот как иногда может проявляться неопределенное поведение (портить работу несвязанного кода).

(Кстати, я не добавил +1 к обоим вызовам strlen, поскольку в объединенной строке по-прежнему будет только один нулевой терминатор.)

Поскольку значение BASE_DIR повторяется, filepath или input, вероятно, перекрывают sprintf память.

Убедитесь, что у <=> и <=> действительно есть выделенная память.

Первая попытка - просто сделать локальную копию <=> и <=> перед вызовом <=>.

А-а-а - острые ощущения от погони, когда вопрос трансформируется, пока мы пытаемся решить проблему!

Текущий код выглядит следующим образом:

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

Вопрос: если это выполняется на веб-сервере, безопасно ли использовать небезопасную функцию потока strtok()? Я собираюсь предположить «Да, это безопасно», хотя я не совсем убежден. Вы напечатали строку header? Вы напечатали значение path? Вы действительно намеревались утечь выделенный malloc() + strcpy()? Вы поняли, что последовательность BASE_DIR не копирует input в filepath?

<Ч>

Исходная версия кода закончилась на:

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

Следовательно, оригинальный предложенный частичный ответ:

  

Вы форматируете в sprintf(); вы печатаете из malloc()?

<Ч>

Какова вероятность того, что (char *) указывает на уже освобожденную память? Когда вы распределяете память, вы можете получить что-нибудь, происходящее с квазислучайной областью, на которую <=> указывал. Другая возможность может заключаться в том, что <=> является указателем на локальную переменную в функции, которая возвратилась, поэтому она указывает на случайное место в стеке, которое используется другим кодом, таким как <=>.

Я также упомянул в комментарии, что вам, возможно, потребуется убедиться, что <=> объявлено, и проверить возвращаемое значение из него. Приведение «<=>» не является обязательным в C (это в C ++), и многие предпочитают не включать приведение, если код строго C и не двуязычный в C и C ++.

<Ч>

Этот код работает для меня:

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

Он производит посторонние пустые строки плюс:

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

Самый простой способ выяснить, что происходит, — это проследить выполнение в отладчике (возможно, перейдя к отслеживанию ассемблерного кода).

Несколько предположений о том, что может произойти:

  • повреждение памяти другим потоком (кажется маловероятным, если это легко повторить)
  • поврежденная куча (также кажется маловероятным, поскольку вы сбрасываете две строки компонентов после malloc() вызов)
  • как упоминал Джонатан Леффлер в комментарии, возможно, вам не хватает заголовка (возможно, stdio.h), и компилятор генерирует неправильную последовательность вызовов/очистки стека для printf/sprintf звонки.Я ожидаю, что в этом случае вы увидите некоторые предупреждения во время компиляции, на которые вам следует обратить внимание.

Какой компилятор/цель вы используете?

Чтобы сделать это правильно, я бы изменил код на:

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

Предложения

<Ч>

В программе нет ничего плохого. ( Обновление: хорошо, теперь есть что-то очевидное. За первый час было опубликовано всего несколько строк, и у них не было серьезных ошибок. ) Вам придется опубликовать больше об этом. Вот несколько идей:

<Ол>
  • malloc(3) возвращает void *, поэтому нет необходимости в его приведении. Если вы получаете предупреждение, скорее всего, это означает, что вы не включили <stdlib.h>. Если нет, вам следует. (Например, в 64-битной системе отсутствие прототипирования gcc может быть довольно серьезным. Некоторые из 64-битных сред действительно не поддерживают K & Amp; R C.: -)
  • Говоря о предупреждениях, убедитесь, что вы их все включаете. С помощью -Wall вы можете включить большинство из них с помощью <=>.
  • Вы не проверяете возвращаемое значение <=> на наличие ошибки.
  • Используйте отладчик памяти наподобие Электрический забор . Есть много вариантов, смотрите мою ссылку.
  • Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top