After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 796692 - sample/bufferlist/buffer: Non-writable container miniobjects allow writable access to their contents, causing memory problems
sample/bufferlist/buffer: Non-writable container miniobjects allow writable a...
Status: RESOLVED FIXED
Product: GStreamer
Classification: Platform
Component: gstreamer (core)
unspecified
Other Linux
: High critical
: 1.15.1
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks: 771525
 
 
Reported: 2018-06-27 13:39 UTC by Sebastian Dröge (slomo)
Modified: 2018-07-12 19:19 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
testcase (1.62 KB, patch)
2018-06-27 13:39 UTC, Sebastian Dröge (slomo)
rejected Details | Review
multiudpsink: Make sure that GstMemory references are valid until we unmap (1.58 KB, patch)
2018-06-27 13:50 UTC, Sebastian Dröge (slomo)
rejected Details | Review
bufferlist: Add test to illustrate #796692 (1.66 KB, patch)
2018-06-28 12:14 UTC, Sebastian Dröge (slomo)
none Details | Review
bufferlist: Ensure buffer and buffer list writability matches (5.88 KB, patch)
2018-06-28 18:20 UTC, Nicolas Dufresne (ndufresne)
rejected Details | Review
buffer: Test-case to show mutability problem of memories in buffers (1.20 KB, patch)
2018-06-29 05:21 UTC, Sebastian Dröge (slomo)
none Details | Review
miniobject: Add parent pointers to the miniobject to influence writability (33.52 KB, patch)
2018-07-03 17:36 UTC, Sebastian Dröge (slomo)
none Details | Review
bufferlist: Add test to ensure that buffers in an non-writable list are not writable (1.70 KB, patch)
2018-07-03 17:36 UTC, Sebastian Dröge (slomo)
none Details | Review
buffer: Add test to ensure that memories in a non-writable buffer are not writable (1.29 KB, patch)
2018-07-03 17:36 UTC, Sebastian Dröge (slomo)
none Details | Review
miniobject: Add parent pointers to the miniobject to influence writability (33.65 KB, patch)
2018-07-05 06:19 UTC, Sebastian Dröge (slomo)
none Details | Review
bufferlist: Add test to ensure that buffers in an non-writable list are not writable (1.73 KB, patch)
2018-07-05 06:19 UTC, Sebastian Dröge (slomo)
none Details | Review
buffer: Add test to ensure that memories in a non-writable buffer are not writable (1.29 KB, patch)
2018-07-05 06:19 UTC, Sebastian Dröge (slomo)
none Details | Review
bufferlist: Prevent gst_buffer_list_foreach() from modifying non-writeable lists (3.96 KB, patch)
2018-07-05 16:49 UTC, Sebastian Dröge (slomo)
none Details | Review
miniobject: Add parent pointers to the miniobject to influence writability (33.11 KB, patch)
2018-07-09 07:37 UTC, Sebastian Dröge (slomo)
committed Details | Review
bufferlist: Add test to ensure that buffers in an non-writable list are not writable (1.73 KB, patch)
2018-07-09 07:37 UTC, Sebastian Dröge (slomo)
committed Details | Review
buffer: Add test to ensure that memories in a non-writable buffer are not writable (1.29 KB, patch)
2018-07-09 07:37 UTC, Sebastian Dröge (slomo)
committed Details | Review
bufferlist: Prevent gst_buffer_list_foreach() from modifying non-writeable lists (3.48 KB, patch)
2018-07-09 07:37 UTC, Sebastian Dröge (slomo)
committed Details | Review
v4l2bufferpool: Remove duplicate check (2.64 KB, patch)
2018-07-12 19:18 UTC, Nicolas Dufresne (ndufresne)
committed Details | Review

Description Sebastian Dröge (slomo) 2018-06-27 13:39:34 UTC
Created attachment 372847 [details] [review]
testcase

In various places we currently use gst_buffer_peek_memory() on a buffer that is passed into the element and then do something with the memory, like mapping it, etc. In general it's unknown in these cases if the buffer is also having another reference elsewhere.

