jacobwilliams / json-fortran

A Modern Fortran JSON API
https://jacobwilliams.github.io/json-fortran/
Other
333 stars 82 forks source link

Some memory leaks from json_value_module #553

Closed borderite closed 3 months ago

borderite commented 3 months ago

I use json-fortran with gfortran 12.2.0 on Debian Linux 12 (bookworm). In checking momery leaks of my codes using valgrind, I have noticed that json-fortran leaves unfreed memory at exit. For example, the following simple fortran code results in memory leaks.

program test
  use json_module
  implicit none
  type(json_file) :: json
  call json%initialize()
  call json%destroy()
end program test

I complied this code by

gfortran -g -Wall -I/usr/local/jsonfortran/lib tmp.f90 -L/usr/local/jsonfortran/lib -ljsonfortran -o./a

and then ran

valgrind --leak-check=full --show-leak-kinds=all ./a

The ouput I got is:

==393001== Memcheck, a memory error detector
==393001== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==393001== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==393001== Command: ./a
==393001== 
==393001== 
==393001== HEAP SUMMARY:
==393001==     in use at exit: 269 bytes in 2 blocks
==393001==   total heap usage: 47 allocs, 45 frees, 28,007 bytes allocated
==393001== 
==393001== 13 bytes in 1 blocks are still reachable in loss record 1 of 2
==393001==    at 0x48407B4: malloc (vg_replace_malloc.c:381)
==393001==    by 0x12281F: __json_value_module_MOD_json_initialize (in /home/ssakata/codesignal/fortran/a)
==393001==    by 0x10EB83: __json_file_module_MOD_initialize_json_core_in_file (in /home/ssakata/codesignal/fortran/a)
==393001==    by 0x10B6D4: MAIN__ (tmp.f90:5)
==393001==    by 0x10B749: main (tmp.f90:2)
==393001== 
==393001== 256 bytes in 1 blocks are still reachable in loss record 2 of 2
==393001==    at 0x48407B4: malloc (vg_replace_malloc.c:381)
==393001==    by 0x122570: __json_value_module_MOD_json_initialize (in /home/ssakata/codesignal/fortran/a)
==393001==    by 0x10EB83: __json_file_module_MOD_initialize_json_core_in_file (in /home/ssakata/codesignal/fortran/a)
==393001==    by 0x10B6D4: MAIN__ (tmp.f90:5)
==393001==    by 0x10B749: main (tmp.f90:2)
==393001== 
==393001== LEAK SUMMARY:
==393001==    definitely lost: 0 bytes in 0 blocks
==393001==    indirectly lost: 0 bytes in 0 blocks
==393001==      possibly lost: 0 bytes in 0 blocks
==393001==    still reachable: 269 bytes in 2 blocks
==393001==         suppressed: 0 bytes in 0 blocks
==393001== 
==393001== For lists of detected and suppressed errors, rerun with: -s
==393001== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
jacobwilliams commented 3 months ago

I'd be curious to know if the results are any different for this variant:

program test
  use json_module
  implicit none 
  call main()

 contains
  subroutine main()
    type(json_file) :: json
    call json%initialize()
    call json%destroy()
  end subroutine main
end program test
jacobwilliams commented 3 months ago

I get no leaks for the modified code I show in the previous message.

==12056== 
==12056== HEAP SUMMARY:
==12056==     in use at exit: 0 bytes in 0 blocks
==12056==   total heap usage: 51 allocs, 51 frees, 19,939 bytes allocated
==12056== 
==12056== All heap blocks were freed -- no leaks are possible
==12056== 
==12056== For lists of detected and suppressed errors, rerun with: -s
==12056== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

I think this is just a case of the compiler not deallocating things at the end of the program (specifically allocatable variables inside the type). They are deallocated when the types go out of scope (e.g. if they are declared in a subroutine, after the subroutine ends) but I don't think the compilers will do that and the end of the program for some reason. I don't think it really matters.

jacobwilliams commented 3 months ago

Note: you can add destroy_core to your json%destroy() call to explicitly deallocate those variables:

  call json%destroy(destroy_core = .true.)