2014-04-10 5 views
1

Boost.Asio를 사용하여 이미지를주고받는 C++ 프로그램을 작성하고 있습니다.char 배열의 포인터를 해제하려고 할 때 오류 : _BLOCK_TYPE_IS_VALID (pHead-> nBlockUse)

내가 오류를 얻을하지 않습니다 컴파일하지만, 실행하고 (비주얼 스튜디오 2012, 윈도우 7 32 비트에서) 이미지를 다음과 같은 오류 메시지가주는 이미지의 충돌을받는 프로그램을 전송 한 경우 :

디버그 어설 션 실패 :

프로그램 : [...] \DataSender.exe
파일 : f:\dd\vctools\crt_bld\self_x86\crt\src\dbgdel.cpp
라인 : 52

표현식 : _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)

4096 바이트의 크기를 읽는 입력 바이트가있는 동안 char 배열에 대한 포인터로 읽습니다. 마지막 반복에서 4096 바이트 미만의 읽기가있는 경우 포인터를 삭제하고 나머지 바이트의 크기 인 char 배열에 대한 포인터를 만듭니다. 여기까지는 여전히 작동합니다.

그러나 루프의 끝에서 char 포인터 배열을 다시 삭제하려고하면 (다음 들어오는 이미지의 표준 크기 4096으로 새 char 포인터 배열을 만들기 위해) 프로그램이 충돌합니다. 여기

는 질문에 내 코드의 발췌 한 것입니다

char* buffer = new char[4096]; 

[...]

int remainingBytes = imageSize; 

[...] 내가 데비안에 같은 코드를 실행

// read data 
while(remainingBytes > 0) 
{ 
    boost::system::error_code error; 

    // use smaller buffer if remaining bytes don't fill the tcp package 
    // fully 
    if(remainingBytes < 4096) 
    { 
     delete[] buffer; // this one doesn't give an error 
     bufferSize = remainingBytes; 
     char* buffer = new char[bufferSize]; 
    } 

    // read from socket into buffer 
    size_t receivedBytes = socket.read_some(
      boost::asio::buffer(buffer, bufferSize), error); 
    remainingBytes -= receivedBytes; 

    // count total length 
    totalReceivedBytes += receivedBytes; 

    // add current buffer to totalBuffer 
    for(int i = 0; i < bufferSize; i++) 
    { 
     totalBuffer.push_back(buffer[i]); 
    } 

    // if smaller buffer has been used delete it and 
    // create usual tcp buffer again 
    if(receivedBytes < 4096) 
    { 
     delete[] buffer; // here the error occurs 
     bufferSize = 4096; 
     char* buffer = new char[bufferSize]; 
    } 
} 

GNU/리눅스 7.2 64 비트 기계, 다음과 같은 오류를 반환 동일한 위치에

*** glibc detected *** ./datasender: double free or corruption (!prev): 0x0000000002503970 ***

나는 문자 포인터의 배열을 할당 해제 할 때 내가 뭔가를 잘못하고 있어요 생각하지만 난 아직 파악되지 않은 : 코드이다.

누군가 나를 올바른 방향으로 안내 할 수 있습니까?

+1

'delete [buffer]; 이제 호기심이 생기고 대신 [delete [] buffer; (묻고, 나는 당신의 진술에 약간 혼란 스럽다.) 아, 그런데 if 문에 할당 한'buffer '는 if 범위에 국한되어 있습니다. 너 여기 누출이야. – JBL

+0

std :: vector를 사용하십시오. 1) 더 안전하고 사용하기 쉽고 2) 아마도 당신이 지금하고있는 새로운/삭제 체조보다 빨리 달릴 것입니다. 버퍼가 작아지면 new []/delete []를 호출하는 벡터를 사용하여 버퍼 크기를 조정하지 않습니다. – PaulMcKenzie

+0

버퍼 크기를 줄이려면 아무 이유도 없습니다. 얼마나 많은 데이터가 수신되었는지 추적하고 그만을 읽으십시오. –

답변

1

remainingBytesreceivedBytes 미만 4096

사실, 한 번 buffer을 삭제하고, 그때 로컬 buffer가 아닌 외부 하나으로 메모리를 할당 할 때 당신은 실제로 두 번 버퍼를 삭제하고 있습니다.

그런 다음 두 번째 if 블록에서 buffer을 삭제하면 두 번째 동일한 버퍼가 삭제됩니다. if 범위에서 수행 한 할당은 메모리 누수입니다. 이것들은 같은 변수가 아닙니다.

당신이 당신의 범위, 당신은 외부 buffer 변수에 메모리를 할당하지, 새로운 변수를 만들에

char* buffer = new char[bufferSize]; 

을 수행 할 때. 따라서 방금 누출 된 버퍼에 메모리를 할당하지 않고 유출 상태가됩니다.

더 이상 살펴 보지 않고도 앞에있는 char*을 차단 블록에서 모두 제거한 다음 디버깅을 계속해야합니다.

+0

정말 고마워요! 이제 효과가 있습니다. 함수의 내부와 외부에서 지역 변수와 전역 변수의 차이 만 있다고 생각했지만 생각해 보았습니다. for 루프의 반복자는 지역적이지만 분명히 분명하지 않았습니다. – Julini

+0

두 가지 : 1) 변수 이름의 가시성에 대한 범위를 생각해보십시오. 함수뿐만 아니라 if-blocks, loop 등 2) 많은 사람들이 지적했듯이, 여러분은 여러분이하고있는 일에'std :: vector'와 같은 표준 컨테이너를 사용하는 것을 고려해야합니다. 당신은이 문제를 만들어내는 많은 메모리 헛소리를 줄였습니다. :) – JBL

0

내가 대신 표준 : : 벡터를 사용합니다 :

#include <vector> 
//... 
std::vector<char> buffer(remainingBytes); 
bufferSize = remainingBytes; 
//... 
while(remainingBytes > 0) 
{ 
    boost::system::error_code error; 

    // use smaller buffer if remaining bytes don't fill the tcp package 
    // fully 
    if(remainingBytes < 4096) 
    { 
     buffer.resize(remainingBytes); 
     bufferSize = remainingBytes; 
    } 

    // read from socket into buffer 
    size_t receivedBytes = socket.read_some(
      boost::asio::buffer(&buffer[0], bufferSize), error); 
    remainingBytes -= receivedBytes; 

    // count total length 
    totalReceivedBytes += receivedBytes; 

    // add current buffer to totalBuffer 
    totalBuffer.insert(totalBuffer.end(), buffer.begin(), 
              buffer.begin() + receivedBytes); 

    // if smaller buffer has been used delete it and 
    // create usual tcp buffer again 
    if(receivedBytes < 4096) 
    { 
     buffer.resize(4096); 
     bufferSize = 4096; 
    } 
} 

에는 메모리 누수가 없을 것입니다.

또한 코드에 버그 (read_some() 함수의 반환 값) 만 수신 한 바이트 수만 복사해야한다고 생각합니다. 대신 bufferSize 문자가 반환되었다고 가정했습니다.