FreeBasic, as you might already know, includes a C-like memory management system, which includes full-fledged pointers, as well as routines to allocate blocks of memory dynamically at runtime. While this leads to great flexibility for the programmer, it also creates the possibility to "shoot yourself in the foot", a la Stroustrup. If you choose to use pointers and dynamic memory allocation, FreeBasic will not protect you from yourself. Using pointers, you can easily access memory that you have not allocated for your use; the compiler cannot check for out-of-bounds accesses because it cannot know the limits of a particular pointer. However, you can allocate a block of memory and forget to deallocate it, or you can try to free the same block of memory twice; this sort of problem is more easily detected. In fact, this article describes the use and implementation of just this sort of tool - a memory leak detector for FreeBasic.
The FreeBasic Memory Leak Detector (FBMLD) is very simple to use; just include the header
fbmld.bi in each source file of your program:
Then use FreeBasic's built-in memory management routines#include "fbmld.bi"
Deallocateas you would normally. When you run your program, FBMLD will print out diagnostic messages starting with
(FBMLD)to inform you of memory management errors in your code.
As an example, here is a (fabricated) example program with some memory management problems:
Option Explicit #include "fbmld.bi" Dim George As Any Ptr, John As Any Ptr, Paul As Any Ptr, Ringo As Any Ptr Print "FreeBasic Memory Leak Detector test" George = CAllocate(123) John = Allocate(456) George = ReAllocate(George, 789) Deallocate(John) Paul = Reallocate(0, 5309) Deallocate(George) Deallocate(George) ' Note that this is a "double free" - we are ' attempting to deallocate George, which has ' already been deallocated. ' ' This will be caught and reported immediately. Ringo = Allocate(867) ' We have not deallocated Paul or Ringo, so ' they will be reported as allocated but ' not deallocated. Print "fbmld test - End"
When the second
Deallocate(George) is executed, FBMLD will print:
George has been deallocated already, so trying to execute it again is not acceptable. In this case, the problem is simple to solve - just remove the second(FBMLD) test.bas(20): Deallocate on unallocated memory (&H322630)
Deallocate(George)line. Some other cases might require more thought, such as when a particular block of memory could be deallocated in more than one place in the code.
When the program ends, two errors relating to memory that has been allocated but not deallocated will be printed:
These bugs can be fixed by adding(FBMLD) test.bas(28): 867 bytes allocated here was not deallocated (&H3265F8) (FBMLD) test.bas(17): 5309 bytes allocated here was not deallocated (&H323FE0)
Deallocate(Ringo)to the end of the program.
Note that the messages will not necessarily contain the exact same memory addresses as given here; the address is printed as a debugging aid only and should not be assumed to be constant.
FBMLD is written in FreeBasic and contained in a single header file,
requiring no extra libraries or external resources beyond the standard
C library, which is always linked (FreeBasic's runtime library depends
The standard memory management functions are removed from the namespace
Option NoKeyword statement.
Then these keywords were redefined with
#define to call replacement functions, using the predefined
__LINE__ preprocessor defines to track where each function was called.
These replacement functions use the standard C library functions
Each function is declared
Private to allow the use of FBMLD in projects with multiple source code files.
A global list is maintained of all allocated memory blocks, and when any memory-management function is called, the list is manipulated accordingly. If allocated memory is freed correctly, it is removed from the list. If any elements remain in the list at the end of the program, they are reported as being allocated but not deallocated.
For thread safety, the built-in mutex routines are used. If you do
not wish your program to be linked to the multithreaded library, just
FBMLD_NO_MULTITHREADING before including the header:
#define FBMLD_NO_MULTITHREADING #include "fbmld.bi"
Normally, FBMLD will print all of its messages with the standard
Just keep in mind that the report at program termination might happen
after the FreeBasic runtime's termination code has already been
executed (file handles closed and so forth).
FBMLD was written by Daniel Verkamp. You can contact him at email@example.com. You can download the fbmld.bi header here.