The decrease of refcount in ##make-u8vector 's code could possibly have to do with that this procedure uses ##c-code rather than ##c-lambda - if the latter would have been used, maybe the refcount decrease wouldn't have been needed.<div>

<br></div><div>I'm still experiencing the memory leak problem though am unclear about where it comes from.<br></div><div><br></div><div>If it would be sqlite now, it would be because that alloc_scmobj somehow was made to leak due to some characteristic of the bigger execution context, that my reduced test case doesn't contain. Possibly I could add that stack management magic code that ##make-u8vector uses just to see if that would make a difference.</div>

<div><br></div><div><br>The leak manifests as a constant increasing of Gambit's live heap size, as shown by (##display-gc-report) / (##gc-report-set! #t) . *debugging*.</div><div><br></div><div><br></div><div>Noone ever experienced a leak in the IO subsystem, right?</div>

<div><br></div><div><br></div><div>Regards, Mikael<br><br><div class="gmail_quote">2013/6/16 Jussi Piitulainen <span dir="ltr"><<a href="mailto:jpiitula@ling.helsinki.fi" target="_blank">jpiitula@ling.helsinki.fi</a>></span><br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Mikael, Marc, the mention of sqlite specifically caught my eye.<br>
<br>
I use the following code for accessing blobs in the database as any<br>
homogeneous vector type in my own SQLite3 FFI of last summer. The code<br>
was exercised as part of a larger program and seemed to work. __STILL<br>
was the key.<br>
<br>
Maybe it should decrease a refcount when __alloc_scmobj fails?<br>
<br>
(c-declare<br>
#<<c-declare-end<br>
static ___SCMOBJ<br>
resqlite3_column_blob(sqlite3_stmt* stmt, int col, int type, int size)<br>
{<br>
   const void *buf = sqlite3_column_blob(stmt, col);<br>
   int n = sqlite3_column_bytes(stmt, col);<br>
   if (n % size) return ___FIX(___UNKNOWN_ERR);<br>
   ___SCMOBJ result = ___EXT(___alloc_scmobj)(type,n,___STILL);<br>
   if (___FIXNUMP(result)) return result;<br>
   memcpy(___BODY(result), buf, n);<br>
   return result;<br>
}<br>
c-declare-end<br>
)<br>
<br>
(define sqlite3-column-u8vector-or-code<br>
  (c-lambda<br>
   (sqlite3-prepared-statement int) scheme-object<br>
   "___result = resqlite3_column_blob(___arg1,___arg2,___sU8VECTOR,1);"))<br>
