Menu

#950 REDIM PRESERVE does not destroy the right array elements of a multidimensional array -> memory leak

closed
nobody
None
compiler
2021-12-05
2021-11-22
No

When decreasing the size of a multidimension array using REDIM PRESERVE, the number of array elements to be destroyed and their locations are not correct (this works for a 1D array).

For more information and test codes, see the 'REDIM PRESERVE does not destroy the right array elements of a multidimensional array -> memory leak' topic on the forum (in 'General'):
https://www.freebasic.net/forum/viewtopic.php?f=3&t=29713

Discussion

  • fxm (freebasic.net)

    By cons, when increasing the size of a multidimensional array using REDIM PRESERVE, the number of array elements to be constructed and their locations are correct.

     
  • fxm (freebasic.net)

    In the example I gave below, there is an error in both the number and location of elements to be destroyed.


    Yet the rule is simple:

    For a dynamic array, if the total number of elements required by REDIM PRESERVE is reduced by "N" elements compared to the total number of existing elements, the last "N" elements of the existing array must be destroyed before reallocating the memory for the new array.

    Then, the only difficulty is to correctly calculate the address zone of the elements to be destroyed:

    • The address of the last element of the array (before resizing) is easy to calculate with the information in the array descriptor (any ptr: base_ptr, uinteger: size, uinteger: element_len).
      Last element address: base_ptr + size - element_len
    • So it suffices to destroy the "N" elements by going up:
    Dim As FBC.FBARRAY Ptr p = FBC.ArrayDescriptorPtr(array())
    For X As Integer = 1 To N
        Cptr(Typeof(array) Ptr, p->base_ptr + p->size - p->element_len * X)->Destructor()
    Next X
    
     

    Last edit: fxm (freebasic.net) 2021-11-27
  • fxm (freebasic.net)

    Simple example to highlight the bug

    In the following code using a UDT with destructor as data-type for the 2D array, and for the transition:
    Redim array(3, 4) -> Redim Preserve array(2, 3)
    we see that only 5 instances are destroyed by 'REDIM PRESERVE' and the wrong ones (not the last 8 instances of the array before resizing):
    (fbc 32-bit)

    Type UDT
        Dim As String s
        Declare Destructor()
    End Type
    
    Declare Sub fillArray(array(Any, Any) As UDT)
    Declare Sub printSizeArray(array(Any, Any) As UDT)
    Declare Sub printArray(array(Any, Any) As UDT)
    
    Destructor UDT()
        Print "destroy instance at address: &h" & Hex(@This)
    End Destructor
    
    Dim As UDT array(Any, Any)
    
    Redim array(3, 4)
    fillArray(array())
    printSizeArray(array())
    printArray(array())
    
    Redim Preserve array(2, 3)
    Print
    printSizeArray(array())
    printArray(array())
    
    Sleep
    
    Sub fillArray(array(Any, Any) As UDT)
        For I As Integer = 0 To Ubound(array, 1)
            For J As Integer = 0 To Ubound(array, 2)
                array(I, J).s = Str(10 * I + J)
            Next J
        Next I
    End Sub
    
    Sub printSizeArray(array(Any, Any) As UDT)
        Print "size: " & Ubound(array, 1) + 1 & "x" & Ubound(array, 2) + 1, "instance address: from &h" & Hex(@array(0, 0)) & " up to &h" & Hex(@array(Ubound(array, 1), Ubound(array, 2)))
    End Sub   
    
    Sub printArray(array(Any, Any) As UDT)
        For I As Integer = 0 To Ubound(array, 1)
            For J As Integer = 0 To Ubound(array, 2)
                Print , "'" & array(I, J).s & "'";
            Next J
            Print
        Next I
        Print
    End Sub
    
    size: 4x5     instance address: from &hA82888 up to &hA8296C
                  '0'           '1'           '2'           '3'           '4'
                  '10'          '11'          '12'          '13'          '14'
                  '20'          '21'          '22'          '23'          '24'
                  '30'          '31'          '32'          '33'          '34'
    
    destroy instance at address: &hA828DC
    destroy instance at address: &hA828D0
    destroy instance at address: &hA828C4
    destroy instance at address: &hA828B8
    destroy instance at address: &hA828AC
    
    size: 3x4     instance address: from &hA82888 up to &hA8290C
                  '0'           '1'           '2'           ''
                  ''            ''            ''            ''
                  '13'          '14'          '20'          '21'
    
    destroy instance at address: &hA8290C
    destroy instance at address: &hA82900
    destroy instance at address: &hA828F4
    destroy instance at address: &hA828E8
    destroy instance at address: &hA828DC
    destroy instance at address: &hA828D0
    destroy instance at address: &hA828C4
    destroy instance at address: &hA828B8
    destroy instance at address: &hA828AC
    destroy instance at address: &hA828A0
    destroy instance at address: &hA82894
    destroy instance at address: &hA82888
    

    Even for a transition that must keep the data with their values at the right addresses:
    Redim array(4, 5) -> Redim Preserve array(3, 5)
    the destroyed instances by 'REDIM PRESERVE' are not the correct instances:
    (fbc 32-bit)

    size: 5x6     instance address: from &hBB2888 up to &hBB29E4
                  '0'           '1'           '2'           '3'           '4'           '5'
                  '10'          '11'          '12'          '13'          '14'          '15'
                  '20'          '21'          '22'          '23'          '24'          '25'
                  '30'          '31'          '32'          '33'          '34'          '35'
                  '40'          '41'          '42'          '43'          '44'          '45'
    
    destroy instance at address: &hBB28F4
    destroy instance at address: &hBB28E8
    destroy instance at address: &hBB28DC
    destroy instance at address: &hBB28D0
    destroy instance at address: &hBB28C4
    destroy instance at address: &hBB28B8
    
    size: 4x6     instance address: from &hBB2888 up to &hBB299C
                  '0'           '1'           '2'           '3'           ''            ''
                  ''            ''            ''            ''            '14'          '15'
                  '20'          '21'          '22'          '23'          '24'          '25'
                  '30'          '31'          '32'          '33'          '34'          '35'
    
    destroy instance at address: &hBB299C
    destroy instance at address: &hBB2990
    destroy instance at address: &hBB2984
    destroy instance at address: &hBB2978
    destroy instance at address: &hBB296C
    destroy instance at address: &hBB2960
    destroy instance at address: &hBB2954
    destroy instance at address: &hBB2948
    destroy instance at address: &hBB293C
    destroy instance at address: &hBB2930
    destroy instance at address: &hBB2924
    destroy instance at address: &hBB2918
    destroy instance at address: &hBB290C
    destroy instance at address: &hBB2900
    destroy instance at address: &hBB28F4
    destroy instance at address: &hBB28E8
    destroy instance at address: &hBB28DC
    destroy instance at address: &hBB28D0
    destroy instance at address: &hBB28C4
    destroy instance at address: &hBB28B8
    destroy instance at address: &hBB28AC
    destroy instance at address: &hBB28A0
    destroy instance at address: &hBB2894
    destroy instance at address: &hBB2888
    
     

    Last edit: fxm (freebasic.net) 2021-11-28
  • fxm (freebasic.net)

    Bug of element destruction for a 2D array (deduced from all my tests):

    • The wrong number of destroyed elements "D" seems to be equal to the size of the second dimension (before resizing) multiplied by the size difference of the first dimension between before and after resizing.
    • The wrong first element destroyed seems to be deduced from the first of the "D" last elements (of the array before resizing) but by dividing its absolute index (0-based) by the number of elements of the second dimension (before resizing).
     
  • Jeff Marshall

    Jeff Marshall - 2021-12-05
    • status: open --> closed
     

Log in to post a comment.

MongoDB Logo MongoDB