3

I have a function that returns a char * pointer in C that looks like this

char * string_val (ARGS)
{
 char * svalue = cJSON_GetObjectItem(nml,var_name)->valuestring;
 return svalue;
}

In Fortran, I assign this to a C pointer (Using iso_c_binding)

type (c_ptr) :: C_String_ptr
...
C_String_ptr = string_val (ARGS)

This part works great.  The string_val function gets called a lot, and I think it's causing a memory leak.  I am trying to free the memory of the svalue pointer, but I have just run into seg faults and memory dumps.  I currently have something like this:

     subroutine c_mem_free (cptr) bind(C,name="c_mem_free")
      use iso_c_binding
      type (c_ptr)   :: cptr   !< The C pointer whose memory needs to be freed
     end subroutine
...
 call c_mem_free(C_String_ptr)

where

 void c_mem_free (void** addrOfptr)
{
  free(*addrOfptr);    /* free the memory pointed to */
  *addrOfptr=NULL;     /* Nullify the pointer ;) */
}

The traceback points to a problem on the free line.  I also tried passing changing cptr to value so type (c_ptr),VALUE :: cptr and having void*addrOfptr and free(addrOfptr) on the C side, but that didn't seem to work either. I've also been unsuccessful in finding the memory location of svalue on the Fortran side. If I use something like

write (6,'(z)')loc(C_String_ptr) write (6,'(z)')loc(c_loc(C_String_ptr))

neither of these gives me the same value as when I printf the location of the memory of svalue. How can I free the memory of the pointer svalue after it's been returned in Fortran? How can I get the location of the svalue memory in Fortran?

francescalus
  • 30,576
  • 16
  • 61
  • 96
byrdman1982
  • 109
  • 7
  • 3
    What mechanism is provided by cJSON for free the memory, if the program were completely written in C? Considering that you have no explicit malloc, I think whatever memory leak you have is occurring due to memory allocated by cJSON, no? If this is the case, I would think your `c_mem_free` should also use whatever mechanism is provided by cJSON. One troubleshooting step would be to write a small program with such a cJSON allocation in a loop, and to try to demonstrate the memory leak, first with the entire program in C, and then with C+Fortran. – Douglas B. Staple Aug 17 '16 at 14:12
  • I think a json tag should by added. I don't know which one, so I am not going to do that. – Vladimir F Героям слава Aug 17 '16 at 15:19
  • @DouglasB.Staple `for ( a = 1; a < 1000000; a = a + 1 ){ cJSON * nml = getnml (my_json_string, nml_name , var_name); svalue = cJSON_GetObjectItem(nml,var_name)->valuestring; // Find the string value free (nml); free (svalue); if (a % 10000 == 0) {printf("a /n");}` That produces no leak. The memory stays about the same. Without free (svalue) the memory used goes way up. cJSON does have a cJSON_free that just uses free. – byrdman1982 Aug 17 '16 at 17:20
  • cJSON seems to be here https://github.com/DaveGamble/cJSON and it has [cJSON_Delete](https://github.com/DaveGamble/cJSON/blob/master/cJSON.c#L80) but I couldn't find getnml(). Is this a wrapper for reading Fortran namelist (in which cJSON is created)? – roygvib Aug 17 '16 at 19:05
  • @roygvib It is a wrapper. The fortran namelist is converted to json, then cJSON is used to get the values of the variables. – byrdman1982 Aug 18 '16 at 11:31
  • If you wanted to avoid C altogether, [JSON-Fortran](https://github.com/jacobwilliams/json-fortran) is an option. – Time Laird Aug 18 '16 at 13:22
  • @TimeLaird The JSON needs to be read and parsed in C for use in Fortran. That's the nature of the project. – byrdman1982 Aug 18 '16 at 18:09
  • Is there any possibility that getnml() creates a lot of redundant cJSON objects for a single namelist file? Also, cJSON_Print() might need manual deallocation of the returned char string (according to [the comment](https://github.com/DaveGamble/cJSON/blob/master/cJSON.h#L69) in the header file). – roygvib Aug 18 '16 at 19:07
  • @roygvib 1. Yes. I started parsing the json in each individual function and using cJSON_Delete(nml) and that worked in my integer and double functions which look more like this `int i = cJSON_GetObjectItem(nml,var_name)->valueint;` Using cJSON_Delete does not work in the function where a string pointer is returned because everything is freed and the pointer points to nothing. I think I have to be more creative. – byrdman1982 Aug 19 '16 at 14:14

1 Answers1

1

As a thumbs up rule, you shouldn't "free" memory allocated outside your code. And this is true with cJSON.

Once you parse the object, the tree is construct in memory and you can reach the objects, its values, change it, etc.

After you finish the processing of your file, you can free the memory calling cJSON_Delete(root);

This routine will take care of everything for you.

If you want to free objects/nodes as you use them, you can use also cJSON_Delete(node); Just remember that this routine is "recoursive". So, if you free a node, it will free all the children AND the siblings too, as you can see by the code here:

/* Delete a cJSON structure. */
void cJSON_Delete(cJSON *c)
{
    cJSON *next;
    while (c)
    {
        next=c->next;
        if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
        if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
        if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
        cJSON_free(c);
        c=next;
    }
}

DON'T use cJSON_Free, as cJSON_Delete will take care of everything, while cJSON_free must be applied to the internal elements of the structure before freeing the structure itself, otherwise you will have a memory leak.

Jauch
  • 1,500
  • 9
  • 19
  • using cJSON_Delete works in my functions for doubles and integers, but if I use it in my string functions, I end up with empty strings because the string is passed as a pointer. – byrdman1982 Aug 19 '16 at 14:12
  • 1
    @byrdman1982, this is the expected behavior as they are pointers. If you need to keep the string after reading it from the JSON structure, you should copy it to a string. The question I keep asking myself is why do you need to free immediately? By definition, a memory leak is a problem in code that cause allocated memory to become inaccessible due to a pointer (for example) going out of scope. Are you sure that is cJSON that is doing this? – Jauch Aug 19 '16 at 14:24
  • What exactly is you seeing that you think you have a memory leak? – Jauch Aug 19 '16 at 14:25