valgrind shows memory leak in vector constructor - c++

I am writing a compiler using bison and C++, and I just checked memory leak with Valgrind. While it shows there's memory leak caused by vector constructor shown below:
==6562== HEAP SUMMARY:
==6562== in use at exit: 90,298 bytes in 27 blocks
==6562== total heap usage: 125 allocs, 98 frees, 100,782 bytes allocated
==6562==
==6562== 80 (32 direct, 48 indirect) bytes in 1 blocks are definitely lost in loss record 19 of 22
==6562== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6562== by 0x40DB9B: __gnu_cxx::new_allocator<std::shared_ptr<Node> >::allocate(unsigned long, void const*) (new_allocator.h:104)
==6562== by 0x40D3B9: std::allocator_traits<std::allocator<std::shared_ptr<Node> > >::allocate(std::allocator<std::shared_ptr<Node> >&, unsigned long) (alloc_traits.h:491)
==6562== by 0x40C465: std::_Vector_base<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > >::_M_allocate(unsigned long) (stl_vector.h:170)
==6562== by 0x41C170: std::_Vector_base<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > >::_M_create_storage(unsigned long) (stl_vector.h:185)
==6562== by 0x41ADB6: std::_Vector_base<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > >::_Vector_base(unsigned long, std::allocator<std::shared_ptr<Node> > const&) (stl_vector.h:136)
==6562== by 0x41A13F: std::vector<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > >::vector(std::vector<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > > const&) (stl_vector.h:320)
==6562== by 0x417ECF: OprNode::OprNode(int, std::vector<std::shared_ptr<Node>, std::allocator<std::shared_ptr<Node> > > const&) (Node.cpp:52)
==6562== by 0x406C7B: opr(int, std::vector<Node*, std::allocator<Node*> > const&) (parser.y:175)
==6562== by 0x40555B: yyparse() (parser.y:125)
==6562== by 0x40748B: main (parser.y:253)
==6562==
==6562== LEAK SUMMARY:
==6562== definitely lost: 32 bytes in 1 blocks
==6562== indirectly lost: 48 bytes in 2 blocks
==6562== possibly lost: 0 bytes in 0 blocks
==6562== still reachable: 90,218 bytes in 24 blocks
==6562== suppressed: 0 bytes in 0 blocks
==6562== Reachable blocks (those to which a pointer was found) are not shown.
==6562== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==6562==
==6562== For counts of detected and suppressed errors, rerun with: -v
==6562== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Relevant code:
class Node {
public:
Node()=default;
virtual void ex(int, int, int) const = 0;
virtual void check(vector<int>&, int) const = 0;
};
class OprNode:public Node {
public:
OprNode(int, const vector<shared_ptr<Node>>&);
void ex(int, int, int) const;
void check(vector<int>&, int) const;
private:
int oper;
vector<shared_ptr<Node>> op;
};
OprNode::OprNode(int oper, const vector<shared_ptr<Node> >& op):oper(oper), op(op) {;}
Node * opr(int oper, const vector<Node *>& op) {
auto v = vector<shared_ptr<Node> >();
for (const auto i: op) {
v.push_back(shared_ptr<Node>(i));
}
return new OprNode(oper, v);
}
Due to the limitation of bison, I must use raw pointer as the return type and content of vector passed into opr.
Thanks a lot!

Related

valgrind detects errors when c++ exception is not caught

