c ++ linux отправка неинициализированной памяти сокетов - PullRequest
0 голосов
/ 15 апреля 2020

Я новичок и использую Debian 10 x64. Почему ошибка в строке с SEND? Кто-то может подсказать мне, как решить эту проблему?

send (socket, (char *) m_MsgBuf + sendBytes, std :: min (m_MsgSize-sendBytes + 2, 1000),

Я получил этот ЖУРНАЛ ОШИБКИ:

==24819== Thread 3:
==24819== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==24819==    at 0x51442B4: __libc_send (send.c:28)
==24819==    by 0x51442B4: send (send.c:23)
==24819==    by 0x1FCFC9: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:117)
==24819==    by 0x231624: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==24819==    by 0x22ECF4: Protocol76::sendThingAppear(Thing const*) (protocol76.cpp:3039)
==24819==    by 0x214DE1: Player::onThingAppear(Thing const*) (player.cpp:2165)
==24819==    by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==24819==    by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==24819==    by 0x223995: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==24819==    by 0x208C43: ConnectionHandler(void*) (otserv.cpp:575)
==24819==    by 0x5139F26: start_thread (pthread_create.c:479)
==24819==    by 0x55F12AE: clone (clone.S:95)
==24819==  Address 0x111137f1 is 289 bytes inside a block of size 16,912 alloc'd
==24819==    at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==24819==    by 0x2086ED: ConnectionHandler(void*) (otserv.cpp:510)
==24819==    by 0x5139F26: start_thread (pthread_create.c:479)
==24819==    by 0x55F12AE: clone (clone.S:95)
==24819== 

КОД:

bool NetworkMessage::WriteToSocket(SOCKET socket)
{
    if (m_MsgSize == 0)
        return true;

    m_MsgBuf[0] = (unsigned char)(m_MsgSize);
    m_MsgBuf[1] = (unsigned char)(m_MsgSize >> 8);

    bool ret = true;
    int32_t sendBytes = 0;
    int32_t flags = 0;
    int32_t retry = 0;

    flags = MSG_DONTWAIT; // 2 ?

    do
    {
        int32_t b = send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000), flags);

        if(b <= 0)
        {   
            int32_t errnum;

            if(errnum == EWOULDBLOCK) 
            {
                b = 0;
                OTSYS_SLEEP(10);
                retry++;

                if(retry == 10) 
                {
                    ret = false;
                    break;
                }
            }
            else
            {
                ret = false;
                break;
            }
        }
        sendBytes += b;
    }while(sendBytes < m_MsgSize+2);

    return ret;
}


