malloc的调试实现 [英] A debugging implementation of malloc

查看:86
本文介绍了malloc的调试实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在lcc-win32的C教程中,我有一个小章节

关于malloc的调试实现。


这是代码,随之而来的解释。


我将非常感谢您对代码和

相关解释的反馈。


----------------------------------------------- ----------------------


而不是直接使用malloc / free这里有两个实现

等效函数带有一些额外的安全功能:

o允许释放NULL并且不是错误。

o双重释放是不可能的。

o检查是否在块结束时立即覆盖。

o内存初始化为零。

o分配的内存计数保存在全局变量中。


#include< stdlib.h>

#define MAGIC 0xFFFF

#define SIGNATURE 12345678L

size_t AllocatedMemory;

void * allocate(size_t size)

{

寄存器char * r;

寄存器int * ip = NULL;

size + = 3 * sizeof(int);

r = malloc(size);

if(r == NULL)

返回r;

AllocatedMemory + = size;

ip =(int *)r;

//在开始时阻止我们写签名

* ip ++ = SIGNATURE;

//然后我们以字节为单位写出块的大小

* ip ++ =( int)size;

//我们将数据空间归零

memset(ip,0,size - 3 * sizeof(int));

//我们在块的末尾写下幻数,

//紧跟数据后面

ip =(int *)(& r [size - sizeof(int)]);

* ip = MAGIC;

//返回指向数据区开头的指针

return( r + 2 * sizeof(int));

}

void release(void * pp)

{

注册int * ip = NULL;

int s;

注册char * p = pp;

if(p = = NULL)//允许释放NULL

return;

//块的开头是数据前的两个整数。

p - = 2 * sizeof(int);

ip =(int *)p;

if(* ip == SIGNATURE){

/ /覆盖签名,以便此块

//不能再次释放

* ip ++ = 0;

s = * ip;

ip =(int *)(& p [s - sizeof(int)]);

if(* ip!= MAGIC){

ErorPrintf(?覆盖块大小%d?,s);

返回;

}

* ip = 0;

AllocatedMemory - = s;

免费(p);

}

else {

/ *该块已被覆盖。抱怨。 * /

ErrorPrintf(?错误的块传递给发布?);

}

}


allocate函数为3个整数添加请求的大小空间。

1)第一个是一个幻数(一个签名),它允许

识别这个块为由我们的分配分配的块

系统。

2)第二个是块的大小。在这两个数字之后,数据

如下。

3)数据之后是第三个数字,位于

的末尾块。对任何块的任何内存覆盖都可能首先覆盖这个数字

。自释放?功能检查,我们

将能够检测到块被覆盖的时间。


任何时候,用户都可以询问大小总分配内存

(循环中的有效块)通过查询AllocatedMemory变量。


?释放函数?接受NULL(被忽略)。如果传递给它的指针

不是NULL,它将检查它是否为有效块,并且

签名仍然存在,即没有内存覆盖

在使用块期间发生。

In the C tutorial for lcc-win32, I have a small chapter
about a debugging implementation of malloc.

Here is the code, and the explanations that go with it.

I would appreciate your feedback both about the code and
the associated explanations.

---------------------------------------------------------------------

Instead of using directly malloc/free here are two implementations of
equivalent functions with some added safety features:
o Freeing NULL is allowed and is not an error.
o Double freeing is made impossible.
o Any overwrite immediately at the end of the block is checked for.
o Memory is initialized to zero.
o A count of allocated memory is kept in a global variable.

#include <stdlib.h>
#define MAGIC 0xFFFF
#define SIGNATURE 12345678L
size_t AllocatedMemory;
void *allocate(size_t size)
{
register char *r;
register int *ip = NULL;
size += 3 * sizeof(int);
r = malloc(size);
if (r == NULL)
return r;
AllocatedMemory += size;
ip = (int *) r;
// At the start of the block we write the signature
*ip++ = SIGNATURE;
// Then we write the size of the block in bytes
*ip++ = (int) size;
// We zero the data space
memset(ip, 0, size - 3*sizeof(int));
// We write the magic number at the end of the block,
// just behind the data
ip = (int *) (&r[size - sizeof(int)]);
*ip = MAGIC;
// Return a pointer to the start of the data area
return (r + 2 * sizeof(int));
}
void release(void *pp)
{
register int *ip = NULL;
int s;
register char *p = pp;
if (p == NULL) // Freeing NULL is allowed
return;
// The start of the block is two integers before the data.
p -= 2 * sizeof(int);
ip = (int *) p;
if (*ip == SIGNATURE) {
// Overwrite the signature so that this block
// can?t be freed again
*ip++ = 0;
s = *ip;
ip = (int *) (&p[s - sizeof(int)]);
if (*ip != MAGIC) {
ErorPrintf(?Overwritten block size %d?, s);
return;
}
*ip = 0;
AllocatedMemory -= s;
free(p);
}
else {
/* The block has been overwritten. Complain. */
ErrorPrintf(?Wrong block passed to release?);
}
}

The allocate function adds to the requested size space for 3 integers.
1) The first is a magic number (a signature) that allows the
identification of this block as a block allocated by our allocation
system.
2) The second is the size of the block. After this two numbers, the data
follows.
3) The data is followed by a third number that is placed at the end of
the block. Any memory overwrite of any block will overwrite probably
this number first. Since the ?release? function checks for this, we
will be able to detect when a block has been overwritten.

At any time, the user can ask for the size of total allocated memory
(valid blocks in circulation) by querying the AllocatedMemory variable.

The ?release function? accepts NULL (that is ignored). If the pointer
passed to it is not NULL, it will check that it is a valid block, and
that the signature is still there, i.e. that no memory overwrites have
happened during the usage of the block.