I notice that the valgrind reports possible memory leak for the following minimal example:
#include <stdexcept>
int main() {
try {
throw std::logic_error("test");
}
catch (std::exception& e) {
std::string msg("test2 ");
msg.append(e.what());
throw std::logic_error(msg);
}
return 0;
}
After compiling it with g++ test.cpp -g, the valgrind detects some errors with valgrind --tool=memcheck --leak-check=full ./a.out. Is this normal?
I concern this issue because the valgrind reports some errors of my R extensions which is similar to this example.
The valgrind version is: 3.10.0.SVN. The gcc version is 4.8.2 (Ubuntu 4.8.2-19ubuntu1). The reported message is shown below:
==8640== Memcheck, a memory error detector
==8640== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==8640== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==8640== Command: ./a.out
==8640==
terminate called after throwing an instance of 'std::logic_error'
what(): test2 test
==8640==
==8640== HEAP SUMMARY:
==8640== in use at exit: 354 bytes in 4 blocks
==8640== total heap usage: 6 allocs, 2 frees, 417 bytes allocated
==8640==
==8640== 29 bytes in 1 blocks are possibly lost in loss record 1 of 4
==8640== at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8640== by 0x4EF13B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x4EF2AE0: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x4EF2EF7: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x400BA7: main (test.cpp:4)
==8640==
==8640== 37 bytes in 1 blocks are possibly lost in loss record 2 of 4
==8640== at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8640== by 0x4EF13B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x4EF1F7A: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x4EF2013: std::string::reserve(unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x4EF225E: std::string::append(char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x400CC6: main (test.cpp:8)
==8640==
==8640== 144 bytes in 1 blocks are possibly lost in loss record 3 of 4
==8640== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8640== by 0x4E944E2: __cxa_allocate_exception (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x400B83: main (test.cpp:4)
==8640==
==8640== 144 bytes in 1 blocks are possibly lost in loss record 4 of 4
==8640== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8640== by 0x4E944E2: __cxa_allocate_exception (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==8640== by 0x400CD0: main (in /home/wush/Test/a.out)
==8640==
==8640== LEAK SUMMARY:
==8640== definitely lost: 0 bytes in 0 blocks
==8640== indirectly lost: 0 bytes in 0 blocks
==8640== possibly lost: 354 bytes in 4 blocks
==8640== still reachable: 0 bytes in 0 blocks
==8640== suppressed: 0 bytes in 0 blocks
==8640==
==8640== For counts of detected and suppressed errors, rerun with: -v
==8640== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 1 from 1)
Aborted (core dumped)

Matrix template, memory leak

I code a simple program to apply a complex function (z,exp(z),...) to a pgm image and return the result. The program is working and does what it should do. However, there are 11 memory leaks that I'm not been able to work out. My guess is that the trouble is in the matrix template container I code and its constructors and destructor.
To debug I'm using valgrind and the program has been written in c++.
The result of running valgrind is the following:
==7690== Memcheck, a memory error detector
==7690== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7690== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==7690== Command: ./tp0 -i f14.pgm -f z -o ff14.pgm
==7690==
==7690==
==7690== HEAP SUMMARY:
==7690== in use at exit: 160 bytes in 11 blocks
==7690== total heap usage: 45 allocs, 34 frees, 18,357 bytes allocated
==7690==
==7690== 8 bytes in 1 blocks are still reachable in loss record 1 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x404871: Matrix<Pixel>::Matrix(unsigned int, unsigned int) (matrix.hpp:44)
==7690== by 0x404471: PGMImage::PGMImage(unsigned int, unsigned int) (pgm_image.cpp:14)
==7690== by 0x405475: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690== by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690== by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690== by 0x404212: main (main.cpp:52)
==7690==
==7690== 8 bytes in 1 blocks are still reachable in loss record 2 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x403703: Matrix<Complex>::Matrix(unsigned int, unsigned int) (matrix.hpp:44)
==7690== by 0x4024A5: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:49)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 8 bytes in 1 blocks are still reachable in loss record 3 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x4049C9: Matrix<Pixel>::Matrix(Matrix<Pixel> const&) (matrix.hpp:56)
==7690== by 0x404579: PGMImage::PGMImage(PGMImage const&) (pgm_image.cpp:31)
==7690== by 0x4024DD: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 12 bytes in 1 blocks are still reachable in loss record 4 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x4048B4: Matrix<Pixel>::Matrix(unsigned int, unsigned int) (matrix.hpp:46)
==7690== by 0x404471: PGMImage::PGMImage(unsigned int, unsigned int) (pgm_image.cpp:14)
==7690== by 0x405475: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690== by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690== by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690== by 0x404212: main (main.cpp:52)
==7690==
==7690== 12 bytes in 1 blocks are still reachable in loss record 5 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x404A15: Matrix<Pixel>::Matrix(Matrix<Pixel> const&) (matrix.hpp:59)
==7690== by 0x404579: PGMImage::PGMImage(PGMImage const&) (pgm_image.cpp:31)
==7690== by 0x4024DD: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 16 bytes in 1 blocks are still reachable in loss record 6 of 11
==7690== at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690== by 0x40445E: PGMImage::PGMImage(unsigned int, unsigned int) (pgm_image.cpp:14)
==7690== by 0x405475: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690== by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690== by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690== by 0x404212: main (main.cpp:52)
==7690==
==7690== 16 bytes in 1 blocks are still reachable in loss record 7 of 11
==7690== at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690== by 0x40248A: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:49)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 16 bytes in 1 blocks are still reachable in loss record 8 of 11
==7690== at 0x4C298A0: operator new[](unsigned long) (vg_replace_malloc.c:389)
==7690== by 0x403740: Matrix<Complex>::Matrix(unsigned int, unsigned int) (matrix.hpp:46)
==7690== by 0x4024A5: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:49)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 16 bytes in 1 blocks are still reachable in loss record 9 of 11
==7690== at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690== by 0x404564: PGMImage::PGMImage(PGMImage const&) (pgm_image.cpp:31)
==7690== by 0x4024DD: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== 24 bytes in 1 blocks are still reachable in loss record 10 of 11
==7690== at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690== by 0x405464: PGMParser::set_pgm_dimensions(std::vector<int, std::allocator<int> >) (pgm_parser.cpp:147)
==7690== by 0x4050CD: PGMParser::get_pgm() (pgm_parser.cpp:94)
==7690== by 0x404D67: PGMParser::PGMParser(std::string const&) (pgm_parser.cpp:25)
==7690== by 0x404212: main (main.cpp:52)
==7690==
==7690== 24 bytes in 1 blocks are still reachable in loss record 11 of 11
==7690== at 0x4C29180: operator new(unsigned long) (vg_replace_malloc.c:324)
==7690== by 0x4024CB: PGMTransformation::PGMTransformation(PGMImage const&, std::string const&) (PGMTransformation.cpp:57)
==7690== by 0x404240: main (main.cpp:55)
==7690==
==7690== LEAK SUMMARY:
==7690== definitely lost: 0 bytes in 0 blocks
==7690== indirectly lost: 0 bytes in 0 blocks
==7690== possibly lost: 0 bytes in 0 blocks
==7690== still reachable: 160 bytes in 11 blocks
==7690== suppressed: 0 bytes in 0 blocks
==7690==
==7690== For counts of detected and suppressed errors, rerun with: -v
==7690== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
The part of code I think is crashing of matrix template is the following:
template<typename T>
class Matrix
{
private:
T** matrix_;
unsigned int rows_;
unsigned int cols_;
public:
Matrix();
Matrix(unsigned int, unsigned int);
Matrix(Matrix const &);
~Matrix();
Matrix const &operator=(Matrix const &);
//more methods...
};
template<typename T>
Matrix<T>::Matrix()
: matrix_(0), rows_(0), cols_(0) {}
template<typename T>
Matrix<T>::Matrix(unsigned int rows, unsigned int cols)
{
matrix_ = new T*[rows];
for(unsigned int i=0; i < rows; i++)
matrix_[i] = new T[cols];
rows_ = rows;
cols_ = cols;
}
template<typename T>
Matrix<T>::Matrix(Matrix<T> const & m_orig)
{
rows_ = m_orig.rows_;
cols_ = m_orig.cols_;
matrix_ = new T*[rows_];
for(unsigned int i=0; i < rows_; i++)
{
matrix_[i] = new T[cols_];
for(unsigned int j=0; j < cols_; j++)
matrix_[i][j]=m_orig.matrix_[i][j];
}
}
template<typename T>
Matrix<T>::~Matrix()
{
for(unsigned int i=0; i < rows_; i++)
delete matrix_[i];
delete []matrix_;
rows_ = 0;
cols_ = 0;
}
template<typename T>
Matrix<T> const & Matrix<T>::operator=(Matrix const & m_orig)
{
if(this != &m_orig)
{
for(unsigned int k=0; k < rows_; k++)
delete matrix_[k];
delete matrix_;
rows_ = m_orig.rows_;
cols_ = m_orig.cols_;
matrix_ = new T*[rows_];
for(unsigned int i=0; i < rows_; i++)
{
matrix_[i] = new T[cols_];
for(unsigned int j=0; j < cols_; j++)
matrix_[i][j]=m_orig.matrix_[i][j];
}
}
return *this;
}
There are other classes that could fail, but valgrind tracks almost every leak to the matrix container.
Your help is greatly appreciated!
You should follow the same "pattern" for deallocation with delete as you do for allocation with new,
for(unsigned int i=0; i < rows_; i++)
delete [] matrix_[i];
// ~~ notice []
delete []matrix_;
Your assignment operator is not exception-safe and fails to use the correct version of delete: it releases the memory using delete matrix_ rather than delete[] matrix_. Given the current implementation you are much better off replacing it by this version:
template <typename T>
Matrix<T> const& Matrix<T>::operator= (Matrix<T> orig) {
this->swap(orig);
return *this;
}
template <typename T>
void Matrix<T>::swap(Matrix<T>& other) {
using std::swap;
swap(this->matrix_, other.matrix_);
}
Aside from fixing the memory issues noted above, it also makes the implementation strong exception safe. Of course, doing so assumes that the copy constructor, destructor, and swap() are correctly implemented as they are leveraged to implement this assignment operator:
A copy of the original is made to create the argument (which may be elided: since a copy is made anyway taking the argument by value rather than be const& can reduce the number of copies).
The argument the left hand side are exchanged, making the left hand side the same as the original argument while the argument now contain the original left hand side state ready to be released.
The argument is destroyed, releasing the original left hand side state.
The destructor is also incorrect: it uses delete matrix_[k] instead of delete[] matrix_[k]. Conventionally objects are destroyed in the opposite order of construction while your code destroys objects in the opposite order. I'd recommend using std::vector<std::vector<T>> to maintain the data inside the Matrix<T>, too.

