2
votes

My app is use in stlinux (sh4) and unfortunately valgrind does not support sh4 cpu. since I saw memory leak with my app, I had used mtrace, and it confirmed that some memory is not free. The problem is, variable of malloc used in the return, therefore I do not have any idea, how could I free it (since if it would be free, then returning in the functions is meaningless)?

I had written cs_malloc (put bellow code from oscam-simple.c in above link), mtrace log says, that in line:

*tmp = malloc (size);

memory is not free

 /* This function encapsulates malloc. It automatically adds an error message to the log if it failed and calls cs_exit(quiterror) if quiterror > -1. 
       result will be automatically filled with the new memory position or NULL on failure. */
    void *cs_malloc(void *result, size_t size, int32_t quiterror){
        void **tmp = result;
        *tmp = malloc (size);
        if(*tmp == NULL){
            cs_log("Couldn't allocate memory (errno=%d %s)!", errno, strerror(errno));
            if(quiterror > -1) cs_exit(quiterror);
        } else {
            memset(*tmp, 0, size);  
        }
        return *tmp;
    }

And then for malloc, I call it, like this:

  // create the AES key entry for the linked list
    if(!cs_malloc(&new_entry, sizeof(AES_ENTRY), -1)) return;

Please take a look at these 3 functions (which malloc is not free , and as other users said, valgrind claim that these codes cause memory leaks module-datastruct-llist.c

The memory leaks cause by 3 different parts:

  1. in below codes "new" would never free , but since it use in return of that function, I don't have idea, how could I free it:

    LL_NODE* ll_append_nolock(LLIST *l, void *obj)
    {
    if (l && obj) {
        LL_NODE *new;
        if(!cs_malloc(&new,sizeof(LL_NODE), -1)) return NULL;
        new->obj = obj;
    
        if (l->last)
            l->last->nxt = new;
        else
            l->initial = new;
        l->last = new;    
    
        l->count++;
        return new;
        }  
        }
    
  2. also "l" use in below function, again since it use in return function, I have no idea how to free it. :

      LLIST *ll_create()
      {
       LLIST *l = cs_malloc(&l, sizeof(LLIST), 0);
       pthread_mutex_init(&l->lock, NULL);
       return l;
       }
    
  3. same story with new :

             LL_NODE *ll_prepend(LLIST *l, void *obj)
            {             
            if (l && obj) {
    
            LL_NODE *new;
            if(!cs_malloc(&new,sizeof(LL_NODE), -1)) return NULL;
    
            new->obj = obj;
            ll_lock(l);
            new->nxt = l->initial;
    
            l->initial = new;
            if (!l->last)
                l->last = l->initial;
            l->count++;
            ll_unlock(l);
    
            return new;
        }
           return NULL;
        }
    

For more functions you could see module-datastruct-llist.c

Would highly appreciate, if any expert tell me, how could I fix that memory leak (if you feel, cs_malloc should be rewritten, or need to add new function, please write the source code you are meaning.

3
For take a deeper look deeper in entire source code , please check this trac browser] : streamboard.tv/oscam/browser/trunk/?rev=5375 - Jimy Cn
Did you consider compiling and testing your application on a standard x86 or x86_64 Linux distribution and use valgrind on it? - Basile Starynkevitch
Other than my C compiler whining about an invalid implicit assignment from void* to void** (but I know what it is trying to do, so a cast clears that) the cs_malloc() function appears sound (or i've not had enough coffee this morning), so I don't think your problem lies there. Start checking the usage. - WhozCraig

3 Answers

0
votes

The most common implementations of malloc use heap memory, which is global, so it's very common to have storage allocated in one place passed around between a number of functions before it is finally freed.

Now, there are for instance calls to ll_append_nolock where you ignore the malloced return. I.e.

ll_append_nolock(it->l, obj);

so to avoid a leak you need to do what you do in other places, i.e let the calling function receive the allocated memory into a pointer:

LL_NODE *n = ll_append_nolock(l, obj);
/* do stuff with "n", which points to memory allocated under the name of "new" */
free(n);

And when you're through with n (which as noted above points to the storage allocted under the name "new", that is: same memory, different names), you free it.

HTH.

0
votes

In your function cs_malloc the first parameter is result however you never assign to it in the function cs_malloc.

Later you use cs_malloc like this

if(!cs_malloc(&new,sizeof(LL_NODE), -1)) return NULL;
    new->obj = obj;

which will not work since since "new" is left uninitialized

you should either assign to result in your cs_malloc or just return the block in cs_malloc, if you fail to allocate just return NULL instead.

e.g.

void *cs_malloc(size_t size, int32_t quiterror)
{
  void* tmp = calloc(1,size);
  if(tmp == NULL)
  {
    cs_log("Couldn't allocate memory (errno=%d %s)!", errno, strerror(errno));
    if(quiterror > -1) cs_exit(quiterror);
  } 
  return tmp;
}

and

  if (new = cs_malloc(sizeof(LL_NODE),-1))
  {
    new->obj = obj;
  }
  else
  {
    return NULL;
  }
0
votes

@Anders Thanks for reply , i would take consideration your note ,an would change it as u described to see memory leaks how it's goes...

How , this line should be change to the new cs_malloc function u had written: 1.

    LLIST *l = cs_malloc(&l, sizeof(LLIST), 0);
    pthread_mutex_init(&l->lock, NULL);
    return l;

2.

if(!cs_malloc(&para,sizeof(struct read_thread_param), -1)) return FALSE;
            para->id=i;