==930== Thread 3:
==930== Conditional jump or move depends on uninitialised value(s)
==930==    at 0x1FCFE7: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:106)
==930==    by 0x208340: ConnectionHandler(void*) (otserv.cpp:427)
==930==    by 0x5139F26: start_thread (pthread_create.c:479)
==930==    by 0x55F12AE: clone (clone.S:95)
==930==
==930== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==930==    at 0x51442B4: __libc_send (send.c:28)
==930==    by 0x51442B4: send (send.c:23)
==930==    by 0x1FCFD9: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:100)
==930==    by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930==    by 0x22ED20: Protocol76::sendThingAppear(Thing const*) (protocol76.cpp:3039)
==930==    by 0x214E0D: Player::onThingAppear(Thing const*) (player.cpp:2165)
==930==    by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==930==    by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==930==    by 0x2239C1: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==930==    by 0x208C6F: ConnectionHandler(void*) (otserv.cpp:575)
==930==    by 0x5139F26: start_thread (pthread_create.c:479)
==930==    by 0x55F12AE: clone (clone.S:95)
==930==  Address 0x111198d1 is 289 bytes inside a block of size 16,912 alloc'd
==930==    at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==930==    by 0x208719: ConnectionHandler(void*) (otserv.cpp:510)
==930==    by 0x5139F26: start_thread (pthread_create.c:479)
==930==    by 0x55F12AE: clone (clone.S:95)
==930==
==930== Conditional jump or move depends on uninitialised value(s)
==930==    at 0x1FCFE7: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:106)
==930==    by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930==    by 0x22ED20: Protocol76::sendThingAppear(Thing const*) (protocol76.cpp:3039)
==930==    by 0x214E0D: Player::onThingAppear(Thing const*) (player.cpp:2165)
==930==    by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==930==    by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==930==    by 0x2239C1: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==930==    by 0x208C6F: ConnectionHandler(void*) (otserv.cpp:575)
==930==    by 0x5139F26: start_thread (pthread_create.c:479)
==930==    by 0x55F12AE: clone (clone.S:95)
==930== Thread 2:
==930== Conditional jump or move depends on uninitialised value(s)
==930==    at 0x1FCFE7: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:106)
==930==    by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930==    by 0x214089: Player::flushMsg() (player.cpp:1867)
==930==    by 0x182338: Game::flushSendBuffers() (game.cpp:6879)
==930==    by 0x17AAB2: Game::checkCreature(unsigned int) (game.cpp:5461)
==930==    by 0x1A4B67: std::mem_fun1_t<void, Game, unsigned int>::operator()(Game*, unsigned int) const (stl_function.h:1284)
==930==    by 0x1A1668: std::binder2nd<std::mem_fun1_t<void, Game, unsigned int> >::operator()(Game* const&)const (binders.h:158)
==930==    by 0x19BCCD: boost::detail::function::void_function_obj_invoker1<std::binder2nd<std::mem_fun1_t<void, Game, unsigned int>>,void, Game*>::invoke(boost::detail::function::function_buffer&, Game*) (function_template.hpp:159)
==930==    by 0x23810D: boost::function1<void, Game*>::operator()(Game*) const (function_template.hpp:768)
==930==    by 0x237FBC: TSchedulerTask::operator()(Game*) (scheduler.h:63)
==930==    by 0x166D2B: Game::eventThread(void*) (game.cpp:1045)
==930==    by 0x5139F26: start_thread (pthread_create.c:479)
==930==
==930== Thread 3:
==930== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==930==    at 0x51442B4: __libc_send (send.c:28)
==930==    by 0x51442B4: send (send.c:23)
==930==    by 0x1FCFD9: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:100)
==930==    by 0x231650: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==930==    by 0x214089: Player::flushMsg() (player.cpp:1867)
==930==    by 0x182338: Game::flushSendBuffers() (game.cpp:6879)
==930==    by 0x224573: Protocol76::parsePacket(NetworkMessage&) (protocol76.cpp:405)
==930==    by 0x223A3F: Protocol76::ReceiveLoop() (protocol76.cpp:86)
==930==    by 0x208E70: ConnectionHandler(void*) (otserv.cpp:611)
==930==    by 0x5139F26: start_thread (pthread_create.c:479)
==930==    by 0x55F12AE: clone (clone.S:95)
==930==  Address 0x11119f5f is 1,967 bytes inside a block of size 16,912 alloc'd
==930==    at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==930==    by 0x208719: ConnectionHandler(void*) (otserv.cpp:510)
==930==    by 0x5139F26: start_thread (pthread_create.c:479)
==930==    by 0x55F12AE: clone (clone.S:95)
==930==

Я использую такой код:

bool NetworkMessage::WriteToSocket(SOCKET socket)
{
    if (m_MsgSize == 0)
        return true;

    m_MsgBuf[0] = (unsigned char)(m_MsgSize);
    m_MsgBuf[1] = (unsigned char)(m_MsgSize >> 8);

    bool ret = true;
    int32_t sendBytes = 0;
    int32_t flags = 0;
    int32_t retry = 0;

    flags = MSG_DONTWAIT; // 2 ?


    while (sendBytes != m_MsgSize) 
    { /* != rather than < */
        int32_t b = send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000), flags);

        if(b <= 0)
        {   
            int32_t errnum;

            if(errnum == EWOULDBLOCK) 
            {
                b = 0;
                OTSYS_SLEEP(10);
                retry++;

                if(retry == 10) 
                {
                    ret = false;
                    break;
                }
            }
            else
            {
                ret = false;
                break;
            }
        }
        sendBytes += b;
    }

    return ret;
}

