代码的第 2 个 运行 之后的 C double free 错误
C double free error after 2nd run of the code
我正在尝试用 C 开发一个库并从内存管理开始。
正在尝试多次测试我的分配函数和释放函数以测试多个分配和释放。
但是,在第 2 个 运行 的免费功能中,我得到了双重免费和崩溃。
我的简单header:
#include <stdio.h>
#include <stdlib.h>
#include "xyz_props.h"
#include <assert.h>
#include <string.h>
Header:
#ifndef XYZ_PROPS_H
#define XYZ_PROPS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#define DEFAULT_MAX_KEY_SIZE_IN_BYTES 256
#define DEFAULT_MAX_VALUE_SIZE_IN_BYTES 4096
/*represents a single linked list node with (key,value) pair*/
typedef struct xyz_config_node
{
char* key;
char* value;
struct xyz_config_node* p_next;
} xyz_config_node;
/*represents all properties*/
typedef struct xyz_config_list
{
xyz_config_node* p_head;
int KEY_SIZE_IN_BYTES;
int VALUE_SIZE_IN_BYTES;
} xyz_config_list;
/*declare variables*/
extern xyz_config_list* p_self;
/*===========================================================================
Function: xyz_config_alloc
Description: allocates heap memory for the wrapper xyz_config_list
* that contains the head node.
Inputs: max_key_size in bytes.
* Input of 0 or greater than 4096 will default to 256 bytes
* length for the key size.
*
* max_value_size in bytes.
* Input of 0 or greater than 4096 will default to 4096 bytes
* length for the value size.
Outputs: pointer to xyz_config_list
==========================================================*/
xyz_config_list* xyz_config_alloc(int max_key_size, int max_value_size);
/*===========================================================================
Function: xyz_config_free
Description: Frees heap memory allocated to xyz_config_list & the
* linked list within xyz_config_list.
Inputs: xyz_config_list** pp_self - pass by reference
Outputs: void
References:
Example call: xyz_config_free(&props);
==========================================================*/
void xyz_config_free(xyz_config_list** pp_self);
实现C文件:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "xyz_props.h"
xyz_config_list* p_self = NULL;
/*=============================================================================
Private Declarations
==============================================================================*/
xyz_config_list* xyz_config_alloc_helper(int max_key_size, int max_value_size, xyz_config_list** props);
/*=============================================================================
* Implementations
==============================================================================*/
xyz_config_list* xyz_config_alloc(int max_key_size, int max_value_size) {
return xyz_config_alloc_helper(max_key_size, max_value_size,&p_self);
}
xyz_config_list* xyz_config_alloc_helper(int max_key_size, int max_value_size, xyz_config_list** props)
{
if (NULL == *props) {
*props = (xyz_config_list*) calloc(1, sizeof(xyz_config_list));
//set max key size
if (max_key_size > 0 && max_key_size<=4096) {
(*props)->KEY_SIZE_IN_BYTES = max_key_size;
} else {
//defaults to 256
(*props)->KEY_SIZE_IN_BYTES = DEFAULT_MAX_KEY_SIZE_IN_BYTES;
fprintf(stderr,"WARNING xyz_config,xyz_config_alloc_helper(), "
"max_key_size MUST be 0<max_key_size<=4096.max_key_size is set to "
"default 256.\n");
}
//set max value size
if (max_value_size > 0 && max_value_size<=4096) {
(*props)->VALUE_SIZE_IN_BYTES = max_value_size;
} else {
//defaults to 4096
(*props)->VALUE_SIZE_IN_BYTES = DEFAULT_MAX_VALUE_SIZE_IN_BYTES;
fprintf(stderr,"WARNING xyz_config,xyz_config_alloc_helper(), "
"max_value_size MUST be 0<max_value_size<=4096.max_value_size is set to "
"default 4096.\n");
}
}
return *props;
}
void xyz_config_free(xyz_config_list** pp_self)
{
if (NULL!=pp_self && NULL!=(*pp_self))
{
xyz_config_node* p_current = (*pp_self)->p_head;
xyz_config_node* p_next = NULL;
//iterate and free the nodes
while (NULL!=p_current)
{
p_next = p_current->p_next;
//free child attributes
free(p_current->key);
free(p_current->value);
//free the node
free(p_current);
p_current = p_next;
}
//free the super structure
if (NULL!=*pp_self)
{
free (*pp_self); //ERROR HAPPENS ON 2ND TIME HERE.
*pp_self = NULL;
}
}
}
主文件:
/*
*
*/
void test();
void test2();
int main(int argc, char** argv) {
test();
return (EXIT_SUCCESS);
}
/*single alloc & free*/
void test()
{
xyz_config_list* props = xyz_config_alloc(128,1600); //defaults to max_key_size=256,max_value_size=4096
assert(props);
//finally free all memory
xyz_config_free(&props);
assert(NULL==props);
printf("free\n");
}
/*multiple allocs & frees*/
void test2()
{
//1-alloc
xyz_config_list* props = xyz_config_alloc(128,1600); //defaults to max_key_size=256,max_value_size=4096
assert(props);
//1-finally free all memory
xyz_config_free(&props);
assert(NULL==props);
//2- alloc
props = xyz_config_alloc(128,1600); //defaults to max_key_size=256,max_value_size=4096
assert(props);
//2-finally free all memory
xyz_config_free(&props); //CRASH in 2nd free function. Output: RUN FINISHED; Segmentation fault; core dumped;
assert(NULL==props);
printf("free\n");
}
第 1 次监视调试器内存和变量 运行:
调试器内存和变量在第二个 运行 出现问题:
任何帮助将不胜感激。
看来问题与在文件范围
中声明变量p_self
有关
xyz_config_list* p_self = NULL;
这个变量在函数xyz_config_alloc_helper
中使用。只有在文件范围变量 p_self
等于 NULL
.
时才会分配内存
xyz_config_list* xyz_config_alloc(int max_key_size, int max_value_size) {
return xyz_config_alloc_helper(max_key_size, max_value_size,&p_self);
^^^^^^^
}
和(在函数xyz_config_alloc_helper
内)
if (NULL == *props) {
*props = (xyz_config_list*) calloc(1, sizeof(xyz_config_list));
但是在函数 xyz_config_free
中变量没有设置为 NULL
因为函数处理函数 test 和 test2 中声明的局部变量,例如
xyz_config_list* props = xyz_config_alloc(128,1600); //defaults to max_key_size=256,max_value_size=4096
assert(props);
//1-finally free all memory
xyz_config_free(&props);
这里是函数的代码片段,它设置为 NULL
本地指针通过引用传递给函数
if (NULL!=*pp_self)
{
free (*pp_self); //ERROR HAPPENS ON 2ND TIME HERE.
*pp_self = NULL;
}
即*pp_self与文件作用域p_self
.
中的对象不是同一个对象
因此,当函数 xyz_config_free
第二次被调用时,它会尝试释放已释放的内存,因为在第二次之前,由于文件作用域变量未设置为,新内存未分配NULL 在函数的先前调用中 xyz_config_free
这个错误的教训是尽量避免定义依赖于文件范围变量的函数。
我正在尝试用 C 开发一个库并从内存管理开始。
正在尝试多次测试我的分配函数和释放函数以测试多个分配和释放。
但是,在第 2 个 运行 的免费功能中,我得到了双重免费和崩溃。
我的简单header:
#include <stdio.h>
#include <stdlib.h>
#include "xyz_props.h"
#include <assert.h>
#include <string.h>
Header:
#ifndef XYZ_PROPS_H
#define XYZ_PROPS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#define DEFAULT_MAX_KEY_SIZE_IN_BYTES 256
#define DEFAULT_MAX_VALUE_SIZE_IN_BYTES 4096
/*represents a single linked list node with (key,value) pair*/
typedef struct xyz_config_node
{
char* key;
char* value;
struct xyz_config_node* p_next;
} xyz_config_node;
/*represents all properties*/
typedef struct xyz_config_list
{
xyz_config_node* p_head;
int KEY_SIZE_IN_BYTES;
int VALUE_SIZE_IN_BYTES;
} xyz_config_list;
/*declare variables*/
extern xyz_config_list* p_self;
/*===========================================================================
Function: xyz_config_alloc
Description: allocates heap memory for the wrapper xyz_config_list
* that contains the head node.
Inputs: max_key_size in bytes.
* Input of 0 or greater than 4096 will default to 256 bytes
* length for the key size.
*
* max_value_size in bytes.
* Input of 0 or greater than 4096 will default to 4096 bytes
* length for the value size.
Outputs: pointer to xyz_config_list
==========================================================*/
xyz_config_list* xyz_config_alloc(int max_key_size, int max_value_size);
/*===========================================================================
Function: xyz_config_free
Description: Frees heap memory allocated to xyz_config_list & the
* linked list within xyz_config_list.
Inputs: xyz_config_list** pp_self - pass by reference
Outputs: void
References:
Example call: xyz_config_free(&props);
==========================================================*/
void xyz_config_free(xyz_config_list** pp_self);
实现C文件:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "xyz_props.h"
xyz_config_list* p_self = NULL;
/*=============================================================================
Private Declarations
==============================================================================*/
xyz_config_list* xyz_config_alloc_helper(int max_key_size, int max_value_size, xyz_config_list** props);
/*=============================================================================
* Implementations
==============================================================================*/
xyz_config_list* xyz_config_alloc(int max_key_size, int max_value_size) {
return xyz_config_alloc_helper(max_key_size, max_value_size,&p_self);
}
xyz_config_list* xyz_config_alloc_helper(int max_key_size, int max_value_size, xyz_config_list** props)
{
if (NULL == *props) {
*props = (xyz_config_list*) calloc(1, sizeof(xyz_config_list));
//set max key size
if (max_key_size > 0 && max_key_size<=4096) {
(*props)->KEY_SIZE_IN_BYTES = max_key_size;
} else {
//defaults to 256
(*props)->KEY_SIZE_IN_BYTES = DEFAULT_MAX_KEY_SIZE_IN_BYTES;
fprintf(stderr,"WARNING xyz_config,xyz_config_alloc_helper(), "
"max_key_size MUST be 0<max_key_size<=4096.max_key_size is set to "
"default 256.\n");
}
//set max value size
if (max_value_size > 0 && max_value_size<=4096) {
(*props)->VALUE_SIZE_IN_BYTES = max_value_size;
} else {
//defaults to 4096
(*props)->VALUE_SIZE_IN_BYTES = DEFAULT_MAX_VALUE_SIZE_IN_BYTES;
fprintf(stderr,"WARNING xyz_config,xyz_config_alloc_helper(), "
"max_value_size MUST be 0<max_value_size<=4096.max_value_size is set to "
"default 4096.\n");
}
}
return *props;
}
void xyz_config_free(xyz_config_list** pp_self)
{
if (NULL!=pp_self && NULL!=(*pp_self))
{
xyz_config_node* p_current = (*pp_self)->p_head;
xyz_config_node* p_next = NULL;
//iterate and free the nodes
while (NULL!=p_current)
{
p_next = p_current->p_next;
//free child attributes
free(p_current->key);
free(p_current->value);
//free the node
free(p_current);
p_current = p_next;
}
//free the super structure
if (NULL!=*pp_self)
{
free (*pp_self); //ERROR HAPPENS ON 2ND TIME HERE.
*pp_self = NULL;
}
}
}
主文件:
/*
*
*/
void test();
void test2();
int main(int argc, char** argv) {
test();
return (EXIT_SUCCESS);
}
/*single alloc & free*/
void test()
{
xyz_config_list* props = xyz_config_alloc(128,1600); //defaults to max_key_size=256,max_value_size=4096
assert(props);
//finally free all memory
xyz_config_free(&props);
assert(NULL==props);
printf("free\n");
}
/*multiple allocs & frees*/
void test2()
{
//1-alloc
xyz_config_list* props = xyz_config_alloc(128,1600); //defaults to max_key_size=256,max_value_size=4096
assert(props);
//1-finally free all memory
xyz_config_free(&props);
assert(NULL==props);
//2- alloc
props = xyz_config_alloc(128,1600); //defaults to max_key_size=256,max_value_size=4096
assert(props);
//2-finally free all memory
xyz_config_free(&props); //CRASH in 2nd free function. Output: RUN FINISHED; Segmentation fault; core dumped;
assert(NULL==props);
printf("free\n");
}
第 1 次监视调试器内存和变量 运行:
调试器内存和变量在第二个 运行 出现问题:
任何帮助将不胜感激。
看来问题与在文件范围
中声明变量p_self
有关
xyz_config_list* p_self = NULL;
这个变量在函数xyz_config_alloc_helper
中使用。只有在文件范围变量 p_self
等于 NULL
.
xyz_config_list* xyz_config_alloc(int max_key_size, int max_value_size) {
return xyz_config_alloc_helper(max_key_size, max_value_size,&p_self);
^^^^^^^
}
和(在函数xyz_config_alloc_helper
内)
if (NULL == *props) {
*props = (xyz_config_list*) calloc(1, sizeof(xyz_config_list));
但是在函数 xyz_config_free
中变量没有设置为 NULL
因为函数处理函数 test 和 test2 中声明的局部变量,例如
xyz_config_list* props = xyz_config_alloc(128,1600); //defaults to max_key_size=256,max_value_size=4096
assert(props);
//1-finally free all memory
xyz_config_free(&props);
这里是函数的代码片段,它设置为 NULL
本地指针通过引用传递给函数
if (NULL!=*pp_self)
{
free (*pp_self); //ERROR HAPPENS ON 2ND TIME HERE.
*pp_self = NULL;
}
即*pp_self与文件作用域p_self
.
因此,当函数 xyz_config_free
第二次被调用时,它会尝试释放已释放的内存,因为在第二次之前,由于文件作用域变量未设置为,新内存未分配NULL 在函数的先前调用中 xyz_config_free
这个错误的教训是尽量避免定义依赖于文件范围变量的函数。