caohaiwd / gperftools

Automatically exported from code.google.com/p/gperftools
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

Some memory leak report with application with bdb and i think something mistake. #238

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
1. Report this leak when comment the last line  "// free(data1.data)"; in 
the program below. And do not report in my application without free, i 
think its contradict.
【Leak of 9 bytes in 1 objects allocated from:
        @ 0x4e9768 __os_umalloc
        @ 0x9 thread_disable_counter】

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db.h>

#include "base/base.h"
#include "base/atomic.h"
#define DATABASE "test.db"

int main(int argc, char **argv) {
  DB_ENV *myEnv;
  DB *dbp;
  DBT key, data;
  DBT key1, data1;
  int ret, t_ret;
  u_int32_t env_flags;
  ret = db_env_create(&myEnv, 0);
  if (ret != 0) {
    fprintf(stderr, "Error creating env handle: %s\n", db_strerror(ret));
    return -1;
  }
  system("rm -rf /tmp/test");
  system("mkdir /tmp/test");
  env_flags = DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG |
              DB_INIT_MPOOL | DB_INIT_TXN | DB_THREAD;
  ret = myEnv->open(myEnv, "/tmp/test", env_flags, 0);
  if (ret != 0) {
    fprintf(stderr, "Environment open failed: %s", db_strerror(ret));
    return -1;
  }
  myEnv->set_cachesize(myEnv, 0, 100000, 1);

  if ((ret = db_create(&dbp, myEnv, 0)) != 0) {
    fprintf(stderr, "db_create: %s\n", db_strerror(ret));
    exit(1);
  }
  dbp->set_flags(dbp, DB_DUP);
  DB_TXN *txn;
  ret = myEnv->txn_begin(myEnv, NULL, &txn, 0);
  if (ret != 0) {
    myEnv->close(myEnv, 0);
    return ret;
  }
  if ((ret = dbp->open(dbp, txn, DATABASE, NULL,
      DB_BTREE, DB_CREATE | DB_THREAD, 0664)) != 0) {
    dbp->err(dbp, ret, "%s", DATABASE);
    dbp->close(dbp, 0);
    txn->abort(txn);
    exit(1);
  }
  txn->commit(txn, 0);
  memset(&key, 0, sizeof(key));
  memset(&data, 0, sizeof(data));
  key.data = const_cast<char*>("sport");
  key.size = sizeof("sport");
  data.data = const_cast<char*>("football");
  data.size = sizeof("football");
  data.flags = DB_DBT_USERMEM;
  DB_TXN *txn1;
  ret = myEnv->txn_begin(myEnv, NULL, &txn1, 0);

  if ((ret = dbp->put(dbp, txn1, &key, &data, 0)) == 0) {
    printf("db: %s: key stored.\n", reinterpret_cast<char*>(key.data));
  } else {
     dbp->err(dbp, ret, "DB->put");
  }
  memset(&key1, 0, sizeof(key1));
  memset(&data1, 0, sizeof(data1));
  key1.data = const_cast<char*>("sport");
  key1.size = sizeof("sport");
  data1.data = const_cast<char*>("football");
  data1.size = sizeof("football");
  data1.flags = DB_DBT_MALLOC;
  if ((ret = dbp->get(dbp, txn1, &key1, &data1, 0)) == 0) {
    printf("db: %s: key retrieved: data was %s.\n",
        reinterpret_cast<char*>(key1.data),
        reinterpret_cast<char*>(data1.data));
  } else {
    dbp->err(dbp, ret, "DB->get");
  }
  if ((ret = dbp->del(dbp, txn1, &key, 0)) == 0) {
    printf("db: %s: key was deleted.\n", 
reinterpret_cast<char*>(key.data));
  } else {
    dbp->err(dbp, ret, "DB->del");
  }

  ret = txn1->commit(txn1, 0);
  if (ret != 0) {
    printf("commit fail");
  }
  if (dbp != NULL) {
    dbp->close(dbp, 0);
  }
  if (myEnv != NULL) {
    myEnv->close(myEnv, 0);
  }
  // free(data1.data);
  return 0;
}

2. I encountered another report in my application with put(). I use it the 
same way with the program above. 
【Leak of 81 bytes in 3 objects allocated from:
        @ 0x4e9768 __os_umalloc】
