views:

335

answers:

2

Before I get blasted on opening another question, this question is related to another question that I opened a few days ago:

http://stackoverflow.com/questions/2303740/c-program-always-crashes-while-doing-a-stdstring-assign

After investigating further based on some of the answers I came up with more questions and more information that may help debug the issue.

So here goes...

The Code in Question:

bool peopleSProtocol::SignalProtocolCreated(BaseProtocol *pProtocol,
        Variant customParameters) {

   LOG("peopleSProtocol::SignalProtocolCreated");

   SetOutboundConnectParameters(customParameters);

   // Tie up the peopleSProtocol Instance to the BaseOutboundStream Instance.
   BaseClientApplication *pApplication = ClientApplicationManager::FindAppByName("peoplestreamer");

   std::string lStreamName;
   printf("1b [%d] [%s]", (int) lStreamName.size(), lStreamName.c_str()); // line 217

   SetApplication(pApplication); // line 218

   printf("1c [%d] [%s]", (int) lStreamName.size(), lStreamName.c_str()); // line 219

   BaseRTAppProtocolHandler *pProtocolHandler = (BaseRTAppProtocolHandler *)pApplication->GetProtocolHandler(PT_OUTBOUNDRT);

   printf("1d [%d] [%s]", (int) lStreamName.size(), lStreamName.c_str());

   uint32_t protocolId = customParameters["customParameters"]["outboundRTProtocolId"];
   uint32_t streamId = customParameters["customParameters"]["streamId"];

   printf("1d [%d] [%s]", (int) lStreamName.size(), lStreamName.c_str());

   BaseOutboundStream *lpBaseOutboundStream = (BaseOutboundStream*)pProtocolHandler->FindByProtocolIdById(protocolId,streamId);

   printf("1e [%d] [%s]", (int) lStreamName.size(), lStreamName.c_str());

   RegisterOutboundStream(lpBaseOutboundStream);

   printf("2 [%d] [%s]", (int) lStreamName.size(), lStreamName.c_str());

   // Get the address of our peer (the RT peer, NOT the peopleS peer)...

   int32_t lRTClientFd = lpBaseOutboundStream->GetProtocol()->GetIOHandler()->GetFd();

   struct sockaddr_in lPeerAddressStruct;
   int lPeerLength = sizeof(lPeerAddressStruct);
   getpeername(lRTClientFd,(sockaddr*)&lPeerAddressStruct,(socklen_t*)&lPeerLength);

   string lPeerIpAddressString = inet_ntoa(lPeerAddressStruct.sin_addr);

   uint16_t lPeerPort = ntohs(lPeerAddressStruct.sin_port);

   printf("3 [%d] [%s]", (int) lStreamName.size(), lStreamName.c_str());

   // Get the name of the file in accordance with the RT spec...

   GetStreamName(STR(M_INVOKE_PARAM(customParameters,1)), lStreamName); // line 247  
   return SendPlayCommand(lStreamName,lPeerIpAddressString,lPeerPort);
}

bool peopleSProtocol::GetStreamName(const char* pRawPath, std::string &pStreamName)
{
   vector<string> parts = split(pRawPath,"/"); // line 260
   pStreamName = parts.back(); // line 261

   parts = split(pStreamName.c_str(),":");
   pStreamName = parts.back();
   return true;
}

#define ADD_VECTOR_END(v,i) (v).push_back((i))

vector<string> split(string str, string separator) {
    vector<string> result;

    string::size_type position = str.find(separator);
    uint32_t separatorLength = separator.length();

    while (position != str.npos) {
        string temp = str.substr(0, position);
        ADD_VECTOR_END(result, temp);
        str = str.substr(position + separatorLength);
        position = str.find(separator);
    }
    ADD_VECTOR_END(result, str);
    return result;
}

The GDB backtrace:

