sprintf()函数使用问题及read_from函数代码技术咨询
sprintf() Issues in Your C read_from Function Let's break down the critical problems with your current sprintf() usage and walk through a secure, reliable fix:
Key Problems with Your Current Code
1. Buffer Overflow Risk
Your formattedOutput buffer is sized at BUF_SIZE * 2 + 2, but there’s no guarantee the combined length of the username and incoming buf won’t exceed this limit. When sprintf() writes past the buffer’s bounds, it corrupts adjacent memory—this can cause crashes, unpredictable behavior, or even security vulnerabilities if an attacker sends crafted input.
2. Format String Injection Vulnerability
If the incoming buf contains format specifiers like %s, %d, or %x, sprintf() will try to read extra arguments from the stack that you haven’t provided. This leads to undefined behavior: it might leak sensitive stack data, crash the program, or open the door to further exploits.
Fixed Implementation with snprintf()
The safest drop-in replacement for sprintf() here is snprintf(), which lets you cap the number of bytes written to prevent overflow. We’ll also fix edge cases like failed reads and avoid echoing messages back to the sender:
int read_from(int client_index, struct sockname *usernames) { int fd = usernames[client_index].sock_fd; char buf[BUF_SIZE + 1]; int num_read = read(fd, buf, BUF_SIZE); // Handle read errors or client disconnects if (num_read <= 0) { usernames[client_index].sock_fd = -1; return fd; } buf[num_read] = '\0'; char formattedOutput[BUF_SIZE * 2 + 2]; // Use snprintf to limit writes and block format injection int bytes_written = snprintf(formattedOutput, sizeof(formattedOutput), "%s: %s", usernames[client_index].username, buf); // Optional: Warn if the message was truncated (useful for debugging) if (bytes_written >= sizeof(formattedOutput)) { fprintf(stderr, "Warning: Message from client %d was truncated\n", client_index); } // Send message to all connected clients (skip the original sender) for (int index = 0; index < MAX_CONNECTIONS; index++) { if (usernames[index].sock_fd != -1 && usernames[index].sock_fd != fd) { // Note: In production, wrap write in a loop to handle partial writes write(usernames[index].sock_fd, formattedOutput, strlen(formattedOutput)); } } return num_read; }
Extra Best Practices
- I fixed the
read(fd, &buf, BUF_SIZE)call—bufis already a pointer to the array’s first element, so&bufis unnecessary (it points to the array itself, not its data). - Always handle
num_read <= 0: a value of 0 means the client closed the connection, while -1 indicates a read error. - The
write()call might not send all data in one go. For production code, write a helper function that loops until all bytes are sent or an error occurs. - If
BUF_SIZEis large (e.g., 4096+), allocatingformattedOutputon the stack could cause stack overflow. Usemalloc()to create a dynamic buffer instead, andfree()it when done.
内容的提问来源于stack exchange,提问作者teemo ammo

