1

I am new to Valgrind (and my C/C++ is rusty) and I am getting an error:

40 bytes in 1 blocks are definitely lost in loss record 35 of 111
==26930==    at 0x4C275C2: operator new(unsigned long) (vg_replace_malloc.c:261)
==26930==    by 0x5EFAFDB: cassie_init_with_timeout (cassie.cc:49)
==26930==    by 0x46E647: ngx_cassandra_upstream_get_peer (ngx_cassandra_upstream.c:274)
==26930==    by 0x41E00B: ngx_event_connect_peer (ngx_event_connect.c:25)

I am guessing that the char *last_error_string is giving me fits, but how do I track this down?

Here is my source:

Creation of the Cassie object:

cassie_t cassie;

char *error = NULL;
cassie = new Cassie(host,port,error,CASSIE_ERROR_NONE);  /* this is line 49 in the above valgrind trace */
cassie->cassandra               = cassandra;

cassie_t is a struct of an Object.

typedef struct Cassie *cassie_t;

I have this because I am wrapping a C++ lib in order to call it from C.

Here is our object cassie_private.h

#include <string>
#include "libcassandra/cassandra.h"
#include "libcassie/cassie.h"

#ifdef __cplusplus
namespace libcassie {
    using namespace std;
    using namespace boost;
    class Cassie
    {
      // TODO do we need the host and the port??
      public:
            const char*     host;
        int             port;
        cassie_error_code_t last_error_code;
        char*           last_error_string; /* I am guessing my memory problem is here */
        tr1::shared_ptr<libcassandra::Cassandra>                    cassandra;

        Cassie();
        Cassie(const char *&host, int &port,char* &in_error_str, cassie_error_code_t error);
        ~Cassie();
    };
#else
    typedef
         struct Cassie
           Cassie; /* this is for in C */
#endif

}

#endif

Here is cassie_private.cc

#include "cassie_private.h"

namespace libcassie {

using namespace std;
using namespace libcassandra;

Cassie::Cassie() :
    host(),
    port(0),
    last_error_code(),
    last_error_string(NULL),
    cassandra()
{}

Cassie::Cassie(const char * &in_host, int &in_port, char* &in_error_str, cassie_error_code_t error) :
        host(in_host),
        port(in_port),
        last_error_code(error),
        last_error_string(in_error_str),
        cassandra()
{}

Cassie::~Cassie() {
    if(last_error_string) delete last_error_string;
}

}

This is being called in order to delete the Object at the end of use:

void cassie_free(cassie_t cassie) {

    if(!cassie) return;
    cassie->~Cassie();
    if(cassie) delete cassie;

}

How do I track this memory leak down?

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
chrislovecnm
  • 2,549
  • 3
  • 20
  • 36
  • 2
    What is cassie.cc line 49? Valgrind seems to be thinking you're calling `new` and then not calling `delete` on said object. – Dan Fego Feb 15 '12 at 19:49
  • 1
    @Dan: It's worse than that; the Valgrind message means that the OP is calling `new` and then discarding the pointer at some point. – Oliver Charlesworth Feb 15 '12 at 19:54
  • @OliCharlesworth: Yeah, that's more correct. Though often the cause is letting a pointer leave scope or get overwritten when you no longer need it, so you should have freed it at some point. :) – Dan Fego Feb 15 '12 at 19:58
  • The `cassie_free` function looks very suspicious. Why are you manually calling the destructor, and then invoking `delete`? And why the redundant check for `NULL`? Also, hiding a pointer behind a typedef is usually considered bad practice, because it makes the resulting code so confusing to read. – Oliver Charlesworth Feb 15 '12 at 20:09
  • As I mentioned my C/C++ is rusty as hell. How would I not use the a typedef in this instance? Use the Cassie struct itself? – chrislovecnm Feb 15 '12 at 20:18
  • @chrislovecnm: Something like `Cassie *cassie = new Cassie(...)`. – Oliver Charlesworth Feb 15 '12 at 20:38

1 Answers1

7

The Valgrind message means that you have allocated some memory (at line 49 of cassie.cc), but you are losing/overwriting the pointer without ever invoking delete on it.

You should track where that pointer value goes (either in the debugger or by inspection), in order to spot where it's being lost. You might consider putting a debugger watchpoint on the pointer; this would identify the problem in the scenario where it's being overwritten. If you're going to do this in the debugger, make sure you've compiled with no optimisations enabled.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680