문제
내 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;
}
제안
프로그램에는 분명히 잘못된 것이 없습니다. (업데이트: 글쎄, 지금 분명한 것이 있습니다. 첫 시간 동안 몇 줄만 게시되었고 심각한 버그가 없었습니다.) 더 많은 것을 게시해야합니다. 몇 가지 아이디어는 다음과 같습니다.
malloc(3)
보고void *
따라서 캐스트 할 필요는 없습니다. 경고를 받고 있다면 아마도 포함하지 않았을 가능성이 높습니다.<stdlib.h>
. 당신이 그렇지 않다면, 당신은해야합니다. (예를 들어, 64 비트 시스템에서 프로토 타이핑이 아닙니다.malloc(3)
상당히 심각 할 수 있습니다. 64 비트 환경 중 일부는 실제로 K & R C를 지원하지 않습니다 :-)- 경고에 대해 말하면, 당신이 그것들을 모두 켜고 있는지 확인하십시오. 와 함께
gcc
당신은 그들 중 대부분을 켜질 수 있습니다-Wall
. - 당신은 반환 값을 확인하지 않습니다
malloc(3)
오류. - 메모리 디버거를 사용하십시오 처럼 전기 울타리. 많은 선택이 있습니다. 내 링크를 참조하십시오.