Now gst_buffer_map() (and other functions) can merge all memories inside the buffer and unref the old memories. This can happen even if the buffer is not writable and it's safe because of the mini object locking stuff, supposedly.

However what happens is that other code might have a pointer to those memories that are unreffed (and destroyed) via gst_buffer_peek_memory(), and then access invalid memory or otherwise fail in interesting ways.

Attached testcase shows this problem in an easy way.


My proposal would be to deprecate gst_buffer_peek_memory() because it's a footgun and can't be used correctly unless you first ensure that your buffer is writable.

And then we can add a new functions possibly that does the same but first ensures that the buffer is actually writable first.

Currently there are many users of gst_buffer_peek_memory() unfortunately.


For the curious, I found this because gst-rtsp-server crashed: multiudpsink was using gst_buffer_peek_memory() for sending the data, and another thread was calling gst_buffer_map() on the same buffer and merging/unreffing the memory then.
Comment 1 Sebastian Dröge (slomo) 2018-06-27 13:50:18 UTC
Created attachment 372850 [details] [review]
multiudpsink: Make sure that GstMemory references are valid until we unmap
Comment 2 Sebastian Dröge (slomo) 2018-06-28 08:48:46 UTC
It's actually much worse than that. Consider the following case: Thread A merges the memories of a buffer while mapping it completely, thread B iterates over all memories to do things with them separately. While iterating in B, thread A can finish, replace all memories and from that point onwards thread B will assert/crash/etc because there are no N memories anymore in the buffer.

The only safe solution to this seems to be to never replace the memories in buffers if they are not writable, and instead only store the merged memory in the GstMapInfo (plus a flag to unref it on unmap). This will mean that merging would happen every single time for such buffers, and even at the same time in multiple threads if we're unlucky. But at least it would be safe :)

Comments?
Comment 3 Tim-Philipp Müller 2018-06-28 08:52:16 UTC
Good thing we're moving to an issue tracker that has emojis.
Comment 4 Sebastian Dröge (slomo) 2018-06-28 08:58:45 UTC
Interesting, actually we only replace the memories if the buffer is writable. So why does this fail at all then, even the original one.

>     if (writable) {
>      _replace_memory (buffer, len, idx, length, gst_memory_ref (nmem));

Needs some more debugging now.

(In reply to Tim-Philipp Müller from comment #3)
> Good thing we're moving to an issue tracker that has emojis.

Good that Bugzilla at least supports unicode so 
Comment 5 Sebastian Dröge (slomo) 2018-06-28 08:59:18 UTC
(In reply to Sebastian Dröge (slomo) from comment #4)

> (In reply to Tim-Philipp Müller from comment #3)
> > Good thing we're moving to an issue tracker that has emojis.
> 
> Good that Bugzilla at least supports unicode so

Except that Bugzilla apparently strips them off when storing the comment. Amazing!
Comment 6 Sebastian Dröge (slomo) 2018-06-28 11:58:31 UTC
Ok, new insights, it is all different again and broken elsewhere :)

So the problem is actually that gst_buffer_list_get() does not increase the reference count. A buffer can have its only reference inside the buffer list (-> it is writable) but the buffer list has a refcount > 1 (-> is not writable): example a tee is passing the same buffer list to two elements downstream.

Now gst_buffer_list_get() on that non-writable buffer list gives back a borrowed buffer, that is the buffer is still writable even if the list itself it not writable and shared in different places. Two threads can then at the same time get a buffer like that and map them, merge memories and break everything. Or otherwise modify buffers because it's considered writable after all but actually is not, however in those cases people would hopefully use gst_buffer_list_get_writable() which does not have the problem.
With mapping it's more hidden because a read-map seems like a read-only operation but is actually not.

So two options here:
1) We deprecate gst_buffer_list_get() and add a new gst_buffer_list_dup() that returns a new reference
2) We never ever replace memories when doing read-mapping in a buffer, even if the buffer was writable. This however does not solve the problem of the buffer being considered writable because of refcount==1
3) Always increase the refcount of buffers in the buffer list twice, but that needs some special care for gst_buffer_list_get_writable() and I'm not actually sure how to implement that properly in that case