推荐答案

jacob navia写道:
jacob navia wrote:
In关于lcc-win32的C教程,我有一个关于malloc的调试实现的小章节。

这是代码,以及随之而来的解释。
<我很感激您对代码和相关解释的反馈。
In the C tutorial for lcc-win32, I have a small chapter
about a debugging implementation of malloc.

Here is the code, and the explanations that go with it.

I would appreciate your feedback both about the code and
the associated explanations.



是否有任何单元测试?


-

Ian Collins。


Are there any unit tests?

--
Ian Collins.


2006-06-24,jacob navia< ja *** @ jacob.remcomp.fr> ;写道:
On 2006-06-24, jacob navia <ja***@jacob.remcomp.fr> wrote:
在lcc-win32的C教程中,我有一个小章节关于malloc的调试实现。

这是代码,和与之相关的解释。

我将非常感谢您对代码和相关解释的反馈。

---------- -------------------------------------------------- ---------

这里有两个
等效函数的实现,而不是直接使用malloc / free,并增加了一些安全功能:
o允许释放NULL并不是一个错误。


免费已经让你免费(NULL)没有错误不是吗?

#include< stdlib.h>
#定义MAGIC 0xFFFF
#define SIGNATURE 12345678L
size_t AllocatedMemory;
void * allocate(size_t size)
{
注册char * r;
注册int * ip = NULL;
size + = 3 * sizeof(int);
r = malloc(size);
if(r == NULL)
return r;
AllocatedMemory + = size;
ip =(int *)r;
//在块的开头我们写签名
* ip ++ = SIGNATURE;
//然后我们以字节为单位写出块的大小
* ip ++ =(int)size;


您也可以在元数据中存储大小。作为size_t反而

截断为int--没有真正的伤害,人们有时会分配大的
块。

//我们将数据空间归零
memset(ip,0,size - 3 * sizeof(int));
//我们在块的末尾写下幻数,
//数据背后
ip =(int *)(& r [size-sizeof(int)]);
* ip = MAGIC;
In the C tutorial for lcc-win32, I have a small chapter
about a debugging implementation of malloc.

Here is the code, and the explanations that go with it.

I would appreciate your feedback both about the code and
the associated explanations.

---------------------------------------------------------------------

Instead of using directly malloc/free here are two implementations of
equivalent functions with some added safety features:
o Freeing NULL is allowed and is not an error.
free already lets you free(NULL) without an error doesn''t it?
#include <stdlib.h>
#define MAGIC 0xFFFF
#define SIGNATURE 12345678L
size_t AllocatedMemory;
void *allocate(size_t size)
{
register char *r;
register int *ip = NULL;
size += 3 * sizeof(int);
r = malloc(size);
if (r == NULL)
return r;
AllocatedMemory += size;
ip = (int *) r;
// At the start of the block we write the signature
*ip++ = SIGNATURE;
// Then we write the size of the block in bytes
*ip++ = (int) size;
You might as well store the size in your "metadata" as a size_t instead
of truncating to int-- no real harm in it, and people do allocate big
blocks sometimes.
// We zero the data space
memset(ip, 0, size - 3*sizeof(int));
// We write the magic number at the end of the block,
// just behind the data
ip = (int *) (&r[size - sizeof(int)]);
*ip = MAGIC;




这可能会导致对齐问题 - 假设大小为17,并且

sizeof(int)4,malloc返回16字节对齐的指针,并且在

上目标机器int必须存储在4字节对齐的地址。


r是0x10(比如说)。 & r [size - 4]将是0x1d,这不是4字节对齐(0x1d%

4是1)


更好地制作你的魔术数字守卫乐队的东西就像一个
char的数组,所以它总是可以在一个块结束时进行,无论块的大小是多少。

块。



This will likely cause alignment problems-- suppose size were 17, and
sizeof (int) 4, malloc returns 16-byte aligned pointers, and that on the
target machine ints have to be stored at 4-byte aligned addresses.

r is 0x10 (say). &r[size - 4] will be 0x1d, which is not 4-byte aligned (0x1d %
4 is 1)

Better to make your magic number guard band something like an array of
char, so it can always go at the end of a block, whatever the size of
the block.


jacob navia写道:
jacob navia wrote:
void release(void * pp)
{
注册int * ip = NULL;
int s;
注册char * p = pp;
if(p == NULL)//允许空闲返回
返回;
//块的开头是两个数据前的整数。
p - = 2 * sizeof(int);


也许考虑对齐检查(p可被sizeof(int)整除)并检查

for p>减法前2 * sizeof(int)。 Paranoid,put保护

反对释放(7);

ip =(int *)p;
if(* ip == SIGNATURE){
//覆盖签名,以便不能再释放此块
* ip ++ = 0;
s = * ip;


我会将s(并称之为大小)带入if {}范围。

ip =(int *)(& p [ s - sizeof(int)]);
void release(void *pp)
{
register int *ip = NULL;
int s;
register char *p = pp;
if (p == NULL) // Freeing NULL is allowed
return;
// The start of the block is two integers before the data.
p -= 2 * sizeof(int);
Maybe consider an alignment check (p divisible by sizeof(int)) and check
for p > 2*sizeof(int) before the subtraction. Paranoid, put protects
against release( 7 );
ip = (int *) p;
if (*ip == SIGNATURE) {
// Overwrite the signature so that this block
// can?t be freed again
*ip++ = 0;
s = *ip;
I''d bring s (and call it size) into the if{} scope.
ip = (int *) (&p[s - sizeof(int)]);




这里有另一个偏执的对齐检查吗?


-

Ian Collins。



Another paranoid alignment check here?

--
Ian Collins.


这篇关于malloc的调试实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