Недопустимое значение free при выполнении назначения std :: string с параметром -O2, установленным в g ++

Прежде чем меня взорвут, когда я открою еще один вопрос, этот вопрос связан с другим вопросом, который я открыл несколько дней назад:

После дальнейшего исследования, основанного на некоторых ответах, я пришел к дополнительным вопросам и дополнительной информации, которая может помочь отладить проблему.

Итак, начнем ...

Рассматриваемый код:

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

Трассировка GDB:

(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

Итак, чтобы объяснить вышесказанное, сбой происходит в строке 261 (см. Комментарии в коде для номеров строк) во время присвоения строки. По какой-то причине он пытается освободить недействительную память, но я не уверен, почему? Адрес, который он пытается освободить, - это не адрес того, что, как я думал, было пустой строкой, назначенной в строке 217 (_M_p = 0x3c52020 получает значение _M_p = 0x2abbad098e78, т.е. пустая строка), а какой-то другой адрес не слишком далеко.

Есть идеи, что может вызвать эту проблему? Мне было интересно, может ли это быть проблемой оптимизации, поскольку этого не происходит в -O0, и я прогнал код через батарею тестов, чтобы попытаться найти целый ряд проблем с повреждением памяти, которые могут вызвать такое странное поведение и ... .пришел с пустыми руками!

Еще одно интересное замечание: если я установил std :: string lStreamName = ""; вместо std :: string lStreamName; программа больше не вылетает ??? Любые идеи, что могло вызвать это? Почему простая инициализация этой строки устранила бы сбой?

Спасибо!


person bbazso    schedule 22.02.2010    source источник
comment
Было бы больно очистить код, чтобы он не был разделен двойным интервалом? хром не позволяет мне выбирать содержимое каждого div.   -  person Robert Karl    schedule 23.02.2010
comment
Что такое split ()? Это случайно не вызывает strtok ()?   -  person    schedule 23.02.2010
comment
Я добавил функцию разделения! Извини за это! Он не использует strtok ()   -  person bbazso    schedule 23.02.2010
comment
Я также немного подчистил код, надеюсь, это поможет!   -  person bbazso    schedule 23.02.2010
comment
Многие случаи повреждения памяти имеют видимые последствия далеко от того, где находится проблема, и многие слегка некорректные программы будут работать правильно на одном уровне оптимизации, а не на другом. (Более агрессивная оптимизация обычно не приводит к ошибкам в правильных программах.) Это может быть сложно.   -  person David Thornley    schedule 23.02.2010
comment
Этот пост до сих пор выглядит бельмом на глазу и почти слишком локализован.   -  person Keith Pinson    schedule 02.02.2013


Ответы (2)


Если не гарантируется, что разбиение не возвращает пустой вектор, я бы добавил проверку, пуст ли он. В противном случае присвоение строки back () пустого вектора может привести к полученному вами поведению.

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;
}
person Dmitry Yudakov    schedule 23.02.2010
comment
Когда я просматриваю код, функция разделения возвращает вектор, который не является пустым и содержит правильную строку, поэтому, похоже, это не проблема, а +1, поскольку это хорошая проверка для кода! - person bbazso; 23.02.2010
comment
Хороший улов! IIRC, вызов back() для пустого вектора приводит к неопределенному поведению. +1 - person Danilo Piazzalunga; 23.02.2010
comment
Я изменил код, чтобы добавить проверку, как вы упомянули, и я никогда не возвращал пустой вектор, поэтому проблема не в этом. Однако я тестировал случай, когда вектор пуст и программа вылетает как в -O0, так и в -O2. Хорошая находка! Странно то, что программа больше не аварийно завершает работу, когда строка, переданная в эту функцию, инициализируется в соответствии с: std :: string lStreamName =; ??? Я не имею понятия почему? Любые идеи ? - person bbazso; 23.02.2010
comment
Честно говоря, я пропустил ту часть, где при первом чтении вылетает только сборка -O2. Не могли бы вы попробовать вместо строковой ссылки вернуть строку? Я знаю, что ваш путь верен, но мне интересно, может ли компилятор каким-то странным образом его оптимизировать. В gdb вы также можете использовать «step» вместо «c» (продолжить) и шаг за шагом увидеть, что приводит к сбою. - person Dmitry Yudakov; 24.02.2010

Вы должны попытаться воспроизвести сбой на автономном примере. Используя предоставленную вами информацию, я протестировал следующий код.

Обратите внимание, что мне нужна была функция split. Не зная, что вы использовали, я взял один из этого вопроса. Если вы используете boost::split или split функцию, которую написали сами, укажите это в своем вопросе.

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

Попробуйте запустить этот код (с -O2, с любыми возможными оптимизациями g ++, с valgrind и т. Д.) И посмотрите, не вылетит ли он снова.

Используя простой автономный пример, вы можете определить, является ли причиной сбоев ошибка в вашем коде или что-то еще (например, конфликтующие библиотеки C ++, как это было в вашем предыдущем вопросе).

person Danilo Piazzalunga    schedule 23.02.2010
comment
Я пробовал это с моей версией функции разделения, и у меня не было сбоев и предупреждений в valgrind, поэтому код, похоже, не является проблемой напрямую. Я думаю, это может быть проблема со ссылками или .so, но я действительно не уверен? - person bbazso; 23.02.2010
comment
Попробуйте снова запустить свой код в valgrind. Если valgrind предупреждает вас о недопустимом доступе к памяти, вы нашли свою ошибку. Однако, если у вас все еще есть проблема, описанная в программе stackoverflow.com/questions/2303740/, скорее всего, проблема в вашей среде, а не в вашем коде. - person Danilo Piazzalunga; 23.02.2010
comment
Если вы можете, попробуйте скомпилировать и запустить код сбоя в другой системе (возможно, используя компилятор по умолчанию, установленный с дистрибутивом) и посмотрите, все ли происходит сбой. - person Danilo Piazzalunga; 23.02.2010
comment
Я пробовал его на Linux RH 4.2, 4.4 и Ubuntu 9.04, и у меня все еще возникает проблема, но пакеты и библиотеки очень похожи, и не все из них являются версиями, которые поставляются с дистрибутивом, поэтому там может быть проблема. , но я понятия не имею, как на чем-то сойтись! - person bbazso; 23.02.2010
comment
Вы использовали компилятор g ++ из дистрибутива хотя бы в одном случае? Ubuntu 9.04 включает gcc 4.3.3, RHEL 4.2 имеет gcc 4.0.1, а RHEL 4.4 использует gcc 4.1.0. Вы проводили эти тесты на одних и тех же машинах или на разных машинах? - person Danilo Piazzalunga; 24.02.2010