检查指针是否指向堆上分配的内存

问题描述:

我想知道指针是否指向使用malloc/new分配的一段内存。我意识到任意地址的答案是“不,你不能”,但我认为可以覆盖malloc/free并跟踪分配的内存范围。检查指针是否指向堆上分配的内存

您是否知道提供此特定工具的内存管理库?
你知道生产代码的东西吗?

Valgrind很好,但它太多了(仪表慢),并且Will说我们不想使用Valgrind这样(使软件崩溃足够好)。
Mudflap是一个非常好的解决方案,但专用于GCC,可悲的是,检查不会简单地返回布尔值(请参阅下面的答案)。
请注意,检查内存写入是否合法是security issue。因此寻找表现是出于动机。

+0

+1,这是关键问题需要测试POD内存(即没有构造函数和析构函数)是否正确分配和释放。我猜C++库在堆管理机制中有答案,因为它需要跟踪分配的内存块及其大小。但我不知道它是否公开这些数据(如果没有,是否可能侵入获取数据) - 我正在寻找答案。 – 2015-01-28 08:47:22

+0

你为什么需要它?知道指针是否有效,或者知道它是否是堆指针? – 2016-08-25 10:05:48

有没有这样做的标准方法,但各种malloc调试工具可能有办法做到这一点。例如,如果使用valgrind,则可以使用VALGRIND_CHECK_MEM_IS_ADDRESSABLE来检查这个和相关的东西

+3

valgrind真棒。 – 2010-06-17 20:09:05

+0

不错!我不知道与图书馆的链接并不标准,但;) – log0 2010-06-17 20:23:15

+1

@Ugo可以说,与图书馆链接并不是标准的。但是,除此之外,诸如valgrind等工具所使用的库肯定是非标准的,这就是为什么它们是特定于平台的原因。 – 2010-06-17 20:39:25

样张,它可能不能有效地完成:

char * p1 = malloc(1); 
free(p1); 
char * p2 = malloc(1); // probably allocates same block as first malloc 

现在无论p1与上堆相同的内存P2点,但只有P2是有效的。

+6

从哲学上讲,它可能会令人失望,但如果它结束了p2指向与p1相同的地址,p1仍然是可修改内存的地址。所以这对我来说很好。 – log0 2010-06-17 20:08:38

+1

@即使C和C++标准都声称p1不能用于访问该内存? – 2010-06-17 20:15:00

+1

Weeeeel也许p2是p1的地址...取决于你的malloc是如何工作的(在valgrind下运行几乎可以保证'p2!= p1'这是故意的,所以你可以在free后检测到使用,但是malloc仍然可以或者可能不(它们中的一些维持一定大小的最近free'd对象的FIFO队列,它们不会返回p1 ...)) – Spudd86 2010-06-17 20:17:49

您可以使用LD_PRELOAD,并将malloc包装在您自己的函数中。

内存分配具有(虚拟)地址和长度。

指针只包含地址。

如果单独跟踪的长度,你可以检查其包含,例如:

int check_contained(const char* src,size_t srclen,const char* sub,size_t sublen) { 
    return (sub >= src) && (sub+sublen < src+srclen); 
} 

的Symbian有一个AllocLen功能,但没有POSIX,也不等同的Win32。

+0

您能否更新链接到AllocLen?它接近死亡:/ – 2015-05-30 21:58:42

+2

@MateuszPiotrowski Symbian已经死了,现在看起来好像是文件:( – Will 2015-06-01 07:09:29

你可以自己做,如果性能是不是为您的应用程序一个真正的问题:

定义MyMalloc(...)和MyFree(...),其中,与调用malloc /*一起,你更新一个(有序的)对列表{地址 - malloc的结果,blockSize - 请求的内存量}。然后,当您需要检查指针p时,您会看到一对满足:地址< = p < =地址+块大小。

其他条件可以/应该检查,如果你想实际使用该指针,这只会告诉如果一个地址正在使用或不。

我做了类似的事情,但不记得它是如何编码的,我手上没有代码。

但基本的想法是覆盖基类的newdelete。在new中设置了静态标志(例如bool inDynamicAlloc=true)。这个标志在基类的构造函数中被质疑。 当它为真时,该对象被分配到堆上,否则在堆上分配。

构造函数随后重置标志。

希望这会有所帮助。

Mudflap(对于gcc)看起来很甜蜜。你必须编译你的软件,但它会检查任何错误的指针访问(堆/堆栈/静态)。它被设计用于生产代码,估计速度在x1.5到x5之间。您也可以在读访问时禁用检查以加速。什么都没有,叉广发行,SEGV或者根据环境参数中止:
用户检查可使用

void __mf_check (void *ptr, __mf_size_t sz, int type, const char *location) 

调用此函数的结果进行。

您可以使用与conservative garbage collector相同的技术来确定指针状对象是否指向堆。事实上,你可能会从bdwgc本身获取源代码。这将是一项不重要的任务,但它可以根据需要控制和移植。 (事实上​​,大部分移植工作已经完成)。

请参阅我们的CheckPointer工具,它将检查每个指针访问的有效性。它不是特别快,但它会捕获即使Valgrind不会捕获的错误(例如指向已释放栈帧的指针等)

Another answer to this question显示了对指针有效性进行纯内存范围检查将无法检测到问题的情况。他是对的,因为如果只有内存范围地址,就无法可靠地检查重新分配的存储块是否被滥用。这被称为时间错误。通过将分配事件与内存块以及范围相关联,您可以检测到这一点。 Checkpointer会这样做,并会检测到错误。

您可以通过调用malloc_size(my_ptr),malloc/malloc.h它返回malloc为您的指针分配的大小,如果指针未分配,则返回0。请记住,malloc会调整分配区块的大小,以确保可以从该指针取消引用最具限制性的类型变量并对齐内存。因此,如果你调用malloc(1)(以及malloc(0)),malloc实际上会返回16字节(在大多数机器上),因为最具限制性的类型的大小为16字节