[gambit-list] Memory leak (?) using `c-define`d functions from foreign release functions.

Estevo euccastro at gmail.com
Wed Jan 1 04:51:29 EST 2014


But wait a minute... I had missed the point that foreigns themselves (that
is, not only the data they point to) have a reference count.  Sure enough,
foreigns that are returned by POINTER_to_SCMOBJ *are ___STILL allocated*!
That means they already have the `data` field I wanted to add to Gambit!

*slaps forehead*


On Mon, Dec 30, 2013 at 7:54 PM, Estevo <euccastro at gmail.com> wrote:

> (Ignore the "q is ..." printout.  As you see in the script, I just printed
> p again there instead, by mistake.)
>
>
> On Mon, Dec 30, 2013 at 7:51 PM, Estevo <euccastro at gmail.com> wrote:
>
>> Well, just with 2 (modified script follows below, again) I get memory
>> corruption (note that it seems like the value of the car of `ptr-serials`
>> has become the string "*** after GC", which is only ever passed to println.)
>>
>> p is #<point* #2 0x28979a0>
>> q is #<point* #2 0x28979a0>
>>
>> release-point called on serial 3
>> found in object table as: #<void* #3 0x28981b0>
>>
>> release-point called on serial 4
>> found in object table as: #<void* #4 0x28979a0>
>>
>> *** after GC:
>> foreign serial is *** after GC:, corresponding to not-there, a
>> mem-allocated something else object with reference count == 10008704
>>
>> Bye.
>>
>>
>> ;----
>>
>> (c-declare "struct { int x; int y; } point;")
>>
>> (define no-err ((c-lambda () scheme-object "___result =
>> ___FIX(___NO_ERR);")))
>>
>> (define ptr-serials '())
>>
>>
>> (c-define (release-point ptr)
>>           ((pointer void)) scheme-object "scm_release_point" ""
>>    (let ((ptr-serial (object->serial-number ptr)))
>>     (set! ptr-serials (cons ptr-serial ptr-serials))
>>
>>     (println "release-point called on serial " ptr-serial)
>>     (println "found in object table as: "
>>               (table-ref ##serial-number-to-object-table ptr-serial
>> 'not-there)))
>>
>>   ((c-lambda ((pointer void)) void "___release_rc") ptr)
>>   no-err)
>>
>> (c-define-type point (type "point" (point*) "scm_release_point"))
>>
>> (define p ((c-lambda () point
>>              "___result_voidstar = ___EXT(___alloc_rc)(sizeof(point));")))
>>
>> (define q ((c-lambda () point
>>              "___result_voidstar = ___EXT(___alloc_rc)(sizeof(point));")))
>>
>> (println "p is " p)
>> (println "q is " p)
>>
>> (set! p #f)
>> (set! q #f)
>>
>> (##gc)
>>
>> (newline)
>> (println "*** after GC:")
>> (for-each
>>   (lambda (ptr-serial)
>>
>>     (print "foreign serial is " ptr-serial)
>>     (print ", corresponding to "
>>            (table-ref ##serial-number-to-object-table ptr-serial
>> 'not-there))
>>
>>     (print ", a "
>>            (if
>>              ((c-lambda (scheme-object) bool "___result =
>> ___MEM_ALLOCATED(___arg1);")
>>               (table-ref ##serial-number-to-object-table ptr-serial
>> 'not-there)) "" "not")
>>            " mem-allocated")
>>
>>     (print " "
>>            ((c-lambda (scheme-object) char-string "___result =
>> ___HD_TYP(___BODY(___arg1)[-1]) == ___STILL ? \"still\" : \"something
>> else\";")
>>             (table-ref ##serial-number-to-object-table ptr-serial
>> 'not-there)))
>>
>>     (println " object with reference count == "
>>              ((c-lambda (scheme-object) int "___result =
>> ___UNTAG(___arg1)[___BODY_OFS - 6 + 1];")
>>               (table-ref ##serial-number-to-object-table ptr-serial
>> 'not-there)))
>>     (newline))
>>   ptr-serials)
>>
>> (println "Bye.")
>>
>>
>>
>>
>> On Mon, Dec 30, 2013 at 6:56 PM, Mikael <mikael.rcv at gmail.com> wrote:
>>
>>> What's the behvior if you allocate 1 000 000 instead, is the problem
>>> amplified proportionally?
>>>
>>>
>>> 2013/12/30 Estevo <euccastro at gmail.com>
>>>
>>>> It seems that's not the problem.  Refcount is 0, yet the object is kept
>>>> alive.
>>>>
>>>> Running the modified script below, I get the following:
>>>>
>>>> [BEGIN OUTPUT]
>>>>
>>>> p is #<point* #2 0x12309a0>
>>>> release-point called on serial 3
>>>> found in object table as: #<void* #3 0x12309a0>
>>>>
>>>> *** after GC:
>>>> foreign serial is 3, corresponding to #<void* #3 0x12309a0>, a
>>>> mem-allocated still object with reference count == 0
>>>> Bye.
>>>>
>>>> [END OUTPUT]
>>>>
>>>>
>>>> ;--------------------------------------------------------------------------------------
>>>>
>>>>
>>>> (c-declare "struct { int x; int y; } point;")
>>>>
>>>> (define no-err ((c-lambda () scheme-object "___result =
>>>> ___FIX(___NO_ERR);")))
>>>>
>>>> (define ptr-serial #f)
>>>>
>>>>
>>>> (c-define (release-point ptr)
>>>>           ((pointer void)) scheme-object "scm_release_point" ""
>>>>   (set! ptr-serial (object->serial-number ptr))
>>>>   (println "release-point called on serial " ptr-serial)
>>>>   (println "found in object table as: "
>>>>     (table-ref ##serial-number-to-object-table ptr-serial 'not-there))
>>>>
>>>>   ((c-lambda ((pointer void)) void "___release_rc") ptr)
>>>>   no-err)
>>>>
>>>> (c-define-type point (type "point" (point*) "scm_release_point"))
>>>>
>>>>
>>>> (define p ((c-lambda () point
>>>>              "___result_voidstar =
>>>> ___EXT(___alloc_rc)(sizeof(point));")))
>>>>
>>>> (println "p is " p)
>>>>
>>>> (set! p #f)
>>>>
>>>> (##gc)
>>>>
>>>> (newline)
>>>> (println "*** after GC:")
>>>> (print "foreign serial is " ptr-serial)
>>>> (print ", corresponding to "
>>>>   (table-ref ##serial-number-to-object-table ptr-serial 'not-there))
>>>>
>>>> (print ", a "
>>>>          (if ((c-lambda (scheme-object) bool "___result =
>>>> ___MEM_ALLOCATED(___arg1);")
>>>>               (table-ref ##serial-number-to-object-table ptr-serial
>>>> 'not-there))
>>>>            ""
>>>>            "not")
>>>>          " mem-allocated")
>>>>
>>>> (print " "
>>>>   ((c-lambda (scheme-object) char-string "___result =
>>>> ___HD_TYP(___BODY(___arg1)[-1]) == ___STILL ? \"still\" : \"something
>>>> else\";")
>>>>    (table-ref ##serial-number-to-object-table ptr-serial 'not-there)))
>>>>
>>>> (println " object with reference count == "
>>>>          ((c-lambda (scheme-object) int "___result =
>>>> ___UNTAG(___arg1)[___BODY_OFS - 6 + 1];")
>>>>           (table-ref ##serial-number-to-object-table ptr-serial
>>>> 'not-there)))
>>>>
>>>> (println "Bye.")
>>>>
>>>>
>>>>
>>>>
>>>> On Mon, Dec 30, 2013 at 10:09 AM, Mikael <mikael.rcv at gmail.com> wrote:
>>>>
>>>>> Refcount is 1 by default so you need to decrease it for it to GFC?
>>>>>
>>>>> Allocate a zillion points and check the two respective ways.
>>>>>
>>>>>
>>>>> 2013/12/29 Estevo <euccastro at gmail.com>
>>>>>
>>>>>>  Here's a more realistic version of what I was trying to do:
>>>>>>
>>>>>> (c-declare "struct { int x; int y; } point;")
>>>>>>
>>>>>> (define no-err ((c-lambda () scheme-object "___result =
>>>>>> ___FIX(___NO_ERR);")))
>>>>>>
>>>>>> (c-define (release-point ptr)
>>>>>>           ((pointer void)) scheme-object "scm_release_point" ""
>>>>>>   (println "release-point called")
>>>>>>   ((c-lambda ((pointer void)) void "___release_rc") ptr)
>>>>>>   no-err)
>>>>>>
>>>>>> (c-define-type point (pointer "point" (point*) "scm_release_point"))
>>>>>>
>>>>>>
>>>>>> (define p ((c-lambda () point
>>>>>>              "___result_voidstar =
>>>>>> ___EXT(___alloc_rc)(sizeof(point));")))
>>>>>>
>>>>>> (println "p is " p)
>>>>>> (set! p #f)
>>>>>>
>>>>>> (##gc)
>>>>>>
>>>>>> (println "Bye.")
>>>>>>
>>>>>> valgrind's complaint is different in this one.  What is leaked here
>>>>>> (again, unless valgrind is giving me a false positive) seems to be the
>>>>>> Scheme representation of `ptr`:
>>>>>>
>>>>>> ==9631== Memcheck, a memory error detector
>>>>>> ==9631== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et
>>>>>> al.
>>>>>> ==9631== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright
>>>>>> info
>>>>>> ==9631== Command: ./test-c-define
>>>>>> ==9631==
>>>>>> p is #<point* #2 0x5c04620>
>>>>>> release-point called
>>>>>> Bye.
>>>>>> ==9631==
>>>>>> ==9631== HEAP SUMMARY:
>>>>>> ==9631==     in use at exit: 158 bytes in 2 blocks
>>>>>> ==9631==   total heap usage: 154 allocs, 152 frees, 4,247,245 bytes
>>>>>> allocated
>>>>>> ==9631==
>>>>>> ==9631== 158 (87 direct, 71 indirect) bytes in 1 blocks are
>>>>>> definitely lost in loss record 2 of 2
>>>>>> ==9631==    at 0x4C2B6CD: malloc (in
>>>>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>>>>> ==9631==    by 0x4C7DC6: ___alloc_mem (os_base.c:185)
>>>>>> ==9631==    by 0x4B6905: alloc_mem_aligned (mem.c:452)
>>>>>> ==9631==    by 0x4B77A7: alloc_scmobj_still (mem.c:1245)
>>>>>> ==9631==    by 0x4B78B1: ___alloc_scmobj (mem.c:1285)
>>>>>> ==9631==    by 0x4C3DEE: ___POINTER_to_SCMOBJ (c_intf.c:5154)
>>>>>> ==9631==    by 0x4B1C88: scm_release_point (test-c-define.c:665)
>>>>>> ==9631==    by 0x4C1027: ___release_foreign (c_intf.c:1713)
>>>>>> ==9631==    by 0x4BAEA4: free_unmarked_still_objs (mem.c:3271)
>>>>>> ==9631==    by 0x4BD472: ___garbage_collect (mem.c:4698)
>>>>>> ==9631==    by 0x4E4357: ___H__20___kernel (_kernel.c:9170)
>>>>>> ==9631==    by 0x4B49B2: trampoline (setup.c:1618)
>>>>>> ==9631==
>>>>>> ==9631== LEAK SUMMARY:
>>>>>> ==9631==    definitely lost: 87 bytes in 1 blocks
>>>>>> ==9631==    indirectly lost: 71 bytes in 1 blocks
>>>>>> ==9631==      possibly lost: 0 bytes in 0 blocks
>>>>>> ==9631==    still reachable: 0 bytes in 0 blocks
>>>>>> ==9631==         suppressed: 0 bytes in 0 blocks
>>>>>> ==9631==
>>>>>> ==9631== For counts of detected and suppressed errors, rerun with: -v
>>>>>> ==9631== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from
>>>>>> 2)
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Thu, Dec 26, 2013 at 11:23 PM, Estevo <euccastro at gmail.com> wrote:
>>>>>>
>>>>>>> Valgrind reports Gambit is leaking a "sfun stack marker" if I call,
>>>>>>> from a foreign release function, another function defined with `c-define`.
>>>>>>> The code below is about the most innocent looking thing I could come up
>>>>>>> with.
>>>>>>>
>>>>>>> Doesn't Gambit like c-define functions called within release
>>>>>>> functions, or is Valgrind giving me a false positive here (as it is wont to
>>>>>>> do quite often.)
>>>>>>>
>>>>>>> ; ~/gambit-dbg/bin/gsc -exe -cc-options -g test-c-define.scm &&
>>>>>>> valgrind --leak-check=full ./test-c-define
>>>>>>>
>>>>>>> (c-declare #<<c-declare-end
>>>>>>>
>>>>>>> typedef struct { int x; int y; } point;
>>>>>>>
>>>>>>> void scm_release_point(unsigned long);
>>>>>>>
>>>>>>> ___SCMOBJ c_release_point(void *ptr) {
>>>>>>>     scm_release_point((unsigned long)ptr);
>>>>>>>     ___EXT(___release_rc)(ptr);
>>>>>>>     return ___FIX(___NO_ERR);
>>>>>>> }
>>>>>>>
>>>>>>> c-declare-end
>>>>>>> )
>>>>>>>
>>>>>>> (c-define (release-point ptr) (unsigned-long) void
>>>>>>> "scm_release_point" ""
>>>>>>>   (println "release-point called"))
>>>>>>>
>>>>>>> (c-define-type point (pointer "point" (point*) "c_release_point"))
>>>>>>>
>>>>>>> (define p ((c-lambda () point
>>>>>>>                  "___result_voidstar =
>>>>>>> ___EXT(___alloc_rc)(sizeof(point));")))
>>>>>>>
>>>>>>> (println "p is " p)
>>>>>>> (set! p #f)
>>>>>>>
>>>>>>> (##gc)
>>>>>>> ; for good measure...
>>>>>>> (##gc)
>>>>>>> (##gc)
>>>>>>>
>>>>>>> (println "Bye.")
>>>>>>>
>>>>>>>
>>>>>>> valgrind --leak-check=full ./test-c-define
>>>>>>> ==16301== Memcheck, a memory error detector
>>>>>>> ==16301== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward
>>>>>>> et al.
>>>>>>> ==16301== Using Valgrind-3.7.0 and LibVEX; rerun with -h for
>>>>>>> copyright info
>>>>>>> ==16301== Command: ./test-c-define
>>>>>>> ==16301==
>>>>>>> p is #<point* #2 0x5c04640>
>>>>>>> release-point called
>>>>>>> Bye.
>>>>>>> ==16301==
>>>>>>> ==16301== HEAP SUMMARY:
>>>>>>> ==16301==     in use at exit: 71 bytes in 1 blocks
>>>>>>> ==16301==   total heap usage: 153 allocs, 152 frees, 4,247,198 bytes
>>>>>>> allocated
>>>>>>> ==16301==
>>>>>>> ==16301== 71 bytes in 1 blocks are definitely lost in loss record 1
>>>>>>> of 1
>>>>>>> ==16301==    at 0x4C2B6CD: malloc (in
>>>>>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>>>>>> ==16301==    by 0x4C922E: ___alloc_mem (os_base.c:185)
>>>>>>> ==16301==    by 0x4B7DB5: alloc_mem_aligned (mem.c:452)
>>>>>>> ==16301==    by 0x4B8C57: alloc_scmobj_still (mem.c:1245)
>>>>>>> ==16301==    by 0x4B8D61: ___alloc_scmobj (mem.c:1285)
>>>>>>> ==16301==    by 0x4B8E44: ___make_vector (mem.c:1362)
>>>>>>> ==16301==    by 0x4C677B: ___make_sfun_stack_marker (c_intf.c:6452)
>>>>>>> ==16301==    by 0x4B359E: scm_release_point (test-c-define.c:139)
>>>>>>> ==16301==    by 0x4B354B: c_release_point (test-c-define.c:130)
>>>>>>> ==16301==    by 0x4C24D7: ___release_foreign (c_intf.c:1713)
>>>>>>> ==16301==    by 0x4BC354: free_unmarked_still_objs (mem.c:3271)
>>>>>>> ==16301==    by 0x4BE922: ___garbage_collect (mem.c:4698)
>>>>>>> ==16301==
>>>>>>> ==16301== LEAK SUMMARY:
>>>>>>> ==16301==    definitely lost: 71 bytes in 1 blocks
>>>>>>> ==16301==    indirectly lost: 0 bytes in 0 blocks
>>>>>>> ==16301==      possibly lost: 0 bytes in 0 blocks
>>>>>>> ==16301==    still reachable: 0 bytes in 0 blocks
>>>>>>> ==16301==         suppressed: 0 bytes in 0 blocks
>>>>>>> ==16301==
>>>>>>> ==16301== For counts of detected and suppressed errors, rerun with:
>>>>>>> -v
>>>>>>> ==16301== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2
>>>>>>> from 2)
>>>>>>>
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> Gambit-list mailing list
>>>>>> Gambit-list at iro.umontreal.ca
>>>>>> https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.iro.umontreal.ca/pipermail/gambit-list/attachments/20140101/2e213a22/attachment.htm>


More information about the Gambit-list mailing list