Предположим, вы инициализировали 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