I am trying to use C++11's std::tr1::shared_ptr to manage SDL_Surface pointers. Note, I am not using Boost. I have defined a deleter for the shared_ptr to use SDL_FreeSurface.
Declared like:
class Engine {
private:
std::tr1::shared_ptr<SDL_Surface> _scr;
std::tr1::shared_ptr<SDL_Surface> _bg;
Defined (in Engine's ctor) like:
_scr = std::tr1::shared_ptr<SDL_Surface>( SDL_SetVideoMode(Data::SCR_WIDTH,
Data::SCR_HEIGHT,
32, SDL_SWSURFACE),
SurfaceDeleter<SDL_Surface>());
_bg = std::tr1::shared_ptr<SDL_Surface>(IMG_Load(Data::IM_BACKGROUND),
SurfaceDeleter<SDL_Surface>());
The custom deleter:
template<typename T>
class SurfaceDeleter{
public:
void operator() (T*& d) const {
if(d){
SDL_FreeSurface(d);
}
}
};
The only object holding the shared_ptr is the Engine. The shared_ptr was used like so:
SDL_BlitSurface(_bg.get(), nullptr, _scr.get(), nullptr);
SDL_Flip(_scr.get());
Valgrind results:
==3648== 8 bytes in 2 blocks are definitely lost in loss record 16 of 292
==3648== at 0x402A018: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3648== by 0x431FBE0: strdup (in /lib/libc-2.14.1.so)
==3648== 1 bytes in 1 blocks are definitely lost in loss record 1 of 292
==3648== at 0x402A018: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3648== by 0x494A590: _XlcDefaultMapModifiers (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x494A99A: XSetLocaleModifiers (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x4097CDB: ??? (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x4083868: SDL_VideoInit (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x40594D9: SDL_InitSubSystem (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x42C3212: (below main) (in /lib/libc-2.14.1.so)
==3648== 980 (68 direct, 912 indirect) bytes in 1 blocks are definitely lost in loss record 258 of 292
==3648== at 0x402A102: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3648== by 0x49402A6: ??? (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x49407A2: ??? (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x494212F: ??? (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x49429BA: _XlcCreateLC (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x4965957: _XlcUtf8Loader (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x494A793: _XOpenLC (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x494A8F1: _XlcCurrentLC (in /usr/lib/libX11.so.6.3.0)
==3648== by 0x4097CDB: ??? (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x4083868: SDL_VideoInit (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x40594D9: SDL_InitSubSystem (in /usr/lib/libSDL-1.2.so.0.11.3)
==3648== by 0x42C3212: (below main) (in /lib/libc-2.14.1.so)
Run valgrind with --track-origins=yes so it shows you where the leaked memory was allocated.
You might also want to use --leak-check=full and --leak-resolution=high (although the latter should be the default)
Related
I'm a new C++ coder and met a problem.
Please view the following code as an example:
#include <iostream>
#include <vector>
#include <thread>
class student{
public:
std::string name;
int id;
};
void foo(){
int k = 1;
std::cout<<"thread a"<<std::endl;
return;
}
void foo2(){
int k = 1;
std::cout<<"thread b"<<std::endl;
return;
}
void foo3(){
std::thread a(foo);
std::thread b(foo2);
a.detach();
b.detach();
return;
}
int main(){
foo3();
return 0;
}
That's an example code. I want two threads running independently and release memory after each one ends. I use valgrind to check memory leak. It shows an error like this:
==63346== Memcheck, a memory error detector
==63346== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==63346== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==63346== Command: ./a.out
==63346==
==63346==
==63346== HEAP SUMMARY:
==63346== in use at exit: 608 bytes in 4 blocks
==63346== total heap usage: 5 allocs, 1 frees, 73,312 bytes allocated
==63346==
==63346== 288 bytes in 1 blocks are possibly lost in loss record 3 of 4
==63346== at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==63346== by 0x40147D9: calloc (rtld-malloc.h:44)
==63346== by 0x40147D9: allocate_dtv (dl-tls.c:375)
==63346== by 0x40147D9: _dl_allocate_tls (dl-tls.c:634)
==63346== by 0x4B4D834: allocate_stack (allocatestack.c:430)
==63346== by 0x4B4D834: pthread_create##GLIBC_2.34 (pthread_create.c:647)
==63346== by 0x494A388: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==63346== by 0x1095B9: std::thread::thread<void (&)(), , void>(void (&)()) (in /home/alan/Avionics/test/a.out)
==63346== by 0x10935C: foo3() (in /home/alan/Avionics/test/a.out)
==63346== by 0x109400: main (in /home/alan/Avionics/test/a.out)
==63346==
==63346== 288 bytes in 1 blocks are possibly lost in loss record 4 of 4
==63346== at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==63346== by 0x40147D9: calloc (rtld-malloc.h:44)
==63346== by 0x40147D9: allocate_dtv (dl-tls.c:375)
==63346== by 0x40147D9: _dl_allocate_tls (dl-tls.c:634)
==63346== by 0x4B4D834: allocate_stack (allocatestack.c:430)
==63346== by 0x4B4D834: pthread_create##GLIBC_2.34 (pthread_create.c:647)
==63346== by 0x494A388: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
==63346== by 0x1095B9: std::thread::thread<void (&)(), , void>(void (&)()) (in /home/alan/Avionics/test/a.out)
==63346== by 0x109372: foo3() (in /home/alan/Avionics/test/a.out)
==63346== by 0x109400: main (in /home/alan/Avionics/test/a.out)
==63346==
==63346== LEAK SUMMARY:
==63346== definitely lost: 0 bytes in 0 blocks
==63346== indirectly lost: 0 bytes in 0 blocks
==63346== possibly lost: 576 bytes in 2 blocks
==63346== still reachable: 32 bytes in 2 blocks
==63346== suppressed: 0 bytes in 0 blocks
==63346== Reachable blocks (those to which a pointer was found) are not shown.
==63346== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==63346==
==63346== For lists of detected and suppressed errors, rerun with: -s
==63346== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
If i replace detach() by join(), there's no memory leak, I'm a little confused. Does anyone can give me some advice? Thanks a lot!
You need to make your main wait until the threads have finished running (or at least that they won't access any global objects after). If you don't make sure of that, not only will you have memory leaks, you may also have undefined behavior.
join does exactly make sure of that. The thread calling it will wait until the thread on which join is called finishes.
On the other hand detach is used to when you don't want to keep the std::thread object around to call join on it, while still having the thread function continue to run. If you detach a thread you need to use some other synchronization mechanism outside the join mechanism to make sure that main doesn't exit while the threads are still doing work (or at least accessing global objects).
There is rarely a need to detach a thread. Making it work is complicated. You don't need to do that.
Instead store the std::thread object somewhere and call join on it when you want to wait for your threads to end, at latest before main returns. That should be the default approach if you don't have a good reason to not use it. If you are a beginner, then you can forget about detach for now.
I'm testing c++17 shared_ptr to see how it handles array delete[], but it failed expectation.
First, c++17 document says shared_ptr<T[]> can handle delete[] properly.
http://eel.is/c++draft/util.smartptr.shared#const-5
Effects: When T is not an array type, constructs a shared_ptr object that owns the pointer p. Otherwise, constructs a shared_ptr that owns p and a deleter of an unspecified type that calls delete[] p.
And reset():
http://eel.is/c++draft/util.smartptr.shared#mod-3
Equivalent to shared_ptr(p).swap(*this).
It will transfer the specification-required custom delete. So from my understanding, pre-c++17 I have to write like this:
shared_ptr<int> t1(new int[7], default_delete<int[]>());
Now it knows when 1st parameter is array type, compiler will generate call to delete [], so that we no longer have to specify delete function explicitly. I had a quick test on Ubuntu20.04 with clang++13:
int main() {
shared_ptr<int> t1(new int[7], default_delete<int[]>());
return 0;
}
Then clang++ mytest.cpp && valgrind ./a.out, no problem. But if I change to:
int main() {
shared_ptr<int> t1(new int[7]);
return 0;
}
Then clang++ mytest.cpp -std=c++17 && valgrind ./a.out will print:
==16407== Command: ./a.out
==16407==
Father
1
==16407== Mismatched free() / delete / delete []
==16407== at 0x483CFBF: operator delete(void*) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16407== by 0x40450A: std::_Sp_counted_ptr<int*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (in /home/troskyv/a.out)
==16407== by 0x4030A2: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (in /home/troskyv/a.out)
==16407== by 0x403059: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (in /home/troskyv/a.out)
==16407== by 0x403998: std::__shared_ptr<int, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (in /home/troskyv/a.out)
==16407== by 0x4020C4: std::shared_ptr<int>::~shared_ptr() (in /home/troskyv/a.out)
==16407== by 0x40152E: main (in /home/troskyv/a.out)
==16407== Address 0x4db34c0 is 0 bytes inside a block of size 28 alloc'd
==16407== at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16407== by 0x4014F7: main (in /home/troskyv/a.out)
==16407==
==16407==
==16407== HEAP SUMMARY:
==16407== in use at exit: 0 bytes in 0 blocks
==16407== total heap usage: 15 allocs, 15 frees, 74,032 bytes allocated
==16407==
==16407== All heap blocks were freed -- no leaks are possible
==16407==
==16407== For lists of detected and suppressed errors, rerun with: -s
==16407== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
There's memory leak. So seems to me although I used -std=c++17 option, shared_ptr still cannot handle delete array automatically.
Where did this get wrong?
I see the answer is difference between shared_ptr<int> and shared_ptr<int[]>. Use of the latter one avoids memory leak.
Thanks, close this question!
I consistently get this trace shown by valgrind. This is an aarch64 system. I want to know if there is anything I can do within my limits to fix this problem, as explained below -
Invalid read of size 8 is at lh_delete by ERR_remove_thread_state (in libcrypto) by soap_free (in gsoap) ? There is no relation as far as I know between these two.
Invalid read by a function in libcrypto, attempts to read 8 bytes that has been freed again by libcrypto. Block itself was also allocated by libcrypto. I have been reading about issues with the version of libcrypto I have. https://curl.se/mail/lib-2016-08/0137.html. I don't think I will be able to upgrade the libcrypto package as that will affect lots of places within the codebase.
What can I do as an alternative ?
==15163== Invalid read of size 8
==15163== at 0x4B5931C: lh_delete (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x4B5CF5F: ??? (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x4B5DE53: ERR_remove_thread_state (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x5915BC7: soap_free (in /opt/MyC/lib/libjci_gsoap.so)
==15163== by 0x672DFF: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x616D3B: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x61AAD7: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x61B69B: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x61159B: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x60CB93: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x60E08B: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x60D6FF: ??? (in /opt/MyC/bin/MyProg)
==15163== Address 0x6e69b28 is 8 bytes inside a block of size 24 free'd
==15163== at 0x4849A00: free (vg_replace_malloc.c:538)
==15163== by 0x4AE3F0B: CRYPTO_free (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x4B59337: lh_delete (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x4B5CF5F: ??? (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x4B5DE53: ERR_remove_thread_state (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x50999B: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x50A473: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x50B437: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x5044CF: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x506433: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x50834F: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x5069B3: ??? (in /opt/MyC/bin/MyProg)
==15163== Block was alloc'd at
==15163== at 0x4848798: malloc (vg_replace_malloc.c:307)
==15163== by 0x4AE3BEB: CRYPTO_malloc (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x4B5928F: lh_insert (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x4B5CD23: ??? (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x4B5E017: ERR_get_state (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x4B5E46B: ERR_put_error (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x4B61B13: EVP_DecryptFinal_ex (in /usr/lib/libcrypto.so.1.0.0)
==15163== by 0x49CBCD3: users::User::decrypt(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /opt/MyC/lib/libuserdatabase.so)
==15163== by 0x49D19DB: users::User::authenticatePassword(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /opt/MyC/lib/libuserdatabase.so)
==15163== by 0x532D01F: Security::authenticate(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /opt/MyC/lib/libonvif_utils.so)
==15163== by 0x504437: ??? (in /opt/MyC/bin/MyProg)
==15163== by 0x506433: ??? (in /opt/MyC/bin/MyProg)
I've tried to change the code to do what I want in different ways but doesn't seem to fix that Valgrind error.
Cadena::Cadena(unsigned tam, char c):s_(new char[tam+1]), tam_(tam)
{
//c is ' ' by default
memset(s_, c, tam+1);
s_[tam]='\0';
}
...
Cadena& Cadena::substr(unsigned i, unsigned tam) const
{
if(i>=tam_||i+tam>tam_) throw out_of_range("Posicion indicada fuera de rango");
Cadena* subCad=new Cadena(tam);
strncpy(subCad->s_, &s_[i], tam);
return *subCad;
}
==9669== Invalid write of size 1
==9669== at 0x1390CC: Cadena::Cadena(unsigned int, char) (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x13972B: Cadena::substr(unsigned int, unsigned int) const (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x12D436: test_cadena(_fctkern_t*) (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x137D42: main (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== Address 0x105bc176f is not stack'd, malloc'd or (recently) free'd
==9669==
==9669==
==9669== Process terminating with default action of signal 11 (SIGSEGV)
==9669== Access not within mapped region at address 0x105BC176F
==9669== at 0x1390CC: Cadena::Cadena(unsigned int, char) (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x13972B: Cadena::substr(unsigned int, unsigned int) const (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x12D436: test_cadena(_fctkern_t*) (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== by 0x137D42: main (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==9669== If you believe this happened as a result of a stack
==9669== overflow in your program's main thread (unlikely but
==9669== possible), you can try to increase the size of the
==9669== main thread stack using the --main-stacksize= flag.
==9669== The main thread stack size used in this run was 8388608.
Another way:
Cadena& Cadena::substr(unsigned i, unsigned tam) const
{
if(i>=tam_||i+tam>tam_) throw out_of_range("Posicion indicada fuera de rango");
char res[tam+1];
strncpy(res, s_+i, tam);
res[tam]='\0';
Cadena* subCad=new Cadena(tam);
return *subCad;
}
==17029== Invalid write of size 1
==17029== at 0x4C3304C: strncpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17029== by 0x13979E: Cadena::substr(unsigned int, unsigned int) const (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==17029== Address 0x1fff001000 is not stack'd, malloc'd or (recently) free'd
==17029==
==17029==
==17029== Process terminating with default action of signal 11 (SIGSEGV)
==17029== Access not within mapped region at address 0x1FFF001000
==17029== at 0x4C3304C: strncpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17029== by 0x13979E: Cadena::substr(unsigned int, unsigned int) const (in /mnt/hgfs/mvpoosf/P1/test-P1-auto)
==17029== If you believe this happened as a result of a stack
==17029== overflow in your program's main thread (unlikely but
==17029== possible), you can try to increase the size of the
==17029== main thread stack using the --main-stacksize= flag.
==17029== The main thread stack size used in this run was 8388608.
I'm passing this test (test-P1-auto):
FCT_TEST_BGN(Cadena - Subcadena: tamanno mayor que longitud restante) {
const Cadena a("0123456789");
fct_chk_ex(out_of_range&, a.substr(9, 2));
}
FCT_TEST_END();
It returns a substring of two elements following the number 8. It's not possible as it throws out_of_range, so the test is OK. But when I use Valgrind, it's giving me those errors and I've been stuck here for hours.
Private part of my class Cadena:
private:
char* s_;
unsigned int tam_;
Sorry for the mistake guys, but as #Some programmer dude commented I didn't put the flag -g on my makefile that allows valgrind to tell me wich lines make the errors. Actually that wasn't the right test, it was the next one:
FCT_TEST_BGN(Cadena - Subcadena: tamanno negativo) {
const Cadena a("0123456789");
fct_chk_ex(out_of_range&, a.substr(9, -1));
}
FCT_TEST_END();
As I can see here Signed to unsigned conversion in C - is it always safe?, there's no way to get a negative value as unsigned and expect the sign "just to be removed". I solved it by changing it to int and checking inside the function if it's negative.
Thanks everyone for your help.
I've been using Valgrind to look for memory leaks in my code, and while no memory leaks are being found, some errors are reported all of them originating at a single function/class method:
==17043== ERROR SUMMARY: 10100 errors from 3 contexts (suppressed: 0 from 0)
==17043==
==17043== 100 errors in context 1 of 3:
==17043== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==17043== at 0x5441DA2: send (send.c:28)
==17043== by 0x404C2D: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x404F1C: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x401F2A: main (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== Address 0x7feffff61 is on thread 1's stack
==17043== Uninitialised value was created by a stack allocation
==17043== at 0x404BE6: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==
==17043==
==17043== 100 errors in context 2 of 3:
==17043== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==17043== at 0x5441DA2: send (send.c:28)
==17043== by 0x404C2D: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x404E8A: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x401F2A: main (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== Address 0x7feffff61 is on thread 1's stack
==17043== Uninitialised value was created by a stack allocation
==17043== at 0x404BE6: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==
==17043==
==17043== 9900 errors in context 3 of 3:
==17043== Syscall param socketcall.sendto(msg) points to uninitialised byte(s)
==17043== at 0x5441DA2: send (send.c:28)
==17043== by 0x404C2D: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x404EE8: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== by 0x401F2A: main (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043== Address 0x7feffff61 is on thread 1's stack
==17043== Uninitialised value was created by a stack allocation
==17043== at 0x404BE6: unix_socket::sendMsg(char, double) (in /home/joao/CloudPT/Bolsa/Webots/controllers/darwin-pi2/client)
==17043==
==17043== ERROR SUMMARY: 10100 errors from 3 contexts (suppressed: 0 from 0)
The sendMsg(const char _type, const double _value), that the errors are pointing at, is part of unix_socket class:
//...
typedef struct{
char type;
double value;
} MESSAGE;
//...
int unix_socket::sendMsg(const char _type, const double _value){
MESSAGE msg;
msg.type=_type;
msg.value=_value;
int n = send(client_sock, &msg, sizeof(msg), 0);
if (n < 0) {
perror("send");
return -1;
}
c_sent=msg.type;
v_sent=msg.value;
return 0;
}
I don't see what is the problem. Where exactly are the uninitialized values? Or should I just ignore the errors reported by Valgrind?
Look at the MESSAGE struct:
typedef struct{
char type;
double value;
} MESSAGE;
Due to data structure alignment, value's address may be forced to align to address of a multiple of word size. Therefore, several unused bytes is padded between MESSAGE::type and MESSAGE::value. Those are the bytes which weren't initialized and thus reported by Valgrind.
As a workaround, you could force initializing the whole struct by memset().
MESSAGE msg;
memset(&msg, 0, sizeof(MESSAGE));
msg.type=_type;
msg.value=_value;
Although #timrau has described quite correctly what the core problem is here (alignment/packing), I'm not a fan of the proposed solution.
You have described a MESSAGE in your code as consisting of a char and a double. The size of the actual data structure in memory however is not sizeof(char) + sizeof(double), and that is the core problem.
The proposed solution suggests simply clearing out all of the bits of the MESSAGE structure before filling in the important bits. The problem I have with that is both a semantic one a technical one -- the size of the data structure sent down the wire is not an accurate representation of what you modeled in the code. In other words, you're not just sending a char and a double -- you're sending a char, a double and some other cruft (padding).
My suggestion is to get rid of the cruft and send only what you modeled in your code.
There is no direct support in C++ to turn off alignment and padding, but all compilers I'm aware of provide a simple mechanism to align data structures to N bytes:
#pragma pack (push, 1)
typedef struct{
char type;
double value;
} MESSAGE;
#pragma pack (pop)
This will make the MESSAGE data structure exactly what you've modeled in your code, with no padding. Doing this makes the memset unnecesarry, and you'll send exactly sizeof(char) + sizeof(double) bytes down the wire.