SHARE
TWEET

lpvBits buffer may NOT straddle multiple virtual memory allo

a guest Jun 11th, 2012 829 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. The buffer pointed to by lpvBits cannot straddle multiple virtual memory allocations.  We have observed this on many different computers with different video cards and versions of Windows.  This may be a very common error in some applications depending on the heap manager that is used.
  2.  
  3. Summary:  Given the observations below, the only safe buffer to pass to lpvBits is one that you have directly allocated using a single call to VirtualAlloc.  Do not use malloc, operator new, GlobalAlloc, HeapAlloc, or other heap allocators; they are not safe to use.
  4.  
  5. For example, the following procedure would fail:
  6.  
  7. 1.  Call VirtualAlloc and reserve/commit a 1 megabyte buffer.
  8. 2.  Call VirtualAlloc and reserve/commit a second 1 megabyte buffer with a base address that immediately follows the allocation from #1.
  9. 3.  Logically, we can now consider the base address for the first allocation to point to a 2 megabyte buffer, because the two commits were adjacent to each other.  (Some memory managers do exactly this.)
  10. 4.  Call GetDIBits for a 1.5 megabyte bitmap with lpvBits == base address for first commit.  The call fails; GetLastError() does not provide any clues.  It turns out that the reason it fails is because the buffer pointed to by lpvBits straddles two VirtualAlloc reservations.
  11.  
  12. The solution is to combine the two VirtualAlloc calls into a single VirtualAlloc call that reserves/commits the required buffer space.  I do not know why this problem occurs, it could be defined/due to any of these factors:
  13.  
  14.  * The GDI function has an undocumented requirement for lpvBits to not straddle multiple VirtualAlloc reserve/commits (i.e. this behavior is by design).
  15.  * The GDI function has a bug where it can't handle buffers that straddle multiple memory commits when it should be able to.
  16.  * The video drivers on the system have a bug such that they impose this undocumented requirement (i.e. not Microsoft's fault).
  17.  
  18. It would be nice if someone at Microsoft could shed some light on this issue.
  19.  
  20. To put this in practical terms, it means that you can't use most heap managers.  The default C/C++ heap manager (operator new, malloc function, etc.) is NOT going to be acceptable in many cases because it does not guarantee that the allocated memory will lie within a single commit.  For example, the C++ Builder & Delphi allocator (for pre-2006; newer FastMM-based versions unknown) will "combine" multiple reservations from VirtualAlloc - exactly this problematic behavior - in order to make the most use out of memory that it gets from VirtualAlloc, and is therefore not compatible with these GDI functions.
  21.  
  22. Even the Microsoft heaps provide no guarantee that allocated memory won't straddle multiple VirtualAlloc reserve/commits.  If the documentation doesn't guarantee it, then you can't depend on it.  This includes Visual C++ malloc, GlobalAlloc, and HeapAlloc.
  23.  
  24. References:
  25.  
  26.  * Doug Lea's malloc implementation has a source code comment stating the following:
  27.  
  28. "Random-looking failures from Win32 GDI API's (eg; SetDIBits()) may be due to bugs in some video driver implementations when pixel buffers are malloc()ed, and the region spans more than one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb) default granularity, pixel buffers may straddle virtual allocation regions more often than when using the Microsoft allocator [note he does NOT say that the Microsoft allocator is 100% safe].  You can avoid this by using VirtualAlloc() and VirtualFree() for all pixel buffers rather than using malloc()."
  29.  
  30.  * The Delphi developer Takuo Nakamur comes to similar findings in the discussion thread titled "That (in)famous Scanline property".
  31.  
  32. "The buffer gotten by GetMem [standard Delphi allocator] cannot be used for GetDIBits and SetDIBits. ... If you uses GetMem in Windows 2000/XP, sometimes GetDIBits and SetDIBits fail.
  33. # GetMem may alocates Memory bolock across pluaral Memory spaces
  34. # allocated by virtualalloc and GetDIBits, SetDIBits, CreateDIBitmap
  35. # StretchDIBits always fail on that memory block.
  36.  
  37.  * My own experience has confirmed that this is indeed a problem on Windows 7 with an NVIDIA graphics card.
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top