Any other ideas?
Comment 7 Jan Schmidt 2018-06-28 12:11:39 UTC
4) Make buffers writable and set a new READONLY flag on them when they're a member of a bufferlist?
Comment 8 Sebastian Dröge (slomo) 2018-06-28 12:14:01 UTC
Created attachment 372860 [details] [review]
bufferlist: Add test to illustrate #796692
Comment 9 Sebastian Dröge (slomo) 2018-06-28 12:23:30 UTC
(In reply to Jan Schmidt from comment #7)
> 4) Make buffers writable and set a new READONLY flag on them when they're a
> member of a bufferlist?

That would interfere with how gst_buffer_list_get_writable() works
Comment 10 Nicolas Dufresne (ndufresne) 2018-06-28 12:27:47 UTC
I think the only way things can works is with the following:
  - A buffer is writable if all memory are writable
  - A buffer list is writable if all GstBuffer is writable

Merging/Replacing/Adding/Removing memory is unsafe it's not the case. Buffers and BufferLists must have a way to stay immutable, otherwise you also break the ability to use tee element.
Comment 11 Sebastian Dröge (slomo) 2018-06-28 12:39:04 UTC
(In reply to Nicolas Dufresne (ndufresne) from comment #10)
> I think the only way things can works is with the following:
>   - A buffer is writable if all memory are writable
>   - A buffer list is writable if all GstBuffer is writable

This seems the wrong way around. A buffer is writable independent of the writability of its memories (you can change the PTS even if all memories are read-only!). And a buffer list is writable even if all buffers are read-only (you can add new read-only buffers to it).

I'm not sure what your point is :) You mean that buffers should only be writable if their parent (the buffer list) is writable and the buffer itself has a refcount of 1?

> Merging/Replacing/Adding/Removing memory is unsafe it's not the case.
> Buffers and BufferLists must have a way to stay immutable, otherwise you
> also break the ability to use tee element.

I don't understand what you mean here. But tee is exactly the case where I ran into this problem.

The problem is simply that buffers in a buffer list are writable although the list itself is not writable. And you can get a reference with refcount==1 from gst_buffer_list_get() in that case. While you are not supposed to modify it in any way, other immutable operations (buffer mapping!) can modify the buffer as an optimization and then all falls apart.
Comment 12 Nicolas Dufresne (ndufresne) 2018-06-28 17:43:16 UTC
Good point, that's right. Seems like a gap in the API. What about taking a ref on all the buffer list buffers in tee, before iterating and pushing ?
Comment 13 Nicolas Dufresne (ndufresne) 2018-06-28 17:52:22 UTC
Nop, I've looked, that won't work, there could be a queue downstream. So maybe what we need is for gst_buffer_list_ref() to ref each GstBuffer. That would create the condition that if GstBufferList is not writable due to 2 ref or more, then GstBuffer are not writable either ?
Comment 14 Nicolas Dufresne (ndufresne) 2018-06-28 18:20:46 UTC
Created attachment 372865 [details] [review]
bufferlist: Ensure buffer and buffer list writability matches

This makes the gst_buffer_list_ref/unref non inline function that will
now ref all the internal buffers. This way, when the buffer list becomes
non-writable, same happens for the buffers inside.
Comment 15 Nicolas Dufresne (ndufresne) 2018-06-28 18:22:12 UTC
A quick attempt, which passes the new test_multiple_mutable_buffer_references(). It makes gst_buffer_list_ref/unref more expensive though, but is overall safe. Note that I didn't update the Win def files.
Comment 16 Nicolas Dufresne (ndufresne) 2018-06-28 18:26:27 UTC
About test_merge_mapped_memory(), I think you must be owner of the GstBuffer, so it's avoidable in general. But I might be missing something.
Comment 17 Sebastian Dröge (slomo) 2018-06-29 03:01:06 UTC
Comment on attachment 372865 [details] [review]
bufferlist: Ensure buffer and buffer list writability matches

Thanks for looking into this, but this is unfortunately API/ABI breakage. It was also one of the things that I thought of, however:

a) existing binaries will only call gst_mini_object_ref() due to it being an inline function before
b) it's perfectly valid to call gst_mini_object_ref/unref() on buffer lists, and code does that. There are code paths that handle buffers and buffer lists the same way as a generic mini object
Comment 18 Sebastian Dröge (slomo) 2018-06-29 03:02:02 UTC
(In reply to Nicolas Dufresne (ndufresne) from comment #16)
> About test_merge_mapped_memory(), I think you must be owner of the
> GstBuffer, so it's avoidable in general. But I might be missing something.

Ignore that one, the test is wrong and that all works correctly :) It was on the way of finding the actual bug, which is in GstBufferList
Comment 19 Nicolas Dufresne (ndufresne) 2018-06-29 03:12:35 UTC
Yeah, I don't think MiniObject already have any mechanism to implement this solution. Do you think it's worth it, or does a solution where buffer_list_get users needs to be aware of writability works fine enough ?
Comment 20 Sebastian Dröge (slomo) 2018-06-29 05:20:52 UTC
(In reply to Nicolas Dufresne (ndufresne) from comment #19)
> Yeah, I don't think MiniObject already have any mechanism to implement this
> solution. Do you think it's worth it, or does a solution where
> buffer_list_get users needs to be aware of writability works fine enough ?

That's not enough unfortunately as explained above (and it already is part of the gst_buffer_list_get_buffer() API that the return value is not writable, that's why get_writable_buffer() exists). The problem is that even if *you* don't do any operation on the buffer that requires writability, some other code outside your control might. Like in my case read-mapping the buffer, which merges and replaces all memories inside the buffer if the buffer happens to be writable.