<br>
The latter definition is then repeated for each vector type and<br>
element size.<br>
<div class="im"><br>
<br>
Mikael <<a href="mailto:mikael.rcv@gmail.com">mikael.rcv@gmail.com</a>> writes:<br>
<br>
> Dear Marc,<br>
><br>
> Just realized there's a memory leak in many Gambit libraries, such as the<br>
> sqlite FFI - their u8vector allocation in C boils down to:<br>
><br>
> ___result = ___EXT(___alloc_scmobj)(___sU8VECTOR,len,___MOVABLE0);<br>
><br>
><br>
><br>
><br>
> Studying ##make-u8vector of _kernel.scm provides some inspiration: It<br>
><br>
>  1) Shows that it's fine to use ___STILL<br>
><br>
>  2) Uses  ___still_obj_refcount_dec ,<br>
><br>
>  3) Has its C code in a ##c-code and not a ##c-lambda<br>
><br>
>  4) Has its surrounding Scheme code in (##declare (not interrupts-enabled))<br>
><br>
>  5) Surrounds the ___alloc_scmobj call by some magic (<br>
</div>> ___FRAME_STORE_RA(___R0)___W_ALL ___R_ALL ___SET_R0(___FRAME_FETCH_RA) )<br>
<div class="im">><br>
> (##make-u8vector provides a code path for small objects apart from this,<br>
> though the use regarded here should be for u8vectors of nontrivial size so<br>
> going with the codepath for large objects should always be fine.)<br>
><br>
><br>
> By applying 1) and 2) I get something that works but can't know if it's<br>
> really correct and safe:<br>
><br>
><br>
> How do you allocate an u8vector in C code in a way that does not leak<br>
> memory, and that safely transfers the new object reference from the C world<br>
> to the Scheme world?<br>
><br>
><br>
><br>
> Thanks!<br>
> Mikael<br>
><br>
><br>
</div>> *How to reproduce*<br>
<div class="im">> Running a test that repeats<br>
><br>
> ((c-lambda () scheme-object "___result =<br>
> ___EXT(___alloc_scmobj)(___sU8VECTOR,10000,___MOVABLE0);"))<br>
><br>
><br>
> over and over e.g.<br>
><br>
> (##gc-report-set! #t)<br>
> (for-each (lambda (x) ((c-lambda () scheme-object "___result =<br>
> ___EXT(___alloc_scmobj)(___sU8VECTOR,10000,___MOVABLE0);")))<br>
>           (string->list (make-string 100000))<br>
> (##gc)<br>
><br>
><br>
> shows that this memory leaks all the allocated memory (!).<br>
><br>
><br>
</div>> *Fix, duno if safe & complete*<br>
<div class="im">><br>
> (##gc-report-set! #t)<br>
> (for-each (lambda (x) ((c-lambda () scheme-object "___result =<br>
> ___EXT(___alloc_scmobj)(___sU8VECTOR,10000,___STILL);<br>
>                                                    if<br>
> (!___FIXNUMP(___result)) ___still_obj_refcount_dec (___result);<br>
>                                                    ")))<br>
>           (string->list (make-string 100000))<br>
> (##gc)<br>
><br>
><br>
><br>
</div>> *Copy of ##make-u8vector of _kernel.scm for reference*<br>
<div><div class="h5">><br>
> (define-prim (##make-u8vector k #!optional (fill (macro-absent-obj)))<br>
>   (##declare (not interrupts-enabled))<br>
>   (let ((v (##c-code #<<end-of-code<br>
><br>
> long i;<br>
> long n = ___INT(___ARG1);<br>
> long words = ___WORDS(n) + 1;<br>
> ___SCMOBJ result;<br>
> if (n > ___CAST(___WORD, ___LMASK>>___LF))<br>
>   result = ___FIX(___HEAP_OVERFLOW_ERR); /* requested object is too big! */<br>
> else if (words > ___MSECTION_BIGGEST)<br>
>   {<br>
>     ___FRAME_STORE_RA(___R0)<br>
>     ___W_ALL<br>
>     result = ___alloc_scmobj (___sU8VECTOR, n, ___STILL);<br>
>     ___R_ALL<br>
>     ___SET_R0(___FRAME_FETCH_RA)<br>
>     if (!___FIXNUMP(result))<br>
>       ___still_obj_refcount_dec (result);<br>
>   }<br>
> else<br>
>   {<br>
>     ___BOOL overflow = 0;<br>
>     ___hp += words;<br>
>     if (___hp > ___ps->heap_limit)<br>
>       {<br>
>         ___FRAME_STORE_RA(___R0)<br>
>         ___W_ALL<br>
>         overflow = ___heap_limit () && ___garbage_collect (0);<br>
>         ___R_ALL<br>
>         ___SET_R0(___FRAME_FETCH_RA)<br>
>       }<br>
>     else<br>
>       ___hp -= words;<br>
>     if (overflow)<br>
>       result = ___FIX(___HEAP_OVERFLOW_ERR);<br>
>     else<br>
>       {<br>
>         result = ___TAG(___hp, ___tSUBTYPED);<br>
>         ___HEADER(result) = ___MAKE_HD_BYTES(n, ___sU8VECTOR);<br>
>         ___hp += words;<br>
>       }<br>
>   }<br>
> if (!___FIXNUMP(result) && ___ARG2 != ___ABSENT)<br>
>   {<br>
>     for (i=0; i<n; i++)<br>
>       ___U8VECTORSET(result,___FIX(i),___ARG2)<br>
>   }<br>
> ___RESULT = result;<br>
><br>
> end-of-code<br>
><br>
>             k<br>
>             fill)))<br>
>     (if (##fixnum? v)<br>
>       (begin<br>
>         (##raise-heap-overflow-exception)<br>
>         (##make-u8vector k fill))<br>
>       v)))<br>
</div></div>> _______________________________________________<br>
> Gambit-list mailing list<br>
> <a href="mailto:Gambit-list@iro.umontreal.ca">Gambit-list@iro.umontreal.ca</a><br>
> <a href="https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list" target="_blank">https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list</a><br>
<br>
</blockquote></div><br></div>