You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu下C语言downloadFile函数内存泄漏及重复执行乱码问题

Troubleshooting Memory Leaks and Garbled Output in Your downloadFile Function

Let's break down the two key issues plaguing your code, along with practical fixes to resolve them:


1. Memory Leak Root Cause & Fix

What's Wrong

Inside your while (len > 0) loop, you're allocating memory for buff with malloc((sizeof(char) * len) + 1); every iteration—but you never call free(buff) to release that memory. Each loop iteration leaves behind a block of orphaned memory that the OS can't reclaim, and repeated calls to downloadFile will pile up these blocks, causing a memory leak over time.

How to Fix It

Add a free(buff); immediately after you're done using the buffer (right before you read the next len value, or before exiting the loop). This ensures every allocated block is cleaned up properly.


2. Garbled Output on Repeated Calls

Several missteps are causing the garbled text—let's tackle each one:

Issue 1: Incorrect String Termination

You commented out buff[strlen(buff)] = '\0';, but even if it was active, this line is broken. The read function pulls raw bytes (which might include \0 characters if you're transferring binary files), and strlen(buff) stops counting at the first \0—so you won't terminate the string correctly for the full len bytes you read.

Fix: Use the actual len value to set the terminator: buff[len] = '\0';—this guarantees all bytes you read are included in the string.

Issue 2: Ignoring read/write Return Values

read and write don't always process the exact number of bytes you request. If there's a network hiccup, they might return fewer bytes than expected. If you ignore this and treat buff as if it has all len bytes, you'll end up with partial data or garbage values that look like garbled text.

Fix: Add logic to verify you've read/written the full amount of data needed. For example, loop until read has pulled all len bytes, and check that write returns the exact number of bytes you intended to send.

Issue 3: Wrong Pointer for Filename Transfer

Your line write(sockfd, &fitxer, len); uses &fitxer—but fitxer is an array, so its name alone is already a pointer to its first element. &fitxer is a pointer to the entire array (type char (*)[STR_BASE]), which works by accident (same starting address) but is incorrect and can lead to unexpected behavior in some contexts.

Fix: Change it to write(sockfd, fitxer, len); to pass the correct pointer type.

Issue 4: Unrestricted Input Risks Buffer Overflow

scanf("%[^\n]",fitxer) doesn't limit how much input it reads. If a user enters a filename longer than STR_BASE, it'll overflow the fitxer buffer, corrupting other stack data and causing unpredictable issues (including garbled output).

Fix: Use fgets instead of scanf to limit input length, then strip the trailing newline character. This prevents buffer overflow.

Issue 5: Uninitialized buff Pointer

You declare char *buff; without initializing it. While you assign it memory in the loop, if the loop exits early (e.g., len is 0 on the first read), you could end up accessing an uninitialized pointer, leading to garbage values.

Fix: Initialize buff to NULL when declaring it, and add a final check to free it if it's still allocated before exiting the function.


Fully Fixed Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

// Assume these constants are defined elsewhere
#define STR_BASE 256
#define MAX 1024
#define FILE_NOT_EXIST -1

void downloadFile(int sockfd) {
    FILE *f = NULL;
    char *buff = NULL;
    int err, len = 0;
    char fitxer[STR_BASE];
    int c;

    // Prompt user for filename
    printf("Introdueix el nom del fitxer que vols descarregar (amb extensió incluida!): ");
    // Clear input buffer (portable alternative to __fpurge)
    while ((c = getchar()) != '\n' && c != EOF);
    // Read filename with length limit to prevent overflow
    if (fgets(fitxer, STR_BASE, stdin) == NULL) {
        perror("Error llegint nom de fitxer");
        return;
    }
    // Remove trailing newline from fgets
    len = strlen(fitxer);
    if (len > 0 && fitxer[len-1] == '\n') {
        fitxer[len-1] = '\0';
        len--;
    }

    // Retry if input is empty
    while(len <= 0) {
        printf("Introdueix el nom del fitxer que vols descarregar (amb extensió incluida!): ");
        while ((c = getchar()) != '\n' && c != EOF);
        if (fgets(fitxer, STR_BASE, stdin) == NULL) {
            perror("Error llegint nom de fitxer");
            return;
        }
        len = strlen(fitxer);
        if (len > 0 && fitxer[len-1] == '\n') {
            fitxer[len-1] = '\0';
            len--;
        }
    }

    // Send filename length to server
    ssize_t bytes_written = write(sockfd, &len, sizeof(int));
    if (bytes_written != sizeof(int)) {
        perror("Error enviant llargada de nom de fitxer");
        return;
    }
    // Send filename (correct pointer usage)
    bytes_written = write(sockfd, fitxer, len);
    if (bytes_written != len) {
        perror("Error enviant nom de fitxer");
        return;
    }

    // Read file existence status from server
    ssize_t bytes_read = read(sockfd, &err, sizeof(int));
    if (bytes_read != sizeof(int)) {
        perror("Error llegint estat de fitxer");
        return;
    }

    if (err == FILE_NOT_EXIST) {
        printf("***El fitxer indicat no existeix al directori!\n");
    } else {
        // Open file for appending
        f = fopen(fitxer, "a");
        if (f == NULL) {
            perror("Error obrint fitxer per escriptura");
            return;
        }
        len = 0;

        // Read file chunks from server
        bytes_read = read(sockfd, &len, sizeof(int));
        while (bytes_read == sizeof(int) && len > 0) {
            // Allocate buffer with space for null terminator
            buff = malloc((sizeof(char) * len) + 1);
            if (buff == NULL) {
                perror("Error de memòria");
                fclose(f);
                return;
            }

            // Ensure we read all len bytes
            ssize_t total_read = 0;
            while (total_read < len) {
                bytes_read = read(sockfd, buff + total_read, len - total_read);
                if (bytes_read <= 0) {
                    perror("Error llegint dades del servidor");
                    free(buff);
                    fclose(f);
                    return;
                }
                total_read += bytes_read;
            }

            // Properly terminate the string
            buff[len] = '\0';
            printf("BUFF = %s / LEN = %d\n", buff, len);

            // Write buffer to file
            if (fputs(buff, f) == EOF) {
                perror("Error escrivint al fitxer");
                free(buff);
                fclose(f);
                return;
            }

            // Read next chunk length
            bytes_read = read(sockfd, &len, sizeof(int));
            // Free current buffer
            free(buff);
            buff = NULL;
        }

        // Clean up file handle
        fclose(f);
        printf("\n\n\n\n\n");
    }

    // Final check to free buffer if loop exited early
    if (buff != NULL) {
        free(buff);
    }
}

Bonus Improvements

  • Portability: Replaced __fpurge(stdin) with a portable input buffer cleanup method, since __fpurge is a GNU-specific extension.
  • Error Handling: Added checks for all critical operations (file opens, memory allocations, network reads/writes) to catch issues early instead of letting them cause silent failures.
  • Binary File Safety: If you're transferring binary files (not just text), replace fputs with fwrite—fputs will modify newline characters, which breaks binary data.

内容的提问来源于stack exchange,提问作者SERGIO GONZÁLEZ ARIZA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:52:11