A possible solution is to never replace the memories of course, but that does not prevent other accidental modifications like this elsewhere.

I think the only possible solutions are
1) Deprecating get_buffer() and add a new dup_buffer() that returns a new reference
2) Find a backwards compatible way of coupling the "parent" (buffer list) refcount with the writability of the buffer


And I just noticed that the same problem does not affect only buffer lists but also GstSample. Exactly same problem really. Aaaand GstBuffer with the contained GstMemories, see following testcase (buffer could be in two places at once, memory refcount==1, both places could modify the memory via e.g. gst_memory_resize() or both map the memory writable and modify them together).


I think we need a general solution for extending miniobject writability so that miniobjects owned by another one are only writable if the parent refcount is 1 and their own is too. I'll experiment with that.
Comment 21 Sebastian Dröge (slomo) 2018-06-29 05:21:49 UTC
Created attachment 372875 [details] [review]
buffer: Test-case to show mutability problem of memories in buffers
Comment 22 Sebastian Dröge (slomo) 2018-06-29 05:53:23 UTC
(In reply to Sebastian Dröge (slomo) from comment #20)

> I think we need a general solution for extending miniobject writability so
> that miniobjects owned by another one are only writable if the parent
> refcount is 1 and their own is too. I'll experiment with that.

GstMiniObject having no padding is not exactly helpful for finding a solution that is backwards compatible :)
Comment 23 Sebastian Dröge (slomo) 2018-06-29 16:27:05 UTC
Ok I'm not really sure how to best implement tracking of the parents of a miniobject. There is simply no sane way to store anything new in miniobjects due to a) miniobjects being allocated by the subclass (so we can't overallocate in gstminiobject.c), b) no padding in GstMiniObject, c) qdata allowing storing of additional data but it involves more allocations and a *global* mutex.

If someone has any ideas that do not involve going from libgstreamer-1.0.so.0 to .so.1 that would be great :) This is really a serious problem
Comment 24 Nicolas Dufresne (ndufresne) 2018-06-29 18:05:28 UTC
I didn't want to propose it, but we are pretty stuck. We could steal qdata pointer, allocate an array of two.

  qdata = g_new (GstQData, 2);

