sprintf()疯了

时间:2009-09-13 17:40:03

标签: c printf

我需要一些帮助,因为它让我的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;
}

8 个答案:

答案 0 :(得分:6)

使用无效指针readPage调用path - 它指向先前使用method指针分配的内存,该指针在调用readPage之前被释放。下一个malloc可以重用这个内存然后发生任何事情......

答案 1 :(得分:4)

嗯,显然这不可能发生: - )

我的猜测是你的堆已经被严重破坏了。

我会查看filepath,input和base使用的实际指针值。我想知道你是否会发现输入非常接近文件路径?

我还会看看最初如何创建filepath,base等,你可以在那里运行缓冲区吗?

答案 2 :(得分:1)

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的价值了吗?你真的打算泄漏分配的path吗?您是否意识到malloc() + strcpy()序列未将BASE_DIR复制到path


代码的原始版本以:

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

因此,原始建议的部分答案:

  

您格式化为input;你是从filepath打印的吗?


filepath指向已释放内存的几率是多少?当您分配内存时,您可能会在filepath过去指向的准随机区域发生任何事情。另一种可能性是filepath是指向已返回的函数中的局部变量的指针 - 因此它指向堆栈中随机的某个地方,正被其他代码重用,例如sprintf()。 / p>

我还在评论中提到,您可能需要确保声明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

答案 3 :(得分:1)

建议


该计划没有明显的错误。 ( 更新: 嗯,现在有一些明显的东西。第一个小时只发布了几行,而且没有严重的错误。 )你将不得不发布更多。以下是一些想法:

  1. malloc(3)返回void *,因此无需投出它。如果您收到警告,则很可能意味着您未包含<stdlib.h>。如果你不是,你应该。 (例如,在64位系统上,不是原型malloc(3)可能非常严重。某些64位环境并不真正支持K&amp; R C.: - )
  2. 说到警告,请确保你全力以赴。使用gcc,您可以使用-Wall启用大部分内容。
  3. 您没有检查malloc(3)的错误返回值。
  4. Use a memory debugger,如Electric Fence。有很多选择,请参阅我的链接。

答案 4 :(得分:1)

试试这段代码:

#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,因为连接的字符串仍然只有一个空终止符。)

答案 5 :(得分:1)

由于BASE_DIR值重复,BASE_DIRfilepath可能与input内存重叠。

确保BASE_DIRfilepath确实分配了内存。

首先尝试在致电BASE_DIR之前制作filepathsprintf的本地副本。

答案 6 :(得分:1)

找出正在发生的事情的最简单方法是在调试器中跟踪执行(可能会删除跟踪汇编代码)。

对可能发生的事情进行一些猜测:

  • 另一个线程的内存损坏(如果这很容易重复,似乎不太可能)
  • 损坏的堆(在malloc()调用后转储2个组件字符串时似乎不太可能)
  • 如Jonathan Leffler在评论中所提到的,您可能缺少标题(可能是stdio.h)并且编译器正在为printf / {{1生成错误的调用/堆栈清理序列调用。如果是这种情况,我希望你能看到一些编译时警告 - 你应该注意的。

您使用的是什么编译器/目标?

答案 7 :(得分:1)

为了正确执行此操作,我将代码更改为:

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