一个有趣的代码问题

OldNewThing发布了一篇很有意思的文章http://blogs.msdn.com/oldnewthing/archive/2010/01/20/9950638.aspx

The wrong way to determine the size of a buffer

A colleague of mine showed me some code from a back-end program on a web server. Fortunately, the company that wrote this is out of business. Or at least I hope they’re out of business!


size = 16384; 

while (size && IsBadReadPtr(buffer, size)) 

{ size--; }

高人就是高人,这个代码其实还是需要好好想一想才能明白为何有问题。

IsBadReadPtr的意思是尝试去读一个不属于自己进程的内存地址,因为指针越界在大多数情况下都是代表错误发生。但是这个函数实际上并不是那么好用,具体原因可以看OldNewThing的这篇文章http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx 介绍的非常详细。

回到这个问题上,在OldNewThing的文章中介绍的非常清楚“But guard page exceptions are raised only once.”,也就是说,IsBadReadPtr将只会有效一次(?need to double check),这个代码逻辑就是有问题的。

再把其中包含的问题列一下,主要参考了文章后的留言。

1)16384这个16K大小来的莫名其妙,当然不排除在某些特定软件设计中,最大就是这个大小。

2)第二个问题,IsBadReadPtr并不是那么好用。

3)这个计算得到的值未必正确。

那么我们该如何获取buffer的大小呢?

在c-faq中告诉我们,通常情况下是没有解决办法的,只能自己保存这个buffer大小。办法也很简单,我们需要申请的时候就把buffer大小记住,需要知道的时候,查找一下就知道了,或者是使用某种数据结构,把buffer的大小以及其他信息放在开头固定的一块大小就行了。

如果是windows,那么有一些特定的办法。可以用_msize来获得malloc申请的buffer。

allocated with LocalAlloc, use LocalSize. For HeapAlloc, use HeapSize. For GlobalAlloc, use GlobalSize,如果使用CoTaskMemalloc,可以先用CoGetMalloc拿到一个IMalloc接口,然后调用GetSize()

这些函数到底好用不好用,还是得靠你自己多测试。最简单牢靠的办法还是自己保存这个size信息。

Tags :

Google Reader Yahoo Facebook Twitter Digg FriendFeed Delicious Google Translate
这篇日志发表于2010年01月21日 6:36 上午。 你可以订阅该日志的所有评论通过 RSS 2.0。 你可以发表评论,或者引用通告

2 条回应

评论(2)引用通告(0)

  1. lisd

    这段程序根本不能实现目的,最直接的原因就是IsBadReadPtr只是判断是否有权限可以读取这段buffer.
    我以不同方式试了一下这段程序,根本不能准确得不到buffer的size。
    因此,我很有疑惑,错误不是很明显的吗?难道这段代码还有可能得到buffer的大小?
    如果的确有可能可以准确得到buffer的大小,那就证明它有运行的可能,和改进的可能(姑且不考虑性能)

    总的来说,我只是有个疑惑:难道这段程序有可能跑对?

    2010年09月9日 12:01 上午 | #1 @
    • lisd

      ps:如果有可能请mail我这个回复。

      2010年09月9日 12:02 上午 | #2 @

发表评论

(Ctrl+Enter)

XHTML:你可以使用这些标签:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>