Heap corruptions when compiling 32Bit project under XP64


#1

I’ve just updated to Windows XP64, and I’ve noticed that compiling my old project that uses JUCE146 with VS2003 leads to Heap Corruptions upon execution. It seems like the fact that the OS is 64Bit somehow breaks something in the compiler’s process. The problem really happens during the build, because when I compile the app on a 32Bit XP system and then let it run on XP64, then everything’s fine. Does anyone know what possible reasons can lead to such problems? I really don’t know where to start looking at.

[EDIT: The problem was actually the fact that the system had a multiprocessor, which made the multithreading-related bug in my app happen more often, not the XP64/VS2003 combo as previously stated.]


#2

Run the Debug version of your application, and turn on MSVC debug heap checking. Make sure you are linking with the Debug runtimes.

Here is some magic code that you should add in your app initialization:

      #include <crtdbg.h>
      int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);

      // check leaks at exit
      flag |= _CRTDBG_LEAK_CHECK_DF;

      // check heap at every heap call
      flag|= _CRTDBG_CHECK_ALWAYS_DF;		// on
      //flag&=~_CRTDBG_CHECK_ALWAYS_DF;		// off

      flag = _CrtSetDbgFlag( flag );

Shortly after your heap gets corrupted, you should get a breakpoint, and this will help you narrow down the place.
Now Juce has some conflicts with the MSVC debug heap interfaces (crtdbg.h) due to macros, so you will need to wrap the place where you include juce.h include like this:

#ifdef _CRTDBG_MAP_ALLOC
# pragma push_macro("calloc")
# pragma push_macro("malloc")
# pragma push_macro("realloc")
# pragma push_macro("free")
# undef calloc
# undef malloc
# undef realloc
# undef free
#endif
//#include "src/juce_WithoutMacros.h"
#include "src/juce.h"
#ifdef _CRTDBG_MAP_ALLOC
# pragma pop_macro("calloc")
# pragma pop_macro("malloc")
# pragma pop_macro("realloc")
# pragma pop_macro("free")
#endif

#3

Thanks, but all these lines did was slow down the program by a factor of 100 or so, but I couldn’t figure out much.

I found an app called BoundsChecker and using that one I seem to have found one place in the JUCE code of JUCE146 that shows a problem:

[code] KERNINGPAIR* getKerningPairs (int& numKPs_) throw()
{
if (kps == 0)
{
numKPs = GetKerningPairs (dc, 0, 0);
kps = (KERNINGPAIR*) juce_calloc (sizeof (KERNINGPAIR) * numKPs); // <------ overrun detected in this block
GetKerningPairs (dc, numKPs, kps);
}

    numKPs_ = numKPs;
    return kps;
}[/code]

It seems like this block gets overrun. But I don’t know where and how to find out.


#4

Adding a check if numKPs == 0 fixed the problem.


#5

Ah, that bit of code’s really old - I haven’t used a malloc for a long long time now. Best to stick to the latest version if you’re doing 64-bit stuff.


#6

Jules, I found 2 other recurring “problems” in JUCE (in the tip) using BoundsChecker. I don’t know if they are important (if they can lead to other problems). But I’m just reporting them.

Problem 1 (in FontDCHolder::loadFont()) :

if (dc != 0)
{
DeleteDC (dc); // <----------- Argument 1 in DeleteDC (HDC__ hdc = 0xE1010FEE) still contains non default/stock objects. Font (0x7E0A1034).
DeleteObject (fontH);
kps.free();
}

DeleteDC Contains Selected Objects

Description
It is improper to DeleteDC a DeviceContext that still contains non-default objects.

Sample Code

void CMainFrame::OnCreateBrush() {
CBrush brush;
Brush.CreateSolidBrush(RGB(0xff,0x00,0xff));
if (true) {
CClientDC dc(this);
CBrush* pOldBrush = dc.SelectObject(&brush);
}
}

Repair
To repair the sample above, add this line before the closing brackets:

dc.SelectObject(pOldBrush);

The repaired code looks like this:

void CMainFrame::OnCreateBrush() {
CBrush brush;
Brush.CreateSolidBrush(RGB(0xff,0x00,0xff));
if (true) {
CClientDC dc(this);
CBrush* pOldBrush = dc.SelectObject(&brush);
dc.SelectObject(pOldBrush);
}
}

Note: The destructor of CDC will DeleteDC the DeviceContext at the end of scope for the if statement.

Problem 2 (in WindowsBitmapImage::~WindowsBitmapImage)

~WindowsBitmapImage()
{
DeleteDC (hdc); // <------------ Argument 1 in DeleteDC (HDC__ hdc = 0x07011387) still contains non default/stock objects. Bitmap (0xB1051267).
DeleteObject (hBitmap);
}


#7

Thanks! I don’t think those actually matter - it’s been running happily like that for years without any problems or leaks, but I’ll take a look and see if I can avoid the warnings!