(gdb) b 217
Breakpoint 3, peopleSProtocol::SignalProtocolCreated (this=0x3c52020, pProtocol=<value optimized out>, customParameters=@0x413f9eb0) at peopleRTstreamer/src/peoplesprotocol.cpp:217
217    printf("1b [%d] [%s]", (int) lStreamName.size(), lStreamName.c_str());
(gdb) p lStreamName 
$1 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x3c52020 "\220R̪�*"}}
(gdb) c
[DEBUG] cpeopleTcpConnection - Connected to 127.0.0.1:37255
[DEBUG] cpeopleTcpConnection - Connected from server address : 127.0.0.1
[New Thread 1096964416 (LWP 10941)]
Breakpoint 4, peopleSProtocol::SignalProtocolCreated (this=0x3c52020, pProtocol=<value optimized out>, customParameters=@0x413f9eb0) at peopleRTstreamer/src/peoplesprotocol.cpp:218
218    SetApplication(pApplication);
(gdb) p lStreamName 
$2 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x2abbad098e78 ""}}
(gdb) c
Breakpoint 5, peopleSProtocol::SignalProtocolCreated (this=0x3c52020, pProtocol=<value optimized out>, customParameters=@0x413f9eb0) at peopleRTstreamer/src/peoplesprotocol.cpp:219
219    printf("1c [%d] [%s]", (int) lStreamName.size(), lStreamName.c_str());
(gdb) p lStreamName 
$3 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x2abbad098e78 ""}}
(gdb) c
[New Thread 1097099584 (LWP 11010)]
1b [0] []1c [0] []1d [0] []1d [0] [][DEBUG] peopleStreamingServer.RTServer - Opening connection from 127.0.0.1
[DEBUG] peopleStreamingServer.RTServer - Using server IP address 127.0.0.1
Breakpoint 6, peopleSProtocol::SignalProtocolCreated (this=0x3c52020, pProtocol=<value optimized out>, customParameters=@0x413f9eb0) at peopleRTstreamer/src/peoplesprotocol.cpp:247
247    GetStreamName(STR(M_INVOKE_PARAM(customParameters,1)), lStreamName);
(gdb) p lStreamName 
$4 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x2abbad098e78 ""}}
(gdb) c
Breakpoint 7, peopleSProtocol::GetStreamName (this=0x3c52020, pRawPath=0x3c40808 "RT://127.0.0.1/mp4:popeye.mp4", pStreamName=@0x413f9e10) at peopleRTstreamer/src/peoplesprotocol.cpp:260
260    vector<string> parts = split(pRawPath,"/");
(gdb) p pStreamName 
$5 = (string &) @0x413f9e10: {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, 
    _M_p = 0x2abbad098e78 ""}}
(gdb) c
*** glibc detected *** /home/ml01/t-live/TEngine/StreamingServer/.libs/peoplestreamingserver: free(): invalid pointer: 0x00002abbad098e60 ***

======= Backtrace: =========
/lib64/libc.so.6[0x3560871634]
/lib64/libc.so.6(cfree+0x8c)[0x3560874c5c]
/home/ml01/t-HEAD/gcc/4.2.4/lib/../lib64/libstdc++.so.6(_ZNSs6assignERKSs+0x90)[0x2abbace3fd20]
/home/ml01/usr/local/lib/RTserver/libpeopleRTstreamer.so(_ZN12peopleSProtocol13GetStreamNameEPKcRSs+0x9a)[0x2aaaaaabd16a]
/home/ml01/usr/local/lib/RTserver/libpeopleRTstreamer.so(_ZN12peopleSProtocol21SignalProtocolCreatedEP12BaseProtocol7Variant+0x2e4)[0x2aaaaaabd894]
/home/ml01/usr/local/lib/RTserver/libpeopleRTstreamer.so(_ZN12TCPConnectorI12peopleSProtocolE7OnEventER11epoll_event+0x1a6)[0x2aaaaaabf046]
/home/ml01/t-HEAD/cRTserver/20091229/lib/libthelib.so(_ZN16IOHandlerManager5PulseEv+0x4a6)[0x2abbad425620]
/home/ml01/usr/local/lib/libpeopleRT.so.0(_ZN3people15cRTServerLoop19RTProtocolHandlerEv+0x55)[0x2abba2d2df45]
/home/ml01/usr/local/lib/libpeopleRT.so.0(_Z19HandleTrafficThreadPv+0x9)[0x2abba2d2e009]
/home/ml01/t-HEAD/glib/2.18.0/lib/libglib-2.0.so.0[0x2abbabc84394]
/lib64/libpthread.so.0[0x35614062f7]
/lib64/libc.so.6(clone+0x6d)[0x35608d1b6d]

(gdb) where
#0  0x0000003560830155 in raise () from /lib64/libc.so.6
#1  0x0000003560831bf0 in abort () from /lib64/libc.so.6
#2  0x000000356086a38b in __libc_message () from /lib64/libc.so.6
#3  0x0000003560871634 in _int_free () from /lib64/libc.so.6
#4  0x0000003560874c5c in free () from /lib64/libc.so.6
#5  0x00002abbace3fd20 in std::string::assign (this=0x413f9e10, __str=<value optimized out>) at /home/ml01/ThirdParty/sources/gcc-4.2.4/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:238
#6  0x00002aaaaaabd16a in peopleSProtocol::GetStreamName (this=<value optimized out>, pRawPath=0x3c40808 "RT://127.0.0.1/mp4:popeye.mp4", pStreamName=@0x413f9e10)
    at /home/ml01/t-HEAD/gcc/4.2.4/lib/gcc/x86_64-pc-linux-gnu/4.2.4/../../../../include/c++/4.2.4/bits/basic_string.h:491
#7  0x00002aaaaaabd894 in peopleSProtocol::SignalProtocolCreated (this=0x3c52020, pProtocol=<value optimized out>, customParameters=@0x413f9eb0) at peopleRTstreamer/src/peoplesprotocol.cpp:247
#8  0x00002aaaaaabf046 in TCPConnector<peopleSProtocol>::OnEvent (this=0x3c40aa0, event=<value optimized out>) at /home/ml01/t-HEAD/cRTserver/20091229/include/cRTserver/netio/epoll/tcpconnector.h:90
#9  0x00002abbad425620 in IOHandlerManager::Pulse () at /home/ml01/ThirdParty/sources/cRTserver/sources/thelib/src/netio/epoll/iohandlermanager.cpp:260
#10 0x00002abba2d2df45 in people::cRTServerLoop::RTProtocolHandler (this=0x3c4c180) at src/RTServerLoop.cpp:77
#11 0x00002abba2d2e009 in HandleTrafficThread (ipData=0x60bc) at src/RTServerLoop.cpp:39
#12 0x00002abbabc84394 in g_thread_create_proxy (data=0x3c4e060) at gthread.c:635
#13 0x00000035614062f7 in start_thread () from /lib64/libpthread.so.0
#14 0x00000035608d1b6d in clone () from /lib64/libc.so.6

