Why doesn't leak detection give me line numbers? - c++

I recently converted a program using raw pointers to std::shared_ptrs and wanted to ensure there was no memory leak. I looked at MSDN's Finding Memory Leaks Using the CRT Library page and followed the instructions to set up the report.
I begin by adding these lines to my file:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
and call the report with - _CrtDumpMemoryLeaks();
I am indeed using new to allocate my memory so, as the page suggests, I added...
#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#define new DBG_NEW
#endif
#endif // _DEBUG
with no significant change in terms of a more precise location of the leak. Instead my report still looks like this:
Detected memory leaks!
Dumping objects ->
{158} normal block at 0x006F8458, 8 bytes long.
Data: < , > DC F6 2C 00 00 00 00 00
{155} normal block at 0x006FAD40, 40 bytes long.
Data: <L> > 4C 3E 17 01 03 00 00 00 01 00 00 00 CD CD CD CD
{154} normal block at 0x006FAB68, 16 bytes long.
Data: <d> > 64 3E 17 01 01 00 00 00 01 00 00 00 00 00 00 00
{149} normal block at 0x006FAC08, 40 bytes long.
Data: <L> > 4C 3E 17 01 03 00 00 00 01 00 00 00 CD CD CD CD
{148} normal block at 0x006FABB8, 16 bytes long.
Data: <d> > 64 3E 17 01 01 00 00 00 01 00 00 00 00 00 00 00
Object dump complete.
The program '[7152] List.exe' has exited with code 0 (0x0).
Unfortunately, the report is generated just prior to exit so it's not possible to see the leak in real time.
By looking at an answer to this question I noticed that I was not loading the pdb file due to the fact it's an empty project. So I followed the advice given here which did fix the pdb problem but failed to fix my issue.
The app was generated from an Empty Console Application, if that matters, and I'm running as an administrator.
Also I'm aware of external tools I could use but I often use computers that I don't have permission to add any to so getting VS to function properly is the ideal solution. Any help getting the report to show the line numbers of the leaks would be great.
Side Note:
I suppose a logical question to ask would be - If you're using managed pointers why do I still have memory leak? Well, I left a couple localized pointers that are only temp holders in sorts etc. that seemingly should not have caused an issue. So, I feel like I know where it is occurring but this is such a simple program I would like to know how this is accomplished so I can use it on larger ones. Thanks.

You need to make sure that the defines and the inclusion of stdlib are before any other includes in the application.
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#define new DBG_NEW
#endif
#endif // _DEBUG
Should be the very first thing in your application.

You have to verify that all classes that you declare inside your project include crtdbg.h and the macro _crtdbg_map_alloc and the report at the end.

I found that I had to put the
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
in every file that might be the potential source of the allocation. I made the assumption that I only needed to do it in the main program where the
_CrtDumpMemoryLeaks();
is called.

Related

Memory Leak (false positive) when an MFC applications uses a DLL

I develop a C++ Library (DLL). When I create a minimal MFC project (VS2017) that links with this DLL its okay. But as soon as any function of the library is used by the MFC application the debugger of the MFC project complains about memory leaks (many lines like the ones below):
Detected memory leaks!
Dumping objects ->
{2255} normal block at 0x000002A4B1F8C360, 48 bytes long.
Data: < > 10 BB F8 B1 A4 02 00 00 B0 BD F8 B1 A4 02 00 00
{2242} normal block at 0x000002A4B1F8BDB0, 48 bytes long.
Data: < > C0 C0 F8 B1 A4 02 00 00 F0 C2 F8 B1 A4 02 00 00
{2220} normal block at 0x000002A4B1F8C2F0, 48 bytes long.
Data: < > 80 C2 F8 B1 A4 02 00 00 10 C9 F8 B1 A4 02 00 00
These are false positives because it occurs also when only an empty test function of the library is called. Moreover this does not happen when the library is linked with a non-MFC project.
What can cause these warnings? Related information:
A VS2013 user said that he can avoid the warnings by changing the
character set of his MFC project. I have tested that in VS2017 but
get still warnings.
A VS2017 user said that the warnings are gone when he delay-loads
the DLL.
In the course of debugging I have compiled the DLL with CMake in order to use settings which are as standard as possible. But no change.

Why does the memory allocation number keep changing for the same memory leak in VS2015 MFC?

