문제

내 C 프로그램에서 나를 당황하기 때문에 이것에 대한 도움이 필요합니다.

나는 2 개의 줄 (베이스 및 경로)이 있습니다.

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

이것이 Sprintf를 호출하기 직전에 Printf가 읽는 방식입니다. 코드 블록은 다음과 같습니다

        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 호출 직전에 해제되는 포인터 readPage. 다음 malloc 이 메모리를 재사용하면 어떤 일이든 일어날 수 있습니다 ...

다른 팁

글쎄, 분명히 이것은 일어날 수 없습니다 :-)

내 생각에 당신의 힙이 이미 끔찍하게 손상되어 있다는 것입니다.

FilePath, Input 및 Base가 사용하는 실제 포인터 값을 살펴 봅니다. 입력이 FilePath에 매우 가깝다는 것을 알게 될지 궁금합니다.

또한 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;
}

이것이 문제가 없다면 코드의 다른 곳에 뭔가 잘못된 것이 있어야합니다. 그것이 정의되지 않은 행동이 때때로 자체적으로 나타날 수있는 방법입니다 (관련없는 코드가 어떻게 작동하는지 엉망입니다).

(BTW, 나는 연결된 문자열에 여전히 널 터미네이터가 하나만있을 것이기 때문에 두 strlen 호출에 +1을 추가하지 않았습니다.)

이후 BASE_DIR 가치도 반복되고 있습니다 BASE_DIR 또는 filepath 아마도 IN을 겹칠 것입니다 input 메모리.

둘 다 확인하십시오 BASE_DIR 그리고 filepath 실제로 메모리를 할당했습니다.

첫 번째 시도는 단지 로컬 사본을 만드는 것입니다. BASE_DIR 그리고 filepath 전화하기 전에 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);
    }
    ...

질문 : 이것이 웹 서버에서 실행중인 경우 스레드 -unsafe 기능을 사용하는 것이 안전합니까? strtok()? 나는 전적으로 확신하지는 않지만 '예, 안전하다'고 가정 할 것입니다. 당신은 인쇄 했습니까? header 끈? 값을 인쇄 했습니까? path? 할당 된 것을 실제로 누출하려고 했습니까? path? 당신은 그것을 깨달았습니까? malloc() + strcpy() 시퀀스는 복사되지 않습니다 BASE_DIR ~ 안으로 path?


코드의 원본 버전은 다음과 같이 끝났습니다.

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

따라서 원본은 제안 된 부분 답변을 제안했습니다.

당신은 포맷합니다 input; 당신은 인쇄합니다 filepath?


그 기회는 무엇입니까? filepath 이미 릴리스 된 메모리를 가리 킵니다. 메모리를 할당하면 준 랜덤 지역에 어떤 일이 일어나는지 filepath 가리키는 데 사용됩니다. 또 다른 가능성은 그럴 수 있습니다 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

무슨 일이 일어나고 있는지 알아내는 가장 쉬운 방법은 디버거에서 실행을 추적하는 것입니다 (어셈블리 코드 추적으로 떨어질 수 있음).

무슨 일이 일어나고 있는지에 대한 몇 가지 추측 :

  • 다른 스레드에 의한 메모리 손상 (이것이 쉽게 반복 가능하다면 가능하지 않은 것 같습니다)
  • 손상된 힙 (또한 2 개의 구성 요소 문자열을 덤프 할 때도 가능하지 않은 것 같습니다. 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;
}

제안


프로그램에는 분명히 잘못된 것이 없습니다. (업데이트: 글쎄, 지금 분명한 것이 있습니다. 첫 시간 동안 몇 줄만 게시되었고 심각한 버그가 없었습니다.) 더 많은 것을 게시해야합니다. 몇 가지 아이디어는 다음과 같습니다.

  1. malloc(3) 보고 void * 따라서 캐스트 할 필요는 없습니다. 경고를 받고 있다면 아마도 포함하지 않았을 가능성이 높습니다. <stdlib.h>. 당신이 그렇지 않다면, 당신은해야합니다. (예를 들어, 64 비트 시스템에서 프로토 타이핑이 아닙니다. malloc(3) 상당히 심각 할 수 있습니다. 64 비트 환경 중 일부는 실제로 K & R C를 지원하지 않습니다 :-)
  2. 경고에 대해 말하면, 당신이 그것들을 모두 켜고 있는지 확인하십시오. 와 함께 gcc 당신은 그들 중 대부분을 켜질 수 있습니다 -Wall.
  3. 당신은 반환 값을 확인하지 않습니다 malloc(3) 오류.
  4. 메모리 디버거를 사용하십시오 처럼 전기 울타리. 많은 선택이 있습니다. 내 링크를 참조하십시오.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top