mtrace is a nice GNU extension which is used to diagnose dynamic memory allocation in C/C++ programs. It can also be used for finding memory leaks. I am going to demonstrate a memory leak problem in a simple C++ program. Look at the following code:
// File: m-test.cpp
#include <iostream>
#include <cstdlib>
#define SIZE 16
using namespace std;
bool isPalindrome(char *);
int main()
{
char *str;
while(true)
{
str = (char *)malloc(SIZE);
cout << "Enter string to check Palindrome or quit to exit: ";
cin >> str;
if(strcmp(str, "quit") == 0)
break;
if(isPalindrome(str))
cout << str << " is a Palindrome." << endl;
else
cout << str << " is NOT a Palindrome." << endl;
}
return 0;
}
bool isPalindrome(char *str)
{
int str_len = strlen(str);
for(int i = 0; i < str_len/2; i++)
if(str[i] != str[str_len-i-1])
return false;
return true;
}
It is a simple C++ program which checks whether the input string is a palindrome or not. I compiled and ran using following commands and it exeucutes perfectly:
munir@ubuntu:~/prog/c$ g++ m-test.cpp -Wall -g -o m-test
munir@ubuntu:~/prog/c$ ./m-test
Enter string to check Palindrome or quit to exit: ababa
ababa is a Palindrome.
Enter string to check Palindrome or quit to exit: abb
abb is NOT a Palindrome.
Enter string to check Palindrome or quit to exit: quit
munir@ubuntu:~/prog/c$
But did you find any thing wrong by reading code?
There is something wrong with dynamic memory allocation by using malloc(). Note that malloc(SIZE) is called every time when the program takes input from command promt. Lets trace the memory allocation using mtrace by following easy steps:
1) Include mcheck.h header file.
2) Place mtrace() in the first line of main(). mtrace will start tracing memory from this point.
3) Place muntrace() in the end of main() to stop tracing.
4) At command promt type export MALLOC_TRACE=mtrace.log to save output in mtrace.log file.
5) Compile and run the program again.
It should execute exactly like before but this time it will create a new file mtrace.log. Now come to the fun part. Open the text from mtrace.log:
munir@ubuntu:~/prog/c$ ./m-test2
Enter string to check Palindrome or quit to exit: aba
aba is a Palindrome.
Enter string to check Palindrome or quit to exit: a
a is a Palindrome.
Enter string to check Palindrome or quit to exit: aa
aa is a Palindrome.
Enter string to check Palindrome or quit to exit: abb
abb is NOT a Palindrome.
Enter string to check Palindrome or quit to exit: anm
anm is NOT a Palindrome.
Enter string to check Palindrome or quit to exit: quit
munir@ubuntu:~/prog/c$ cat mtrace.log
= Start
@ ./m-test2:(__gxx_personality_v0+0x161)[0x80488e5] + 0x804a378 0x10
@ ./m-test2:(__gxx_personality_v0+0x161)[0x80488e5] + 0x804a390 0x10
@ ./m-test2:(__gxx_personality_v0+0x161)[0x80488e5] + 0x804a3a8 0x10
@ ./m-test2:(__gxx_personality_v0+0x161)[0x80488e5] + 0x804a3c0 0x10
@ ./m-test2:(__gxx_personality_v0+0x161)[0x80488e5] + 0x804a3d8 0x10
@ ./m-test2:(__gxx_personality_v0+0x161)[0x80488e5] + 0x804a3f0 0x10
= End
munir@ubuntu:~/prog/c$
This is not in very readable form but what I understood from this result is that my program was allocated 0x10 bytes(16 bytes in decimal) of memory 6 times because malloc() was called 6 times.
Since the content of the log file is not very clear to understand therefore I am going to use a useful Perl script to interpret the results. This script is also called mtrace and its syntax is very simple to use: mtrace program log-file
munir@ubuntu:~/prog/c$ mtrace m-test2 mtrace.log
Memory not freed:
-----------------
Address Size Caller
0x0804a378 0x10 at /home/munir/prog/c/m-test2.cpp:17
0x0804a390 0x10 at /home/munir/prog/c/m-test2.cpp:17
0x0804a3a8 0x10 at /home/munir/prog/c/m-test2.cpp:17
0x0804a3c0 0x10 at /home/munir/prog/c/m-test2.cpp:17
0x0804a3d8 0x10 at /home/munir/prog/c/m-test2.cpp:17
0x0804a3f0 0x10 at /home/munir/prog/c/m-test2.cpp:17
munir@ubuntu:~/prog/c$
This indicates that there is a potential memory leak in program at line 17 which is caused by dynamic memory allocation by calling malloc() and the program does not free the allocated memory. free() must be used in order to solve the problem. Here is the final version with no such memory leak:
// File: m-test3.cpp
#include <iostream>
#include <cstdlib>
#define SIZE 16
using namespace std;
bool isPalindrome(char *);
int main()
{
char *str;
while(true)
{
str = (char *)malloc(SIZE);
cout << "Enter string to check Palindrome or quit to exit: ";
cin >> str;
if(strcmp(str, "quit") == 0)
{
free(str);
break;
}
if(isPalindrome(str))
cout << str << " is a Palindrome." << endl;
else
cout << str << " is NOT a Palindrome." << endl;
free(str);
}
return 0;
}
bool isPalindrome(char *str)
{
int str_len = strlen(str);
for(int i = 0; i < str_len/2; i++)
if(str[i] != str[str_len-i-1])
return false;
return true;
}
And running the test again:
munir@ubuntu:~/prog/c$ g++ m-test3.cpp -Wall -g -o m-test3
munir@ubuntu:~/prog/c$ ./m-test3
Enter string to check Palindrome or quit to exit: a
a is a Palindrome.
Enter string to check Palindrome or quit to exit: aaa
aaa is a Palindrome.
Enter string to check Palindrome or quit to exit: abc
abc is NOT a Palindrome.
Enter string to check Palindrome or quit to exit: aBbabBa
aBbabBa is a Palindrome.
Enter string to check Palindrome or quit to exit: aBbabBA
aBbabBA is NOT a Palindrome.
Enter string to check Palindrome or quit to exit: quit
munir@ubuntu:~/prog/c$ cat mtrace.log
= Start
@ ./m-test3:(__gxx_personality_v0+0x171)[0x8048915] + 0x804a378 0x10
@ ./m-test3:(__gxx_personality_v0+0x244)[0x80489e8] - 0x804a378
@ ./m-test3:(__gxx_personality_v0+0x171)[0x8048915] + 0x804a378 0x10
@ ./m-test3:(__gxx_personality_v0+0x244)[0x80489e8] - 0x804a378
@ ./m-test3:(__gxx_personality_v0+0x171)[0x8048915] + 0x804a378 0x10
@ ./m-test3:(__gxx_personality_v0+0x244)[0x80489e8] - 0x804a378
@ ./m-test3:(__gxx_personality_v0+0x171)[0x8048915] + 0x804a378 0x10
@ ./m-test3:(__gxx_personality_v0+0x244)[0x80489e8] - 0x804a378
@ ./m-test3:(__gxx_personality_v0+0x171)[0x8048915] + 0x804a378 0x10
@ ./m-test3:(__gxx_personality_v0+0x244)[0x80489e8] - 0x804a378
@ ./m-test3:(__gxx_personality_v0+0x171)[0x8048915] + 0x804a378 0x10
@ ./m-test3:(__gxx_personality_v0+0x1bd)[0x8048961] - 0x804a378
= End
munir@ubuntu:~/prog/c$ mtrace m-test3 mtrace.log
No memory leaks.
munir@ubuntu:~/prog/c$
So we just saw how easy is to detect memory leak using mtrace utility.
Source codes: m-test.cpp m-test2.cpp m-test3.cpp
Screen shot: here
August 5, 2006 at 7:57 pm |
cool!
August 7, 2006 at 9:25 am |
very nicely written
August 7, 2006 at 10:31 pm |
Whoaa!
MS Ambassador .. using UBUNTU, GNU C Compiler, and alikes!!
Where is the world coming to..!?
Waisay, quite an informative post, I have been looking for some tuts on mtrace myself a couple of days back.. and this one is a pleasant intro read on the topic~!!
Good work, keep it up, MS Amboo!
August 8, 2006 at 2:06 am |
>MS Ambassador .. using UBUNTU, GNU C Compiler, and alikes!!
>Where is the world coming to..!?
LOL!
Actually the ultimate goal is to destroy AAK‘s system which is the center of anti MS activities now a days and the idea is to attack the enemy with his own weapons. :-P
August 10, 2006 at 12:10 pm |
Dude:
You can’t even come close to penetrating my system, first of all. Secondly, you’ll have to do more than simply use Ubuntu, g++, cat, and whatever lame GUI editor you use to defeat me. Thirdly, only lamer coders who know jack about how memory allocation, in general, and dyname memory allocation, in particular, works depend on things like mtrace et al. You have gotta rise from that level of lame-ness to even think about defeating me.
O, little one! I wish you luck.
August 12, 2006 at 12:45 am |
only lamer coders who know jack about how memory allocation, in general, and dyname memory allocation, in particular, works depend on things like mtrace et al.
Who said that memory allocation in g++ depends on mtrace?
FYI mtrace() traces memory allocation using malloc(), realloc() and free() only. See man page on mtrace for more information.
BTW your comments made me laugh so hard :D
Keep dreaming my dear script kiddo and keep practice running meta-exploit and others’ perl scripts. May be you will be able to write a simple “Hello, World” by yourself before I actually come to penetrate your system.
August 12, 2006 at 4:52 pm |
Dude, you clearly missed my point by a LONG shot. Read the part of my post about mtrace again, and again, and again, until you understand what the heck I’m talking about.
August 14, 2006 at 1:48 am |
Whatever you say and whatever you mean, one thing is clear: Your Slackware is in danger and nothing can save it from me. :-)
August 15, 2006 at 9:32 am |
Dream on, boy! :-P
June 21, 2007 at 2:44 pm |
Very useful article.
Keep posting!
October 5, 2007 at 3:04 am |
Nice article and the last comment.lol
May 14, 2008 at 7:03 pm |
great article
June 11, 2008 at 8:03 pm |
[…] Memory Leaks Using mtraceA small tutorial on how to find memory leaks in C++ using mtrace.https://munir.wordpress.com/2006/08/05/finding-memory-leaks-using-mtrace/How to detect memory leaks with LoadRunner – visual tutorialHow to detect memory leaks with […]
August 16, 2008 at 11:40 pm |
Your blog is interesting!
Keep up the good work!
August 20, 2008 at 1:18 pm |
it good…….working fine
November 19, 2008 at 1:45 pm |
Thank you for this useful info!
I am curious about your Perl-script: how do you find out which source code line that belongs to each allocation / deallocation?
November 29, 2010 at 6:23 pm |
Thanks for the work.. It is very well written..
November 29, 2010 at 6:39 pm |
@Jonas: That perl script is kind of available. You might have it in /usr/bin. Check it out..
April 7, 2011 at 6:22 am |
very well written !
March 24, 2012 at 1:49 pm |
Excellent article but I usually use Valgrind and Deleaker (Windows) for debugging .
February 25, 2017 at 2:13 pm |
[…] Refer to https://munir.wordpress.com/2006/08/05/finding-memory-leaks-using-mtrace/ […]