I'm trying to remove memory leaks in my app using VS2015 and MFC in VC++.
The answers to this similar question did not help: How to detect memory leak when memory allocation number isn't always same?
In Configuration Properties>C/C++>Code Generation,
I changed the option selected for Runtime Library from /MT to /MTd.
The app is not multi-threaded(afaik).
The memory allocation number changes between program runs, leading me to different places in the code.
The procedure I use worked well before:
I copy a memory allocation number from the previous memory leakage report, and start the app.
When it stops at the breakpoint, I go to the Watch Window, and paste it in the value column of _crtBreakAlloc.
(Eg _crtBreakAlloc 1171).
Then run the program on until it breaks, and use the Call Stack to locate the unfreed object.
// Example of the memory report
...
{1171} client block at 0x088157A0, subtype c0, 224 bytes long.
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\dumpcont.cpp(23) : atlTraceGeneral - a ProgressBar object at $088157A0, 224 bytes long
{223} normal block at 0x01E79600, 324 bytes long.
Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...
// Example of the next report
...
{1112} client block at 0x08B30480, subtype c0, 224 bytes long.
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\dumpcont.cpp(23) : atlTraceGeneral - a ProgressBar object at $08B30480, 224 bytes long
{223} normal block at 0x01F693D8, 324 bytes long.
Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...
Note the memory allocation number "1171" changes to "1112", also affecting all the numbers above it.
This happens even after starting the PC with only VS2015 opened, and doing nothing between adjacent runs of the program. I keep each run of the program exactly the same each time, doing the same things, in the same order.
E.g. load the same file, press the same buttons/keys etc.
To remap operator new, the code has-
//stdafx.h
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#else
#define DBG_NEW new
#endif
// CImage.h : main header file for the CImage application
#define _CRTDBG_MAP_ALLOC // Supports memory leakage detection.
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#endif
#endif
Any help will be very much appreciated. Thank you
There are many answers to this. Your shown code isn't specific enough to tell you more.
Do you spawn other threads in the init code? This will change the behaviour, because the sequence of execution isn't guaranteed.
When you terminate your program, you UI usually also saves it state (MFC-Next). This state is loaded again, when you start again. Different UI settings may cause it.
Different data. Even breaking a different command line or any other different input string into CString or std::string elements may cause a shift. Because depending on the input.
Even when creating windows, some message processing might differ from start to start of the program, depending on when timer and paint messages will take place.
I am sure that there are other reasons that I missed... this list may grow...
In your case it is a very early stage when I see the allocation number. And looking at the objects name that is reported in your question, I am sure it has to do with the UI.
So it may help, to clear all registry entries of your program, and make sure that the input data is really the same.
Even it should help, to break into your code in an earlier stage. (i.E. at allocation 1100). Step over and out and look what happens in your code. Watch the allocation count in the watch window. There are so many allocations, so I am sure that you find the code fast and easy with a few steps.

Memory leak when using anything involving wxFileName

I'm making use of wxWidgets in my program for directory management and compressing/uncompromising collections of files. As I've been building my file system, I've noticed that I get memory leaks every run. After a lot of testing, I realized that any time I use any functions related to wxFileName, I get a memory leak. I'm using wx widgets 3.0.1, and my standalone example is as follows.
#include <wx\filename.h>
int main()
{
wxFileName::Mkdir("Test");
return 0;
}
The result is the same if I make an instance of the wxFileName class.
How do I make wx widgets not create a memory leak? I want to be able to package large collections of files in one file, and read the data from them with various other libraries (via extracting the zip to a temporary folder and reading the data from there). I haven't been able to get any other library to zip/unzip entire folders, so I really need to be able to use wxWidgets without a memory leak.
I read in another thread that the visual studios debugger is falsely identifying the memory leaks, but I ran it through AQtime and it confirmed that there was indeed a memory leak.
The exact debug output involving the memory leak is as follows:
Detected memory leaks!
Dumping objects ->
{1087} normal block at 0x009B4BC0, 64 bytes long.
Data: <\+= d+= l+= t+= > 5C 2B 3D 00 64 2B 3D 00 6C 2B 3D 00 74 2B 3D 00
{1086} normal block at 0x009B4880, 772 bytes long.
Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
{1085} normal block at 0x009B4680, 28 bytes long.
Data: < H > 80 48 9B 00 C1 00 00 00 00 00 00 00 CD CD CD CD
Object dump complete.
After a bit of digging (it WOULD be the digging I did AFTER posting the question) I found that when you're using wxWidgets without creating a wxWidgets app object, you need to use the following two functions:
wxInitialize()
and
wxUninitialize()
So the fixed version of my code is as follows:
#include <wx/app.h>
#include <wx\filename.h>
int main()
{
wxInitialize();
wxFileName::Mkdir("Waka Waka");
wxUninitialize();
return 0;
}
I suggest if anyone is using wxWidgets purely for the file management to either call these functions in the constructor and destructor of whatever class handles files, or at the beginning and end of your program's main loop.

Setting endianness of VS debugger