Use qdata[0].data as out private pointer, and qdata[1].data as our qdata storage. Or something along these lines ... not great. From there, we could add a new function callback (ref callback), or implement your parenting design, which seems more lightweight.
Comment 25 Sebastian Dröge (slomo) 2018-06-30 07:45:41 UTC
(In reply to Nicolas Dufresne (ndufresne) from comment #24)
> I didn't want to propose it, but we are pretty stuck. We could steal qdata
> pointer, allocate an array of two.
> 
>   qdata = g_new (GstQData, 2);

Yeah we can basically do anything we want with the qdata pointer and qdata length integer, they're only internally used.

I was thinking of always allocating something (parent tracking and the actual qdata storage) into the pointer but that would mean that every miniobject is now going to be two allocations. Far from ideal but probably the best of all options at this point.

Note that the pointer is a plain gpointer, we can store a struct there that directly stores the parents and then the qdata. No need to keep the current qdata struct there, it's internal. I guess that's the only good news :)

> Use qdata[0].data as out private pointer, and qdata[1].data as our qdata
> storage. Or something along these lines ... not great. From there, we could
> add a new function callback (ref callback)

Similar to what you did in your bufferlist patch so that bufferlist can override that reffing also refs each buffer inside it? That's quite heavy and I would prefer to not do that :)

> or implement your parenting design, which seems more lightweight.