Valgrind identifies memory leaks when using string-type member (compiling with nvcc)

I'm not sure if it's a bug or not, but when I use string-type members inside structures or classes, valgrind identifies memory leaks. I've tried to build a simple code based on my own application, I'm sorry if it is still big...
// ====================================================================
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
// ====================================================================
string int2str(const int &i) {
return static_cast<ostringstream*>(
&(ostringstream() << i))->str();
}
// ====================================================================
class P;
// ====================================================================
struct Node {
virtual char isType() const = 0;
};
// ====================================================================
struct X : Node {
string st;
int id;
X(const string &_st, const int &_id);
char isType() const { return 'x'; };
// Those member functions are after class P declaration:
P use_as_P();
P use_as_P(const P &arg0);
P use_as_P(const P &arg0, const P &arg1);
};
X::X(const string &_st, const int &_id) : st(_st), id(_id) { }
// ====================================================================
class P {
friend struct X;
private:
Node *node;
vector<P> children;
public:
P() : node(NULL) {};
P(const P &source);
void swap(P &other);
string print_this();
~P();
};
P::P(const P &source) {
this->children = source.children;
switch(source.node->isType()) {
case 'x':
this->node = new X(static_cast<X*>(source.node)->st,
static_cast<X*>(source.node)->id);
break;
}
}
void P::swap(P &other) {
std::swap(this->node, other.node);
std::swap(this->children, other.children);
}
string P::print_this() {
string msg = "( ";
msg += static_cast<X*>(this->node)->st;
msg += int2str(static_cast<X*>(this->node)->id);
msg += " ";
for(size_t i = 0; i < this->children.size(); i++)
msg += children.at(i).print_this();
msg += ") ";
return msg;
}
P::~P() {
if(this->node != NULL)
delete node;
this->children.clear();
}
// ====================================================================
P X::use_as_P() {
P ast_aux;
ast_aux.node = new X(this->st,this->id);
return ast_aux;
}
P X::use_as_P(const P &arg0) {
P ast_aux;
ast_aux.node = new X(this->st,this->id);
ast_aux.children.push_back(arg0);
return ast_aux;
}
P X::use_as_P(const P &arg0, const P &arg1) {
P ast_aux;
ast_aux.node = new X(this->st,this->id);
ast_aux.children.push_back(arg0);
ast_aux.children.push_back(arg1);
return ast_aux;
}
// ====================================================================
// ** MAIN **
// ====================================================================
int main(int argc, char **argv)
{
X a("how",0), b("what",1), c("why",2), d("when",3);
P testing = a.use_as_P(b.use_as_P(c.use_as_P()),d.use_as_P());
cout << testing.print_this() << endl;
return 0;
}
// ====================================================================
Compiling with:
nvcc -arch sm_20 -o LEAK_test_with_string LEAK_test_with_string.cu
And here goes the valgrind's analysis:
==5877== Memcheck, a memory error detector
==5877== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5877== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5877== Command: ./LEAK_test_with_string
==5877==
( how0 ( what1 ( why2 ) ) ( when3 ) )
==5877==
==5877== HEAP SUMMARY:
==5877== in use at exit: 114 bytes in 4 blocks
==5877== total heap usage: 47 allocs, 43 frees, 3,701 bytes allocated
==5877==
==5877== 28 bytes in 1 blocks are definitely lost in loss record 1 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x403691: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877== : st(_st), id(_id) {}
==5877== 28 bytes in 1 blocks are definitely lost in loss record 2 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x40375A: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877==
==5877== 29 bytes in 1 blocks are definitely lost in loss record 3 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x4036F7: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877==
==5877== 29 bytes in 1 blocks are definitely lost in loss record 4 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x4037BD: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877==
==5877== LEAK SUMMARY:
==5877== definitely lost: 114 bytes in 4 blocks
==5877== indirectly lost: 0 bytes in 0 blocks
==5877== possibly lost: 0 bytes in 0 blocks
==5877== still reachable: 0 bytes in 0 blocks
==5877== suppressed: 0 bytes in 0 blocks
==5877==
==5877== For counts of detected and suppressed errors, rerun with: -v
==5877== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 2 from 2)
The "it's a bug" wondering comes when I change the C++ string member into a plain C char* member. One just need to change this part of the above written code:
// ====================================================================
struct X : Node {
char st[6]; // <=============== HERE!
int id;
X(const string &_st, const int &_id);
char isType() const { return 'x'; };
// Those member functions are after class P declaration:
P use_as_P();
P use_as_P(const P &arg0);
P use_as_P(const P &arg0, const P &arg1);
};
X::X(const string &_st, const int &_id) : id(_id) { // <=============== HERE!
strcpy(st, _st.c_str()); // <=============== HERE!
}
// ====================================================================
Note that I still use string in my code, but now there isn't any string member declared. This way, valgrind doesn't complain anymore:
==5977== Memcheck, a memory error detector
==5977== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5977== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5977== Command: ./LEAK_test_without_string
==5977==
( how0 ( what1 ( why2 ) ) ( when3 ) )
==5977==
==5977== HEAP SUMMARY:
==5977== in use at exit: 0 bytes in 0 blocks
==5977== total heap usage: 57 allocs, 57 frees, 3,986 bytes allocated
==5977==
==5977== All heap blocks were freed -- no leaks are possible
==5977==
==5977== For counts of detected and suppressed errors, rerun with: -v
==5977== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Does anybody have an insight on this? I mean, is this a bug that should be reported or is there something that I'm actually missing in my string-version code?
Since no one's bitten the bullet I'll expand my comment: Your Node class does not have a virtual destructor, this makes the following line
delete node;
invoke undefined behaviour - this will only call the destructor for Node, the destructor for X is never called.
The solution is simple, provide a virtual destructor for Node:
struct Node {
virtual char isType() const = 0;
virtual ~Node() =default;
// or virtual ~Node(){} if your compiler does not support defaulted functions.
}
You can now safely delete base pointers of Node that point to inherited classes.
The reason for the memory leak when using a std::string is because when you delete the base pointer node, the destructor for X is not called, and so neither is the destructor for st. The char array version doesn't leak because node points to a simple block of memory, and X in this case doesn't have any complex members that require destruction, so delete node luckily releases all of the memory allocated for X and its members. Remember that this is undefined behaviour however and the compiler can legitimately do whatever it wants to.
If you have a base class with even a single virtual function, always add a virtual destructor. You can make a case for omitting a virtual destructor if you are absolutely sure you won't be deleting inherited classes using a pointer to the base class, but it's safer to just add one anyway just in case (the gcc compiler flag -Weffc++ will also tell you as much).

