Tracking segfault with valgrind, and understanding valgrind output - c++

I am trying to debug my C++ program, which is segfaulting.
I checked my code to see if I could find the cause of the segfault. I placed some cout statements to narrow down the location at which the fault occured.
I found the function call which produces the segfault. It is inside a callback function. The line is
inputbox->TestFunc();
although this is meaningless to the reader.
This was confirmed by the backtrace in GDB. (I couldn't get any more useful info from GDB other than the backtrace, but I am not too familiar with debugging tools.)
I attempted to produce a MWE, and failed. I failed because when I stripped down parts of the code to produce a MWE, the problem went away. (So my guess is it is something subtle, not trivial.)
I tried writing a MWE from scratch, copying my inheritance structures, and this failed.
Part of my problem is that I cannot simply remove "xyz" bit of code, because this changing one function argument breaks lots of other code due to inheritance structures that are in place.
I have done a few other tests, such as moving the "problem section of code" to different functions, such as the layer just below int main(), and in these places, there does not seem to be a problem.
A call to inputbox->TestFunc2() does not crash. TestFunc2() is not an overridden virtual function. TestFunc() is, and I think this might hint at the cause of the problem. (Although not directly, as copying the inhertance structure into a MWE makes the problem go away.)
Both of those test functions just cout the name of the function and then return. They don't read/write anything to memory.
I didn't post anything to SO for a while because I wasn't able to formulate a question in a manner which might be able to get some meaningful response, however some internet searches suggested that I try to use valgrind to debug the issue.
With that, here is the valgrind output
==8379== Memcheck, a memory error detector
==8379== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8379== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==8379== Command: ./a.out
==8379==
==8379== Conditional jump or move depends on uninitialised value(s)
==8379== at 0x4C32EA6: rawmemchr (vg_replace_strmem.c:1402)
==8379== by 0x5E8C3C1: _IO_str_init_static_internal (strops.c:41)
==8379== by 0x5E7FB96: vsscanf (iovsscanf.c:40)
==8379== by 0x5E7A306: sscanf (sscanf.c:32)
==8379== by 0xEC17E4A: ??? (in /usr/lib/x86_64-linux-gnu/libdrm.so.2.4.0)
==8379== by 0xEC18182: ??? (in /usr/lib/x86_64-linux-gnu/libdrm.so.2.4.0)
==8379== by 0xEC1BBF8: drmGetDevice (in /usr/lib/x86_64-linux-gnu/libdrm.so.2.4.0)
==8379== by 0xD7622D6: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==8379== by 0xD761694: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==8379== by 0xD735988: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==8379== by 0xD731B9A: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==8379== by 0xD731FD1: glXQueryExtensionsString (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==8379==
==8379== Syscall param writev(vector[...]) points to uninitialised byte(s)
==8379== at 0x5EF6E70: __writev_nocancel (syscall-template.S:84)
==8379== by 0x94BB41C: ??? (in /usr/lib/x86_64-linux-gnu/libxcb.so.1.1.0)
==8379== by 0x94BB81C: ??? (in /usr/lib/x86_64-linux-gnu/libxcb.so.1.1.0)
==8379== by 0x94BB89C: xcb_writev (in /usr/lib/x86_64-linux-gnu/libxcb.so.1.1.0)
==8379== by 0x6D6EA7D: _XSend (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==8379== by 0x6D6EF71: _XReply (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==8379== by 0x6D59E2E: XInternAtom (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==8379== by 0x4EFE46A: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x4EFF364: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x4EEF2EF: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x4EEF07E: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x4E55456: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== Address 0xd1a9813 is 35 bytes inside a block of size 16,384 alloc'd
==8379== at 0x4C2DBC5: calloc (vg_replace_malloc.c:711)
==8379== by 0x6D5EEC5: XOpenDisplay (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==8379== by 0x4EFD53F: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x4EEF02B: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x4E55456: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x10CF85: main (main.cpp:61)
==8379==
_ftm_ address: 0x12a0b610
SetPosition(0, 0)
Inputbox::TestFunc2()
Inputbox::TestFunc()
Inputbox::Draw()
0,0
SetPosition(0, 600)
refreshdelay set to: 16
ENTERED MAIN
SetPosition(0, 0)
Inputbox::TestFunc2()
Inputbox::TestFunc()
Inputbox::Draw()
derived2::function()
function was called ok
Window address: 0xffefffa00
Window 0
Window::TestFunc()
this=0xffefffa00
FontTextureManager::TestFunc()
this=0x12a0b610
current_window->_ftm_ address: 0x12a0b610
==8379== Conditional jump or move depends on uninitialised value(s)
==8379== at 0x4EEBA2D: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x128278: Window::Height() const (Window.hpp:773)
==8379== by 0x12794E: fc_open(Window*) (FunctionCallback.cpp:133)
==8379== by 0x10D257: main (main.cpp:109)
==8379==
==8379== Use of uninitialised value of size 8
==8379== at 0x4EEBA32: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x128278: Window::Height() const (Window.hpp:773)
==8379== by 0x12794E: fc_open(Window*) (FunctionCallback.cpp:133)
==8379== by 0x10D257: main (main.cpp:109)
==8379==
==8379== Use of uninitialised value of size 8
==8379== at 0x12827D: Window::Height() const (Window.hpp:774)
==8379== by 0x12794E: fc_open(Window*) (FunctionCallback.cpp:133)
==8379== by 0x10D257: main (main.cpp:109)
==8379==
==8379== Conditional jump or move depends on uninitialised value(s)
==8379== at 0x4EEBA23: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x12823C: Window::Width() const (Window.hpp:766)
==8379== by 0x127966: fc_open(Window*) (FunctionCallback.cpp:133)
==8379== by 0x10D257: main (main.cpp:109)
==8379==
==8379== Use of uninitialised value of size 8
==8379== at 0x4EEBA28: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==8379== by 0x12823C: Window::Width() const (Window.hpp:766)
==8379== by 0x127966: fc_open(Window*) (FunctionCallback.cpp:133)
==8379== by 0x10D257: main (main.cpp:109)
==8379==
==8379== Use of uninitialised value of size 8
==8379== at 0x128241: Window::Width() const (Window.hpp:767)
==8379== by 0x127966: fc_open(Window*) (FunctionCallback.cpp:133)
==8379== by 0x10D257: main (main.cpp:109)
==8379==
SetPosition(400, 300)
INPUTBOX...
Inputbox::TestFunc2()
==8379== Invalid read of size 8
==8379== at 0x1279BF: fc_open(Window*) (FunctionCallback.cpp:136)
==8379== by 0x10D257: main (main.cpp:109)
==8379== Address 0x340 is not stack'd, malloc'd or (recently) free'd
==8379==
==8379==
==8379== Process terminating with default action of signal 11 (SIGSEGV)
==8379== Access not within mapped region at address 0x340
==8379== at 0x1279BF: fc_open(Window*) (FunctionCallback.cpp:136)
==8379== by 0x10D257: main (main.cpp:109)
==8379== If you believe this happened as a result of a stack
==8379== overflow in your program's main thread (unlikely but
==8379== possible), you can try to increase the size of the
==8379== main thread stack using the --main-stacksize= flag.
==8379== The main thread stack size used in this run was 8388608.
==8379==
==8379== HEAP SUMMARY:
==8379== in use at exit: 29,970,438 bytes in 46,548 blocks
==8379== total heap usage: 109,878 allocs, 63,330 frees, 61,448,020 bytes allocated
==8379==
==8379== LEAK SUMMARY:
==8379== definitely lost: 461,536 bytes in 124 blocks
==8379== indirectly lost: 176 bytes in 4 blocks
==8379== possibly lost: 28,306,879 bytes in 43,538 blocks
==8379== still reachable: 1,201,847 bytes in 2,882 blocks
==8379== suppressed: 0 bytes in 0 blocks
==8379== Rerun with --leak-check=full to see details of leaked memory
==8379==
==8379== For counts of detected and suppressed errors, rerun with: -v
==8379== Use --track-origins=yes to see where uninitialised values come from
==8379== ERROR SUMMARY: 23 errors from 9 contexts (suppressed: 0 from 0)
Segmentation fault
The key line appears to be Invalid read of size 8 at 0x1279BF: fc_open(Window*) (FunctionCallback.cpp:136)
What does this information mean, and what should I be looking for in my code that might have caused this error?
Code snippet:
void fc_open(Window *const current_window)
{
derived2 *object = new derived2;
object->function();
std::cout << "function was called ok" << std::endl;
std::cout << "Window address: " << current_window << std::endl;
std::cout << current_window->TestName() << std::endl;
current_window->TestFunc();
current_window->_ftm_->TestFunc();
std::cout << "current_window->_ftm_ address: " << current_window->_ftm_ << std::endl;
Inputbox *inputbox = new Inputbox(current_window->_ftm_);
std::cout << "inputbox=" << inputbox << std::endl;
inputbox->SetPosition(current_window->Width() / 2, current_window->Height() / 2);
std::cout << "INPUTBOX..." << std::endl;
inputbox->TestFunc2();
inputbox->TestFunc(); // BOOM
}

Issue solved: Information for future readers.
It is highly unlikely that this information will help anyone in future, but just in case, here is the cause of the problem.
First, let us review the code in the function which was causing the segfault:
Inputbox *inputbox = new Inputbox(current_window->_ftm_);
inputbox->SetPosition(current_window->Width() / 2, current_window->Height() / 2);
inputbox->TestFunc2();
inputbox->TestFunc();
I have no idea why TestFunc2() didn't blow up and TestFunc() did.
The problem was actually being caused by the call to SetPosition, which takes 2 integers as arguments.
Now let us check the Width and Height functions:
int Width() const
{
int *w;
SDL_GetWindowSize(_window_.get(), w, nullptr);
return *w;
}
This is clearly wrong and was caused by not paying attention. It should be:
int Width() const
{
int w;
SDL_GetWindowSize(_window_.get(), &w, nullptr);
return w;
}
Valgrind hinted at the cause of the problem in the printed messages about the Width and Height functions.
I still don't fully understand why the segfault occured when it did however. My guess is this is due to some sort of optimization re-ordering?

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.

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 seg fault on mpi hello world

I get a seg-fault applying valgrind to a very simple MPI program:
#include "mpi.h"
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
// Initialize parallel
int rank, numProcess;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numProcess);
std::cout << "Hello world, - Rank " << rank << "\n";
MPI_Finalize();
return 0;
}
Calling mpirun -np 2 ./mpi_test works as expected. However, mpirun -np 2 valgrind ./mpi_test returns a long list of errors and does not say Hello world. I am aware that valgrind can detect false positives in MPI, but here it will not even run a simple hello world program. Below is the errors I get.
==85595== Memcheck, a memory error detector
==85595== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==85595== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==85595== Command: ./mpi_test
==85595==
==85596== Memcheck, a memory error detector
==85596== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==85596== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==85596== Command: ./mpi_test
==85596==
==85596== Syscall param msg->desc.port.name points to uninitialised byte(s)
==85596== at 0x10070B34A: mach_msg_trap (in /usr/lib/system/libsystem_kernel.dylib)
==85596== by 0x10070A796: mach_msg (in /usr/lib/system/libsystem_kernel.dylib)
==85596== by 0x100704485: task_set_special_port (in /usr/lib/system/libsystem_kernel.dylib)
==85596== by 0x1008A010E: _os_trace_create_debug_control_port (in /usr/lib/system/libsystem_trace.dylib)
==85596== by 0x1008A0458: _libtrace_init (in /usr/lib/system/libsystem_trace.dylib)
==85596== by 0x10026B9DF: libSystem_initializer (in /usr/lib/libSystem.B.dylib)
==85596== by 0x10001AA1A: ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==85596== by 0x10001AC1D: ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==85596== by 0x1000164A9: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==85596== by 0x100016440: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==85596== by 0x100015523: ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==85596== by 0x1000155B8: ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) (in /usr/lib/dyld)
==85596== Address 0x10488d25c is on thread 1's stack
==85596== in frame #2, created by task_set_special_port (???:)
==85596==
==85595== Syscall param msg->desc.port.name points to uninitialised byte(s)
==85595== at 0x10070B34A: mach_msg_trap (in /usr/lib/system/libsystem_kernel.dylib)
==85595== by 0x10070A796: mach_msg (in /usr/lib/system/libsystem_kernel.dylib)
==85595== by 0x100704485: task_set_special_port (in /usr/lib/system/libsystem_kernel.dylib)
==85595== by 0x1008A010E: _os_trace_create_debug_control_port (in /usr/lib/system/libsystem_trace.dylib)
==85595== by 0x1008A0458: _libtrace_init (in /usr/lib/system/libsystem_trace.dylib)
==85595== by 0x10026B9DF: libSystem_initializer (in /usr/lib/libSystem.B.dylib)
==85595== by 0x10001AA1A: ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==85595== by 0x10001AC1D: ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==85595== by 0x1000164A9: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==85595== by 0x100016440: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==85595== by 0x100015523: ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==85595== by 0x1000155B8: ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) (in /usr/lib/dyld)
==85595== Address 0x10488d25c is on thread 1's stack
==85595== in frame #2, created by task_set_special_port (???:)
==85595==
--85595-- UNKNOWN task message [id 3445, to mach_task_self(), reply 0x707]
--85596-- UNKNOWN task message [id 3445, to mach_task_self(), reply 0x707]
--85595-- UNKNOWN task message [id 3445, to mach_task_self(), reply 0x707] (repeated 2 times)
--85596-- UNKNOWN task message [id 3445, to mach_task_self(), reply 0x707] (repeated 2 times)
--85596-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option
--85595-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option
--85596-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 2 times)
--85595-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 2 times)
--85596-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 4 times)
--85595-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 4 times)
--85595-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 8 times)
--85596-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 8 times)
==85595== Thread 2:
==85595== Invalid read of size 4
==85595== at 0x100868899: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
==85595== by 0x100868886: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85595== by 0x10086808C: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85595== Address 0x18 is not stack'd, malloc'd or (recently) free'd
==85595==
==85595== Invalid read of size 8
==85595== at 0x100866435: _pthread_mutex_lock_slow (in /usr/lib/system/libsystem_pthread.dylib)
==85595== by 0x100560117: dyldGlobalLockAcquire() (in /usr/lib/system/libdyld.dylib)
==85595== by 0x100021F95: ImageLoaderMachOCompressed::doBindFastLazySymbol(unsigned int, ImageLoader::LinkContext const&, void (*)(), void (*)()) (in /usr/lib/dyld)
==85595== by 0x10000986C: dyld::fastBindLazySymbol(ImageLoader**, unsigned long) (in /usr/lib/dyld)
==85595== by 0x100560281: dyld_stub_binder (in /usr/lib/system/libdyld.dylib)
==85595== by 0x100382977: ??? (in /usr/local/Cellar/open-mpi/3.0.0_2/lib/libopen-pal.40.dylib)
==85595== by 0x25805BBB1: ???
==85595== by 0x100868886: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85595== by 0x10086808C: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85595== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==85595==
==85595==
==85595== Process terminating with default action of signal 11 (SIGSEGV)
==85595== Access not within mapped region at address 0x0
==85595== at 0x100866435: _pthread_mutex_lock_slow (in /usr/lib/system/libsystem_pthread.dylib)
==85595== by 0x100560117: dyldGlobalLockAcquire() (in /usr/lib/system/libdyld.dylib)
==85595== by 0x100021F95: ImageLoaderMachOCompressed::doBindFastLazySymbol(unsigned int, ImageLoader::LinkContext const&, void (*)(), void (*)()) (in /usr/lib/dyld)
==85595== by 0x10000986C: dyld::fastBindLazySymbol(ImageLoader**, unsigned long) (in /usr/lib/dyld)
==85595== by 0x100560281: dyld_stub_binder (in /usr/lib/system/libdyld.dylib)
==85595== by 0x100382977: ??? (in /usr/local/Cellar/open-mpi/3.0.0_2/lib/libopen-pal.40.dylib)
==85595== by 0x25805BBB1: ???
==85595== by 0x100868886: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85595== by 0x10086808C: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85595== If you believe this happened as a result of a stack
==85595== overflow in your program's main thread (unlikely but
==85595== possible), you can try to increase the size of the
==85595== main thread stack using the --main-stacksize= flag.
==85595== The main thread stack size used in this run was 8388608.
--85595:0:schedule VG_(sema_down): read returned -4
==85595==
==85595== HEAP SUMMARY:
==85595== in use at exit: 358,368 bytes in 3,295 blocks
==85595== total heap usage: 5,625 allocs, 2,330 frees, 721,547 bytes allocated
==85595==
==85596== Thread 2:
==85596== Invalid read of size 4
==85596== at 0x100868899: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
==85596== by 0x100868886: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85596== by 0x10086808C: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85596== Address 0x18 is not stack'd, malloc'd or (recently) free'd
==85596==
==85596== Invalid read of size 8
==85596== at 0x100866435: _pthread_mutex_lock_slow (in /usr/lib/system/libsystem_pthread.dylib)
==85596== by 0x100560117: dyldGlobalLockAcquire() (in /usr/lib/system/libdyld.dylib)
==85596== by 0x100021F95: ImageLoaderMachOCompressed::doBindFastLazySymbol(unsigned int, ImageLoader::LinkContext const&, void (*)(), void (*)()) (in /usr/lib/dyld)
==85596== by 0x10000986C: dyld::fastBindLazySymbol(ImageLoader**, unsigned long) (in /usr/lib/dyld)
==85596== by 0x100560281: dyld_stub_binder (in /usr/lib/system/libdyld.dylib)
==85596== by 0x100382977: ??? (in /usr/local/Cellar/open-mpi/3.0.0_2/lib/libopen-pal.40.dylib)
==85596== by 0x25805BBB1: ???
==85596== by 0x100868886: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85596== by 0x10086808C: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85596== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==85596==
==85596==
==85596== Process terminating with default action of signal 11 (SIGSEGV)
==85596== Access not within mapped region at address 0x0
==85596== at 0x100866435: _pthread_mutex_lock_slow (in /usr/lib/system/libsystem_pthread.dylib)
==85596== by 0x100560117: dyldGlobalLockAcquire() (in /usr/lib/system/libdyld.dylib)
==85596== by 0x100021F95: ImageLoaderMachOCompressed::doBindFastLazySymbol(unsigned int, ImageLoader::LinkContext const&, void (*)(), void (*)()) (in /usr/lib/dyld)
==85596== by 0x10000986C: dyld::fastBindLazySymbol(ImageLoader**, unsigned long) (in /usr/lib/dyld)
==85596== by 0x100560281: dyld_stub_binder (in /usr/lib/system/libdyld.dylib)
==85596== by 0x100382977: ??? (in /usr/local/Cellar/open-mpi/3.0.0_2/lib/libopen-pal.40.dylib)
==85596== by 0x25805BBB1: ???
==85596== by 0x100868886: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85596== by 0x10086808C: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
==85596== If you believe this happened as a result of a stack
==85596== overflow in your program's main thread (unlikely but
==85596== possible), you can try to increase the size of the
==85596== main thread stack using the --main-stacksize= flag.
==85596== The main thread stack size used in this run was 8388608.
--85596:0:schedule VG_(sema_down): read returned -4
==85596==
==85596== HEAP SUMMARY:
==85596== in use at exit: 358,368 bytes in 3,295 blocks
==85596== total heap usage: 5,625 allocs, 2,330 frees, 721,547 bytes allocated
==85596==
==85595== LEAK SUMMARY:
==85595== definitely lost: 9,159 bytes in 47 blocks
==85595== indirectly lost: 8,112 bytes in 111 blocks
==85595== possibly lost: 0 bytes in 0 blocks
==85595== still reachable: 325,270 bytes in 2,982 blocks
==85595== suppressed: 15,827 bytes in 155 blocks
==85595== Rerun with --leak-check=full to see details of leaked memory
==85595==
==85595== For counts of detected and suppressed errors, rerun with: -v
==85595== Use --track-origins=yes to see where uninitialised values come from
==85595== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 1 from 1)
==85596== LEAK SUMMARY:
==85596== definitely lost: 3,839 bytes in 1 blocks
==85596== indirectly lost: 0 bytes in 0 blocks
==85596== possibly lost: 72 bytes in 3 blocks
==85596== still reachable: 336,638 bytes in 3,138 blocks
==85596== suppressed: 17,819 bytes in 153 blocks
==85596== Rerun with --leak-check=full to see details of leaked memory
==85596==
==85596== For counts of detected and suppressed errors, rerun with: -v
==85596== Use --track-origins=yes to see where uninitialised values come from
==85596== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 1 from 1)
-------------------------------------------------------
Primary job terminated normally, but 1 process returned
a non-zero exit code. Per user-direction, the job has been aborted.
-------------------------------------------------------
--------------------------------------------------------------------------
mpirun noticed that process rank 0 with PID 0 on node cu-vpn-colorado-edu-198 exited on signal 11 (Segmentation fault: 11).
--------------------------------------------------------------------------
I would be suspecting that there is something up with Valgrind and possible your OS.
As I can compile and run your program without any issues on Linux:
tb-xps ../tmp$ mpicxx -o h2 h2.cpp
tb-xps ../tmp$ mpirun -n 1 ./h2
Hello world, - Rank 0
tb-xps ../tmp$ mpirun -n 1 valgrind ./h2
==3544== Memcheck, a memory error detector
==3544== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3544== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3544== Command: ./h2
==3544==
==3544== Thread 3:
==3544== Syscall param epoll_pwait(sigmask) points to unaddressable byte(s)
==3544== at 0x5F5AFE6: epoll_pwait (in /usr/lib/libc-2.26.so)
==3544== by 0x6536DDC: ??? (in /usr/lib/openmpi/libopen-pal.so.40.0.0)
==3544== by 0x653AEDA: opal_libevent2022_event_base_loop (in /usr/lib/openmpi/libopen-pal.so.40.0.0)
==3544== by 0x90CA0CE: ??? (in /usr/lib/openmpi/openmpi/mca_pmix_pmix2x.so)
==3544== by 0x5C4E08B: start_thread (in /usr/lib/libpthread-2.26.so)
==3544== by 0x5F5AE7E: clone (in /usr/lib/libc-2.26.so)
==3544== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==3544==
Hello world, - Rank 0
==3544==
==3544== HEAP SUMMARY:
==3544== in use at exit: 1,899 bytes in 44 blocks
==3544== total heap usage: 17,910 allocs, 17,866 frees, 3,993,061 bytes allocated
==3544==
==3544== LEAK SUMMARY:
==3544== definitely lost: 372 bytes in 4 blocks
==3544== indirectly lost: 1,288 bytes in 34 blocks
==3544== possibly lost: 0 bytes in 0 blocks
==3544== still reachable: 239 bytes in 6 blocks
==3544== suppressed: 0 bytes in 0 blocks
==3544== Rerun with --leak-check=full to see details of leaked memory
==3544==
==3544== For counts of detected and suppressed errors, rerun with: -v
==3544== ERROR SUMMARY: 39 errors from 1 contexts (suppressed: 0 from 0)
tb-xps ../tmp$ uname -a
Linux tb-xps 4.15.3-1-ARCH #1 SMP PREEMPT Mon Feb 12 23:01:17 UTC 2018 x86_64 GNU/Linux
Also since I am not a C++ programmer, I'd get rid of the iostream and just use printf, I'd also re-arrange my includes and add some white-spaces:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
Do you have access to a different machine? Are you able to ask a Valgrind mailing list?

