mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-06 23:48:53 +00:00
gststructure: Fix gst_structure_take ownership handling
The old code would leave a dangling pointer in oldstr_ptr if two threads attempted to take the same structure into the same location at the same time: 1. First "oldstr == newstr" check (before the loop) fails. 2. Compare-and-exchange fails, due to a second thread completing the same gst_structure_take. 3. Second "oldstr == newstr" check (in the loop) succeeds, loop breaks. 4. "oldstr" check succeeds, old structure gets freed. 5. oldstr_ptr now contains a dangling pointer. This shouldn't happen in code that handles ownership sanely, so check that we don't try to do this and complain loudly. Also simplify the function by using a do-while loop, like gst_mini_object_take. https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/413
This commit is contained in:
parent
e45f187d13
commit
a20ff6aaf4
1 changed files with 12 additions and 12 deletions
|
@ -511,12 +511,15 @@ gst_clear_structure (GstStructure ** structure_ptr)
|
||||||
* a #GstStructure to take
|
* a #GstStructure to take
|
||||||
* @newstr: (transfer full) (allow-none): a new #GstStructure
|
* @newstr: (transfer full) (allow-none): a new #GstStructure
|
||||||
*
|
*
|
||||||
* Atomically modifies a pointer to point to a new object.
|
* Atomically modifies a pointer to point to a new structure.
|
||||||
* The #GstStructure @oldstr_ptr is pointing to is freed and
|
* The #GstStructure @oldstr_ptr is pointing to is freed and
|
||||||
* @newstr is taken ownership over.
|
* @newstr is taken ownership over.
|
||||||
*
|
*
|
||||||
* Either @newstr and the value pointed to by @oldstr_ptr may be %NULL.
|
* Either @newstr and the value pointed to by @oldstr_ptr may be %NULL.
|
||||||
*
|
*
|
||||||
|
* It is a programming error if both @newstr and the value pointed to by
|
||||||
|
* @oldstr_ptr refer to the same, non-%NULL structure.
|
||||||
|
*
|
||||||
* Returns: %TRUE if @newstr was different from @oldstr_ptr
|
* Returns: %TRUE if @newstr was different from @oldstr_ptr
|
||||||
*
|
*
|
||||||
* Since: 1.18
|
* Since: 1.18
|
||||||
|
@ -528,22 +531,19 @@ gst_structure_take (GstStructure ** oldstr_ptr, GstStructure * newstr)
|
||||||
|
|
||||||
g_return_val_if_fail (oldstr_ptr != NULL, FALSE);
|
g_return_val_if_fail (oldstr_ptr != NULL, FALSE);
|
||||||
|
|
||||||
oldstr = g_atomic_pointer_get ((gpointer *) oldstr_ptr);
|
do {
|
||||||
|
|
||||||
if (G_UNLIKELY (oldstr == newstr))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
|
|
||||||
oldstr_ptr, oldstr, newstr))) {
|
|
||||||
oldstr = g_atomic_pointer_get ((gpointer *) oldstr_ptr);
|
oldstr = g_atomic_pointer_get ((gpointer *) oldstr_ptr);
|
||||||
if (G_UNLIKELY (oldstr == newstr))
|
if (G_UNLIKELY (oldstr == newstr)) {
|
||||||
break;
|
g_return_val_if_fail (newstr == NULL, FALSE);
|
||||||
}
|
return FALSE;
|
||||||
|
}
|
||||||
|
} while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
|
||||||
|
oldstr_ptr, oldstr, newstr)));
|
||||||
|
|
||||||
if (oldstr)
|
if (oldstr)
|
||||||
gst_structure_free (oldstr);
|
gst_structure_free (oldstr);
|
||||||
|
|
||||||
return oldstr != newstr;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue