7

也许我完全失明或愚蠢,但我不明白我是如何在这里遇到 valgrind 问题的。Valgrind 给了我这个:

==3728== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==3728==    at 0x57835DC: send (send.c:33)
==3728==    by 0x4058B7: CBSocketSend (CBLibEventSockets.c:287)
==3728==    by 0x4E522FB: CBNetworkCommunicatorOnCanSend (CBNetworkCommunicator.c:649)
==3728==    by 0x40564F: CBCanSend (CBLibEventSockets.c:235)
==3728==    by 0x526E54B: event_base_loop (event.c:1346)
==3728==    by 0x405244: CBStartEventLoop (CBLibEventSockets.c:154)
==3728==    by 0x5A54E99: start_thread (pthread_create.c:308)
==3728==  Address 0x5e7b6b4 is 20 bytes inside a block of size 24 alloc'd
==3728==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3728==    by 0x4E51E2A: CBNetworkCommunicatorOnCanSend (CBNetworkCommunicator.c:592)
==3728==    by 0x40564F: CBCanSend (CBLibEventSockets.c:235)
==3728==    by 0x526E54B: event_base_loop (event.c:1346)
==3728==    by 0x405244: CBStartEventLoop (CBLibEventSockets.c:154)
==3728==    by 0x5A54E99: start_thread (pthread_create.c:308)
==3728==
==3728== (action on error) vgdb me ...

当这种情况发生时,GDB 会给出回溯:

0x00000000057835dc in __libc_send (fd=<optimized out>, buf=<optimized out>,
    n=<optimized out>, flags=<optimized out>) at ../sysdeps/unix/sysv/linux/x86_64/send.c:33
33  ../sysdeps/unix/sysv/linux/x86_64/send.c: No such file or directory.
(gdb) bt
#0  0x00000000057835dc in __libc_send (fd=<optimized out>, buf=<optimized out>,
    n=<optimized out>, flags=<optimized out>) at ../sysdeps/unix/sysv/linux/x86_64/send.c:33
#1  0x00000000004058b8 in CBSocketSend (socketID=20,
    data=0x5e7b6a0 "\371\276\264\331version", len=24)
    at /media/sf_BitEagle_Projects/cbitcoin/dependencies/sockets/CBLibEventSockets.c:287
#2  0x0000000004e522fc in CBNetworkCommunicatorOnCanSend (vself=0x5e76c30, vpeer=0x5e791c0)
    at /media/sf_BitEagle_Projects/cbitcoin/src/structures/CBObject/CBNetworkCommunicator/CBNetworkCommunicator.c:649
#3  0x0000000000405650 in CBCanSend (socketID=20, eventNum=4, arg=0x5e7a2d0)
    at /media/sf_BitEagle_Projects/cbitcoin/dependencies/sockets/CBLibEventSockets.c:235
#4  0x000000000526e54c in event_process_active_single_queue (activeq=0x5e78be0,
    base=0x5e78710) at event.c:1346
#5  event_process_active (base=<optimized out>) at event.c:1416
#6  event_base_loop (base=0x5e78710, flags=0) at event.c:1617
#7  0x0000000000405245 in CBStartEventLoop (vloop=0x5e78eb0)
    at /media/sf_BitEagle_Projects/cbitcoin/dependencies/sockets/CBLibEventSockets.c:154
#8  0x0000000005a54e9a in start_thread (arg=0x7a74700) at pthread_create.c:308
#9  0x00000000057824bd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#10 0x0000000000000000 in ?? ()

所以在这里可以看出,代码正在向 send() 发送一些分配的 24 字节数据,这就是 CBSocketSend 中发生的事情,然后 valgrind 在数据的 20 字节处向 sendto 抱怨。

我用这段代码填写数据:

peer->sendingHeader = malloc(24);
if (NOT peer->sendingHeader) {
    CBNetworkCommunicatorDisconnect(self, peer, 0, false);
    return;
}
peer->sendingHeader[0] = self->networkID;
peer->sendingHeader[1] = self->networkID >> 8;
peer->sendingHeader[2] = self->networkID >> 16;
peer->sendingHeader[3] = self->networkID >> 24;
// Get the message we are sending.
CBMessage * toSend = peer->sendQueue[peer->sendQueueFront];
// Message type text
if (toSend->type == CB_MESSAGE_TYPE_VERSION)
    memcpy(peer->sendingHeader + 4, "version\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_VERACK)
    memcpy(peer->sendingHeader + 4, "verack\0\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_ADDR)
    memcpy(peer->sendingHeader + 4, "addr\0\0\0\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_INV)
    memcpy(peer->sendingHeader + 4, "inv\0\0\0\0\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_GETDATA)
    memcpy(peer->sendingHeader + 4, "getdata\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_GETBLOCKS)
    memcpy(peer->sendingHeader + 4, "getblocks\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_GETHEADERS)
    memcpy(peer->sendingHeader + 4, "getheaders\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_TX)
    memcpy(peer->sendingHeader + 4, "tx\0\0\0\0\0\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_BLOCK)
    memcpy(peer->sendingHeader + 4, "block\0\0\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_HEADERS)
    memcpy(peer->sendingHeader + 4, "headers\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_GETADDR)
    memcpy(peer->sendingHeader + 4, "getaddr\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_PING)
    memcpy(peer->sendingHeader + 4, "ping\0\0\0\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_PONG)
    memcpy(peer->sendingHeader + 4, "pong\0\0\0\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_ALERT)
    memcpy(peer->sendingHeader + 4, "alert\0\0\0\0\0\0\0", 12);
else if (toSend->type == CB_MESSAGE_TYPE_ALT)
    memcpy(peer->sendingHeader + 4, toSend->altText, 12);
// Length
if (toSend->bytes){
    peer->sendingHeader[16] = toSend->bytes->length;
    peer->sendingHeader[17] = toSend->bytes->length << 8;
    peer->sendingHeader[18] = toSend->bytes->length << 16;
    peer->sendingHeader[19] = toSend->bytes->length << 24;
}else{
    memset(peer->sendingHeader + 16, 0, 4);
}
// Checksum
peer->sendingHeader[20] = toSend->checksum[0];
peer->sendingHeader[21] = toSend->checksum[1];
peer->sendingHeader[22] = toSend->checksum[2];
peer->sendingHeader[23] = toSend->checksum[3];

您可以很清楚地看到所有数据都已分配,对吗?那么 valgrind 在做什么呢?

您可以在这里看到明显引起麻烦的完整功能:https ://github.com/MatthewLM/cbitcoin/blob/master/src/structures/CBObject/CBNetworkCommunicator/CBNetworkCommunicator.c#L582

CBSocketSend 是这样的:

int32_t CBSocketSend(uint64_t socketID,uint8_t * data,uint32_t len){
    ssize_t res = send((evutil_socket_t)socketID, data, len, CB_SEND_FLAGS);
    if (res >= 0)
        return (int32_t)res;
    if (errno == EAGAIN)
        return 0; // False event. Wait again.
    return CB_SOCKET_FAILURE; // Failure
}

在这里:https ://github.com/MatthewLM/cbitcoin/blob/master/dependencies/sockets/CBLibEventSockets.c#L286

谢谢你。

4

1 回答 1

6

以下 Valgrind 参数可能有助于确定未初始化数据的来源:

--track-origins=yes

您也可以尝试使用

 --vgdb-error=0

在初始化字节 20 之前和之后放置断点,并使用memcheck命令get_vbits验证发生了什么。

于 2012-09-07T06:19:49.480 回答