EDIT

последний раз, когда у меня была похожая ошибка, мне нужно было использовать этот код, и теперь все работает: sigemptyset(&sigh.sa_mask); ИЛИ memset(&sigh, 0, sizeof(sigh)); здесь я нашел все msgBuf и msg Size в файлы моего проекта. Видите ли вы что-нибудь интересное здесь? m_MsgBuf wklejto.pl / 828244 m_MsgSize wklejto.pl / 828245

РЕДАКТИРОВАТЬ

, поэтому я сделал это в файле NetworkMessage. cpp Я добавил в AddString / AddU32 / AddU16 / AddByte this:

#ifdef CHECKVAL
    checkval(m_MsgBuf+m_ReadPos, stringlen);
#endif  

вверху этого файла я добавил:

#include "player.h"

#ifdef CHECKVAL
    extern int checkval(unsigned char * buff, int len);
#endif

и до конца добавил этот код к игрок. cpp

#ifdef CHECKVAL
int checkval(unsigned char * buff, int len)
{
   int r = 0;

   buff -= len;
   while (len--)
     r += *buff++;
   return r;
}
#endif

а также я изменил char на unsigned char - bcs Я получил ошибку invalid conversion from ‘unsigned char*’ to ‘char*’

END. Я добавил к компилятору это -DCHECKVAL

, после этого я вижу ту же ошибку

==15290== Thread 3:
==15290== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==15290==    at 0x51442B4: __libc_send (send.c:28)
==15290==    by 0x51442B4: send (send.c:23)
==15290==    by 0x1FCFDC: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:105)
==15290==    by 0x231728: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==15290==    by 0x22EDF8: Protocol76::sendThingAppear(Thing const*) (protocol76. cpp:3039)
==15290==    by 0x214E99: Player::onThingAppear(Thing const*) (player.cpp:2165)
==15290==    by 0x1829D0: Game::sendAddThing(Player*, Position const&, Thing const*) (game.cpp:7005)
==15290==    by 0x16789F: Game::placeCreature(Position&, Creature*, int*) (game.cpp:1260)
==15290==    by 0x223A99: Protocol76::ConnectPlayer(int*) (protocol76.cpp:66)
==15290==    by 0x208CFB: ConnectionHandler(void*) (otserv.cpp:575)
==15290==    by 0x5139F26: start_thread (pthread_create.c:479)
==15290==    by 0x55F12AE: clone (clone.S:95)
==15290==  Address 0x11116331 is 289 bytes inside a block of size 16,912 alloc'd
==15290==    at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==15290==    by 0x2087A5: ConnectionHandler(void*) (otserv.cpp:510)
==15290==    by 0x5139F26: start_thread (pthread_create.c:479)
==15290==    by 0x55F12AE: clone (clone.S:95)
==15290==
==15290== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==15290==    at 0x51442B4: __libc_send (send.c:28)
==15290==    by 0x51442B4: send (send.c:23)
==15290==    by 0x1FCFDC: NetworkMessage::WriteToSocket(int) (networkmessage.cpp:105)
==15290==    by 0x231728: Protocol76::flushOutputBuffer() (protocol76.cpp:3574)
==15290==    by 0x214115: Player::flushMsg() (player.cpp:1867)
==15290==    by 0x182338: Game::flushSendBuffers() (game.cpp:6879)
==15290==    by 0x22464B: Protocol76::parsePacket(NetworkMessage&) (protocol76.cpp:405)
==15290==    by 0x223B17: Protocol76::ReceiveLoop() (protocol76.cpp:86)
==15290==    by 0x208EFC: ConnectionHandler(void*) (otserv.cpp:611)
==15290==    by 0x5139F26: start_thread (pthread_create.c:479)
==15290==    by 0x55F12AE: clone (clone.S:95)
==15290==  Address 0x111169bf is 1,967 bytes inside a block of size 16,912 alloc'd
==15290==    at 0x4836DEF: operator new(unsigned long) (vg_replace_malloc.c:344)
==15290==    by 0x2087A5: ConnectionHandler(void*) (otserv.cpp:510)
==15290==    by 0x5139F26: start_thread (pthread_create.c:479)
==15290==    by 0x55F12AE: clone (clone.S:95)
==15290==

