Details
-
Bug
-
Status: Closed
-
Critical
-
Resolution: Fixed
-
proton-c-0.18.0
-
None
Description
ssl_client_options probably cannot be self-assigned. See the attached report from clang-analyzer, which looks very plausible.
The problem is that assuming x == *this, the assignment operator will decref and then incref the same value. Assuming the reference count was 1 to start with, there will be use-after-free.
This probably does not matter that much in real-world code, but I found some quotations that making self assignment work is really important in C++...
58 ssl_domain& internal::ssl_domain::operator=(const ssl_domain&x) { 59 if (impl_) impl_->decref(); 60 impl_ = x.impl_; 61 server_type_ = x.server_type_; 62 if (impl_) impl_->incref(); 63 return *this; 64 }
I believe the static analyzer is correct, because when I do not make any changes to the examples/cpp/ssl example, Valgrind does not report errors concerning the class, but if I add a ssl_cli = ssl_cli;, then I get
$ valgrind ./ssl -c /home/jdanek/Work/repos/qpid-proton/examples/cpp/ssl_certs/ ==4950== Memcheck, a memory error detector ==4950== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==4950== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info ==4950== Command: ./ssl -c /home/jdanek/Work/repos/qpid-proton/examples/cpp/ssl_certs/ ==4950== ==4950== Invalid read of size 4 ==4950== at 0x4E715CC: incref (ssl_domain.cpp:37) ==4950== by 0x4E715CC: proton::internal::ssl_domain::operator=(proton::internal::ssl_domain const&) (ssl_domain.cpp:62) ==4950== by 0x4032F0: operator= (ssl.hpp:172) ==4950== by 0x4032F0: main (ssl.cpp:176) ==4950== Address 0x766a3c0 is 0 bytes inside a block of size 16 free'd ==4950== at 0x4C2D2EB: operator delete(void*) (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x4E715FA: decref (ssl_domain.cpp:40) ==4950== by 0x4E715FA: proton::internal::ssl_domain::operator=(proton::internal::ssl_domain const&) (ssl_domain.cpp:59) ==4950== by 0x4032F0: operator= (ssl.hpp:172) ==4950== by 0x4032F0: main (ssl.cpp:176) ==4950== Block was alloc'd at ==4950== at 0x4C2C22F: operator new(unsigned long) (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x4E7166C: proton::internal::ssl_domain::pn_domain() (ssl_domain.cpp:72) ==4950== by 0x4E7195C: proton::ssl_client_options::ssl_client_options(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, proton::ssl::verify_mode) (ssl_domain.cpp:120) ==4950== by 0x4032B9: main (ssl.cpp:175) ==4950== ==4950== Invalid read of size 4 ==4950== at 0x4E71619: decref (ssl_domain.cpp:39) ==4950== by 0x4E71619: proton::internal::ssl_domain::~ssl_domain() (ssl_domain.cpp:66) ==4950== by 0x4032F8: ~ssl_client_options (ssl.hpp:172) ==4950== by 0x4032F8: main (ssl.cpp:175) ==4950== Address 0x766a3c0 is 0 bytes inside a block of size 16 free'd ==4950== at 0x4C2D2EB: operator delete(void*) (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x4E715FA: decref (ssl_domain.cpp:40) ==4950== by 0x4E715FA: proton::internal::ssl_domain::operator=(proton::internal::ssl_domain const&) (ssl_domain.cpp:59) ==4950== by 0x4032F0: operator= (ssl.hpp:172) ==4950== by 0x4032F0: main (ssl.cpp:176) ==4950== Block was alloc'd at ==4950== at 0x4C2C22F: operator new(unsigned long) (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x4E7166C: proton::internal::ssl_domain::pn_domain() (ssl_domain.cpp:72) ==4950== by 0x4E7195C: proton::ssl_client_options::ssl_client_options(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, proton::ssl::verify_mode) (ssl_domain.cpp:120) ==4950== by 0x4032B9: main (ssl.cpp:175) ==4950== ==4950== Invalid read of size 8 ==4950== at 0x4E71620: ~ssl_domain_impl (ssl_domain.cpp:36) ==4950== by 0x4E71620: decref (ssl_domain.cpp:40) ==4950== by 0x4E71620: proton::internal::ssl_domain::~ssl_domain() (ssl_domain.cpp:66) ==4950== by 0x4032F8: ~ssl_client_options (ssl.hpp:172) ==4950== by 0x4032F8: main (ssl.cpp:175) ==4950== Address 0x766a3c8 is 8 bytes inside a block of size 16 free'd ==4950== at 0x4C2D2EB: operator delete(void*) (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x4E715FA: decref (ssl_domain.cpp:40) ==4950== by 0x4E715FA: proton::internal::ssl_domain::operator=(proton::internal::ssl_domain const&) (ssl_domain.cpp:59) ==4950== by 0x4032F0: operator= (ssl.hpp:172) ==4950== by 0x4032F0: main (ssl.cpp:176) ==4950== Block was alloc'd at ==4950== at 0x4C2C22F: operator new(unsigned long) (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x4E7166C: proton::internal::ssl_domain::pn_domain() (ssl_domain.cpp:72) ==4950== by 0x4E7195C: proton::ssl_client_options::ssl_client_options(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, proton::ssl::verify_mode) (ssl_domain.cpp:120) ==4950== by 0x4032B9: main (ssl.cpp:175) ==4950== ==4950== Invalid read of size 4 ==4950== at 0x52B8840: pn_ssl_domain_free (openssl.c:559) ==4950== by 0x4E71628: ~ssl_domain_impl (ssl_domain.cpp:36) ==4950== by 0x4E71628: decref (ssl_domain.cpp:40) ==4950== by 0x4E71628: proton::internal::ssl_domain::~ssl_domain() (ssl_domain.cpp:66) ==4950== by 0x4032F8: ~ssl_client_options (ssl.hpp:172) ==4950== by 0x4032F8: main (ssl.cpp:175) ==4950== Address 0x76c1c08 is 24 bytes inside a block of size 40 free'd ==4950== at 0x4C2CDEB: free (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x4E715ED: ~ssl_domain_impl (ssl_domain.cpp:36) ==4950== by 0x4E715ED: decref (ssl_domain.cpp:40) ==4950== by 0x4E715ED: proton::internal::ssl_domain::operator=(proton::internal::ssl_domain const&) (ssl_domain.cpp:59) ==4950== by 0x4032F0: operator= (ssl.hpp:172) ==4950== by 0x4032F0: main (ssl.cpp:176) ==4950== Block was alloc'd at ==4950== at 0x4C2DBD5: calloc (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x52B8C26: pn_ssl_domain (openssl.c:490) ==4950== by 0x4E71BB9: proton::ssl_domain_impl::ssl_domain_impl(bool) (ssl_domain.cpp:33) ==4950== by 0x4E7167B: proton::internal::ssl_domain::pn_domain() (ssl_domain.cpp:72) ==4950== by 0x4E7195C: proton::ssl_client_options::ssl_client_options(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, proton::ssl::verify_mode) (ssl_domain.cpp:120) ==4950== by 0x4032B9: main (ssl.cpp:175) ==4950== ==4950== Invalid free() / delete / delete[] / realloc() ==4950== at 0x4C2D2EB: operator delete(void*) (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x4032F8: ~ssl_client_options (ssl.hpp:172) ==4950== by 0x4032F8: main (ssl.cpp:175) ==4950== Address 0x766a3c0 is 0 bytes inside a block of size 16 free'd ==4950== at 0x4C2D2EB: operator delete(void*) (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x4E715FA: decref (ssl_domain.cpp:40) ==4950== by 0x4E715FA: proton::internal::ssl_domain::operator=(proton::internal::ssl_domain const&) (ssl_domain.cpp:59) ==4950== by 0x4032F0: operator= (ssl.hpp:172) ==4950== by 0x4032F0: main (ssl.cpp:176) ==4950== Block was alloc'd at ==4950== at 0x4C2C22F: operator new(unsigned long) (in /nix/store/gv9x2j31hvn0wf37h4jmb9xz6vgc3vvv-valgrind-3.12.0/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4950== by 0x4E7166C: proton::internal::ssl_domain::pn_domain() (ssl_domain.cpp:72) ==4950== by 0x4E7195C: proton::ssl_client_options::ssl_client_options(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, proton::ssl::verify_mode) (ssl_domain.cpp:120) ==4950== by 0x4032B9: main (ssl.cpp:175) ==4950== ==4950== ==4950== HEAP SUMMARY: ==4950== in use at exit: 98,536 bytes in 3,275 blocks ==4950== total heap usage: 3,651 allocs, 377 frees, 237,715 bytes allocated ==4950== ==4950== LEAK SUMMARY: ==4950== definitely lost: 0 bytes in 0 blocks ==4950== indirectly lost: 0 bytes in 0 blocks ==4950== possibly lost: 0 bytes in 0 blocks ==4950== still reachable: 98,536 bytes in 3,275 blocks ==4950== suppressed: 0 bytes in 0 blocks ==4950== Rerun with --leak-check=full to see details of leaked memory ==4950== ==4950== For counts of detected and suppressed errors, rerun with: -v ==4950== ERROR SUMMARY: 8 errors from 5 contexts (suppressed: 0 from 0)
Hat tip to rkubis for help with C++.