2010-01-17 4 views
1

Ok. 그래서이 함수는 init()입니다.매우 이상한 malloc 오류

void init() 
{ 
fstream file; 
int index = 0; 

char temp_list[60000][15]; 

listlen = 0; 
current_index = 0; 

file.open("en_US.dic"); 
while(!file.eof()) 
{ 
    file >> temp_list[index]; 
    index++; 
} 

listlen = index; 
file.close(); 
file.open("en_US.dic"); 

word_list = new char*[listlen]; 

int count = 0; 
for(int i = 0; i < listlen; i++) 
{ 
    word_list[i] = new char[21]; 
    file >> word_list[i]; 
} 

file.close(); 
} 

이 코드는 오류없이 올바르게 컴파일되고 실행됩니다. 내가 선

word_list[i] = new char[21] 

나는 다음과 같은 오류가

word_list[i] = new char[x] //x < 21 

로를 변경할 때 그러나 :

dict: malloc.c:3074: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed. 

나는 프로그래밍 (< 2 년) 다소 새로운 해요, 그리고 나는 이런 것을 본적이 없다. 누구든지 아이디어가 있습니까? 미리 감사드립니다!

+0

어디에도 x가 표시되지 않습니까? x는 무엇으로 설정되어 있습니까? – Pace

+0

플랫폼이란 무엇입니까? 컴파일러? –

+1

제쳐두고, 파일의 끝 부분에 대한 점검이 잘못되었습니다. http://stackoverflow.com/questions/21647/ –

답변

1

파일의 길이가 20 자 이상인 경우 file >> word_list[i]은 할당 된 버퍼의 끝을지나 작성하므로 오류가 발생할 수 있습니다. 이를 buffer overflow이라고합니다.

이 문제는 temp_list에 기록 할 때도 발생하지만이 경우 버퍼 오버플로는 다음 단어에 사용 된 메모리를 덮어 쓰게되므로 피해가 적습니다.

이 문제를 해결하는 한 가지 방법은 char * 대신 std::string의 배열을 사용하는 것입니다. 할당은 자동으로 이와 같이 처리됩니다.

4

귀하의 단어 중 하나가 x에 지정된 값보다 길다는 것을 추측합니다.

이렇게되면 malloc 버퍼가 오버플로됩니다.

N 바이트를 할당하는 경우 N 바이트 이상을 쓰지 않아야합니다.

연산자 >> 및 char 버퍼를 사용하는 것은 재앙의 방법입니다. operator >>는 단어 분리 기호에 도달 할 때까지 읽기/쓰기를 유지합니다. 연산자 >>는 char * 버퍼의 크기를 모르기 때문에 단어가 버퍼보다 ​​길면 버퍼를 오버플로합니다. 연산자 >>를 사용하여 단어를 추출하려면 std :: string을 사용하십시오. 의 malloc을 구현하는

매우 일반적인 방법 무슨 일이 일어나고 무엇

는 버퍼의 malloc에서 반환 사이에 부기 데이터를 가지고있다. 이 데이터를 덮어 쓰면 malloc이 더 이상 데이터 구조를 만들지 않는다는 가정이 사라집니다. 다음의 malloc 내부의 당신이 사용자 버퍼에 8 바이트를 할당하지만 12 바이트를 작성하는 경우

+------------------+-------------+------------------+-------------+----------- 
| malloc internals | user buffer | malloc internals | user buffer | etc... 
+------------------+-------------+------------------+-------------+----------- 

그래서, 당신은 그냥 휴지통에 한 처음 4 바이트 :

그래서, malloc에이 같은 뭔가가 기록.

while (!file.eof()) 
{ 
    file >> temp_list[index]; 
    index++; 
} 

당신은 다음 작업이, 경우에만 이전 히트 EOF를 실패 있는지 file.eof()을 테스트 할 수 없습니다, 그리고 :

+0

아. 감사. 나는 Roger Pate의 충고에 기초하여 처음부터 다시 디자인하기 시작했는데, 이것은 훨씬 더 의미가 있습니다. –

5

이 그 코드와 세 가지 주요 문제, 여기에 두 가지가 있습니다 즉, 일반적으로 실패한 경우에만 유용합니다, 그래서으로 변경 : 스트림을 추출로

while (file >> temp_list[index]) { 
    index++; 
} 

(>>) 돌아가서 스트림 테스트 할 수있다 이 코드는 추출이 성공하면 각 반복마다 스트림을 테스트하고 인덱스 만 증분합니다.