I have a half-finished patch of that but then all the un-extensibleness of GstMiniObject frustrated me too much to continue that this week. I'll take a look at finishing that next week by adding another allocation to each miniobject as outlined above.
Comment 26 Sebastian Dröge (slomo) 2018-06-30 14:36:44 UTC
(In reply to Sebastian Dröge (slomo) from comment #25)

> Yeah we can basically do anything we want with the qdata pointer and qdata
> length integer, they're only internally used.

And with that I found a solution that does not require allocations in the majority of cases and is even lock-free.
Comment 27 Sebastian Dröge (slomo) 2018-07-03 17:36:08 UTC
Created attachment 372939 [details] [review]
miniobject: Add parent pointers to the miniobject to influence writability

Every container of miniobjects now needs to store itself as parent in
the child object, and remove itself again at a later time.

A miniobject is only writable if there is at most one parent, and that
parent is writable itself, and if the reference count of the miniobject
is 1.

GstBuffer (for memories), GstBufferList (for buffers) and GstSample (for
caps, buffer, bufferlist) was updated accordingly.

Without this it was possible to have e.g. a bufferlist with refcount 2
in two places, modifying the same buffer with refcount 1 at the same
time.
Comment 28 Sebastian Dröge (slomo) 2018-07-03 17:36:14 UTC
Created attachment 372940 [details] [review]
bufferlist: Add test to ensure that buffers in an non-writable list are not writable
Comment 29 Sebastian Dröge (slomo) 2018-07-03 17:36:21 UTC
Created attachment 372941 [details] [review]
buffer: Add test to ensure that memories in a non-writable buffer are not writable
Comment 30 Sebastian Dröge (slomo) 2018-07-03 17:46:56 UTC
This currently breaks the rtpbasepayload test. There are buffers there that are not writable anymore after this change but expected to be writable. Investigating tomorrow
Comment 31 Sebastian Dröge (slomo) 2018-07-05 06:19:38 UTC
Created attachment 372947 [details] [review]
miniobject: Add parent pointers to the miniobject to influence writability

Every container of miniobjects now needs to store itself as parent in
the child object, and remove itself again at a later time.

A miniobject is only writable if there is at most one parent, and that
parent is writable itself, and if the reference count of the miniobject
is 1.

GstBuffer (for memories), GstBufferList (for buffers) and GstSample (for
caps, buffer, bufferlist) was updated accordingly.

Without this it was possible to have e.g. a bufferlist with refcount 2
in two places, modifying the same buffer with refcount 1 at the same
time.
Comment 32 Sebastian Dröge (slomo) 2018-07-05 06:19:49 UTC
Created attachment 372948 [details] [review]
bufferlist: Add test to ensure that buffers in an non-writable list are not writable
Comment 33 Sebastian Dröge (slomo) 2018-07-05 06:19:56 UTC
Created attachment 372949 [details] [review]
buffer: Add test to ensure that memories in a non-writable buffer are not writable
Comment 34 Sebastian Dröge (slomo) 2018-07-05 16:49:52 UTC
Created attachment 372952 [details] [review]
bufferlist: Prevent gst_buffer_list_foreach() from modifying non-writeable lists

Previously gst_buffer_list_foreach() could modify (drop or replace)
buffers in non-writable lists, which could cause all kinds of problems
if other code also has a reference to the list and assumes that it stays
the same.
Comment 35 Sebastian Dröge (slomo) 2018-07-05 16:51:34 UTC
(In reply to Sebastian Dröge (slomo) from comment #34)
> Created attachment 372952 [details] [review] [review]
> bufferlist: Prevent gst_buffer_list_foreach() from modifying non-writeable
> lists
> 
> Previously gst_buffer_list_foreach() could modify (drop or replace)
> buffers in non-writable lists, which could cause all kinds of problems
> if other code also has a reference to the list and assumes that it stays
> the same.

This is a different bug from everything else in this ticket and also existed since forever, but on top of the other changes it is easier to fix (because we already have another reference to buffers in non-writable lists anyway and don't have to save them from the callback destroying them).
Comment 36 Sebastian Dröge (slomo) 2018-07-05 16:56:37 UTC
With this, all tests in core/base/good/rtsp-server are passing btw, it's probably good to go but I'd like to have a review first. The changes are not exactly trivial.
Comment 37 Jan Schmidt 2018-07-05 17:42:08 UTC
Review of attachment 372947 [details] [review]:

A few comments / re-wording of things

::: gst/gstbufferlist.c
@@ +267,3 @@
+     * by removing ourselves as parent
+     */
+     *

This is potentially more expensive than needed if the buffer_list is already not writable - in which case we could skip the check on every buffer and just ref them

::: gst/gstminiobject.c
@@ +76,3 @@
+ * guint and gpointer in the GstMiniObject struct in
+ * a rather complicated way to store the parent(s) and qdata.
+ * Originally the were just the number of qdatas and the qdata.

Probably add a FIXME 2.0 around here so it gets removed one day

@@ +86,3 @@
+ *
+ * Unless we're in state 3, we always have to move to Locking state
+ * states:

atomatically -> atomically

@@ +157,3 @@
   mini_object->free = free_func;
 
+  mini_object->priv_uint = PRIV_DATA_STATE_NO_PARENT;

This needs to use g_atomic_int_set() to make sure the value is written out to memory.

@@ +952,3 @@
+ * writability of @object: if the @parent is not writable, @object is also not
+ * writable, regardless of its refcount. @object is only writable if all
+ * @parent: a parent #GstMiniObject

"This adds @parent as a parent for @object. Having one ore more parents affects the
writability of @object: if a @parent is not writable, @object is also not
writable, regardless of its refcount. @object is only writable if all
the parents are writable and its own refcount is exactly 1."

@@ +981,3 @@
+     *
+     * Note that in this case we did not store PRIV_DATA_STATE_LOCKED! */
+gst_mini_object_add_parent (GstMiniObject * object, GstMiniObject * parent)

This code repeats a few times - maybe factor it out? Also the comment 'Have full struct now...' is confusing here.

@@ +993,3 @@
+
+  /* Now we either have to add to the full struct, or add our one and only
+

This comment is also misleading - the full struct was already added a few lines above

@@ +1054,3 @@
+     * from the beginning
+     *
+    while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));

Same comments about comments as for add_parent() here.

@@ +1090,3 @@
+
+    /* Unlock again */
+

Probably should restore the original state if the parent passed to remove_parent() didn't match the only parent, rather than setting it to NO_PARENT.

::: gst/gstsample.c
@@ +281,1 @@
   old = sample->buffer_list;

Worth a shortcut check if old == buffer_list here? (and for buffers and caps below)
Comment 38 Jan Schmidt 2018-07-05 17:43:22 UTC
Review of attachment 372948 [details] [review]:

Straightforward
Comment 39 Jan Schmidt 2018-07-05 17:44:07 UTC
Review of attachment 372949 [details] [review]:

Straightforward too
Comment 40 Jan Schmidt 2018-07-05 17:46:01 UTC
Review of attachment 372952 [details] [review]:

Looks good

::: gst/gstbufferlist.c
@@ +271,3 @@
      */
     was_writable = gst_buffer_is_writable (buf);
+    if (was_writable && list_was_writable)

Ah, this implements one of the comments I made on the initial patch
Comment 41 Sebastian Dröge (slomo) 2018-07-09 07:37:32 UTC
Created attachment 372975 [details] [review]
miniobject: Add parent pointers to the miniobject to influence writability

Every container of miniobjects now needs to store itself as parent in
the child object, and remove itself again at a later time.

A miniobject is only writable if there is at most one parent, and that
parent is writable itself, and if the reference count of the miniobject
is 1.

GstBuffer (for memories), GstBufferList (for buffers) and GstSample (for
caps, buffer, bufferlist) was updated accordingly.

Without this it was possible to have e.g. a bufferlist with refcount 2
in two places, modifying the same buffer with refcount 1 at the same
time.
Comment 42 Sebastian Dröge (slomo) 2018-07-09 07:37:43 UTC
Created attachment 372976 [details] [review]
bufferlist: Add test to ensure that buffers in an non-writable list are not writable
Comment 43 Sebastian Dröge (slomo) 2018-07-09 07:37:49 UTC
Created attachment 372977 [details] [review]
buffer: Add test to ensure that memories in a non-writable buffer are not writable
Comment 44 Sebastian Dröge (slomo) 2018-07-09 07:37:56 UTC
Created attachment 372978 [details] [review]
bufferlist: Prevent gst_buffer_list_foreach() from modifying non-writeable lists

Previously gst_buffer_list_foreach() could modify (drop or replace)
buffers in non-writable lists, which could cause all kinds of problems
if other code also has a reference to the list and assumes that it stays
the same.
Comment 45 Sebastian Dröge (slomo) 2018-07-09 07:45:59 UTC
Attachment 372975 [details] pushed as 6fa3514 - miniobject: Add parent pointers to the miniobject to influence writability
Attachment 372976 [details] pushed as 13a45c0 - bufferlist: Add test to ensure that buffers in an non-writable list are not writable
Attachment 372977 [details] pushed as 111faa5 - buffer: Add test to ensure that memories in a non-writable buffer are not writable
Attachment 372978 [details] pushed as cb51bd6 - bufferlist: Prevent gst_buffer_list_foreach() from modifying non-writeable lists
Comment 46 Nicolas Dufresne (ndufresne) 2018-07-12 19:18:08 UTC
Created attachment 373011 [details] [review]
v4l2bufferpool: Remove duplicate check

We were calling gst_v4l2_is_buffer_valid() before and inside
gst_v4l2_buffer_pool_qbuf() as we needed to access the group. The second
check failed since the writability of the buffer get inherited from the
GstMemory, which lead to pipeline failure. As we cannot avoid the extra
ref, it would be racy otherwise, just pass the group to _dbuf() so it
does not have to call gst_v4l2_is_buffer_valid() again.
Comment 47 Nicolas Dufresne (ndufresne) 2018-07-12 19:18:31 UTC
Comment on attachment 373011 [details] [review]
v4l2bufferpool: Remove duplicate check

Attachment 373011 [details] pushed as 38b68cb - v4l2bufferpool: Remove duplicate check
Comment 48 Nicolas Dufresne (ndufresne) 2018-07-12 19:19:32 UTC
(In reply to Nicolas Dufresne (ndufresne) from comment #47)
> Comment on attachment 373011 [details] [review] [review]
> v4l2bufferpool: Remove duplicate check
> 
> Attachment 373011 [details] pushed as 38b68cb - v4l2bufferpool: Remove
> duplicate check

Attached here, just so that we are aware of the kind of regression this may cause.