0
votes

I have been using cython for some time now without any problem. I make extensive use of malloc functions in most modules of my project, yet in this particular module realloc fails me in a strange way. Here is the faulty function:


    cdef MeshFace* addFace(self, cVector* p1, cVector* p2, 
              cVector* p3, cVector* normal):
            cdef cVector* pts[3]
            cdef MeshFace* f = NULL
            cdef void* ptr = NULL

            pts[0] = p1
            pts[1] = p2
            pts[2] = p3

            if(self._facenum >= self._facemem - 2):
                self._facemem = <int>(<double>self._facemem*1.25)
                ptr = realloc(self._faceList,
                  self._facemem*sizeof(MeshFace))
                if ptr == NULL:
                  return NULL
                self._faceList = ptr

             f = &self._faceList[self._facenum]
             MFace_init2(f, &pts[0], 3, NULL)

             self._facenum += 1

This function gets called multiple times to add faces to the mesh. Yet when the "facenum" values reaches somewhere around 600, python raises a memory error: error for object 0x100bef800: incorrect checksum for freed object - object was probably modified after being freed.

Other places I do use malloc without ANY problem. BTW: I run the program on a MacBook Pro (8GB RAM)

What am I doing wrong?

NB: the variable "_faceList" is initialized further up in the code using a malloc on 512 unit of struct MeshFace

2
This is missing a minimal reproducible example - there's no way for anyone but you to test this. However, I'm suspicious of the indentation of self._faceList = ptr - DavidW
I have corrected the indentation problem. Yaah, the project is quite large. I just can't post it here. - N. Wells
The problem is most likely elsewhere. You'll be doing something with that memory (e.g. accidentally modifying it/freeing it through a dangling pointer). The realloc is where the issue is detected, but isn't likely to be the origin - DavidW
The pointer "_faceList" is never modified anywhere, same with the returned value "f", which iis only read for rendering. I guess it has to do with ANOTHER pointer to a different memory address. How can it be possible? - N. Wells
You can write beyond the end of an array to where _faceList is. You could allocate something, free something, not clear the pointer and then when _faceList is realloced it could end up with the same address as the pointer you were using before - DavidW

2 Answers

0
votes

It was not obvious, but my insight is that python or the system (here OSX) kind of keeps a table of allocated pointer variables, so that after calling the "free" method, it IS NECESSARY to CLEAR the pointer variable by EXPLICITLY setting its value to NULL.

Example:


    free(pointer)
    pointer = NULL

This is NOT obvious as it is not for example mentioned in this post about proper ways to release memory in "C": Best way to release memory allocated using malloc

I hope this helps someone else. And thanks very much for the down-vote!

0
votes

All the answers provided previously are good, but the final solution to any memory allocation problem, I have found, is the use of a memory allocation interceptor such as DMALLOC. DMALLOC is debug memory allocation library that can be added to any C/C++ project. It intercepts any call to the standard functions malloc, free, calloc, etc, and allow for a detailed follow up of unfreed memory pointers. This way segmentation errors can be identified very fast. DMALLOC is available at DMALLOC.COM.

Also, a lesser solution is the use of ADB. ADB with its backtrace command can help narrow the part of the code that causes the issue. It is less precise than dmalloc, but requires no additional library to be coupled with the project.