хмм. ... но эта функция выглядит интересной ConnectionHandler в строке 510 это проблема?

            Protocol76* protocol;
            protocol = new Protocol76(s);

и:

Protocol76::Protocol76(SOCKET s)
{
    OTSYS_THREAD_LOCKVARINIT(bufferLock);

    player = NULL;
    pendingLogout = false;

    windowTextID = 0;
    readItem = NULL;
    this->s = s;
}

full ConnectionHandler и пароль is 123

введите описание ссылки здесь

строка 510 в файле 152 как вы думаете?

что-то вроде этого может быть достаточно?

int checkval(unsigned char * buff, int len)
{
    buff -= len;

    ofstream bufile ("buff.txt");

    if (bufile.is_open())
    {
        while (len--)
        {
            bufile << "buff: " << *buff << "len: " << len;
        }
        bufile.close();
    }
}

1 Ответ

0 голосов
/ 15 апреля 2020

Предположим, вы инициализировали m_MsgSize байтов в m_MsgBuf и хотите отправить их в oop блоке за блоком, размер которого

std::min(m_MsgSize-sendBytes+2, 1000)

из-за "+2" в зависимости от начального значения m_MsgSize вы можете отправить 1 или 2 дополнительных байта после первых m_MsgSize байтов, эти дополнительные байты могут быть просто не инициализирован или даже вне m_MsgBuf с неопределенным поведением

Также обратите внимание, что если вы выполните

  int32_t sendBytes = 0

  while (sendBytes != m_MsgSize) { /* != rather than < */
     int32_t b = send(socket, (char*)m_MsgBuf+sendBytes, std::min(m_MsgSize-sendBytes+2, 1000), ...);

     ... error management
     sendBytes += b;
  }

из-за ошибки, вызванной +2, вы можете иметь sendBytes больше m_MsgSize с вероятными плохими эффектами.

Просто удалите это "+2"


[редактировать после вас измените свой вопрос / ваш ответ]

Ваш +2 не является проблемой в случае, если m_MsgSize не считает два дополнительных байта для отправки длины следующих байтов

valgrind сигнализируют о нескольких ошибках, и они касаются байтов внутри буфера, а не 1 или 2 последних, для меня это означает, что вы копируете в m_MsgBuf несколько байтов без инициализации. Иногда valgrind не сигнализирует сразу, когда значение не было инициализировано, например, вы можете иметь:

int i; // not initialized

f(i); // nothing signaled by valgrind even i not initialized


...