----------snippet-------------
open evn...
open db...

{
  DBT local_key, local_value;
  memset(&local_key, 0, sizeof(local_key));
  memset(&local_value, 0, sizeof(local_value));
  local_key.data = const_cast<void*>(static_cast<const void*>(&kfp));
  local_key.size = sizeof(kfp);
  bdb::BdbValueItem bvi;
  bvi.mutable_key()->assign(key.key());
  bvi.mutable_value()->assign(value);
  string store_value;
  bvi.SerializeToString(&store_value); 
  local_value.data =
      const_cast<void*>(static_cast<const void*>(store_value.c_str()));
  local_value.flags = DB_DBT_USERMEM;
  local_value.size = store_value.size() + 1;

  // Memory leak with the following 4 lines, and no leak without the 
following 4 lines
  if (txn == NULL) {    
    ret = db_->put(db_, NULL, &local_key, &local_value, put_flags);
  } else {    
    ret = db_->put(db_, txn->txn_, &local_key, &local_value, put_flags);
  }
  if (ret == DB_LOCK_DEADLOCK) {
    return kDeadlock;
  }
}

close env...
close db...

Original issue reported on code.google.com by owandyw...@gmail.com on 29 Apr 2010 at 6:57

GoogleCodeExporter commented 9 years ago
local_value.flags = DB_DBT_USERMEM;
local_value.size = store_value.size() + 1;
->
local_value.flags = DB_DBT_USERMEM;
local_value.ulen = store_value.size() + 1;

is the same report

Original comment by owandyw...@gmail.com on 29 Apr 2010 at 7:23

GoogleCodeExporter commented 9 years ago
I'm not sure I understand your bug report.  When I try running your program 
above, 
when the 'free' line is commented out, I get a leak error, and when the 'free' 
line is 
not commented out, I get no leak error.  That's exactly what I would expect 
when using 
DB_DBT_MALLOC.  Is that not what you're seeing?

I can't evaluate your second example, since it's just a snippet.  If you can 
provide a 
full program that demonstrates the problem, I could try running it as well.

Original comment by csilv...@gmail.com on 30 Apr 2010 at 1:18

GoogleCodeExporter commented 9 years ago
Many thanks for your reply. You are right, the DB_DBT_MALLOC ask the users to 
free it them-selfs.
About the second example, my style perhaps not good. I found a similar example 
db-
4.8.26/examples_c/bench_001.c. There is a function 'fill', and the following 
snippet
197         memset(&key, 0, sizeof(DBT));
198         memset(&data, 0, sizeof(DBT));
199         key.data = &i;
200         key.size = sizeof(i);
201         data.data = data_val = malloc(datalen);
202         memcpy(data_val->str, "0123456789012345678901234567890123456789",
203             datalen - sizeof(data_val->id));
204         data.size = datalen;
205         data.flags = DB_DBT_USERMEM;
There is a malloc on line201 but no matching free. I try out that there is 
memory 
leak without free. Is the example without free a bug? There is no related 
information  
in the manual, wish your help!

Original comment by owandyw...@gmail.com on 30 Apr 2010 at 3:51

GoogleCodeExporter commented 9 years ago
If I understand you right, you're saying that you malloc the memory but don't 
free it, 
and the heap-checker is detecting that as a memory leak.  That seems exactly 
right to 
me.  What would you expect, that's different?

Original comment by csilv...@gmail.com on 30 Apr 2010 at 4:06

GoogleCodeExporter commented 9 years ago
Yes. I encountered two problems as post before. Firstly, when i using 
DB_DBT_MALLOC, 
i think bdb should free itself , its should not leave free to user. Now this 
problem 
is clear though i think this style is not good. Secondly, i think before 
db->put i 
malloc a buffer and free it is proper. But, i found the official example 
examples_c/bench_001.c malloc without free. When i followed the example and 
found 
memory leak. So i'm not sure is there something wrong with the bdb example or 
with 
heap-checker.

Original comment by owandyw...@gmail.com on 30 Apr 2010 at 4:41

GoogleCodeExporter commented 9 years ago
I'd say the documentation is wrong: nothing I know about bdb says it frees 
memory that 
you allocate.  I don't see any bugs here.

Original comment by csilv...@gmail.com on 30 Apr 2010 at 5:24