electronstudio / raylib-python-cffi

Python CFFI bindings for Raylib
http://electronstudio.github.io/raylib-python-cffi
Eclipse Public License 2.0
142 stars 29 forks source link

Ubuntu 20.04: unload_image() results in double free or corruption (out) #56

Closed madgrizzle closed 2 years ago

madgrizzle commented 2 years ago

When using the opencv example in Ubuntu 20.04, upon closing the window it kicks out the above error message. This doesn't seem to happen on my Windows 10 machine. I've used the code from that example in my application (runs on the Ubuntu 20.04 machine) which displays images to the screen that come in from a webcam. However, if I attempt to unload_image() after creating the texture, it crashes with that error message. If I don't unload the image, then I eventually run out of memory and the application is killed.

electronstudio commented 2 years ago

I think what happens in the example is that opencv_image and raylib_image both contain pointers to the same memory buffer. When you unload_image, raylib frees the memory. Then when the program exits, opencv_image goes out of scope, so the Python garbage collector deletes it. Part of this deletion is freeing the memory pointed to, resulting in a double-free error, because that memory has already been freed.

What's happening in your program, I don't know. The example only crashes at the end, whereas your program crashes immediately (?) so something must be different between them.

If the crashes are happening when your opencv images go out of scope and/or when the garbage collector runs, then I would suggest maintaining global references to them at all times so they are never garbage collected.

Alternatively, don't create raylib images and opencv images that share memory. Create the opencv image, then copy the buffer to a new buffer, then use the new buffer to create the raylib image.

madgrizzle commented 2 years ago

Thanks for the response. In my application (which display a webcam) it is constantly create and 'unloading' the frame in a loop. I did some checking and it seems to crash right after the second image being unloaded. I also changed the opencv.py demo to reload the image in the loop and it crashes after a 5 or so iteration. I've been searching raylib+ubuntu issues with unload image and haven't really anything other than https://github.com/raysan5/raylib/issues/689 and that was 3 years ago.

It's odd though that this doesn't occur on my Windows machine. Anyway, thanks for the input, I'll see about copying the buffer.

madgrizzle commented 2 years ago

I discovered that using ffi.release(pointer_to_image_data) instead of unload_image(opencv_image) seemed to accomplished what I needed. No crashes and it no longer continues to consume memory. /shrug

electronstudio commented 2 years ago

That’s cool.

My speculations:

Windows Python didn’t crash because either the GC behaviour is different or because Windows has protection against double free errors.

Using FFI to release the memory works because then Python knows the memory is already released and so when the GC deletes the image it doesn’t attempt to free it again. Using Raylib to release the memory is just calling Raylibs C code which Python knows nothing about so it didn’t know memory was freed.

madgrizzle commented 2 years ago

Yep.. it does seem somewhat logical that if you create the pointer to the memory via FFI then you need to release it via FFI. I guess many using raylib don't need to do it this way, but raylib is really useful for my application (my robot's video display) when using opencv's imshow doesn't do what you need it to do. Thanks again.