Why does valgrind say basic SDL program is leaking memory? - c++

Here is the SDL program:
#include <SDL/SDL.h>
int main(int argc, char** argv){
SDL_Init(SDL_INIT_VIDEO);
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 16, SDL_HWSURFACE);
SDL_Quit();
return 0;
}
Compiled with the command:
g++ -o test test.cpp -lSDL
And here is the output of valgrind:
christian#christian-laptop:~/cpp/tetris$ valgrind --leak-check=full ./test
==3271== Memcheck, a memory error detector
==3271== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3271== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info
==3271== Command: ./test
==3271==
==3271==
==3271== HEAP SUMMARY:
==3271== in use at exit: 91,097 bytes in 1,258 blocks
==3271== total heap usage: 14,250 allocs, 12,992 frees, 2,615,177 bytes allocated
==3271==
==3271== 10 bytes in 2 blocks are definitely lost in loss record 8 of 134
==3271== at 0x4024C1C: malloc (vg_replace_malloc.c:195)
==3271== by 0x4946F04: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4945DA1: _XimEncodeLocalICAttr (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4947195: _XimSetICValueData (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x493FDF1: _XimLocalCreateIC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4922478: XCreateIC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x407AA64: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x407BCBB: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x4069C2A: SDL_VideoInit (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x403F9D3: SDL_InitSubSystem (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x403FA36: SDL_Init (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x8048658: main (in /home/christian/cpp/tetris/test)
==3271==
==3271== 12 bytes in 1 blocks are definitely lost in loss record 12 of 134
==3271== at 0x4024C1C: malloc (vg_replace_malloc.c:195)
==3271== by 0x4A3DA8D: ???
==3271== by 0x4A3D48C: ???
==3271== by 0x4A3D5A4: ???
==3271== by 0x4A3DD26: ???
==3271== by 0x4A38BC5: ???
==3271== by 0x4A38FCD: ???
==3271== by 0x40717DD: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x407BDCA: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x4069C2A: SDL_VideoInit (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x403F9D3: SDL_InitSubSystem (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x403FA36: SDL_Init (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271==
==3271== 112 (8 direct, 104 indirect) bytes in 1 blocks are definitely lost in loss record 102 of 134
==3271== at 0x4024D12: realloc (vg_replace_malloc.c:476)
==3271== by 0x492847E: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492976D: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492AA41: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492B1A4: _XlcCreateLC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x494B4FA: _XlcDefaultLoader (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4933153: _XOpenLC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x49332C2: _XlcCurrentLC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4933761: XSetLocaleModifiers (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x407161D: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x407AD8F: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x407BCBB: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271==
==3271== 112 (8 direct, 104 indirect) bytes in 1 blocks are definitely lost in loss record 103 of 134
==3271== at 0x4024D12: realloc (vg_replace_malloc.c:476)
==3271== by 0x492847E: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492976D: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492AA41: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492B1A4: _XlcCreateLC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x494B4FA: _XlcDefaultLoader (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4933153: _XOpenLC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x493327D: _XrmInitParseInfo (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4918F20: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x491AF37: XrmGetStringDatabase (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x48F8459: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x48F864E: XGetDefault (in /usr/lib/libX11.so.6.2.0)
==3271==
==3271== LEAK SUMMARY:
==3271== definitely lost: 38 bytes in 5 blocks
==3271== indirectly lost: 208 bytes in 8 blocks
==3271== possibly lost: 0 bytes in 0 blocks
==3271== still reachable: 90,851 bytes in 1,245 blocks
==3271== suppressed: 0 bytes in 0 blocks
==3271== Reachable blocks (those to which a pointer was found) are not shown.
==3271== To see them, rerun with: --leak-check=full --show-reachable=yes
==3271==
==3271== For counts of detected and suppressed errors, rerun with: -v
==3271== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 93 from 14)
Why is this basic SDL program leaking memory?

Even for basic OpenGL "hello world" program without the full SDL, Valgrind gives me similar warnings deep inside the OpenGL libraries. It's peculiar, but I've assumed
The library implementors know what they're doing (probably preallocating some small static buffers they never bother to free),
Even if they don't, it's a one-time leak that'll be reclaimed by the OS when the program terminates,
and haven't lost much sleep over it.

This is normal for the graphics API library (OpenGL, Vulkan, etc) and windowing API (X11, SDL, etc). This best option is to use valgrind suppression files to ignore these errors.
Here is how to do it with Linux, SDL & OpenGL:
Let's say the program you are debugging is called 'prog.out' (remember to replace prog.out with the actual name of your program),
You can export suppression info like this:
valgrind --leak-check=full --show-reachable=yes --show-leak-kinds=all --error-limit=no --gen-suppressions=all --log-file=supdata.log ./prog.out
You can now extract the suppression info from 'supdata.log' using a script or manually. You can use wildcards ('*', '...') to make suppressions more generic (thereby not having to update the suppression file each time you update your code).
After that, whenever you debug your program you would include the suppression file from now on. For example, I made the suppression file below 'linux_sdl_gl.sup'. It works well for me when developing using SDL and OpenGL on Linux. It ignores all of OpenGL, SDL and X11 built in errors so that I can easily find errors I create. Feel free to use it in your development.
When I debug my code I use the following call to valgrind. This allows me to find any new system bugs that my suppression file may have missed.
valgrind --gen-suppressions=all --suppressions=./linux_sdl_gl.sup --leak-check=full --show-leak-kinds=all ./prog.out
file: linux_sdl_gl.sup
# Copyright (c) <'2019'> <'Alrick Grandison'>
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
{
opengl_memcpy_addr8
Memcheck:Addr8
fun:memcpy#GLIBC*
obj:/usr/lib/x86_64-linux-gnu/dri/*_dri.so
...
}
{
opengl_memcpy_addr1
Memcheck:Addr1
fun:memcpy#GLIBC*
obj:/usr/lib/x86_64-linux-gnu/dri/*_dri.so
...
}
{
opengl_memset_addr8
Memcheck:Addr8
fun:memset
obj:/usr/lib/x86_64-linux-gnu/dri/*_dri.so
...
}
{
sdl_leak_reachable
Memcheck:Leak
match-leak-kinds: reachable
...
fun:SDL_Init_REAL
...
}
{
x11_leak_reachable
Memcheck:Leak
match-leak-kinds: reachable
...
obj:/usr/lib/x86_64-linux-gnu/libX11.so.*
...
}
{
sdl_leak_indirect
Memcheck:Leak
match-leak-kinds: indirect
...
fun:SDL_Init_REAL
...
}
{
sdl_leak_definite
Memcheck:Leak
match-leak-kinds: definite
...
fun:SDL_Init_REAL
...
}
# OpenGL Calls DL under the Hood - Taken straight out of Valgrind --gen-suppressions
# Could overlap with non-graphics DL api calls
# But, If you are not using DL directly, then don't worry about this
{
dl_leak_reachable
Memcheck:Leak
match-leak-kinds: reachable
...
fun:dlopen##GLIBC*
...
}
# Same as above but more generic
# Could overlap with non-graphics DL api calls
# But, If you are not using DL directly, then don't worry about this
{
dl_leak_reachable
Memcheck:Leak
match-leak-kinds: reachable
...
fun:_dl_*
...
}
{
x11_leak_indirect
Memcheck:Leak
match-leak-kinds: indirect
...
obj:/usr/lib/x86_64-linux-gnu/libX11.so.*
...
}
{
x11_leak_definite
Memcheck:Leak
match-leak-kinds: definite
...
obj:/usr/lib/x86_64-linux-gnu/libX11.so.*
...
}
{
x11_leak_possible
Memcheck:Leak
match-leak-kinds: possible
...
obj:/usr/lib/x86_64-linux-gnu/libX11.so.*
...
}
{
opengl_leak_reachable
Memcheck:Leak
match-leak-kinds: reachable
...
obj:/usr/lib/x86_64-linux-gnu/libGLX.so.*
...
}
github: valgrind supression code

Every SDL_Surface you load should be freed before the call of SDL_Quit().
To do this, just use SDL_FreeSurface(surfaceName) to free up the surface that you allocated on memory.

SDL definitely has a memory leak issue with SDL_TLSCleanup and SDL_TLSData.
In fact, SDL_TLSCleanup is never called for the main thread.

Singletons are pretty much always a 'leak' with standard implementations. That is usually ok, though, since normally it's not like you want to unload your ability to do things like print to the console.

Related

Delete in Fortran

I must edit the complex code that is written with Fortran. Actually, I do not have good knowledge about Fortran. So in this post, I hope receive your help.
In this code, someone declare variables by header file-commonkb.h :
common/cntrl2/SWNU,BB6(500,500)
real*8 SWNU,BB6
when I run:
valgrind --tool=memcheck --leak-check=full --log-file=log ./main
I have the error:
==4026== Memcheck, a memory error detector
==4026== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4026== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==4026== Command: ./main
==4026== Parent PID: 3252
==4026==
==4026== Warning: set address range perms: large range [0x324000, 0x28499000) (defined)
==4026==
==4026== HEAP SUMMARY:
==4026== in use at exit: 1,072 bytes in 4 blocks
==4026== total heap usage: 10,875 allocs, 10,871 frees, 733,306 bytes allocated
==4026==
==4026== 536 (24 direct, 512 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 4
==4026== at 0x290C8B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4026== by 0x292EF7F4: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.4.0.0)
==4026== by 0x29474D25: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.4.0.0)
==4026== by 0x2946C3B9: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.4.0.0)
==4026== by 0x292EE867: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.4.0.0)
==4026== by 0x284A9732: call_init (dl-init.c:72)
==4026== by 0x284A9732: _dl_init (dl-init.c:119)
==4026== by 0x2849A0C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)
==4026==
==4026== 536 (24 direct, 512 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==4026== at 0x290C8B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4026== by 0x292EF7F4: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.4.0.0)
==4026== by 0x29474D25: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.4.0.0)
==4026== by 0x2946C48B: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.4.0.0)
==4026== by 0x292EE867: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.4.0.0)
==4026== by 0x284A9732: call_init (dl-init.c:72)
==4026== by 0x284A9732: _dl_init (dl-init.c:119)
==4026== by 0x2849A0C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)
==4026==
==4026== LEAK SUMMARY:
==4026== definitely lost: 48 bytes in 2 blocks
==4026== indirectly lost: 1,024 bytes in 2 blocks
==4026== possibly lost: 0 bytes in 0 blocks
==4026== still reachable: 0 bytes in 0 blocks
==4026== suppressed: 0 bytes in 0 blocks
==4026==
==4026== For counts of detected and suppressed errors, rerun with: -v
==4026== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
How can I solve this problem?
Thank you for your help.

valgrind doesn't recognize invalid write

Valgring doesn`t detect memory errors.
I am using valgrind 3.11, gcc 5.4.0 under ubuntu and
have an incorrect code in my program, like in the sample.
I analyzed this program, using valgrind. But valgrind doesn't report about any errors.
#include <string.h>
int main(){
int a[3];
memcpy(a,"aaabbbcccdddeeefffggghhh", 24);
return 0;
}
What's wrong with valgrind?
valgrind doesn't know a, not its size then, while you stay in the stack it cannot detect the error
To compare, having that :
#include <string.h>
int main(){
int * a = new int[3];
memcpy(a,"aaabbbcccdddeeefffggghhh", 24);
return 0;
}
valgrind can detect the error because it knows the size of the allocated block :
pi#raspberrypi:/tmp $ valgrind ./a.out
==16164== Memcheck, a memory error detector
==16164== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16164== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16164== Command: ./a.out
==16164==
==16164== Invalid write of size 8
==16164== at 0x4865F44: ??? (in /usr/lib/arm-linux-gnueabihf/libarmmem.so)
==16164== Address 0x4bc9f60 is 8 bytes inside a block of size 12 alloc'd
==16164== at 0x48485F0: operator new[](unsigned int) (vg_replace_malloc.c:417)
==16164== by 0x105A7: main (v.cc:3)
==16164==
==16164== Invalid write of size 8
==16164== at 0x4865F54: ??? (in /usr/lib/arm-linux-gnueabihf/libarmmem.so)
==16164== Address 0x4bc9f68 is 4 bytes after a block of size 12 alloc'd
==16164== at 0x48485F0: operator new[](unsigned int) (vg_replace_malloc.c:417)
==16164== by 0x105A7: main (v.cc:3)
==16164==
==16164==
==16164== HEAP SUMMARY:
==16164== in use at exit: 12 bytes in 1 blocks
==16164== total heap usage: 2 allocs, 1 frees, 20,236 bytes allocated
==16164==
==16164== LEAK SUMMARY:
==16164== definitely lost: 12 bytes in 1 blocks
==16164== indirectly lost: 0 bytes in 0 blocks
==16164== possibly lost: 0 bytes in 0 blocks
==16164== still reachable: 0 bytes in 0 blocks
==16164== suppressed: 0 bytes in 0 blocks
==16164== Rerun with --leak-check=full to see details of leaked memory
==16164==
==16164== For counts of detected and suppressed errors, rerun with: -v
==16164== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 3)

How to cleanup definitely a curl handle?

I have the following sample source code which allow to send a HTTP request with libcurl.
I noticed massive memory usage. debug with valgrind show memory leak. Even that I used curl_easy_cleanup(). I used also curl_easy_reset(), curl_global_cleanup() but they don't have any effect at all and the memory leak persist.
I need to know how to free allocated memory by libcurl.
Here after a basic simple source code that initiate and clean libcurl.
int main()
{
CURL* pEasy = NULL;
pEasy = curl_easy_init();
if (pEasy != NULL)
{
curl_easy_setopt(pEasy, CURLOPT_USERNAME, "test");
curl_easy_setopt(pEasy, CURLOPT_PASSWORD, "test");
curl_easy_setopt(pEasy, CURLOPT_URL, "http:/192.168.22.217:3000");
curl_easy_perform(pEasy);
curl_easy_cleanup(pEasy);
}
}
Valgrind show memory leak of this program.
Find below the valgrind output
sudo valgrind --leak-check=full --show-leak-kinds=all ./mem
==7215== Memcheck, a memory error detector
==7215== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==7215== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==7215== Command: ./mem
==7215==
==7215==
==7215== HEAP SUMMARY:
==7215== in use at exit: 6,957 bytes in 67 blocks
==7215== total heap usage: 1,445 allocs, 1,378 frees, 199,287 bytes allocated
==7215==
==7215== 3 bytes in 1 blocks are still reachable in loss record 1 of 60
==7215== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7215== by 0x5136489: strdup (strdup.c:42)
==7215== by 0x5E65B14: PR_NewLogModule (in /usr/lib/x86_64-linux-gnu/libnspr4.so)
==7215== by 0x5E707A9: ??? (in /usr/lib/x86_64-linux-gnu/libnspr4.so)
==7215== by 0x4E8FB38: ??? (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x4E67344: ??? (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x4E674F7: curl_easy_init (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x400872: main (in /home/mem_test/mem)
==7215==
==7215== 3 bytes in 1 blocks are still reachable in loss record 2 of 60
==7215== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7215== by 0x5136489: strdup (strdup.c:42)
==7215== by 0x5E65B14: PR_NewLogModule (in /usr/lib/x86_64-linux-gnu/libnspr4.so)
==7215== by 0x5E7081B: ??? (in /usr/lib/x86_64-linux-gnu/libnspr4.so)
==7215== by 0x4E8FB38: ??? (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x4E67344: ??? (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x4E674F7: curl_easy_init (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x400872: main (in /home/mem_test/mem)
==7215==
==7215== 4 bytes in 1 blocks are still reachable in loss record 3 of 60
==7215== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7215== by 0x5136489: strdup (strdup.c:42)
==7215== by 0x5E65B14: PR_NewLogModule (in /usr/lib/x86_64-linux-gnu/libnspr4.so)
==7215== by 0x5E707BC: ??? (in /usr/lib/x86_64-linux-gnu/libnspr4.so)
==7215== by 0x4E8FB38: ??? (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x4E67344: ??? (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x4E674F7: curl_easy_init (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x400872: main (in /home/mem_test/mem)
==7215==
......................
==7215==
==7215== 1,344 bytes in 8 blocks are still reachable in loss record 60 of 60
==7215== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7215== by 0x5E79749: PR_NewMonitor (in /usr/lib/x86_64-linux-gnu/libnspr4.so)
==7215== by 0x5E6995D: ??? (in /usr/lib/x86_64-linux-gnu/libnspr4.so)
==7215== by 0x5E70899: ??? (in /usr/lib/x86_64-linux-gnu/libnspr4.so)
==7215== by 0x4E8FB38: ??? (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x4E67344: ??? (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x4E674F7: curl_easy_init (in /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4.4.0)
==7215== by 0x400872: main (in /home/mem_test/mem)
==7215==
==7215== LEAK SUMMARY:
==7215== definitely lost: 0 bytes in 0 blocks
==7215== indirectly lost: 0 bytes in 0 blocks
==7215== possibly lost: 0 bytes in 0 blocks
==7215== still reachable: 6,957 bytes in 67 blocks
==7215== suppressed: 0 bytes in 0 blocks
==7215==
==7215== For counts of detected and suppressed errors, rerun with: -v
==7215== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
How to clean properly the curl memories?
Doing a curl_global_init(0) before curl_easy_init() and doing a curl curl_global_cleanup() after curl_easy_cleanup() seems to fix the issue
==21041== Memcheck, a memory error detector
==21041== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==21041== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==21041== Command: ./a.out
==21041==
==21041==
==21041== HEAP SUMMARY:
==21041== in use at exit: 0 bytes in 0 blocks
==21041== total heap usage: 1,452 allocs, 1,452 frees, 418,773 bytes allocated
==21041==
==21041== All heap blocks were freed -- no leaks are possible
==21041==
==21041== For counts of detected and suppressed errors, rerun with: -v
==21041== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Valgrind error and memory leaks with Python/C API

I'm actually developping a game in C++ and trying to do the AI with a script langage. To do so, i choosed Python2 with Python/C api.
My AI is actually working but there is a big problem : when I run valgrind on my program, there is a lot of error and memory leaks. So, I would know if this happened because of my code or by the API ?
Here is a summary of my class AI :
IA::IA()
{
setenv("PYTHONPATH",".",1);
Py_Initialize();
PyRun_SimpleString("import sys");
pName = PyBytes_FromString((char*)"Test");
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, "push_f");
}
IA::~IA()
{
Py_DECREF(pValue);
Py_DECREF(pModule);
Py_DECREF(pName);
Py_Finalize();
}
void IA::LaunchIA(float x, float y, float z)
{
PyObject *toSend;
toSend = Py_BuildValue("(OOO)", TlistMob, TlistPlayer, pDPosIA);
pResult = PyObject_CallObject(pFunc, toSend);
PyErr_Print();
printf("return = %f\n", (float)PyInt_AsLong(pResult));
}
My (very) simple Python code :
def push_f(MobList, PlayerList, pos):
return 0
And the valgrind error (x1000) :
==11602== Memcheck, a memory error detector
==11602== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==11602== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==11602== Command: ./a.out
==11602==
==11602== Invalid read of size 4
==11602== at 0x4FCE173: PyObject_Free (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F02FC2: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4FBDE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F85BAD: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F872FF: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F88559: PyImport_ImportModuleLevel (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4EFF697: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F4B1E2: PyObject_Call (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x5021446: PyEval_CallObjectWithKeywords (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4EF45C5: PyEval_EvalFrameEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x502201B: PyEval_EvalCodeEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4EF0B88: PyEval_EvalCode (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== Address 0x693c020 is 2,560 bytes inside a block of size 2,731 free'd
==11602== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11602== by 0x4F81D28: PyMarshal_ReadLastObjectFromFile (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F85A22: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F872FF: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F88559: PyImport_ImportModuleLevel (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4EFF697: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F4B1E2: PyObject_Call (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x5021446: PyEval_CallObjectWithKeywords (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4EF45C5: PyEval_EvalFrameEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x502201B: PyEval_EvalCodeEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4EF0B88: PyEval_EvalCode (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F851B3: PyImport_ExecCodeModuleEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== Block was alloc'd at
==11602== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11602== by 0x4F81CDF: PyMarshal_ReadLastObjectFromFile (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F85A22: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F872FF: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F88559: PyImport_ImportModuleLevel (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4EFF697: ??? (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F4B1E2: PyObject_Call (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x5021446: PyEval_CallObjectWithKeywords (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4EF45C5: PyEval_EvalFrameEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x502201B: PyEval_EvalCodeEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4EF0B88: PyEval_EvalCode (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602== by 0x4F851B3: PyImport_ExecCodeModuleEx (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==11602==
==11602==
==11602== HEAP SUMMARY:
==11602== in use at exit: 491,741 bytes in 204 blocks
==11602== total heap usage: 3,301 allocs, 3,097 frees, 3,567,424 bytes allocated
==11602==
==11602== LEAK SUMMARY:
==11602== definitely lost: 0 bytes in 0 blocks
==11602== indirectly lost: 0 bytes in 0 blocks
==11602== possibly lost: 1,072 bytes in 2 blocks
==11602== still reachable: 490,669 bytes in 202 blocks
==11602== suppressed: 0 bytes in 0 blocks
==11602== Rerun with --leak-check=full to see details of leaked memory
==11602==
==11602== For counts of detected and suppressed errors, rerun with: -v
==11602== Use --track-origins=yes to see where uninitialised values come from
==11602== ERROR SUMMARY: 497 errors from 25 contexts (suppressed: 0 from 0)
In my main, you need to know that I'm creating only one IA object.
Am I doing something wrong ? Or is it just the API ?
(This is not a duplicate because I run valgrind on my C++ executable and not Python, my c++ is running the script)
Thanks in advance !!!
I initially suggested this as a duplicate. I don't think that's the case any more, but it still gives useful advice on removing false positives from the Valgrind output for Python programs.
Beyond that there are a number of specific issues with your program:
No error checking - the Python C API typically uses a NULL return value to indicate an error. There are clearly various ways of writing error checking code, but I'd be tempted to go for something like
IA::IA() :
pModule(NULL), pDict(NULL), pFunc(NULL), pName(NULL) // initially null initialize everything
{
setenv("PYTHONPATH",".",1);
Py_Initialize();
// I don't think you actually use this line, so maybe remove it
if (PyRun_SimpleString("import sys") == -1) goto error;
pName = PyBytes_FromString((char*)"Test");
if (!pName) goto error;
pModule = PyImport_Import(pName);
if (!pModule) goto error;
pDict = PyModule_GetDict(pModule);
if (!pDict) goto error;
pFunc = PyDict_GetItemString(pDict, "push_f");
if (!pFunc) goto error;
return; // completed OK
error:
Py_XDECREF(pName); // XDECREF is OK with NULL...
Py_XDECREF(pModule);
Py_XDECREF(pDict);
Py_XDECREF(pFunc);
PyErr_Print();
throw std::runtime_error(""); // ??? - possibly get and use the error string
// see https://stackoverflow.com/a/1418703/4657412
}
I'm aware people are suspicious of goto but in this case it's a reasonably clean way of jumping to an error handling block. You can structure it differently if you like.
The destructor doesn't decref pFunc, which looks like a memory leak.
IA::LaunchIA similarly is lacking working error checking.
IA::LaunchIA never decrefs toSend, pResult, TlistMob, TlistPlayer, pDPosIA. Some of these are related to the incompleteness of the code you show, but if they aren't decrefed then you're leaking memory.
You call PyErr_Print() without checking for an error. The documentation says:
Call this function only when the error indicator is set. (Otherwise it will cause a fatal error!)
I suspect that this might be your biggest problem.
Those are all the issues I can see. Without a minimal complete example it's impossible to actually check what you're seeing. Given you're using C++ you might be well advised to use/make a decent, object oriented wrapper for PyObject* to avoid having to worry about reference counting yourself - Boost Python has one.

Using valgrind to find a memory leak in the mysql c++ client

I'm using valgrind to try and track down a memory leak is the mysql c++ client distributed from mysql.
In both the examples (resultset.cpp) and my own program, there is a single 56 byte block that is not freed. In my own program, I've traced the leak to a call to the mysql client.
Here are the results when I run the test:
valgrind --leak-check=full --show-reachable=yes ./my-executable
==29858== Memcheck, a memory error detector
==29858== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==29858== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==29858== Command: ./my-executable
==29858==
==29858==
==29858== HEAP SUMMARY:
==29858== in use at exit: 56 bytes in 1 blocks
==29858== total heap usage: 693 allocs, 692 frees, 308,667 bytes allocated
==29858==
==29858== 56 bytes in 1 blocks are still reachable in loss record 1 of 1
==29858== at 0x4C284A8: malloc (vg_replace_malloc.c:236)
==29858== by 0x400D334: _dl_map_object_deps (dl-deps.c:506)
==29858== by 0x4013652: dl_open_worker (dl-open.c:291)
==29858== by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==29858== by 0x4012FF9: _dl_open (dl-open.c:583)
==29858== by 0x7077BCF: do_dlopen (dl-libc.c:86)
==29858== by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==29858== by 0x7077D26: __libc_dlopen_mode (dl-libc.c:47)
==29858== by 0x72E5FEB: pthread_cancel_init (unwind-forcedunwind.c:53)
==29858== by 0x72E614B: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)
==29858== by 0x72E408F: __pthread_unwind (unwind.c:130)
==29858== by 0x72DDEB4: pthread_exit (pthreadP.h:265)
==29858==
==29858== LEAK SUMMARY:
==29858== definitely lost: 0 bytes in 0 blocks
==29858== indirectly lost: 0 bytes in 0 blocks
==29858== possibly lost: 0 bytes in 0 blocks
==29858== still reachable: 56 bytes in 1 blocks
==29858== suppressed: 0 bytes in 0 blocks
==29858==
==29858== For counts of detected and suppressed errors, rerun with: -v
==29858== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 8 from 6)
I have a few questions regarding this:
How should I interpret the --show-reachable block?
Is that block useful for me to try and zero in on the error?
If the block is not useful, does valgrind have another mechanism that would help me trace the leak?
If not, is there some other tool (hopefully OSS on linux) to help me narrow this down?
Thanks in advance..
UPDATE: Here is the code that I found on my system for the definition of pthread_exit. I'm not certain that this is the actual source that is being invoked. However, if it is, can anyone explain what might be going wrong?
void
pthread_exit (void *retval)
{
/* specific to PTHREAD_TO_WINTHREAD */
ExitThread ((DWORD) ((size_t) retval)); /* thread becomes signalled so its death can be waited upon */
/*NOTREACHED*/
assert (0); return; /* void fnc; can't return an error code */
}
Reachable just means that the blocks had a valid pointer referencing them in scope when the program exited, which indicates that the program does not explicitly free everything on exit because it relies on the underlying OS to do so. What you should be looking for are lost blocks, where blocks of memory lost all references to them and can no longer be freed.
So, the 56 bytes were probably allocated in main, which did not explicitly free them. What you posted does not show a memory leak. It shows main freeing everything but what main allocated because main assumes that when it dies, all memory will be reclaimed by the kernel.
Specifically, it's pthread (in main) making this assumption (which is a valid assumption on darn near everything found in production written in the last 15+ years). The need to free blocks that still have a valid reference on exit is a bit of a contentious point, but for this specific question all that needs to be mentioned is that the assumption was made.
Edit
It's actually pthread_exit() not cleaning something up on exit, but as explained it probably doesn't need to (or quite possibly can't) once it reaches that point.