getline() valgrind memory leak

I am getting a memory leak with getline, and I am not sure why or how to stop it.
Here is the report from valgrind:
==26681==
==26681== HEAP SUMMARY:
==26681== in use at exit: 1,756 bytes in 73 blocks
==26681== total heap usage: 223 allocs, 150 frees, 15,523 bytes allocated
==26681==
==26681== 28 bytes in 1 blocks are possibly lost in loss record 1 of 4
==26681== at 0x4A075BC: operator new(unsigned long) (vg_replace_malloc.c:298)
==26681== by 0x4CCC4B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (new_allocator.h:94)
==26681== by 0x4CCD227: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (basic_string.tcc:631)
==26681== by 0x4CCD30F: std::string::reserve(unsigned long) (basic_string.tcc:512)
==26681== by 0x4CCD5D4: std::string::append(char const*, unsigned long) (basic_string.tcc:310)
==26681== by 0x4C86384: std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) (istream.cc:397)
==26681== by 0x4026ED: main (test.cpp:210)
==26681==
==26681== LEAK SUMMARY:
==26681== definitely lost: 0 bytes in 0 blocks
==26681== indirectly lost: 0 bytes in 0 blocks
==26681== possibly lost: 28 bytes in 1 blocks
==26681== still reachable: 1,728 bytes in 72 blocks
==26681== suppressed: 0 bytes in 0 blocks
==26681== Reachable blocks (those to which a pointer was found) are not shown.
==26681== To see them, rerun with: --leak-check=full --show-reachable=yes
==26681==
==26681== For counts of detected and suppressed errors, rerun with: -v
==26681== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)
Here is line 210 of test.cpp
bool pending = getline(inputfile, line);
Some more lines:
string line;
bool pending = getline(inputfile, line);
int round = readOption(inputfile);
int num = readOption(inputfile);
I think it has something to do with when getline fails, and because line is a string it somehow never deallocates that memory. How do I prevent this?
readOption also uses getline but I think it has no memory leaks because string line is defined locally and then goes out of scope, effectively cleaning the memory?
Edit 1:
I have "solved" the issue by making a dummy function :
bool getnewline(ifstream &inputfile) {
string line;
return getline(inputfile, line);
}
However it seems stupid to do this, I am not sure why valgrind is complaining if there is no leak. I am still after a better/clean solution to this issue.
When you exit a C++ program by calling the exit() function, the object destructors are not run. This can result in Valgrind reporting memory leaks.
I know this is almost a year old but I came upon this answer looking specifically for a getline() memory leak issue and want to give minimum instructions on how I was able to reproduce this specific issue, as I think it just comes from defining a std::string variable and not exiting cleanly from the program.
Given the following:
leaky.cpp:
#include <iostream>
int main(int argc, char ** argv) {
std::string x = "x";
exit(1);
return 0;
}
Compile string:
g++ -g -Wall -Wpedantic --std=gnu++11 leaky.cpp -o leaky
Valgrind invocation:
valgrind --tool=memcheck --leak-check=full ./leaky
Doing this will reveal that there is indeed a leak:
==4434== Memcheck, a memory error detector
==4434== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4434== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==4434== Command: ./leaky
==4434==
==4434==
==4434== HEAP SUMMARY:
==4434== in use at exit: 16 bytes in 1 blocks
==4434== total heap usage: 1 allocs, 0 frees, 16 bytes allocated
==4434==
==4434== 16 bytes in 1 blocks are possibly lost in loss record 1 of 1
==4434== at 0x402A6DC: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4434== by 0x40F8213: std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.19)
==4434== by 0x40FA125: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.19)
==4434== by 0x40FA7AF: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.19)
==4434== by 0x804875E: main (leaky.cpp:3)
==4434==
==4434== LEAK SUMMARY:
==4434== definitely lost: 0 bytes in 0 blocks
==4434== indirectly lost: 0 bytes in 0 blocks
==4434== possibly lost: 16 bytes in 1 blocks
==4434== still reachable: 0 bytes in 0 blocks
==4434== suppressed: 0 bytes in 0 blocks
==4434==
==4434== For counts of detected and suppressed errors, rerun with: -v
==4434== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
And of course to try to include an answer to the question, exit(1) forces the program to quit without invoking any destructors, as far as I know--I've only been using C++ for a month and a half, so I'm not really an expert.
Perhaps the C++ class in question is doing something with pointers that suggests possibly leaky behavior to Valgrind.
I get diagnostics about this in a project in which I allocate some arrays, but then I adjust the pointer to the third element so that indices [-2] and [-1] are used to store some meta-information. There is no leak because I restore the pointer and free the arrays correctly.
Valgrind sees that the objects are referenced, however, that they are not referenced "nicely" via pointers to their base address, but only via interior pointers. It looks like a possible leak since no pointer exists for freeing the object.
A situation like this could happen in leaky programs: programs that, say, allocate a big object, give pieces of it (via pointers) to other modules, and then leak the big object. Interior pointers do suggest a leak.
It could be that getline is chummy with the representation of basic::string<> and does something of that sort. When you copy the object, the new object doesn't do anything funny: it just references the string data by its base address. The old object is gone, and it freed the data.
Just a hypothesis.
By the way, in that aforementioned program, I fixed things for Valgrind by retaining an extra pointer to the base address in the vector objects managing those arrays. This extra pointer is only present when the software is built for Valgrind debugging (along with other features, like use of the Valgrind client request API).

