#10287: memleak in bitset_realloc()
-----------------------+----------------------------------------------------
   Reporter:  mvngu    |       Owner:  rlm       
       Type:  defect   |      Status:  new       
   Priority:  major    |   Milestone:  sage-4.6.1
  Component:  memleak  |    Keywords:            
     Author:           |    Upstream:  N/A       
   Reviewer:           |      Merged:            
Work_issues:           |  
-----------------------+----------------------------------------------------
 See [https://groups.google.com/group/sage-
 devel/browse_thread/thread/57890c6e134a5d45 this thread] for some
 background information.

 The relevant module is

 {{{
 sage/misc/bitset.pxi
 }}}

 and the function concerned is `bitset_realloc()`. A memleak occurs when we
 have a bitset of positive size (or capacity) and then reallocate the size
 to be zero. To pick up the memleak, I first loaded Sage 4.6.1.alpha1 under
 valgrind and quit Sage without doing any computation. The resulting
 memleak summary is:

 {{{
 ==26274== LEAK SUMMARY:
 ==26274==    definitely lost: 80 bytes in 3 blocks.
 ==26274==    indirectly lost: 240 bytes in 10 blocks.
 ==26274==      possibly lost: 562,324 bytes in 1,305 blocks.
 ==26274==    still reachable: 60,547,159 bytes in 41,676 blocks.
 ==26274==         suppressed: 0 bytes in 0 blocks.
 ==26274== Reachable blocks (those to which a pointer was found) are not
 shown.
 ==26274== To see them, rerun with: --leak-check=full --show-reachable=yes
 }}}

 I then applied the following patch to the Sage library:

 {{{
 #!diff
 # HG changeset patch
 # User Minh Van Nguyen <[email protected]>
 # Date 1289991585 28800
 # Node ID 0554c5d2f725c4d29a6ca0176249b3febb235be2
 # Parent  8c722bce2f917caab751122ef48b6057821142de
 imported patch test.patch

 diff --git a/module_list.py b/module_list.py
 --- a/module_list.py
 +++ b/module_list.py
 @@ -978,6 +978,9 @@
      Extension('sage.misc.session',
                sources = ['sage/misc/session.pyx']),

 +    Extension('sage.misc.test',
 +              sources = ['sage/misc/test.pyx']),
 +
      ################################
      ##
      ## sage.modular
 diff --git a/sage/misc/test.pyx b/sage/misc/test.pyx
 new file mode 100644
 --- /dev/null
 +++ b/sage/misc/test.pyx
 @@ -0,0 +1,12 @@
 +include "../ext/stdsage.pxi"
 +include "bitset_pxd.pxi"
 +include "bitset.pxi"
 +
 +def test():
 +    cdef bitset_t a
 +    bitset_init(a, 10)
 +    try:
 +        bitset_realloc(a, 0)
 +    except MemoryError:
 +        pass
 +    bitset_free(a)
 }}}

 I loaded Sage under valgrind again and performed the following
 computation:

 {{{
 #!python
 sage: from sage.misc.test import test
 sage: test()
 }}}

 which resulted in the following memleak summary:

 {{{
 ==16502== LEAK SUMMARY:
 ==16502==    definitely lost: 88 bytes in 4 blocks.
 ==16502==    indirectly lost: 240 bytes in 10 blocks.
 ==16502==      possibly lost: 563,732 bytes in 1,308 blocks.
 ==16502==    still reachable: 60,550,541 bytes in 41,691 blocks.
 ==16502==         suppressed: 0 bytes in 0 blocks.
 ==16502== Reachable blocks (those to which a pointer was found) are not
 shown.
 ==16502== To see them, rerun with: --leak-check=full --show-reachable=yes
 }}}

 Notice that despite the function `test()` explicitly freeing memory,
 the report on "definitely lost" shows that we leaked an extra 8 bytes
 (compare the 80 and 88 above in the first and second memleak
 summaries, respectively). Finally, I applied the following patch to
 the Sage library:

 {{{
 #!diff
 # HG changeset patch
 # User Minh Van Nguyen <[email protected]>
 # Date 1289992646 28800
 # Node ID 9b5492b0ccc3a23626435f30433ebc52a673499f
 # Parent  0554c5d2f725c4d29a6ca0176249b3febb235be2
 imported patch memleak.patch

 diff --git a/sage/misc/bitset.pxi b/sage/misc/bitset.pxi
 --- a/sage/misc/bitset.pxi
 +++ b/sage/misc/bitset.pxi
 @@ -52,8 +52,10 @@
      cdef unsigned long size_old = bits.size
      if size_old == size: return 0
      bits.limbs = (size - 1)/(8*sizeof(unsigned long)) + 1
 -    bits.bits = <unsigned long*>sage_realloc(bits.bits, bits.limbs *
 sizeof(unsigned long))
 -    if bits.bits == NULL:
 +    tmp = <unsigned long*>sage_realloc(bits.bits, bits.limbs *
 sizeof(unsigned long))
 +    if tmp != NULL:
 +        bits.bits = tmp
 +    else:
          bits.limbs = limbs_old
          raise MemoryError
      bits.size = size
 }}}

 I loaded Sage under valgrind a third time and performed the following
 computation, same as above:

 {{{
 #!python
 sage: from sage.misc.test import test
 sage: test()
 }}}

 The corresponding memleak summary is:

 {{{
 ==22029== LEAK SUMMARY:
 ==22029==    definitely lost: 80 bytes in 3 blocks.
 ==22029==    indirectly lost: 240 bytes in 10 blocks.
 ==22029==      possibly lost: 564,252 bytes in 1,309 blocks.
 ==22029==    still reachable: 60,550,168 bytes in 41,696 blocks.
 ==22029==         suppressed: 0 bytes in 0 blocks.
 ==22029== Reachable blocks (those to which a pointer was found) are not
 shown.
 ==22029== To see them, rerun with: --leak-check=full --show-reachable=yes
 }}}

 Notice that the summary for "definitely lost" now shows 80 bytes, the same
 as for the first memleak summary above. Thus the patch `memleak.patch`
 fixes the memleak in `sage.misc.bitset.bitset_realloc`.

-- 
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/10287>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sage-trac?hl=en.

Reply via email to