OOFILE | Downloads | Purchasing | Press | Services | Company Information | Soapbox | References | F.A.Q. | HOME

Debugging Tools

Debug Log

OOFILE 1.3b2d15 added the ability to define a log file name and have most database actions logged. This is extremely useful when tracking down bugs with changes of state, particularly things like the database being unexpectedly in a different sort order.

Warning: the logs can grow very quickly. In particular a GUI application will generate a lot of entries as the rows are displayed in database browsers. Logs of several hundred kb are common.

Debug logging will also slow you down, but not as much as a memory debugger like SmartHeap® or Spotlight®.

Debug logging may help you identify unnecessary database operations, as well as outright bugs.

Enabling debug logging

Add a
#define OOF_DEBUG_LOG_NAME "oof.debuglog"
as a global define for your project. It may be worth keeping a separate build with logging, to avoid recompiling all files.

"oof.debuglog" is just a name chosen for this example. You can choose any name you like that's a legal file name. The test of logging being enabled is #ifdef OOF_DEBUG_LOG_NAME.

Writing your own entries to the log

OOF_DEBUG_LOG is always defined and calls dbConnect::logComment which takes either a const char* or ostream& param.

Therefore you can embed calls like
OOF_DEBUG_LOG("Entering XXX about to save");
throughout your code and they will compile out if you don't define OOF_DEBUG_LOG_NAME.

Debugging tactics with the log

The log is opened and closed with each entry, to guarantee file writing. This is also useful if you want to get a small log for a given area of code, whilst running the debugger.

Sample log entries

dbBrowseHelper::selectRecNo	0	on table	1124010
 
dbBrowseHelper::selectRecNo	0	on table	1124238
 
dbTable::cloneWithoutSelection()
table: Q	111dcb0	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: allRecs
 
 
dbTable::setTableValid(true)
table: Q	11c20d8	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: empty
 
 
dbTable::start()
table: P	110a2e8	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: allRecs
 
 
dbTable::ContextChange() - requireExplicit
table: P	110a2e8	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: allRecs
 
 
dbSorter::sortNow	10fdbb0	sorting: P (110a2e8)
 
dbTable::cloneWithoutSelection()
table: P	110a2e8	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: allRecs
 
 
dbTable::setTableValid(true)
table: P	11c9348	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: empty
 
 
selectJustRecordPointer(313018)table: P	11c9348	(valid)	Connection: 10fca80
RecState: eUnloaded	Offset: 0	Clean	Iter: 0	State: empty
           

Debugging that Catches Errors

Note for CodeWarrior users: Ensure your project is built with the standard output libraries linked in, NOT console.stubs.c

That way if OOFILE error handling kicks in, you get a print in a console window.

For anyone else, the following techniques assume that at some point a print to standard console output can occur and be seen. You need to make sure that your application will allow this.


SmartHeap or other Memory Debuggers

If you use MicroQuill's SmartHeap product, or want to use the Visual C++ debug runtime library or CodeWarrior's DebugNew then defining OOF_MEM_DEBUG_LAST_INCLUDE will include a specified memory debugger and perform pool validation at selected points to aid in detecting bugs such as memory overwrites. This runs a LOT slower but provides a high degree of assurance.

eg:

#define OOF_MEM_DEBUG_LAST_INCLUDE "oofDebugNew.h"

for your entire project, to have that debug setup file included.

As of OOFILE 1.4, the debug files are:

oofDebugNew.h - standard CodeWarrior DebugNew
oofDebugVC.h - Visual C++ Debug runtime library
oofSmartheap.h - SmartHeap from MicroQuill (formerly cross-platform, no longer available on Mac) is not just a memory debugger but superb runtime allocator as well for faster, more-robust release builds.

You can also easily define your own file if you have a a heap checker that can be forced to check the heap at regular intervals.



OVERVIEW of OOF_DEBUG

OOF_DEBUG is a #define flag, that will turn on debugging modes within OOFILE. These are in the nature of development-time checks and so you may not want them left in released applications! However, the errors they trigger will be handled by the standard error handler (dbConnect::raise), so you could theoretically cope with them yourself. Most of the OOF_DEBUG errors are programmer errors, and it should not be relied on as (say) a range-checking recovery mechanism.


OVERRUNS ON OOF_DICTIONARY

If you write to an unallocated cell that is more than one past the previous high point (ie: not just an append) then OOF_DictRep::operator[](long) will report the error. This catches problems such as incorrect copying of objects (mainly our mistakes) or scrambling memory so that the index being used on the dictionary is a ridiculous value.


RANGE ERRORS ON NUMERIC FIELDS

Conversion from a double to a long, or short and conversion from a long to a short are range-checked when the fields are assigned a value.


INAPPROPRIATE ACTIONS LOCKED

Attempting to add a record while read-locked will raise an error.

Attempts to set a read lock whilst write-locked and vice versa will raise an error, as will failing to match the number of ApplyLock calls to ReleaseLock's.


 

Feature index

(c) Copyright A.D. Software 1994-2004 (All Rights Reserved).
Last Updated: 7th May 2004