Valgrind error with std::cin

Here is my code:
std::string getword()
{
std::string temp;
std::cin >> temp;
return temp;
}
Valgrind throws an error on the line std::cin >> temp.
Here is the valgrind output for those who asked:
HEAP SUMMARY:
==18490== in use at exit: 33 bytes in 1 blocks
==18490== total heap usage: 397 allocs, 396 frees, 12,986 bytes allocated
==18490==
==18490== 33 bytes in 1 blocks are possibly lost in loss record 1 of 1
==18490== at 0x4C2AF8E: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18490== by 0x4EEE3B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==18490== by 0x4EEF127: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==18490== by 0x4EEF20F: std::string::reserve(unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==18490== by 0x4EA7D14: std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==18490== by 0x401681: getword() (netsim.cc:29)
==18490== by 0x401F6E: main (netsim.cc:96)
==18490==
==18490== LEAK SUMMARY:
==18490== definitely lost: 0 bytes in 0 blocks
==18490== indirectly lost: 0 bytes in 0 blocks
==18490== possibly lost: 33 bytes in 1 blocks
==18490== still reachable: 0 bytes in 0 blocks
==18490== suppressed: 0 bytes in 0 blocks
==18490==
==18490== For counts of detected and suppressed errors, rerun with: -v
==18490== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)
netsim.cc:96 is the second call to getword() in the program. That code reads
std::string network = getword();
netsim.cc:29 is the code for getword() itself. Line 29 is the line
std::cin >> temp
I still don't understand why this happened but I managed to resolve the issue.
I had the code
std::string s = getword();
immediatly above
std::string network = getword();
I made both s and network global variables and somehow the issue was resolved.
If anyone can explain why that is though I would be grateful.
I'm not a valgrind Expert, but I'm tentative to say that this is a false positive. In fact, it might even be a false positive generated by valgrind itself. Looking at the Leak Summary and seeing the core origin of the leak, I get suspicious:
// The one right below this, that's at the top of that valgrind error
==18490== at 0x4C2AF8E: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18490== by 0x4EEE3B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
Now why would valgrind be reporting a memory leak from its own shared library ? Something doesn't seem right here. Either valgrind itself isn't very clean in how its allocating that memory (and valgrind has its own leak! Oh noes!) or it's throwing a really strange false positive. Unless the newest branches of GCC have produced a memory leak for std::string and the istream& operator<< recently, I can't imagine this actually leaking. std::cin and std::cout have been being used for ages, and it makes no sense that valgrind would toss an error over it, especially when your client code isn't making a single new/delete call.
So, in short, there's a few things that could be happening here:
valgrind is leaking. (Maybe? It's originating from a valgrind function)
GCC is leaking? (Hesitant to say this)
valgrind is drunk! :[
In either case, ignore it and move on. I doubt this is going to shatter your netsim in any crucial way.
I hope it clears up soon, and I'm sorry my answer can only say this much, but these are the best shots I can give.