void f(int i)
{
   int j = i + 1; // here valgrind signal a non initialized value

Я думаю, что вы в этом случае.

Обратите внимание на это может быть не ошибкой, представьте, что вы делаете это:

// set some elements
char s[20];
...    
strcpy(s, "aze");
...
memcpy(m_MsgBuf + 2, /* save 2 bytes for the length */
       s, sizeof(s));
m_MsgSize = sizeof(s);
... may be some oher element added from m_MsgSize+2 and updating m_MsgSize
NetworkMessage::WriteToSocket(socket);

только 4 байта были инициализированы в s , но чтобы получить постоянный размер, отправьте (как минимум) 20 байтов => 16 байтов в буфере соответствуют неинициализированным значениям => valgrind сообщит им

Чтобы узнать, если вы находитесь в случае «без ошибок» или если valgrind сигнализирует о реальной проблеме, которую вы должны проанализируйте настройку всех значений, которые вы помещаете в буфер, но опять же предупреждение valgrind может занять некоторое время, чтобы сигнализировать об использовании неинициализированного значения, это значение может использоваться несколькими промежуточными местоположениями, прежде чем достигнуть hte буфер, который вы отправляете


[редактировать из вашего замечания, дающего фрагмент кода]

Инициализированное значение, вероятно, исходит от вызывающего метода NetworkMessage :: AddXXX , например NetworkMessage :: AddByte получает в качестве аргумента неинициализированный байт.

Тот факт, что у вас есть этот класс с выделенным методом для добавления данных в буфер, является Вероятно, вы можете изменить их определения с помощью дополнительного кода, чтобы искусственно использовать байты из буфера, чтобы valgrind обнаружил неинициализированное значение. Вы можете поместить дополнительные коды, защищенные #ifdef ... #endif, чтобы легко активировать / деактивировать его

Например (используйте тип m_MsgBuf , чтобы ввести параметр buff из checkval , я использовал "char *", потому что я не знаю тип m_MsgBuf ):

#ifdef CHECKVAL
extern int checkval(char * buff, int len);
#endif

void NetworkMessage::AddByte(unsigned char value)
{
    if(!canAdd(1))
        return;
    m_MsgBuf[m_ReadPos++] = value;
    m_MsgSize++;
#ifdef CHECKVAL
    checkval(m_MsgBuf+m_ReadPos, 1);
#endif
}

void NetworkMessage::AddU16(uint16_t value)
{
    if(!canAdd(2))
        return;
    m_MsgBuf[m_ReadPos++] = (unsigned char)(value);
    m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 8);
    m_MsgSize += 2;
#ifdef CHECKVAL
    checkval(m_MsgBuf+m_ReadPos, 2);
#endif
}

void NetworkMessage::AddU32(uint32_t value)
{
    if(!canAdd(4))
        return;
    m_MsgBuf[m_ReadPos++] = (unsigned char)(value);
    m_MsgBuf[m_ReadPos++] = (unsigned char)(value >>  8);
    m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 16);
    m_MsgBuf[m_ReadPos++] = (unsigned char)(value >> 24);
    m_MsgSize += 4;
#ifdef CHECKVAL
    checkval(m_MsgBuf+m_ReadPos, 4);
#endif
}

void NetworkMessage::AddString(const char* value)
{
    uint32_t stringlen = (uint32_t) strlen(value);
    if(!canAdd(stringlen+2) || stringlen > 8192)
        return;

#ifdef USING_VISUAL_2005
    strcpy_s((char*)m_MsgBuf + m_ReadPos, stringlen, value); //VISUAL
#else
    AddU16((uint16_t)stringlen);
    strcpy((char*)m_MsgBuf + m_ReadPos, value);
#endif //USING_VISUAL_2005
    m_ReadPos += stringlen;
    m_MsgSize += stringlen;
#ifdef CHECKVAL
    checkval(m_MsgBuf+m_ReadPos, stringlen);
#endif
}

checkval должен иметь доступ к каждому байту, например:

#ifdef CHECKVAL
int checkval(char * buff, int len)
{
   int r = 0;

   buff -= len;
   while (len--)
     r += *buff++;
   return r;
}
#endif

и поместить checkval в файл, отличный от которого * NetworkMessage: Addxxx "определены, чтобы убедиться, что компилятор не может обнаружить его бесполезно вычислять сумму байтов из буфера или бесполезно вызывать checkval , поскольку возвращаемое значение никогда не используется и checkval не имеет побочного эффекта.

Если суммировать байта недостаточно, чтобы заставить valgrind проверить, инициализированы ли байты или нет, измените определение, например, чтобы сохранить байты в файле и т. д. c

Конечно, определение компиляции CHECKVAL через опцию компилятора или jus t добавление временного

#define CHECKVAL

до определения checkval и до его объявления

Когда valgrind обнаружит неинициализированный байт в checkval вы сможете узнать, откуда берется это значение, посмотрев на стек вызовов, также производимых valgrind

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...