1

我读了很多书,包括这里的 SO,这表明这通常是一个非常糟糕的主意,你唯一可以安全地做的就是退出程序。我不确定这是不是真的。

这是用于将大量分配交给 malloc 的池化内存分配器。在 pool_free() 期间,需要检查指针是否属于池或使用 malloc 分配。通过将地址向下舍入到最近的 1MB 边界,我得到了一个指向池中内存块开头的指针,或者如果使用了 malloc,则为 undefined。在第一种情况下,我可以轻松地验证内存块是否属于池,但是,如果不是,我将无法通过此验证,或者我将遇到访问冲突(请注意,这是一个只读进程)。我不能用 SEH (Windows) 捕捉到这一点或处理信号 (POSIX) 并简单地将其视为失败的验证吗?(即只有在使用 malloc 时才有可能,因此将 ptr 传递给 free())

编辑:人们似乎缺少上面的 OR。如果指针是用 malloc 分配的,我不希望出现访问冲突,但这是一种可能的结果。使用指向块开头(在 1MB 边界处)的指针的过程是验证幻数,然后跟随指向内存池的指针,并检查它是否确实包含上述​​指向块的指针。如果这些只读步骤中的任何一个产生访问冲突,它肯定会失败验证,就像任何单个步骤失败一样。

4

4 回答 4

2

你需要一个更好的测试。如果使用 malloc 作为舍入点也可能已分配给您的应用程序,则无法真正保证您将获得 AV,因此您可以访问该内存。

于 2010-05-28T22:15:38.780 回答
1

无需实现反应机制。您可以通过将堆分配对齐到 1 MB 边界来解决问题:

  1. 视窗:_aligned_malloc(size, 1<<20)
  2. Unix:memalign(1<<20, size)

使用这种方法,四舍五入到 1 MB 可以保证指向分配的内存块,您只需辨别该地址是在池中还是在池外(在这种情况下,它显然是malloced)。

您需要小心,您只对真正的大对象使用对齐的堆分配。例如,如果您将其用于大小 > 100 kB,分配器将在对象之间留下巨大的间隙。理想情况下,仅将其用于不适合 1 MB 池块的对象。

于 2010-05-28T22:14:16.600 回答
0

好的,inazaruk 发布了一个被严重否决的答案,然后被删除,建议使用 IsBadReadPtr + VirtualQuery(以避免保护或禁止访问页面。)阅读他发布的链接提醒我,读取内存的随机区域具有更差的潜力副作用比访问冲突。

意外访问线程堆栈末尾的保护页,如果该线程堆栈增长,将导致程序突然终止。

因此,捕获访问冲突可能是不安全的。这回答了这个问题。

于 2010-05-29T00:16:31.377 回答
0

我觉得应该是安全的。但可能是个坏主意。

但是,如果您需要将池分配的内存与非池分配的内存混合,我认为您需要在某处存储有关该信息的信息。也许使用 pool_alloc() 进行的每个内存分配都可能有一个很小的标题,在实际分配之前“隐藏”。此标头可以保存有关如何分配的信息。所以 char *block = (char *)pool_alloc(32) 实际上会分配 32+sizeof(BlockHeader) 字节。并且 block - sizeof(BlockHeader) 将提供对标题的访问。

根据 msdn,IsBadReadPtr 已过时:

重要此功能已过时,不应使用。尽管它的名字,它不保证指针是有效的或指向的内存可以安全使用。有关详细信息,请参阅本页上的备注。

于 2010-05-28T22:25:31.613 回答