I am using VS 2012 and programming in C++. I have a wide string
wchar_t *str = L"Hello world".
Technically I read the string from a file but I don't know if that makes a difference. When I look at str in the memory window it looks like this:
00 48 00 65 00 6c 00 6c 00 6f 00 2c 00 20 00 77 00 6f 00 72 00 6c 00 64 00 21 00
As you can see the string is stored in memory as big-endian.
When I hover my mouse over the string I get:
L"䠀攀氀氀漀Ⰰ 眀漀爀氀搀℀"
And after I reverse the endianness of str the memory looks like:
48 00 65 00 6c 00 6c 00 6f 00 2c 00 20 00 77 00 6f 00 72 00 6c 00 64 00 21 00 00
And the hover over looks like:
L"Hello, world!"
It seems that the debugger displays UTF-16 in little-endian by default. My program reads big-endian files so it is very tedious to keep reversing the endianness of all strings to debug them. Is there any way to change the endianness of the debugger's display?
Except for debug purposes I can do all my processing in big endian.
It's not only the debugger. The wchar_t function of Visual Studio are little endian as the host is. When you want to process the data you need to reverse the string endianess to little endian anyway.
It's worth to have this change even if you output the strings to a file with a different endianess. Strings are defined as a byte sequence, your endianess applied to a string looks strange anyhow.
Your best shot in getting this to work is to define your own type and create a debugger type visualizer for it (see Customizing the Visual Studio Debugger Display of Your Data, or here).
Or maybe you can quick-hack it by shifting the address by 1 byte in watch window.
You're working with a non-native string format that just happens to "feel" similar to the native format. So you are tempted to think there should be almost a way to do it. But to the debugger, it's just a foreign binary format. The debugger is not designed to handle foreign endianness just as it does not handle visualizing an OGG stream packet.
If you want to use available tools for manipulating native-endian Unicode strings, you'll need to convert to native-endian Unicode format.
As has been pointed out, VS uses the native endianness, which is
little endian on an Intel/AMD. The problem is that you're not
reading the strings correctly; you should imbue the
std::istream with a locale which reads UTF-16BE (since this is
apparently the encoding form you're trying to read).
std::istream (or rather the backing std::filebuf) will
automatically do the code translation on the fly when reading
and writing.
You can set the endianness of the Memory window using the context menu. Right-click in the Memory window and check "Big Endian".

Tracking memory leak

The situation:
I see around + 120kbytes increase when closing the class,
so when i close the clas few times memory increases - and i need to find out what is causing this.
Just looking for any good tip or trick of how to find out what is not freed/released with vstudio 2010 - any ideas?
Here's more clearly what i do ( very simplified )
class cSomeClass
{
cSomeClass();
~cSomeClass();
int Initialize();
void Deinitialize();
}
cSomeClass cCamera;
main()
{
Sleep(10000);
// Do Init / Deinit to find out if we are freeing the memory
while(1)
{
// Init camera
if(cCamera.Initialize()==0)
{
// Rest for a while
Sleep(1500);
cCamera.Deinitialize();
// Rest for a while
Sleep(1500);
}
}
}
I just did a small application to init / deinit the class object to see
in the 'task manager' if my memory for this application is returning to it's starting value - but it is not, it keeps incrementing every time i initialize the cSomeClass - so i believe i have something that is initialized but not freed in Deinitialize.
Update:
I don't think it is a simple memory growth, when application is launched it stabilizes itself after 10 seconds to let's say : 1MB of ram then when while(1) kicks in every Initialize i call i get +120kBytes in overall application memory ( checked in task manager ).
Update:
Thanks to Chad - got it sniffed with
_CrtDumpMemoryLeaks
Detected memory leaks!
Dumping objects ->
{76} normal block at 0x003F4BC8, 32 bytes long.
Data: <Logitech QuickCa> 4C 6F 67 69 74 65 63 68 20 51 75 69 63 6B 43 61
{75} normal block at 0x003F4B80, 8 bytes long.
Data: < K? > 20 4B 3F 00 00 00 00 00
{74} normal block at 0x003F4B20, 32 bytes long.
Data: < K? K? > 80 4B 3F 00 C8 4B 3F 00 CD CD CD CD CD CD CD CD
{70} normal block at 0x003F4A30, 8 bytes long.
Data: < )i > 0C 29 69 00 00 00 00 00
Object dump complete.
The most straight forward method is to use the Windows API functions for memory usage tracking, like _CrtDumpMemoryLeaks.
Using this in conjunction with _CrtMemCheckpoint can prove to be vital when tracking down stubborn leaks.
If you are using MFC, you can optionally define DEBUG_NEW, which adds additional tracking to the global new/delete operators, giving you file and line numbers for each allocation that leaks, this can be extremely helpful as well, but it doesn't work with some implementations of new (std::nothrow, for instance).
I'm not sure exactly what you mean by "closing the class", but if you're able to run your code in Linux valgrind is always a great option to track memory leaks. Purify also works well in Windows but it's $$.
Another approach is to try to stop the problem up front: Use smart pointers instead of raw pointers.
Finally make sure that you're actually seeing a leak and not just a memory growth up to a certain plateau.