Вопрос
Мне нужна помощь с этим, так как это сбивает меня с толку в моей программе на 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
вы можете включить большинство из них с помощью <=>.