this code is obviously leaking the memory allocated by curl_easy_init()
import libcurl
proc initializer_generator() : proc =
var started = false
proc fun() =
if started:
discard global_init(GLOBAL_DEFAULT)
return fun
let init_curl = initializer_generator()
init_curl()
discard easy_init()
and if I run it with valgrind i get
==20004== Memcheck, a memory error detector
==20004== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==20004== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==20004== Command: ./gc_test
==20004==
==20004==
==20004== HEAP SUMMARY:
==20004== in use at exit: 101,649 bytes in 78 blocks
==20004== total heap usage: 3,394 allocs, 3,316 frees, 210,683 bytes
allocated
==20004==
==20004== 37,967 (21,256 direct, 16,711 indirect) bytes in 1 blocks are
definitely lost in loss record 17 of 17
==20004== at 0x4C2EF35: calloc (in
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20004== by 0x5B5F35E: ??? (in /usr/lib/libcurl.so.4.5.0)
==20004== by 0x5B6C3D5: curl_easy_init (in /usr/lib/libcurl.so.4.5.0)
==20004== by 0x109E6C: NimMainModule (in
/home/walter/code/nim_test/gc_test)
==20004== by 0x109CC4: NimMainInner (in
/home/walter/code/nim_test/gc_test)
==20004== by 0x109D00: NimMain (in /home/walter/code/nim_test/gc_test)
==20004== by 0x109D4E: main (in /home/walter/code/nim_test/gc_test)
==20004==
==20004== LEAK SUMMARY:
==20004== definitely lost: 21,256 bytes in 1 blocks
==20004== indirectly lost: 16,711 bytes in 4 blocks
==20004== possibly lost: 0 bytes in 0 blocks
==20004== still reachable: 63,682 bytes in 73 blocks
==20004== suppressed: 0 bytes in 0 blocks
==20004== Reachable blocks (those to which a pointer was found) are not
shown.
==20004== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==20004==
==20004== For counts of detected and suppressed errors, rerun with: -v
==20004== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
so far, so good.. but If I replace the last line with this
let curl = easy_init()
this is what I get when I run the program with valgrind
==23000== Memcheck, a memory error detector
==23000== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==23000== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==23000== Command: ./gc_test
==23000==
==23000==
==23000== HEAP SUMMARY:
==23000== in use at exit: 63,682 bytes in 73 blocks
==23000== total heap usage: 3,389 allocs, 3,316 frees, 172,716 bytes
allocated
==23000==
==23000== LEAK SUMMARY:
==23000== definitely lost: 0 bytes in 0 blocks
==23000== indirectly lost: 0 bytes in 0 blocks
==23000== possibly lost: 0 bytes in 0 blocks
==23000== still reachable: 63,682 bytes in 73 blocks
==23000== suppressed: 0 bytes in 0 blocks
==23000== Reachable blocks (those to which a pointer was found) are not
shown.
==23000== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==23000==
==23000== For counts of detected and suppressed errors, rerun with: -v
==23000== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
I really cannot understand how can it not leak memory anymore: the only right
way to free the memory allocated by easy_init is to call easy_cleanup on the
same pointer, which cannot happen since the compiler doesn't know anything
about it, in the same way I don't think it is possible for the compiler not to
call easy_init only because the returned value is not used, since it doesn't
know whether it has side effects or not. What's happening under the hood, then?