Problem: How to use Deleaker in C++ Builder

Environment

– C++Builder 10.3.3

– Deleaker 2019.39.0.0

– Windows 10

In this post I’ll review Deleaker, a mature product for detecting memory leaks. It works with C++, C#, Delphi and .NET. If you’re interested in finding out about a very helpful tool for finding memory leaks, read on!

A memory leak occurs when a program dynamically, i.e. at run time, allocates memory but doesn’t release that memory when it is finished using it. If the program subsequently asks for more memory the operating system has less to offer because it thinks that the initially allocated memory is still in use. Repeated leaks can lead to drastic slow-downs in the program and eventually crashes. Continual memory leaks can be particularly damaging in programs that run for long times, such as background tasks on servers, or in code that runs on hardware with small amounts of memory, e.g., embedded devices.

Memory leaks are particularly pernicious in C++ because it has no garbage collection, i.e. automatic reclamation of memory. There are compensating techniques such as RAII, in which memory allocated in a class constructor is deallocated in the destructor. Smart pointers, such as unique_ptr , are another way to avoid memory leaks. Despite these efforts though leaks can creep in, both in our code and in libraries or frameworks that we may use to make our programs.

Detecting memory leaks is difficult for a number of reasons. First off, the effects of a leak are often subtle and not noticeable until many leaks have occurred. Secondly, the consequences of a leak may not always be reproducible. Whether or not a leak has an effect depends on how much memory has already been allocated, how many leaks have already taken place, how much memory the program is trying to allocate, etc. Finally, typical results of a leak – such as a decrease in program running speed, may instead be due to other causes outside of the program, for example other software running concurrently or the way the operating system schedules its jobs.

So how can we detect and find memory leaks? One good way is to use a leak detector – software that is merged with a target program and reports memory leaks that occur when the program runs. Leak detectors can make spotting memory that has not been deallocated much faster than simply running your program many times and watching for degradation or errors.

In this post I’ll review Deleaker, a mature product for detecting memory leaks. It works with C++, C#, Delphi and .NET. It can operate as stand-alone software or be incorporated into Microsoft Visual Studio or Embarcadero RAD Studio. You can download a demo or a free trial version here. In this article I’ll only run Deleaker on C++ code and use it via RAD Studio, not in its stand-alone form.

Preparation

First download a trial or full version of Deleaker from here . Shut down RAD Studio and double-click on the file you downloaded to install Deleaker. The installer will let you choose which version or versions of RAD Studio to install Deleaker in. Deleaker has on-line documentation including an introduction to memory leaks, a tutorial for using the software within Visual Studio and with Delphi, and additional reference material. Although Visual Studio is different than RAD Studio and Delphi is not the language this post deals with, it’s easy to apply the material in the tutorials to C++ Builder. Similarly, there’s a link to a short video tutorial entitled “Find Leaks in Delphi and C++ Builder” on this page but the use with C++ Builder is not actually demonstrated at all.

When you re-open C++ Builder you should see a new menu item (Deleaker) between Run and Component on the main menu. Clicking on Deleaker shows you its menu, namely:



By default, Enabled is checked. This incorporates Deleaker into your program. All you have to do is compile, link and run. After the program ends Deleaker pops up a window with its report on memory leakage. We’ll examine this window in detail below. If you don’t want Deleaker in your program simply un-check Enabled and run.

Program

In this review I’ll just try out Deleaker from a simple console-mode program. If you want to create the application, select File | New and choosing “Console Application – C++ Builder”. In the New Console Application dialog box set Target Framework to None. This creates a pure C++ program – no VCL or FireMonkey involved. By default, the program is made with the 32-bit CLANG compiler and is in the debug configuration. For clarity, I renamed the source file to test.cpp .

#pragma hdrstop #pragma argsused #ifdef _WIN32 #include <tchar.h> #else typedef char _TCHAR; #define _tmain main #endif #include <stdio.h> int _tmain(int argc, _TCHAR* argv[]) { return 0; }

I’ll insert the test code above the return 0 line. Until the end of this article when I add a line to bring in the FireMonkey framework the above code won’t change so I won’t show it anymore.

Let’s start the tests with some simple dynamic allocations using new .

// TEST 1 - deleted element double* p1 = new double; delete p1; // TEST 2 - undeleted element double* p2 = new double; // TEST 3 - replace undeleted element double* p3 = new double; p3 = new double; delete p3;

Test 1 verifies that Deleaker does not report correct code as an error. The test simply allocates a double and then deallocates it. The code is the essence of what correct dynamic allocation should look like. Test 2 again allocates memory but does not deallocate it. Deleaker should report this memory leak.

Test 3 simulates a programmer allocating memory to a pointer but then forgetting to deallocate the memory before re-using the pointer with new memory. The test allocates memory and points p3 to it. The code then allocates more memory but still using p3 and finally deletes the last allocated memory. This is a memory leak because the code never deallocates the initial memory. Deleaker should find this problem.

When the program finished running Deleaker displays this window:

Figure 1 – Deleaker results for Tests 1-3

My first impression is that the display is awfully cluttered. It is – but after thinking about it I decided that that’s not a big issue. The program user will never see this window – only the programmer will and she is probably willing to sacrifice readability for convenient access to Deleaker’s results and functionality.

The first two rows of the display tell you about Deleaker itself, e.g., what version, license information and how to get help. The third row lets you set Deleaker’s many options and, under the Allocation Types drop-down box, shows what software components Deleaker is monitoring for memory leaks. Un-checking the Enable Deleaker box lets you disable Deleaker on the next run of your program. As mentioned previously you can do the same thing via the Deleaker item in the main menu.

