realloc() 可能泄漏:当 realloc() 分配内存失败时,原始指针丢失

realloc() possible leak: when realloc() fails in allocating memory, original pointer is lost

我知道这个问题已经被问过很多次了,但似乎每次出现这个问题都略有不同。

我有以下 C 应用程序,它从一个名为 word_generator() 的函数接收一个字符串,然后过滤每个传入的字符串,一旦满足条件,当前字符串将存储在一个名为 output_char_buffer.

由于传入的数据是可变长度的,所以涉及到的char数组需要动态调整大小。

该应用程序似乎在运行,但静态分析工具正在抱怨并显示以下消息:

warning: V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 'output_char_buffer' is lost.
Consider assigning realloc() to a temporary pointer.

代码如下:

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

char *word_generator(int selector)
{
    switch(selector)
    {
        case 0:
            return "gpu-log-02_05_2022_12_37_56_784";
            break;
        case 1:
            return "glsl-debug.txt";
            break;
        case 2:
            return "compiler.log";
            break;
        case 3:
            return "shader.pub";
            break;
        case 4:
            return "fluid-sim-variantA.cache";
            break;
        default:
            printf("ERROR: Request out of range!\n");
    }
    return "";
}


int main() {

    char *output_char_buffer;
    output_char_buffer = NULL;

    // Simulate incoming data.
    for (int i = 0; i < 5; i++)
    {
        printf("Test string[%d]: %s\n", i, word_generator(i));
        
        unsigned long local_buffer_length = strlen(word_generator(i));
        unsigned long input_buffer_length = 0;

        char *input_char_buffer = (char*)malloc(local_buffer_length + 1);
        
        if (input_char_buffer != NULL)
        {
            strcpy(input_char_buffer, word_generator(i));
            input_buffer_length = strlen(input_char_buffer);
        }
        else
        {
            // Clean-up.
            free(input_char_buffer);
            input_char_buffer = NULL;

            printf("ERROR: Failed to allocate char buffer memory!\n");

            // Exit with an error state.
            return 1;
        }
        
        // Verbose debug.
        printf("\tCurrent input buffer (value: %s, length: %lu)\n", input_char_buffer, input_buffer_length);
        
        char key[] = "compiler.log";
        
        // Verbose debug.
        printf("\tCurrent key (value: %s, length: %lu)\n", key, strlen(key));

        if (strcmp(input_char_buffer, key) == 0)
        {
            printf("\t\t__MATCH__\n");
            
            output_char_buffer = (char*)realloc(output_char_buffer, (local_buffer_length + 1));
            
            if (output_char_buffer != NULL)
            {
                strcpy(output_char_buffer, input_char_buffer);
            }
            else
            {
                // Clean-up.
                free(output_char_buffer);
                output_char_buffer = NULL;
                
                printf("ERROR: Failed to fetch char buffer memory!\n");
                
                // Exit with an error state.
                return 1;
            }
        }

        // Clean-up.
        free(input_char_buffer);
        input_char_buffer = NULL;
    }

    // Check the final value of the string container.
    printf("Result: %s\n", output_char_buffer);
    
    // Clean-up and finish.
    free(output_char_buffer);
    output_char_buffer = NULL;
    
    return 0;
}

输出:

Test string[0]: gpu-log-02_05_2022_12_37_56_784
        Current input buffer (value: gpu-log-02_05_2022_12_37_56_784, length: 31)
        Current key (value: compiler.log, length: 12)
Test string[1]: glsl-debug.txt
        Current input buffer (value: glsl-debug.txt, length: 14)
        Current key (value: compiler.log, length: 12)
Test string[2]: compiler.log
        Current input buffer (value: compiler.log, length: 12)
        Current key (value: compiler.log, length: 12)
                __MATCH__
Test string[3]: shader.pub
        Current input buffer (value: shader.pub, length: 10)
        Current key (value: compiler.log, length: 12)
Test string[4]: fluid-sim-variantA.cache
        Current input buffer (value: fluid-sim-variantA.cache, length: 24)
        Current key (value: compiler.log, length: 12)
Result: compiler.log

为该问题标记的行是这一行:

output_char_buffer = (char*)realloc(output_char_buffer, (local_buffer_length + 1));

处理这个问题的安全方法是什么?

代码中有 2 个 realloc 实例。第二个,原来的指针确实被覆盖了:

output_char_buffer = (char*)realloc(output_char_buffer, (local_buffer_length + 1));

您应该将 return 值存储到一个临时变量中,这样您就可以在发生故障时释放原始指针,从而避免内存泄漏。

另请注意,您的代码中的清理不完整:您应该释放 input_char_bufferoutput_char_buffer,以防它已在上一次迭代期间分配。

这是修改后的版本:

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

const char *word_generator(int selector) {
    switch (selector) {
    case 0:  return "gpu-log-02_05_2022_12_37_56_784";
    case 1:  return "glsl-debug.txt";
    case 2:  return "compiler.log";
    case 3:  return "shader.pub";
    case 4:  return "fluid-sim-variantA.cache";
    default: printf("ERROR: Request out of range!\n");
             return "";
    }
}

int main() {
    char *output_char_buffer = NULL;

    // Simulate incoming data.
    for (int i = 0; i < 5; i++) {
        const char *word = word_generator(i);
        printf("Test string[%d]: %s\n", i, word);

        size_t local_buffer_length = strlen(word);

        char *input_char_buffer = (char*)malloc(local_buffer_length + 1);
        if (input_char_buffer == NULL) {
            // Clean-up.
            free(output_char_buffer);
            output_char_buffer = NULL;

            printf("ERROR: Failed to allocate char buffer memory!\n");
            // Exit with an error state.
            return 1;
        }

        strcpy(input_char_buffer, word);
        size_t input_buffer_length = strlen(input_char_buffer);

        // Verbose debug.
        printf("\tCurrent input buffer (value: %s, length: %zu)\n",
               input_char_buffer, input_buffer_length);

        char key[] = "compiler.log";

        // Verbose debug.
        printf("\tCurrent key (value: %s, length: %zu)\n", key, strlen(key));

        if (strcmp(input_char_buffer, key) == 0) {
            printf("\t\t__MATCH__\n");

            char *temp = (char *)realloc(output_char_buffer, local_buffer_length + 1);
            if (temp == NULL) {
                // Clean-up.
                free(output_char_buffer);
                output_char_buffer = NULL;
                free(input_char_buffer);
                input_char_buffer = NULL;

                printf("ERROR: Failed to fetch char buffer memory!\n");

                // Exit with an error state.
                return 1;
            }
            output_char_buffer = temp;
            strcpy(output_char_buffer, input_char_buffer);
        }

        // Clean-up.
        free(input_char_buffer);
        input_char_buffer = NULL;
    }

    // Check the final value of the string container.
    printf("Result: %s\n", output_char_buffer);

    // Clean-up and finish.
    free(output_char_buffer);
    output_char_buffer = NULL;
    return 0;
}