How to use curl + ssl without memleak disaster

I have written a simple curl get wrapper to access http, https content. If I run my testcases with valgrind, I can see some still reachable sectors. Yes I know they are not as evil as lost references or definitely losts. But i want to keep my project clean.
If I disable SSL with curl_global_init(CURL_GLOBAL_NOTHING) no memleaks are detected. But then there is also no https support. So I guess its a libcrypt, libssl problem? What can I do to initialize and cleanup a https curl call correctly without having valgrind notifications?
jami#jami-mbp:rcc$ valgrind --leak-check=full --show-reachable=yes ./tests/testsuite
==7171== Memcheck, a memory error detector
==7171== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==7171== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==7171== Command: ./tests/testsuite
==7171==
==7171== Conditional jump or move depends on uninitialised value(s)
==7171== at 0x703784B: ASN1_STRING_set (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x702552C: ASN1_mbstring_ncopy (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x7025753: ASN1_mbstring_copy (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x7026614: ASN1_STRING_to_UTF8 (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x7027A42: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x7027FA6: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x702E4E2: ASN1_item_ex_d2i (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x702F09F: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x702F2E7: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x702EB50: ASN1_item_ex_d2i (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x702F09F: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x702F2E7: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171==
OK (3)
==7171==
==7171== HEAP SUMMARY:
==7171== in use at exit: 64 bytes in 2 blocks
==7171== total heap usage: 10,535 allocs, 10,533 frees, 898,726 bytes allocated
==7171==
==7171== 32 bytes in 1 blocks are still reachable in loss record 1 of 2
==7171== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7171== by 0x6F821FF: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x700A82E: sk_new (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x6D012A9: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==7171== by 0x6D031F8: SSL_COMP_get_compression_methods (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==7171== by 0x6D08618: SSL_library_init (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==7171== by 0x549A1E2: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.2.0)
==7171== by 0x54A1B89: curl_global_init (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.2.0)
==7171== by 0x559240: RCC::IO::HttpClient::get(std::string) (HttpClient.cpp:53)
==7171== by 0x559FFE: HttpClientTest::testBasicRequest() (HttpClientTest.cpp:55)
==7171== by 0x55BB11: CppUnit::TestCaller<HttpClientTest>::runTest() (TestCaller.h:166)
==7171== by 0x56FA081: CppUnit::TestCaseMethodFunctor::operator()() const (in /usr/lib/libcppunit-1.12.so.1.0.0)
==7171==
==7171== 32 bytes in 1 blocks are still reachable in loss record 2 of 2
==7171== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7171== by 0x6F821FF: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x700A84C: sk_new (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==7171== by 0x6D012A9: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==7171== by 0x6D031F8: SSL_COMP_get_compression_methods (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==7171== by 0x6D08618: SSL_library_init (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==7171== by 0x549A1E2: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.2.0)
==7171== by 0x54A1B89: curl_global_init (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.2.0)
==7171== by 0x559240: RCC::IO::HttpClient::get(std::string) (HttpClient.cpp:53)
==7171== by 0x559FFE: HttpClientTest::testBasicRequest() (HttpClientTest.cpp:55)
==7171== by 0x55BB11: CppUnit::TestCaller<HttpClientTest>::runTest() (TestCaller.h:166)
==7171== by 0x56FA081: CppUnit::TestCaseMethodFunctor::operator()() const (in /usr/lib/libcppunit-1.12.so.1.0.0)
==7171==
==7171== LEAK SUMMARY:
==7171== definitely lost: 0 bytes in 0 blocks
==7171== indirectly lost: 0 bytes in 0 blocks
==7171== possibly lost: 0 bytes in 0 blocks
==7171== still reachable: 64 bytes in 2 blocks
==7171== suppressed: 0 bytes in 0 blocks
==7171==
==7171== For counts of detected and suppressed errors, rerun with: -v
==7171== Use --track-origins=yes to see where uninitialised values come from
==7171== ERROR SUMMARY: 4 errors from 1 contexts (suppressed: 2 from 2)
The curl wrapper (essential part of it):
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
std::string HttpClient::get(std::string url)
{
curl_global_init(CURL_GLOBAL_ALL);
CURL *curl = NULL;
CURLcode result;
std::string readBuffer = "";
curl = curl_easy_init();
if (curl == 0)
throw std::runtime_error("Unable to create CURL instance");
if (useProxy)
curl_easy_setopt(curl, CURLOPT_PROXY, proxyHost.c_str());
if (useAuth)
authenticate(curl);
if (followRedirect)
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
LOG_DEBUG("http client fetch " + url);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_POST, false);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
result = curl_easy_perform(curl);
if (result != CURLE_OK) {
curl_easy_cleanup(curl);
throw std::runtime_error(curl_easy_strerror(result));
}
curl_easy_cleanup(curl);
curl_global_cleanup();
return readBuffer;
}
Run the tests with:
valgrind --leak-check=full --show-reachable=yes -v ./tests/testsuite
Ok, I accept the good answer from Joachim Pileborg (a comment under the main question). OpenSSL use some data per process which survives the lifecycle of my program. So valgrind detect it as still reachable and my OpenSSL initialization/finalization seems to be correct. Thank you Joachim

Why does valgrind say basic SDL program is leaking memory?

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.