题
我需要一些帮助,因为它让我在我的 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
因为它根本不明白。
** 我在 malloc 语句中添加了 9000 以防止程序崩溃(因为字符串的大小明显大于 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,base等,你可以在那里运行缓冲区吗?
试试这段代码:
#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;
}
如果这没有问题,那么代码中的其他地方一定有问题。这就是未定义的行为有时可能表现出来的方式(搞乱不相关的代码如何工作)。
(顺便说一下,我没有为两个strlen调用添加+1,因为连接的字符串仍然只有一个空终止符。)
由于BASE_DIR
值重复,filepath
或input
可能与sprintf
内存重叠。
确保<=>和<=>确实已经分配了内存。
首先尝试在调用<=>之前制作<=>和<=>的本地副本。
Aaah - 在我们试图解决问题的过程中,随着问题的变化,追逐的快感!
目前的代码如下:
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);
}
...
问题:如果这是在Web服务器上运行,使用线程不安全函数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()
称呼) - 正如 Jonathan Leffler 在评论中提到的,您可能会丢失标题(也许
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;
}