Weird stack smash error - caused by unused, uninitialized member variable

1k views Asked by At

Today I had a fun bug where apparently my stack got smashed, overriding the G++ return-point canary (I think that's the protection used).

My offending class was this:

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

The thing was, the client variable was initialized in the initializer list, but not the endpoint (it's not used in the ClientSendContext, since it only sends to one endpoint, but no matter). The smash-stack occured once every three times I executed my test (or something like that) which is weird, since I do the exact same thing (must be thread timing issue).

However, as soon I remove the endpoint variable, it works fine! How can this be? It wasn't used in any way, g++ didn't warn me about it... Valgrind was quiet aswell.

(Could someone with high rep please edit my question and add stack-smash or something like that as a tag?)

Alright, an update with more code, posted on pastebin:

http://pastebin.com/xiWx8xjV

That should be all the methods called. The inner most send method is part of a templated class. The same send method works fine when the UdpServer uses it.. I'm just a bit stumped right now.

EDIT: Code now put directly here:

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

And the error message:

*** 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]
1

There are 1 answers

2
tony gil On

this error is (almost always) caused by appending more elements to an array/vector than said array/vector has been declared as having. therefore i would pay specific attention to all char and uint8 arrays in your code.

though the dump might make sense for someone who understands linux c++ profoundly, it makes no sense for mere mortals and debugging using it is not the fastest solution.

i like the old school approach: print flags to show up to what point your program goes without exceptions. you can usually isolate the offending array(s) this way quite quickly.

as an example, i was having the exact same problem with this code:

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

the weirdest thing was that the error did NOT occur when i assigned a string that had 12 characters to bufOut (declared as having 6 elements), but rather after

return unixTimeOut;

nevertheless, i changed the declaration to

unsigned char bufOut[12];

and the problem was solved.