Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ Memory Leakage - boost library

I have observed a memory leakage in the following program:

// g++ -std=c++11 32_MyTime.cpp 
//
// valgrind --leak-check=full ./a.out 
//


#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

using namespace std;

class MyTime {
private:
  int year;
  int month;
  int day;
  int hour;
  boost::posix_time::ptime *ptrTime;
  void update() {
    year = ptrTime->date().year();
    month = ptrTime->date().month();
    day = ptrTime->date().day();
    hour = ptrTime->time_of_day().hours(); 
  }
public:
  ~MyTime() {
    if (ptrTime!=nullptr) delete ptrTime;
  }
  MyTime(int y, int m, int d, int h):year{y},month{m},day{d},hour{h} {
    ptrTime = new boost::posix_time::ptime(
    boost::gregorian::date(year, month, day),
    boost::posix_time::hours(hour));       
  }
  void addHours(int nHours) {
    if (ptrTime!=nullptr) delete ptrTime;
    ptrTime = new boost::posix_time::ptime(
        boost::gregorian::date(year, month, day),
        boost::posix_time::hours(hour+nHours));
    update();
  }
  int getYear()  const { return year; }
  int getMonth() const { return month; }
  int getDay()   const { return day; }
  int getHour()  const { return hour; }
  void set(int y, int m, int d, int h) {
    if (ptrTime!=nullptr) delete ptrTime;
    ptrTime = new boost::posix_time::ptime(
        boost::gregorian::date(y, m, d),
        boost::posix_time::hours(h));
    update();
  }
  time_t getSecSince() const {
    return (*ptrTime - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds();
  }
  const boost::posix_time::ptime* getPTime() const {
    return ptrTime;
  }
  bool operator==(const MyTime& other) const {
    return *ptrTime==*other.getPTime();
  }
  bool operator!=(const MyTime& other) const {
    return !(*this == other);
  }
  bool operator<(const MyTime& other) const {
    return *ptrTime < *(other.getPTime());
  }
  bool operator<=(const MyTime& other) const {
    return *ptrTime <= *(other.getPTime());
  }
  bool operator>(const MyTime& other) const {
    return *ptrTime > *other.getPTime();
  }
  bool operator>=(const MyTime& other) const {
    return *ptrTime >= *other.getPTime();
  }
};

void test() {

    MyTime t1 {2016,5,21,17};
    MyTime t2 {2016,5,22,10};

    bool print = false;

    if (print) {
    cout << "From : " << *t1.getPTime() << endl;  // Memory leak
    cout << "To   : " << *t2.getPTime() << endl;  // Memory leak
    }

    cout << " t1 < t2  " << (t1<t2)  << endl;
        cout << " t1 > t2  " << (t1>t2)  << endl;
        cout << " t1 == t2 " << (t1==t2) << endl;
        cout << " t1 < t1  " << (t1<t1)  << endl;
        cout << " t1 > t1  " << (t1>t1)  << endl;
        cout << " t1 == t1 " << (t1==t1) << endl;


    while (t1<=t2) {
      if (print)
            cout << "> Time : " << *t1.getPTime() << "    " << t1.getSecSince() << endl;  // Memory leak
      int s = t1.getSecSince();
      t1.addHours(1);
    }


}

int main() {
  test();
}

I have analysed the program with valgrind and the class should be error free (from the point of view of memory leakage).

This instruction causes the leakage:

cout << "From : " << *t1.getPTime() << endl;  // Memory leak

but I do not understand why. I assume that the boost library has no error. It could be some copy constructor (just an explanation attempt).

How could I avoid it?

It is not vital for me to solve the issue (the code is there just for debugging), but it important to understand why it happens to avoid similar error in the future.

EDIT The code as it is has no memory leakage. You have to turn on the printing to get the leakage: print = true;

EDIT 2 Valgrind execution with print = true;

==22204== 
==22204== HEAP SUMMARY:
==22204==     in use at exit: 1,748 bytes in 31 blocks
==22204==   total heap usage: 223 allocs, 192 frees, 38,751 bytes allocated
==22204== 
==22204== LEAK SUMMARY:
==22204==    definitely lost: 0 bytes in 0 blocks
==22204==    indirectly lost: 0 bytes in 0 blocks
==22204==      possibly lost: 619 bytes in 20 blocks
==22204==    still reachable: 1,129 bytes in 11 blocks
==22204==         suppressed: 0 bytes in 0 blocks
==22204== Rerun with --leak-check=full to see details of leaked memory
==22204== 
==22204== For counts of detected and suppressed errors, rerun with: -v
==22204== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

Valgrind execution with print = true; and a LOT MORE cout:

==22277== HEAP SUMMARY:
==22277==     in use at exit: 1,748 bytes in 31 blocks
==22277==   total heap usage: 79,279 allocs, 79,248 frees, 15,972,927 bytes allocated
==22277== 
==22277== LEAK SUMMARY:
==22277==    definitely lost: 0 bytes in 0 blocks
==22277==    indirectly lost: 0 bytes in 0 blocks
==22277==      possibly lost: 619 bytes in 20 blocks
==22277==    still reachable: 1,129 bytes in 11 blocks
==22277==         suppressed: 0 bytes in 0 blocks
==22277== Rerun with --leak-check=full to see details of leaked memory
==22277== 
==22277== For counts of detected and suppressed errors, rerun with: -v
==22277== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

Valgrind execution with empty main:

==22211== Memcheck, a memory error detector
==22211== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==22211== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==22211== Command: ./a.out
==22211== 
==22211== 
==22211== HEAP SUMMARY:
==22211==     in use at exit: 0 bytes in 0 blocks
==22211==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==22211== 
==22211== All heap blocks were freed -- no leaks are possible
==22211== 
==22211== For counts of detected and suppressed errors, rerun with: -v
==22211== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
like image 473
PeptideChain Avatar asked Nov 09 '22 14:11

PeptideChain


1 Answers

Ok. The leak is a false report:

==20323== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1
==20323==    at 0x4C2BBCF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20323==    by 0x4EC21FF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==20323==    by 0x4010609: call_init.part.0 (dl-init.c:72)
==20323==    by 0x401071A: call_init (dl-init.c:30)
==20323==    by 0x401071A: _dl_init (dl-init.c:120)
==20323==    by 0x4000D09: ??? (in /lib/x86_64-linux-gnu/ld-2.21.so)
==20323== 

As you can see it's allocated from some shared library initializer. If you remove all code from main, it remains the same.

For print = true I notice the leaked facets (that's by design).


Secondly, as others have said, don't do the new thing. There is no need to emulate the badness of Java and invite all kinds of programmer error.

Just use a ptime member already. To be honest I don't even see why you'd duplicate the year, month, day and hour fields at all, but here you are:

Live On Coliru

I'd suggest removing all duplication in the first place:

Live On Coliru

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

class MyTime : public boost::posix_time::ptime {

    using ptime = boost::posix_time::ptime;
    using date  = boost::gregorian::date;

  public:
    MyTime(short unsigned y, short unsigned m, short unsigned d, short unsigned h) 
        : ptime {date{y, m, d}, boost::posix_time::hours(h)}
    { }

    void addHours(int nHours) { *this += boost::posix_time::hours(nHours); }

    int getYear()  const { return date().year();  }
    int getMonth() const { return date().month(); }
    int getDay()   const { return date().day();   }
    int getHour()  const { return time_of_day().hours(); }

    // instead of set, just assign `v = { 2016, 5, 22, 9 }`
    time_t getSecSince() const { return (*this - ptime{date{1970, 1, 1}}).total_seconds(); }
};

void test() {

    MyTime t1{ 2016, 5, 21, 17 };
    MyTime t2{ 2016, 5, 22, 10 };

    bool print = false;

    if (print) {
        std::cout << "From : " << t1 << std::endl;
        std::cout << "To   : " << t2 << std::endl;
    }

    std::cout << " t1 < t2  " << (t1 < t2)  << std::endl;
    std::cout << " t1 > t2  " << (t1 > t2)  << std::endl;
    std::cout << " t1 == t2 " << (t1 == t2) << std::endl;
    std::cout << " t1 < t1  " << (t1 < t1)  << std::endl;
    std::cout << " t1 > t1  " << (t1 > t1)  << std::endl;
    std::cout << " t1 == t1 " << (t1 == t1) << std::endl;

    while (t1 <= t2) {
        if (print)
            std::cout << "> Time : " << t1 << "    " << t1.getSecSince() << std::endl;
        int s = t1.getSecSince();
        t1.addHours(1);
    }
}

int main() {
    test(); 
}

BONUS Alternative Design

Since MyTime is really just extra operations on ptime now, why not:

Live On Coliru

using MyTime = boost::posix_time::ptime;
using MyDate = boost::gregorian::date;

MyTime make_hdate(short unsigned y, short unsigned m, short unsigned d, short unsigned h) {
    return { MyDate{ y, m, d }, boost::posix_time::hours(h) };
}

MyTime addHours(MyTime const &mt, int nHours) {
    return mt + boost::posix_time::hours(nHours); 
}

time_t getSecSince(MyTime const &mt) {
    return (mt - MyTime{ MyDate{ 1970, 1, 1 } }).total_seconds(); 
}
like image 120
sehe Avatar answered Nov 15 '22 13:11

sehe