我知道这个问题已经被问过很多次了,但似乎每次这个问题的发生都略有不同。
我有以下C应用程序,它从一个名为word_generator()
的函数接收字符串,然后过滤每个传入字符串,一旦满足条件,当前字符串存储在一个名为output_char_buffer
的字符数组中。
由于传入数据的长度是可变的,因此过程中涉及的字符数组需要动态调整大小。
应用程序似乎正在工作,但是静态分析工具用以下消息抱怨:
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]: %sn", 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("tt__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: %sn", 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));
您应该将返回值存储到一个临时变量中,以便在失败的情况下释放原始指针,从而避免内存泄漏。
还要注意,代码中的清理是不完整的:您应该释放input_char_buffer
和output_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]: %sn", 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("tt__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: %sn", output_char_buffer);
// Clean-up and finish.
free(output_char_buffer);
output_char_buffer = NULL;
return 0;
}