2011-02-16 5 views
2

으로 인해 발생했습니다. 이제 막 스택이 박살 났으며 G ++ 리턴 포인트 카나리아를 무시한 재미있는 버그가있었습니다 (사용 된 보호라고 생각합니다).이상한 스택 스매시 오류 - 사용하지 않은 초기화되지 않은 멤버 변수

내 기분을 상하게하는 클래스는이이었다

class ClientSendContext : public SendContext 
    { 
     public: 
      ClientSendContext(UdpClient& client); 
      void send(boost::asio::const_buffer buffer); 
     private: 
      boost::asio::ip::udp::endpoint endpoint; 
      UdpClient& client; 
    }; 

것은이 클라이언트 변수가 초기화 목록에서 초기화 있지만 하였다되지 엔드 포인트 (그것은 단지 하나의 엔드 포인트에 송신 한 후이의 ClientSendContext 사용하지 않을 것 , 상관 없습니다). 스매쉬 스택은 3 번마다 한 번씩 발생했는데, 똑같은 일을하기 때문에 (이상한 스레드 타이밍이어야 함) 이상한 테스트를 실행했습니다.

그러나 끝점 변수를 제거하자마자 제대로 작동합니다. 어떻게 이럴 수있어? 그것은 어떤 식 으로든 사용되지 않았습니다. g ++은 그것에 대해 경고하지 않았습니다 ... Valgrind도 조용했습니다.

http://pastebin.com/xiWx8xjV

: 페이스트 빈에 게시

(높은 담당자와 함께 누군가가 내 질문을 편집하고 태그로 그렇게 스택 분쇄 또는 뭔가를 추가 시겠어요?)

좋아, 더 많은 코드와 업데이 트를,

모든 메소드가 호출되어야합니다. 가장 많이 송신되는 메서드는 템플릿 화 된 클래스의 일부입니다. UdpServer가 사용할 때 동일한 send 메소드가 잘 작동합니다. 지금 당황 스럽습니다.

편집 : 코드는 지금 바로 여기에 넣어 :

