GstMemory needs warnings in documentation or rework
A GstMemory object created with gst_memory_new_wrapped(0, ...)
can easily induce data-races.
As you know, it is a data-race to memcpy
a memory block that is being written to. So one would think there is a mechanism to avoid writable memory from being copied without locking that memory or without having a reference count equal to 1. However, the longer I dig in the code, the more I realize that GstMemory is only safe when it is directly wrapped in a buffer and then accessed only through GstBuffer's API.
Let me detail this: gst_memory_new_wrapped()
will simply call _sysmem_new()
which calls _sysmem_init()
which in turns calls gst_memory_init()
with _sysmem_allocator
as allocator. _sysmem_allocator
is a GstAllocator of type GstAllocatorSysmem, which uses _sysmem_copy()
as copy function. That function basically does an allocation followed by a memcpy()
without any thread safety mechanism.
Notice that _fallback_mem_copy()
maps the memory with read access before copying but that function is not used with the GstAllocatorSysmem. Hence the behavior is not uniform among allocators.
Therefore, when one calls gst_memory_copy()
on memory created with GstAllocatorSysmem, it will simply do a memcpy()
without any protection against possible data-races. No, the user is not supposed to lock the memory before doing a copy: it is not specified anywhere, and even functions like gst_buffer_append_memory()
will simply call gst_memory_copy()
if the memory is locked (potentially with write access) by another buffer (see ´_memory_get_exclusive_reference()´).
In my humble opinion, in addition to being unnecessarily complicated (see #302), the behavior of GstMemory is broken in the sense that it does not offer the guarantee one would expect when reading its API. If copying memory requires mapping/locking it with read access, it must be clearly specified and done in GStreamer internal code like ´_memory_get_exclusive_reference()´ and removed from allocators copy functions like _fallback_mem_copy()
. The mapping/locking can also be done in the gst_memory_copy()
function itself or in the allocator's copy function. Consistency is probably the key here.