이제 char 배열로 추출 할 때 입력 스트림은 공백에서 멈추지 만, 사용자가 지정하지 않으면 저장할 수있는 최대 길이를 알 수 없습니다. 나중에 코드에서 이와 같은 오류가 발생하는 이유는 예상보다 훨씬 많은 데이터를 읽는 것으로 의심되어 자신의 모든 것을 지나치게 짓밟고 있기 때문입니다. 고정 :

#include <fstream> 
#include <iostream> 
#include <string> 
#include <vector> 

void init() { 
    typedef std::vector<std::string> C; // for later convenience 
    C words; 
    { 
    ifstream file ("en_US.dic"); 
    if (!file) { 
     std::cerr << "could not open file\n"; 
     // handle error: throw an exception, call abort(), etc. 
    } 
    for (std::string word; file >> word;) { 
     words.push_back(word); 
    } 
    // if you want to read lines instead: 
    //for (std::string line; std::getline(file, line);) { 
    // words.push_back(line); 
    //} 
    } 
    // now use words[0] through words[words.size() - 1] 
    std::cout << "Read " << words.size() << " words:\n"; 
    for (int i = 0; i < words.size(); ++i) { 
    std::cout << " " << words[i] << '\n'; 
    } 
    std::cout << "Output again:\n"; 
    for (C::const_iterator i = words.begin(); i != words.end(); ++i) 
    { 
    std::cout << " " << *i << '\n'; 
    } 
} 
+0

+1 EOF 문제를 지적하고'std :: string'과'std :: vector'를 제안하십시오. –

+0

와우! 엄청 고마워! 나는이 전에 벡터에 대해 거의 알지 못했다. stl에 대한 나의 경험은 제한되어 있으므로 조금 더 던져야합니다. 다시 한 번 감사드립니다! –

0

당신은 여기에 당신의 디자인을 변경할 수 있습니다 :

while (file >> std::setw(15) >> temp_list[index]) { 
    index++; 
} 

그러나, 마지막 주요 문제는 당신이 자원을 할당하고이를 누설, 그래서 대신 벡터와 문자열을 사용합니다. 사전은 거대합니다.
은 모든 단어 (데이터)를 메모리로 가져 오려면이 필요합니까?

사전은 거대하기 때문에 동시에 전체적으로 메모리에있을 필요가 없도록 설계되었습니다. 전문 사전에는 전체 데이터 파일보다 작은 색인 테이블이 있습니다. 원칙적인 아이디어는 인덱스 테이블이 작아서 모든 데이터를 한꺼번에 전달하는 것이 아니라 메모리로 전달하여 메모리에 보관할 수 있다는 것입니다.

초기 색인 테이블을 메모리에 보관하여 프로그램을 최적화했습니다. 첫 번째 인덱스 테이블의 결과는 다른 테이블 (또는 다른 파일의 이름)에 대한 파일 오프셋입니다. 이 2 차 테이블은 필요한 경우 메모리에 저장되며, 정확한 항목이 발견 될 때까지 계속됩니다.

은 다음 항목 (웹 검색)를 참조하십시오 :

  • B+ Tree
  • 색인 테이블
  • 블록 I/O
  • 파일 오프셋
+0

기본적으로, 나는 스크래블을위한 프로그램을 만들고 있습니다. 그래서 매번 사전 전체를 검색해야합니다. 참조 주셔서 감사합니다. –

0

이 것 정말 엉망 :

for(int i = 0; i < listlen; i++) 
{ 
    word_list[i] = new char[21]; 
    file >> word_list[i]; 
} 

단어가 20 자보다 큰 경우 ('\ 0'의 경우 +1). 그러면 기본적으로 메모리 관리자가 사용하는 wsa를 메모리에 낙서하게됩니다. 이로 인해 후속 할당 및 할당 해제와 관련된 모든 종류의 문제가 발생합니다.

char temp_list[60000][15]; 

비록 한 줄에서 단어가 다음 줄에 겹쳐 수 있습니다, 이것은 당신이 실제로를 읽고 있었다하지 않는 문제가 없었을 것이다 : 버퍼가 연속 이었기 때문에

그것은 이전 루프에서 일 큰 단어를 temp_list [59999] (다른 변수와 겹칠 수도 있음)에 넣습니다.

+0

당신이 옳다고 생각합니다. 나는 프로그램을 완전히 다시 디자인하고있어. 그래서 나는 어떤 문제도 없어야한다. 감사합니다. –