So to explain the above, the crash is occuring on line 261 (see comments in code for line numbers) during the string assign. For some reason it tries to free invalid memory, but I'm not sure why? The address it tries to free is not the address of what I thought was the empty string assigned on line 217 (_M_p = 0x3c52020 gets set to _M_p = 0x2abbad098e78 i.e. the empty string) but some other address not too far off.

Any ideas what could be causing this issue? I was wondering if this could be an optimization issue since it does not occur in -O0 and I have ran the code through a battery of tests to try and find a whole slew of memory corruption issues that may cause this weird behavior and ....came up empty handed!

Another interesting note is that if I set std::string lStreamName = ""; instead of std::string lStreamName; the program no longer crashes??? Any Ideas what could cause this? Why would a simple initialization of this string eliminate the crash?

Thanks!

A: 

You should try to reproduce the crash with a self-contained example. Using the information you gave us, I tested the following code.

Note that I needed a split function. Not knowing what you used, I took one from this question. If you use boost::split or a split function you wrote yourself, please include it in your question.

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

bool GetStreamName(const char* pRawPath, std::string& pStreamName)
{
    std::vector<std::string> parts = split(pRawPath,'/'); // line 260
    pStreamName = parts.back(); // line 261

    parts = split(pStreamName.c_str(),':');
    pStreamName = parts.back();
    return true;
}

int main()
{
    std::string streamName;
    GetStreamName("/some:weird/path/of:x/a:/stream:foo", streamName);
    std::cout << streamName << std::endl;
}

Try to run this code (with -O2, with any g++ optimizations you can think of, with valgrind, etc.) and see if it crashes again.

Using a simple, self-contained example, you can determine if the source of the crashes is an error in your code or anything else (such as conflicting C++ libraries, as it was in your previous question).

Danilo Piazzalunga
I tried this with my version of the split function and I did not get a crash nor did I get a warning in valgrind and so the code does not seem to be the problem directly. I think it could be a linking or .so issue, but I'm really not sure?
bbazso
Try running your code again in valgrind. If valgrind warns you about invalid memory access, you have found your bug.However, if you still have the problem described in http://stackoverflow.com/questions/2303740/c-program-always-crashes-while-doing-a-stdstring-assign, most certainly the problem is in your environment and not in your code.
Danilo Piazzalunga
If you can, please try compiling and running your crashing code on another system (possibly using the default compiler installed with the distro) and see if you still get the crash.
Danilo Piazzalunga
I've tried it on Linux RH 4.2, 4.4 and Ubuntu 9.04 and I still get the problem, but the packages and libs are very similar and not all of them are the versions that come with the distro and so there could be a problem there, but I have no idea how to converge on something!
bbazso
Did you use the distribution's g++ compiler at least in one case? Ubuntu 9.04 includes gcc 4.3.3, RHEL 4.2 has gcc 4.0.1 and RHEL 4.4 uses gcc 4.1.0.Did you perform these tests on the same machines or on different machines?
Danilo Piazzalunga
+2  A: 

If it's not guarantied that split doesn't return empty vector I'd add a check if it's empty. Otherwise assigning back() of empty vector to a string could lead to the behavior that you receive.

bool GetStreamName(const char* pRawPath, std::string& pStreamName)
{
    std::vector<std::string> parts = split(pRawPath,'/'); // line 260
    if( parts.size() == 0 )
    {
        cout << "Cannot parse '" << pRawPaths << "'" << endl;
        return false;
    }
    pStreamName = parts.back(); // line 261

    parts = split(pStreamName.c_str(),':');
    pStreamName = parts.back();
    return true;
}
Dmitry Yudakov
When I step through the code the split function returns a vector that is not empty and contains the correct string and so this does not seem to be the problem, but +1 since this is a good check to have in the code!
bbazso
Good catch! IIRC, calling `back()` on an empty vector results in undefined behavior. +1
Danilo Piazzalunga
I changed the code to add in a check like you mentioned and I was never returning an empty vector and so this was not the problem. However, I tested the case when the vector is empty and the program crashes in both -O0 and -O2. Good find! The weird thing is that the program does not crash anymore when the string passed into this function is initialized as per: std::string lStreamName = ""; ??? I have no idea why? Any ideas ?
bbazso
To be honest I missed the part with only -O2 build crash on the first reading. Could you try instead of the string reference to return the string? I know your way is valid, but I wonder if the compiler could optimize it in some weird way.In gdb you could also use 'step' instead of 'c'(continue) and to see step by step what leads to the crash.
Dmitry Yudakov