Appendix B
Common questions and troubleshooting

This appendix includes a guide to troubleshooting common memory problems. Please read this information carefully — it addresses many common problems that other SmartHeap users have called our technical support staff about.

B.1 Compiler/linker issues

Borland C++ compiler

Microsoft C/C++ compiler

#undef new

on the line just before the call to IMPLEMENT_XXX, and then:

#define new DEBUG_NEW

on the line following this MFC macro. See §3.2.4, “Debug SmartHeap and C++ operator new,” for an example and explanation of this technique.

Watcom C/C++ compiler

Other compilers

B.2 Compatibility with third-party products

Inmark zApp

The Inmark zApp Class Library defines operator new such that it returns zero-initialized memory. Since SmartHeap, like ANSI, does not zero-initialize memory in operator new by default, some integration is required for SmartHeap to support zApp.

To produce a version of operator new that works with zApp, you must compile the file shnew.cpp in the SmartHeap source directory, supplying the define ZAPP on the compiler command line. For example, the following command line compiles Runtime and Debug versions, respectively, of the SmartHeap C++ module with Microsoft Visual C++:

cl /c /AL /Gs2 /GA /DZAPP=1 shnew.cpp
cl /c /AL /Gs2 /GA /DZAPP=1 /DMEM_DEBUG=1 shnew.cpp

Then either link the resulting object file into your application, or replace the module shnew in the SmartHeap library with the zApp-compatible replacement.

B.3 Memory bugs

Programmer errors that cause memory-related bugs are a common problem. The symptoms of such bugs include memory protection violations (also known as access violations, bus errors, segmentation violations, GP faults, or UAEs), hangs, or any other weird behavior. The following questions will help you pin-point the cause of such problems:

Have you recompiled SmartHeap? If so, is the problem reproducible with the distributed binary version of SmartHeap?

If the problem occurs only in the version of SmartHeap you recompiled, look for compiler compatibility or product build problems. Did you use a supported compiler and compiler version?

Are you using the Debug version of SmartHeap?

If not, relink with Debug SmartHeap and try to reproduce the problem. Debug SmartHeap will automatically detect many kinds of memory bugs.

Is the Debug SmartHeap safety level set to MEM_SAFETY_DEBUG?

If not, try to reproduce the problem with MEM_SAFETY_DEBUG in effect — if the bug is an overwrite, it may not be caught with a safety level lower than MEM_SAFETY_DEBUG.

Have you tried placing calls to MemPoolCheck before the point of failure?

MemPoolCheck finds memory overwrites that are not detected automatically. This is a very common type of programmer error that can usually be detected only by validating the pool with MemPoolCheck. If you are allocating memory with malloc or new, you should supply MemDefaultPool as the pool parameter to MemPoolCheck. It is important to test the return value of MemPoolCheck; some types of corruption don’t produce an error-handling callback, but all errors cause MemPoolCheck to return FALSE.

Are you are doing everything stated above and still haven’t seen a SmartHeap error report?

If so, the bug could be an overwrite into memory that is in use elsewhere or a write to a wild pointer. Try using dbgMemSetGuardSize to increase the size of the overwrite guards around blocks. Also try dbgMemDeferFreeing so all writes to free blocks are detected.

Is a memory protection violation (or “GPF”) occurring in the Debug version of SmartHeap but not in the Runtime version of SmartHeap?

One possible cause is dereferencing a pointer read from a previously freed memory block. Data freed in Runtime SmartHeap may still be present in memory, but Debug SmartHeap fills all bytes of freed blocks with the pattern established by dbgMemSetFreeFill (default value 0xDD).

A similar error can occur if you dereference a pointer read from uninitialized memory, or from outside the bounds of an allocation. Debug SmartHeap fills these types of memory with the value established by dbgMemSetInUseFill (default 0xEB) and dbgMemSetGuardFill (default 0xFC), respectively.

If MemPoolCheck detects a memory overwrite, a message box will show you the address of the overwritten block. If you compile all of your modules with MEM_DEBUG, it also reports the file, line, and pass count at the last point when the overwrite was known not to have occurred yet. You can move the call to MemPoolCheck successively closer to the reported file/line/pass count to isolate the cause of the overwrite.

Is a crash occurring in the error handler that you established with MemSetErrorHandler?

The most likely causes are (1) that your error-handling callback function does not have the correct calling convention (far pascal for 16-bit x86 platforms) or (2) for 16-bit x86 platforms, that the function is not declared with _loadds (DOS) or _export (Windows).

SmartHeap provides a macro, MEM_CALLBACK that defines the calling convention and sets DS up correctly for each platform. You should define your error handler as follows:

MEM_BOOL MEM_CALLBACK MyErrorFn(MEM_ERROR_FN);

Are you getting a memory protection violation (“GPF”) in the 16 bit Windows version of SmartHeap?

If so, try to reproduce the problem while running Dr. Watson or a similar post-mortem debugger. If you call MicroQuill technical support about such a problem, please fax or e-mail us a copy of the Dr. Watson report.

Please add the following settings to your WIN.INI file prior to running Dr. Watson when reproducing your problem:

[Dr. Watson]
showinfo=disassembly errorlog paramlog locals
dislen=32
disstack=10
gpcontinue=0

If possible, also produce a .SYM file for your EXEs and DLLs so Dr. Watson will have symbolic information. .SYM files for the SmartHeap DLLs are included in all SmartHeap releases for exactly this purpose. Produce a .SYM file with Microsoft C/C++ by running MAPSYM. For Borland C++ 3.1, use BUILDSYM.

Is the memory allocated from a task (executing instance) or from a DLL?

If the memory is allocated from a DLL, see section B.4 below.

Is SmartHeap reporting a “MEM_BAD_POINTER” error?

If so, this could mean:

Is SmartHeap reporting a “MEM_BAD_MEM_POOL” error?

If so, this could mean:

B.4 DLLs (16-bit Windows only)

This section is specific to the 16-bit Windows version of SmartHeap.

Allocating memory from DLLs is a common source of memory problems because of a misunderstanding of DLL vs. task memory ownership and problems with DLL initialization or termination.

Memory allocated from a DLL is normally owned by the task current at the time of the allocation; this memory is implicitly freed when that task terminates. Memory allocated from a shared memory pool, on the other hand, remains accessible until it’s explicitly freed or until the Windows module (that is, every instance of an EXE, or a DLL) from which it was allocated terminates.

Here are some guidelines for allocating memory from DLLs:

For more information about using SmartHeap with DLLs, see the “Getting started” guide for your compiler.

B.5 C++

If SmartHeap does not seem to be overriding global operator new, make sure that the SmartHeap library appears before the C++ compiler runtime library. If the linker still resolves to the compiler’s operator new, you can force it to link in SmartHeap new by placing a reference to SmartHeap_new inside one of your functions — see the example in §2.3.4, “C++ memory API.”

B.6 ANSI C (malloc, etc.)

B.7 Macintosh-specific problems

If your Mac application is hanging or crashing when you think SmartHeap should be reporting an error, the problem may be that you haven’t initialized the Dialog Manager. The SmartHeap default error handler uses Alerts to report errors. If the Dialog Manager and related ToolBox facilities are not initialized, a crash will occur deep inside the Alert routine that SmartHeap calls.

For an example of the specific initialization calls SmartHeap requires, see the file shtestd.c in the samples::debug folder of the SmartHeap release.


SmartHeap Programmer’s Guide