void doTest(bool& failed) 
{ 
    ReceiveHelper helper(failed); 

    boost::threadpool::pool pool(2); 
    int port = 55600; 
    boost::asio::io_service service; 
    udp::endpoint thisPoint = udp::endpoint(address::from_string("127.0.0.1"), 
      port); 
    udp::endpoint receivePoint; 
    udp::socket socket(service, thisPoint); 
    socket.async_receive_from(boost::asio::buffer(helper.buffer), receivePoint, boost::bind(&ReceiveHelper::handleReceive, 
      &helper, boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    pool.schedule(boost::bind(&boost::asio::io_service::run, &service)); 
    voip::network::client::UdpClient client; 
    client.connect(thisPoint); 
    client.send(1, "Hello!"); 
    boost::this_thread::sleep(boost::posix_time::milliseconds(1)); 
    service.stop(); 
} 

class ReceiveHelper { 
private: 
    bool& failed; 

    public: 
     ReceiveHelper(bool & failed) : failed(failed), buffer() 
     { 

     } 
     boost::array<uint8_t, BUF_SIZE> buffer; 
     void handleReceive(const boost::system::error_code & error, size_t numBytes) 
     { 
      if(numBytes != 8) 
       return; 
      if(std::string((char*)buffer.c_array(), 6) != "Hello!") 
       return; 
      failed = false; 
     } 
}; 

void UdpClient::send(uint8_t handler, std::string message) 
{ <-------------------------------------------------------------------------------------- Canary at this point fails 
    ClientSendContext context(*this); 
    ClientConnection::send(context, handler, message); 
} <-------------------------------------------------------------------------------------- Canary at this point fails 

    void send(SendContext & sendContext, uint8_t handler, std::string & message) 
    { 
     uint8_t *array = new uint8_t[message.size() + 2]; 
     memcpy(array, message.c_str(), message.size()); 
     boost::asio::mutable_buffer buffer(array, message.size() + 2); 
     prepareMessage(handler, buffer); 
     sendContext.send(buffer); 
     delete[] array; 
    } 

    size_t prepareMessage(uint8_t handler, boost::asio::mutable_buffer message) 
    { 
     size_t messageLength = boost::asio::buffer_size(message); 
     uint8_t* data = boost::asio::buffer_cast<uint8_t*>(message); 
     data[messageLength - 1] = network::handler; 
     data[messageLength - 2] = handler; 
     return messageLength; 
    } 

그리고 오류 메시지 :이 오류는

*** stack smashing detected ***: ./testclient terminated 
======= Backtrace: ========= 
/lib/libc.so.6(__fortify_fail+0x37)[0x58e9537] 
/lib/libc.so.6(__fortify_fail+0x0)[0x58e9500] 
./testclient(_ZN4voip7network6client9UdpClient4sendEhSs+0x85)[0x46b449] 
./testclient(_ZN4voip4test6client18SuiteTestUdpClient6doTestERb+0x2dd)[0x44c7c1] 
./testclient(_ZNK4voip4test6client18SuiteTestUdpClient17TestClientCanSend7RunImplEv+0x2f)[0x44c957] 
./testclient(_ZN8UnitTest11ExecuteTestINS_4TestEEEvRT_RKNS_11TestDetailsE+0x9a)[0x469551] 
./testclient(_ZN8UnitTest4Test3RunEv+0x23)[0x46920f] 
./testclient(_ZNK8UnitTest10TestRunner7RunTestEPNS_11TestResultsEPNS_4TestEi+0x7c)[0x469b74] 
./testclient(_ZNK8UnitTest10TestRunner10RunTestsIfINS_4TrueEEEiRKNS_8TestListEPKcRKT_i+0x8f)[0x469ddb] 
./testclient(_ZN8UnitTest11RunAllTestsEv+0x53)[0x4697b7] 
./testclient(main+0x9)[0x44ca62] 
/lib/libc.so.6(__libc_start_main+0xfe)[0x5808d8e] 
./testclient[0x44c429] 
======= Memory map: ======== 
00400000-00494000 r-xp 00000000 08:05 150971        /home/max/Documents/c++proj/voip/build/testclient 
00693000-00694000 r--p 00093000 08:05 150971        /home/max/Documents/c++proj/voip/build/testclient 
00694000-00695000 rw-p 00094000 08:05 150971        /home/max/Documents/c++proj/voip/build/testclient 
00695000-00696000 rw-p 00000000 00:00 0 
04000000-04020000 r-xp 00000000 08:05 560792        /lib/ld-2.12.1.so 
04020000-04022000 rw-p 00000000 00:00 0 
0403f000-04045000 rw-p 00000000 00:00 0 
04220000-04221000 r--p 00020000 08:05 560792        /lib/ld-2.12.1.so 
04221000-04222000 rw-p 00021000 08:05 560792        /lib/ld-2.12.1.so 
04222000-04223000 rw-p 00000000 00:00 0 
04223000-04224000 rwxp 00000000 00:00 0 
04a23000-04a24000 r-xp 00000000 08:05 145700        /usr/lib/valgrind/vgpreload_core-amd64-linux.so 
04a24000-04c23000 ---p 00001000 08:05 145700        /usr/lib/valgrind/vgpreload_core-amd64-linux.so 
04c23000-04c24000 r--p 00000000 08:05 145700        /usr/lib/valgrind/vgpreload_core-amd64-linux.so 
04c24000-04c25000 rw-p 00001000 08:05 145700        /usr/lib/valgrind/vgpreload_core-amd64-linux.so 
04c25000-04c2d000 r-xp 00000000 08:05 145715        /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 
04c2d000-04e2c000 ---p 00008000 08:05 145715        /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 
04e2c000-04e2d000 r--p 00007000 08:05 145715        /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 
04e2d000-04e2e000 rw-p 00008000 08:05 145715        /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 
04e2e000-04e46000 r-xp 00000000 08:05 557639        /lib/libpthread-2.12.1.so 
04e46000-05045000 ---p 00018000 08:05 557639        /lib/libpthread-2.12.1.so 
05045000-05046000 r--p 00017000 08:05 557639        /lib/libpthread-2.12.1.so 
05046000-05047000 rw-p 00018000 08:05 557639        /lib/libpthread-2.12.1.so 
05047000-0504b000 rw-p 00000000 00:00 0 
0504b000-05133000 r-xp 00000000 08:05 656172        /usr/lib/libstdc++.so.6.0.14 
05133000-05332000 ---p 000e8000 08:05 656172        /usr/lib/libstdc++.so.6.0.14 
05332000-0533a000 r--p 000e7000 08:05 656172        /usr/lib/libstdc++.so.6.0.14 
0533a000-0533c000 rw-p 000ef000 08:05 656172        /usr/lib/libstdc++.so.6.0.14 
0533c000-05351000 rw-p 00000000 00:00 0 
05351000-053d3000 r-xp 00000000 08:05 560787        /lib/libm-2.12.1.so 
053d3000-055d2000 ---p 00082000 08:05 560787        /lib/libm-2.12.1.so 
055d2000-055d3000 r--p 00081000 08:05 560787        /lib/libm-2.12.1.so 
055d3000-055d4000 rw-p 00082000 08:05 560787        /lib/libm-2.12.1.so 
055d4000-055e9000 r-xp 00000000 08:05 521495        /lib/libgcc_s.so.1 
055e9000-057e8000 ---p 00015000 08:05 521495        /lib/libgcc_s.so.1 
057e8000-057e9000 r--p 00014000 08:05 521495        /lib/libgcc_s.so.1 
057e9000-057ea000 rw-p 00015000 08:05 521495        /lib/libgcc_s.so.1 
057ea000-05964000 r-xp 00000000 08:05 557476        /lib/libc-2.12.1.so 
05964000-05b63000 ---p 0017a000 08:05 557476        /lib/libc-2.12.1.so 
05b63000-05b67000 r--p 00179000 08:05 557476        /lib/libc-2.12.1.so 
05b67000-05b68000 rw-p 0017d000 08:05 557476        /lib/libc-2.12.1.so 
05b68000-05b6d000 rw-p 00000000 00:00 0 
05b6d000-05f6d000 rwxp 00000000 00:00 0 
05f6d000-05f6e000 ---p 00000000 00:00 0 
05f6e000-0676e000 rw-p 00000000 00:00 0 
0676e000-0676f000 ---p 00000000 00:00 0 
0676f000-06f6f000 rw-p 00000000 00:00 0 
06f6f000-06f70000 ---p 00000000 00:00 0 
06f70000-07770000 rw-p 00000000 00:00 0 
07770000-07771000 ---p 00000000 00:00 0 
07771000-07f71000 rw-p 00000000 00:00 0 
38000000-381fc000 r-xp 00200000 08:05 145710        /usr/lib/valgrind/memcheck-amd64-linux 
383fb000-383fe000 rw-p 003fb000 08:05 145710        /usr/lib/valgrind/memcheck-amd64-linux 
383fe000-3927e000 rw-p 00000000 00:00 0 
402001000-403272000 rwxp 00000000 00:00 0 
403272000-403274000 ---p 00000000 00:00 0 
403274000-403374000 rwxp 00000000 00:00 0 
403374000-403376000 ---p 00000000 00:00 0 
403376000-40583e000 rwxp 00000000 00:00 0 
40583e000-405840000 ---p 00000000 00:00 0 
405840000-405940000 rwxp 00000000 00:00 0 
405940000-405942000 ---p 00000000 00:00 0 
405942000-405946000 rwxp 00000000 00:00 0 
405946000-405948000 ---p 00000000 00:00 0 
405948000-405a48000 rwxp 00000000 00:00 0 
405a48000-405a4a000 ---p 00000000 00:00 0 
405a4a000-405a4e000 rwxp 00000000 00:00 0 
405a4e000-405a50000 ---p 00000000 00:00 0 
405a50000-405b50000 rwxp 00000000 00:00 0 
405b50000-405b52000 ---p 00000000 00:00 0 
405b52000-405b5a000 rwxp 00000000 00:00 0 
405b5a000-405b5c000 ---p 00000000 00:00 0 
405b5c000-405c5c000 rwxp 00000000 00:00 0 
405c5c000-405c5e000 ---p 00000000 00:00 0 
405c5e000-405c62000 rwxp 00000000 00:00 0 
7feffd000-7ff001000 rwxp 00000000 00:00 0 
7fffb9f36000-7fffb9f57000 rw-p 00000000 00:00 0       [stack] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0     [vsyscall] 
+4

대부분이 엔드 포인트 변수가없는이 클래스의 크기가 변경되면 다른 코드에 여전히 존재하는 버그가 숨겨집니다. 이 클래스의 인스턴스를 만드는 코드에서 오버런을 확인하십시오. – Erik

+0

@Erik Grumble ..1 마일 떨어진 곳에있는 것을 보았을 것입니다. 물론 스택 오버런을 검사 할 수있는 도구가 있습니까? – Max

+0

스택이 메소드에서 코드에 의해 손상됩니다. 클래스 선언이 아닙니다. 잘못된 코드를 올렸습니다. –

답변

1

(거의 항상)보다 상기 배열/벡터에 더 많은 요소를 추가하여 원인을 array/vector가 갖는 것으로 선언되었습니다. 따라서 코드에서 모든 char 및 uint8 배열에 특히주의해야합니다.

리눅스 C++을 이해하는 사람에게는 덤프가 의미가 있지만 단순한 필사자에게는 적합하지 않으며 디버깅을 사용하는 것이 가장 빠른 해결책은 아닙니다.

저는 옛 학교 접근법을 좋아합니다 : 프로그램이 예외없이 어떤 지점에 나타나는지 보여주기위한 인쇄 플래그. 보통 이런 식으로 문제가되는 어레이를 아주 빨리 분리 할 수 ​​있습니다. 예를 들어

,이 코드와 동일한 문제가되었다

이상한 것은 내가 선언 bufOut 12 개 문자를 가진 문자열을 (할당 할 때 오류가 발생하지 않은 것이 었습니다
std::string GetTimeStringFromDump(unsigned char *bufDumpIn, int startDate) { 
    unsigned char bufOut[6]; 
    for (int counter02=0;counter02<12;counter02++) { 
    bufOut[counter02] = bufDumpIn[counter02+startDate]; 
    } 
    std::string unixTimeOut = GetTimeStringNew(bufOut); 
    std::cout << "UnixTimeOUT: " << unixTimeOut << std::endl; 
    return unixTimeOut; 
} 

) (6 개) 요소를 갖는 것이 아니라 그럼에도

return unixTimeOut; 

제가
unsigned char bufOut[12]; 
로 선언 변경

및 문제가 해결되었습니다.

+2

안녕하세요 토니, 대답 주셔서 감사합니다. 반환에서 오류가 발생하는 이유에 대해 설명해 줄 수 있다고 생각합니다. 많은 컴파일러가 여러 지점에서 알려진 패딩 값을 추가합니다. 반환 지점에서 값이 확인됩니다. 어쨌든, 내 오류 스택에 값을 참조하는 콜백에 의해 발생했습니다. 이 콜백은 (버그로 인해) 늦게 발사되어 스택이 박살나 게했다. :) – Max

+0

@Max 그럴 수도 있습니다. 통찰력을 가져 주셔서 감사합니다. 많은 사람들이 이런 종류의 오류를 디버깅하는 동안 이러한 내부를 더 잘 이해할 수있는 이점이 있습니다. 위대한 질문, upvoted옵니다! :) –