The fourth row lets you take a snapshot, i.e., save the results of a Deleaker run, and compare it to other snapshots. This is a good way to see what effects changes you’ve made to your code have had on memory leaks. As a quick test, I took two snapshots of the same run so that each snapshot had the same errors. Next I looked at the differences in the two runs by pressing the Compare With button. Deleaker reported that there were “No leaks found”. This is incorrect because each run had a leak. To avoid being misleading Deleaker should really say “No differences found”. I made this recommendation to the vendor.

The fifth row controls what information is displayed in the remainder of the window. The default is Allocations, which shows the memory leaks and detailed information about them. Fig. 1 is the Deleaker result for the run with tests 1-3. It shows that there were memory leaks on line 24 (Test 2) and line 27 (Test 3) and no others in the source file test.cpp . Great! Deleaker found the two memory leaks and didn’t report any false leaks. And by the way, double-clicking on a row that specifies a source-file line that contains an error highlights that line in RAD Studio. That’s a nice touch!

One thing to notice is that Deleaker reports leaks in three lines of System.pas . This is disconcerting because test.cpp is a pure C++ program. It doesn’t explicitly use VCL, FireMonkey or the RTL (Delphi run-time library) so how are Delphi files getting involved? It would be helpful if the Deleaker C++ Builder documentation provided an explanation.

Allocating memory for a single int or double is sort of silly. What’s reasonable and common is to allocate arrays of these data types. The next code snippet adds three more tests. Tests 4-6 are the equivalents of Tests 1-3 but for arrays instead of single elements.

// TEST 4 - deleted array int* p4 = new int[10]; delete [] p4; // TEST 5 - undeleted array int* p5 = new int[10]; // TEST 6 - replace undeleted array int* p6 = new int[10]; p6 = new int[10]; delete [] p6;

Again, Deleaker performs well. It finds the leaks in Test 5 and Test 6 but doesn’t falsely report a leak for Test 4.

For my last series of tests I’ll examine how well Deleaker handles memory-allocation problems with components in an framework, namely FireMonkey. To bring in FireMonkey I insert the line



#include <fmx.h>



at the top of the source code. Then I add four tests:

// TEST 7 - deleted FireMonkey component TEdit* p7 = new TEdit( nullptr ); // deleted delete p7; // TEST 8 - undeleted FireMonkey component TEdit* p8 = new TEdit( nullptr ); // undeleted // TEST 9 - implicitly deleted FireMonkey component TEdit* p9a = new TEdit( nullptr ); // deleted TButton* p9b = new TButton( p9a ); // implicitly deleted delete p9a; // TEST 10 - implicitly deleted FireMonkey component TEdit* p10a = new TEdit( nullptr ); // undeleted TButton* p10b = new TButton( p10a ); // implicitly undeleted

Test 7 dynamically creates a TEdit component and then deletes it. Test 8 does the same but doesn’t delete the component. Test 9 creates a TEdit and then a TButton whose parent is that TEdit . Because of the way FireMonkey works, when the code deletes the TEdit that component deletes the TButton , so Test 9 should not show any memory leaks. In Test 10 however, the code does not delete the TEdit . This means that its memory is not deallocated and neither is the memory for the TButton that has it as its parent. In other words, Test 10 has two memory leaks.

So how does Deleaker do? It passes with flying colors. It reports no problems with Test 7 and Test 9, one memory leak in Test 8 and two in Test 10. Well done!

In case you’d like to run the test program yourself, here’s the complete code:

#include <fmx.h> #pragma hdrstop #pragma argsused #ifdef _WIN32 #include <tchar.h> #else typedef char _TCHAR; #define _tmain main #endif #include <stdio.h> int _tmain(int argc, _TCHAR* argv[]) { // add code here // TEST 1 - deleted element double* p1 = new double; delete p1; // TEST 2 - undeleted element double* p2 = new double; // TEST 3 - replace undeleted element double* p3 = new double; p3 = new double; delete p3; // TEST 4 - deleted array int* p4 = new int[10]; delete [] p4; // TEST 5 - undeleted array int* p5 = new int[10]; // TEST 6 - replace undeleted array int* p6 = new int[10]; p6 = new int[10]; delete [] p6; // TEST 7 - deleted FireMonkey component TEdit* p7 = new TEdit( nullptr ); // deleted delete p7; // TEST 8 - undeleted FireMonkey component TEdit* p8 = new TEdit( nullptr ); // undeleted // TEST 9 - implicitly deleted FireMonkey component TEdit* p9a = new TEdit( nullptr ); // deleted TButton* p9b = new TButton( p9a ); // implicitly deleted delete p9a; // TEST 10 - implicitly deleted FireMonkey component TEdit* p10a = new TEdit( nullptr ); // undeleted TButton* p10b = new TButton( p10a ); // implicitly undeleted return 0; }

Summary

Deleaker is a memory-leak detector that you incorporate into your C++ Builder programs. It finds memory leaks in your own code as well as in frameworks and operating-system calls that you may be using.

Pros:

Finds the leaks without making false readings

Extremely easy to incorporate into and remove from your code

Easy to install

Cons (all minor):

Could use some more documentation about its use in C++ Builder

Documentation should discuss Delphi leaks detected in C++ programs

Interface could be made less cluttered

Download a demo or a free trial version of Deleaker here.