[Pyrex] Python Strings and PyMem_Malloc/Free

Grant McDonald gmcdonald at infocomp.com
Thu Jun 30 08:06:38 CEST 2005


Hi,

I fear I may have been operating under a false assumption with regards to
creating Python strings. This assumption goes like this:

1) Whatever memory you PyMem_Malloc you should always PyMem_Free.
2) For strings you malloc and need to turn into python strings assign them
to a python variable in Pyrex then PyMem_Free the pointer to the string
before you return the python object.
3) This shouldn't present a problem because PyString_FromString copies the
string to an internal representation (this is my assumption).

I believe the last statement may be completely erroneous :). Here is some
code based upon this assumption:

cdef class Interface:
    cdef TRK_HANDLE trkHandle
    cdef TRK_ASSOC_HANDLE trkAssociationHandle
    cdef TRK_RECORD_HANDLE trkRecordHandle
    cdef TRK_NOTE_HANDLE trkNoteHandle
    cdef TRK_ATTFILE_HANDLE trkAttFileHandle
    cdef TRK_IMPORT_HANDLE trkImportHandle
    cdef TRK_EXPORT_HANDLE trkExportHandle

    .
    .
    .

    def GetNote(self):
        cdef TRK_UINT bufferSize, remaining, max, titleSize, result
        cdef LPSTR buffer, title, temp_buffer
        
        result = TrkGetNoteDataLength(self.trkNoteHandle, &bufferSize)
        if result != TRK_SUCCESS:
            raise ExtensionExceptions.TrackerError, result
            
        buffer = <LPSTR>PyMem_Malloc(sizeof(char)*bufferSize)
        if buffer == NULL:
            raise Exception, "Could not malloc %d bytes!!" % bufferSize
        temp_buffer = <LPSTR>PyMem_Malloc(sizeof(char)*bufferSize)
        if temp_buffer == NULL:
            raise Exception, "Could not malloc %d bytes!!" % bufferSize
        memset(buffer, 0x00, bufferSize)
        memset(temp_buffer, 0x00, bufferSize)
            
        if bufferSize > 10000:
            max = 10000
        else:
            max = bufferSize
            
        remaining = bufferSize
        pyNote = ''
            
        while remaining != 0:
            result = TrkGetNoteData(self.trkNoteHandle, max, temp_buffer,
&remaining)
            if result != TRK_SUCCESS and result != TRK_E_DATA_TRUNCATED:
                PyMem_Free(buffer)
                PyMem_Free(temp_buffer)
                raise ExtensionExceptions.TrackerError, result
            strcat(buffer, temp_buffer)
            memset(temp_buffer, 0x00, bufferSize)
        
        titleSize = 200
        
        title = <LPSTR>PyMem_Malloc(sizeof(char)*titleSize)
        if title == NULL:
            raise Exception, "Could not malloc %d bytes!!" % titleSize
        memset(title, 0x00, titleSize)
        
        result = TrkGetNoteTitle(self.trkNoteHandle, titleSize, title)
        if result != TRK_SUCCESS:
            PyMem_Free(buffer)
            PyMem_Free(temp_buffer)
            PyMem_Free(title)
            raise ExtensionExceptions.TrackerError, result
        
        pyTitle = title
        pyNote = buffer
        
        # it is this code that appears to be problematic
        PyMem_Free(buffer)
        PyMem_Free(temp_buffer)
        PyMem_Free(title)
        
        return (pyTitle,pyNote)

As the code stands calling this function _sometimes_ crashes the Python
interpreter (usually the 3rd or 5th call) with an access violation (mem
address 0x0000000 which would imply a null pointer reference). If I comment
out the final three calls to PyMem_Free then the problem does not arise.

If my assumption is wrong does the same hold true for structures? I have
similar malloc/free calls for structures which save data from them and then
free the structure memory before returning.

Any information is appreciated,

Grant M.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.copyleft.no/pipermail/pyrex/attachments/20050630/015bf551/attachment.html


More information about the Pyrex mailing list