C语言TCP Socket简易Torrent客户端内存损坏问题排查求助
Hey there, sorry to hear you're stuck with those frustrating random memory crashes in your torrent client—those are always the trickiest bugs to track down. You already fixed the malloc off-by-one bug with aux, so let's dig into other potential culprits in your code and workflow:
1. Uninitialized Memory & Buffer Overflows in Block Handling
Looking at your block receiving code:
ssize_t recv_payload = recv(socket_client,&bloque_rebut,mida,0);
If your block_t struct includes a pointer field (like data to store the actual block content), you're directly writing raw network data into the struct itself—not into allocated memory for that pointer. This will almost certainly overwrite adjacent memory or corrupt the heap, leading to unpredictable crashes.
Fix this by explicitly allocating memory for the block data before receiving:
// After getting `mida` from get_block_size bloque_rebut.data = malloc(mida); if (!bloque_rebut.data) { perror("Failed to allocate memory for block data"); exit(EXIT_FAILURE); } // Now receive into the allocated buffer (use the recv_all helper below) ssize_t recv_payload = recv_all(socket_client, bloque_rebut.data, mida); // Don't forget to free bloque_rebut.data after storing the block!
Also, if mida is large (e.g., multi-megabyte blocks), storing this struct on the stack could trigger stack overflow—heap allocation is safer here.
2. TCP Stream Mismanagement (Sticky/Partial Packets)
TCP is a stream protocol, not a message-based one. Your current code assumes that the first recv gets exactly the message header, and the second gets exactly the full payload—but that's not guaranteed. You might get partial reads, or even multiple messages stuck together (粘包), which will corrupt your block data and cause memory errors when parsing.
Fix this by writing a helper function to guarantee full reception of a specified number of bytes:
ssize_t recv_all(int sock, void *buf, size_t len) { size_t total_received = 0; while (total_received < len) { ssize_t bytes = recv(sock, (char*)buf + total_received, len - total_received, 0); if (bytes <= 0) { // Error or connection closed unexpectedly return bytes; } total_received += bytes; } return total_received; }
Use this function for all your recv calls to ensure you get exactly the data you need, no more no less.
3. Byte Order & Peer Address Handling
Your manual byte-shifting for the peer IP address is error-prone:
uint32_t direccion=0x0; direccion |= ((uint32_t) Torrent_Client.peers[peer_count].peer_address[3]); direccion = direccion << 8; direccion |= ((uint32_t) Torrent_Client.peers[peer_count].peer_address[2]); // ... and so on
If peer_address is stored in network byte order (big-endian, standard for torrent protocols), your manual shift will convert it to host byte order—but client_addr.sin_addr.s_addr expects a network byte order value. This could lead you to connect to an invalid IP, receive garbage data, and trigger random memory corruption.
Replace this with standard byte-order functions to avoid mistakes:
// Assuming peer_address is a 4-byte array in network order client_addr.sin_addr.s_addr = *((uint32_t*)Torrent_Client.peers[peer_count].peer_address);
4. Unchecked Array Access & Peer Validation
You're accessing Torrent_Client.peers[peer_count] without verifying that peer_count is within the bounds of the peers array. If peer_count is larger than the actual number of peers (or if peers is uninitialized), this will read out-of-bounds memory, leading to undefined behavior (random crashes included).
Add a check before accessing the peer:
if (peer_count >= Torrent_Client.peer_total) { perror("Peer index out of bounds"); exit(EXIT_FAILURE); }
Make sure Torrent_Client.peer_total is properly set by create_torrent_from_metainfo_file.
5. Debugging Tools to Pinpoint the Exact Issue
Random memory bugs are hard to spot with just code inspection—use these tools to get concrete data:
- Valgrind: Run your program with
valgrind --leak-check=full --track-origins=yes ./your_client your_torrent.torrent. It will flag uninitialized memory access, buffer overflows, and memory leaks with exact line numbers. - GDB: If your program crashes, use
gdb ./your_client coreto load the crash dump. Runbtto get a backtrace of where the crash happened. You can also set watchpoints on suspicious variables to catch when they're modified unexpectedly.
内容的提问来源于stack exchange,提问作者Desiree Pasion Rodriguez Sanch

