(void *) 的 realloc 中的内存泄漏以连接字符串
Memory leak in realloc of (void *) to concatenate string
给定一个带有空指针 (void *) value
的结构对象,该对象使用 malloc 初始化以保存字符串 "chapt"
.
之后,使用 realloc
获得足够的内存来连接另一个字符串。
/* Standard Imports */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
struct generic_type
{
void *value;
void (*add)(struct generic_type, int);
};
/* Function Declarations */
static void TestRun();
static void AddNumToString(struct generic_type element, int num);
#define TEST_ARRAY_SIZE 1
int main(int argc, char *argv[])
{
TestRun();
(void) argc;
(void) *argv;
return 0;
}
static void TestRun()
{
struct generic_type element;
element.value = malloc(sizeof(char) * 6);
assert (NULL != element.value);
element.value = strcpy(element.value, "chapt");
element.add = AddNumToString;
element.add(element, 10);
free(element.value);
}
static void AddNumToString(struct generic_type element, int num)
{
size_t num_length = snprintf(NULL, 0, "%d", num);
size_t str_length = strlen((char *)(element.value));
size_t new_length = str_length + num_length + 1;
char *num_string = (char *)malloc(sizeof(char) * (num_length + 1));
sprintf(num_string, "%d", num);
element.value = realloc(element.value, sizeof(char) * new_length);
assert (NULL != element.value);
element.value = strcat(((char *)(element.value)), num_string);
free(num_string);
}
此实现产生了正确的输出,但存在内存泄漏:
==29031== Memcheck, a memory error detector
==29031== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==29031== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==29031== Command: ./a.out
==29031==
==29031== Invalid free() / delete / delete[] / realloc()
==29031== at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x1088EB: TestRun (teststructs.c:40)
==29031== by 0x108862: main (teststructs.c:22)
==29031== Address 0x522d040 is 0 bytes inside a block of size 6 free'd
==29031== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x108999: AddNumToString (teststructs.c:52)
==29031== by 0x1088DF: TestRun (teststructs.c:39)
==29031== by 0x108862: main (teststructs.c:22)
==29031== Block was alloc'd at
==29031== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x10887B: TestRun (teststructs.c:34)
==29031== by 0x108862: main (teststructs.c:22)
==29031==
==29031==
==29031== HEAP SUMMARY:
==29031== in use at exit: 8 bytes in 1 blocks
==29031== total heap usage: 3 allocs, 3 frees, 17 bytes allocated
==29031==
==29031== 8 bytes in 1 blocks are definitely lost in loss record 1 of 1
==29031== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x108999: AddNumToString (teststructs.c:52)
==29031== by 0x1088DF: TestRun (teststructs.c:39)
==29031== by 0x108862: main (teststructs.c:22)
==29031==
==29031== LEAK SUMMARY:
==29031== definitely lost: 8 bytes in 1 blocks
==29031== indirectly lost: 0 bytes in 0 blocks
==29031== possibly lost: 0 bytes in 0 blocks
==29031== still reachable: 0 bytes in 0 blocks
==29031== suppressed: 0 bytes in 0 blocks
==29031==
==29031== For counts of detected and suppressed errors, rerun with: -v
==29031== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
问题似乎出在 realloc
行,但我似乎看不出问题所在。
在初始化期间分配足够的内存并避免 realloc
解决了问题,但我更清楚为什么这在此时不起作用。
AddNumToString
按值传递其 element
参数,因此它获得传递给它的对象的 copy。这意味着当你做
element.value = realloc(element.value, sizeof(char) * new_length);
element
中包含的原始指针被释放,但新的指针存储在副本中。 AddNumToString
returns时副本丢失,所以新分配的space被泄露。更糟糕的是,调用者中的对象保持不变;特别是,它仍然包含现在已被释放的原始指针。因此,当它最终被释放时(未显示在您当前的代码中),这是一个双重释放,这很糟糕。
您可能希望 AddNumToString
取一个指向 struct generic_type
的指针,这样它就可以实际修改对象。
给定一个带有空指针 (void *) value
的结构对象,该对象使用 malloc 初始化以保存字符串 "chapt"
.
之后,使用 realloc
获得足够的内存来连接另一个字符串。
/* Standard Imports */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
struct generic_type
{
void *value;
void (*add)(struct generic_type, int);
};
/* Function Declarations */
static void TestRun();
static void AddNumToString(struct generic_type element, int num);
#define TEST_ARRAY_SIZE 1
int main(int argc, char *argv[])
{
TestRun();
(void) argc;
(void) *argv;
return 0;
}
static void TestRun()
{
struct generic_type element;
element.value = malloc(sizeof(char) * 6);
assert (NULL != element.value);
element.value = strcpy(element.value, "chapt");
element.add = AddNumToString;
element.add(element, 10);
free(element.value);
}
static void AddNumToString(struct generic_type element, int num)
{
size_t num_length = snprintf(NULL, 0, "%d", num);
size_t str_length = strlen((char *)(element.value));
size_t new_length = str_length + num_length + 1;
char *num_string = (char *)malloc(sizeof(char) * (num_length + 1));
sprintf(num_string, "%d", num);
element.value = realloc(element.value, sizeof(char) * new_length);
assert (NULL != element.value);
element.value = strcat(((char *)(element.value)), num_string);
free(num_string);
}
此实现产生了正确的输出,但存在内存泄漏:
==29031== Memcheck, a memory error detector
==29031== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==29031== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==29031== Command: ./a.out
==29031==
==29031== Invalid free() / delete / delete[] / realloc()
==29031== at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x1088EB: TestRun (teststructs.c:40)
==29031== by 0x108862: main (teststructs.c:22)
==29031== Address 0x522d040 is 0 bytes inside a block of size 6 free'd
==29031== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x108999: AddNumToString (teststructs.c:52)
==29031== by 0x1088DF: TestRun (teststructs.c:39)
==29031== by 0x108862: main (teststructs.c:22)
==29031== Block was alloc'd at
==29031== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x10887B: TestRun (teststructs.c:34)
==29031== by 0x108862: main (teststructs.c:22)
==29031==
==29031==
==29031== HEAP SUMMARY:
==29031== in use at exit: 8 bytes in 1 blocks
==29031== total heap usage: 3 allocs, 3 frees, 17 bytes allocated
==29031==
==29031== 8 bytes in 1 blocks are definitely lost in loss record 1 of 1
==29031== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x108999: AddNumToString (teststructs.c:52)
==29031== by 0x1088DF: TestRun (teststructs.c:39)
==29031== by 0x108862: main (teststructs.c:22)
==29031==
==29031== LEAK SUMMARY:
==29031== definitely lost: 8 bytes in 1 blocks
==29031== indirectly lost: 0 bytes in 0 blocks
==29031== possibly lost: 0 bytes in 0 blocks
==29031== still reachable: 0 bytes in 0 blocks
==29031== suppressed: 0 bytes in 0 blocks
==29031==
==29031== For counts of detected and suppressed errors, rerun with: -v
==29031== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
问题似乎出在 realloc
行,但我似乎看不出问题所在。
在初始化期间分配足够的内存并避免 realloc
解决了问题,但我更清楚为什么这在此时不起作用。
AddNumToString
按值传递其 element
参数,因此它获得传递给它的对象的 copy。这意味着当你做
element.value = realloc(element.value, sizeof(char) * new_length);
element
中包含的原始指针被释放,但新的指针存储在副本中。 AddNumToString
returns时副本丢失,所以新分配的space被泄露。更糟糕的是,调用者中的对象保持不变;特别是,它仍然包含现在已被释放的原始指针。因此,当它最终被释放时(未显示在您当前的代码中),这是一个双重释放,这很糟糕。
您可能希望 AddNumToString
取一个指向 struct generic_type
的指针,这样它就可以实际修改对象。