mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-09 07:52:36 +00:00
clock: Keep weak reference to underlying clock
Fixes potential segmentation fault when using a GstClockID that is referencing an already freed GstClock Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/187
This commit is contained in:
parent
8abe052590
commit
36ab067905
3 changed files with 116 additions and 9 deletions
102
gst/gstclock.c
102
gst/gstclock.c
|
@ -249,7 +249,10 @@ gst_clock_entry_new (GstClock * clock, GstClockTime time,
|
||||||
"created entry %p, time %" GST_TIME_FORMAT, entry, GST_TIME_ARGS (time));
|
"created entry %p, time %" GST_TIME_FORMAT, entry, GST_TIME_ARGS (time));
|
||||||
|
|
||||||
entry->refcount = 1;
|
entry->refcount = 1;
|
||||||
|
#ifndef GST_DISABLE_DEPRECATED
|
||||||
entry->clock = clock;
|
entry->clock = clock;
|
||||||
|
#endif
|
||||||
|
g_weak_ref_init (&entry->ABI.clock, clock);
|
||||||
entry->type = type;
|
entry->type = type;
|
||||||
entry->time = time;
|
entry->time = time;
|
||||||
entry->interval = interval;
|
entry->interval = interval;
|
||||||
|
@ -270,7 +273,8 @@ gst_clock_entry_reinit (GstClock * clock, GstClockEntry * entry,
|
||||||
GstClockTime time, GstClockTime interval, GstClockEntryType type)
|
GstClockTime time, GstClockTime interval, GstClockEntryType type)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (entry->status != GST_CLOCK_BUSY, FALSE);
|
g_return_val_if_fail (entry->status != GST_CLOCK_BUSY, FALSE);
|
||||||
g_return_val_if_fail (entry->clock == clock, FALSE);
|
g_return_val_if_fail (gst_clock_id_uses_clock ((GstClockID) entry, clock),
|
||||||
|
FALSE);
|
||||||
|
|
||||||
entry->type = type;
|
entry->type = type;
|
||||||
entry->time = time;
|
entry->time = time;
|
||||||
|
@ -354,6 +358,8 @@ _gst_clock_id_free (GstClockID id)
|
||||||
if (entry->destroy_data)
|
if (entry->destroy_data)
|
||||||
entry->destroy_data (entry->user_data);
|
entry->destroy_data (entry->user_data);
|
||||||
|
|
||||||
|
g_weak_ref_clear (&entry->ABI.clock);
|
||||||
|
|
||||||
/* FIXME: add tracer hook for struct allocations such as clock entries */
|
/* FIXME: add tracer hook for struct allocations such as clock entries */
|
||||||
|
|
||||||
g_slice_free (GstClockEntry, id);
|
g_slice_free (GstClockEntry, id);
|
||||||
|
@ -526,7 +532,9 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
|
||||||
entry = (GstClockEntry *) id;
|
entry = (GstClockEntry *) id;
|
||||||
requested = GST_CLOCK_ENTRY_TIME (entry);
|
requested = GST_CLOCK_ENTRY_TIME (entry);
|
||||||
|
|
||||||
clock = GST_CLOCK_ENTRY_CLOCK (entry);
|
clock = g_weak_ref_get (&entry->ABI.clock);
|
||||||
|
if (G_UNLIKELY (clock == NULL))
|
||||||
|
goto invalid_entry;
|
||||||
|
|
||||||
/* can't sync on invalid times */
|
/* can't sync on invalid times */
|
||||||
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
|
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
|
||||||
|
@ -549,6 +557,7 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
|
||||||
if (entry->type == GST_CLOCK_ENTRY_PERIODIC)
|
if (entry->type == GST_CLOCK_ENTRY_PERIODIC)
|
||||||
entry->time = requested + entry->interval;
|
entry->time = requested + entry->interval;
|
||||||
|
|
||||||
|
gst_object_unref (clock);
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -556,13 +565,20 @@ invalid_time:
|
||||||
{
|
{
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
|
||||||
"invalid time requested, returning _BADTIME");
|
"invalid time requested, returning _BADTIME");
|
||||||
|
gst_object_unref (clock);
|
||||||
return GST_CLOCK_BADTIME;
|
return GST_CLOCK_BADTIME;
|
||||||
}
|
}
|
||||||
not_supported:
|
not_supported:
|
||||||
{
|
{
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported");
|
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported");
|
||||||
|
gst_object_unref (clock);
|
||||||
return GST_CLOCK_UNSUPPORTED;
|
return GST_CLOCK_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
invalid_entry:
|
||||||
|
{
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "clock entry %p lost its clock", id);
|
||||||
|
return GST_CLOCK_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -600,7 +616,9 @@ gst_clock_id_wait_async (GstClockID id,
|
||||||
|
|
||||||
entry = (GstClockEntry *) id;
|
entry = (GstClockEntry *) id;
|
||||||
requested = GST_CLOCK_ENTRY_TIME (entry);
|
requested = GST_CLOCK_ENTRY_TIME (entry);
|
||||||
clock = GST_CLOCK_ENTRY_CLOCK (entry);
|
clock = g_weak_ref_get (&entry->ABI.clock);
|
||||||
|
if (G_UNLIKELY (clock == NULL))
|
||||||
|
goto invalid_entry;
|
||||||
|
|
||||||
/* can't sync on invalid times */
|
/* can't sync on invalid times */
|
||||||
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
|
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
|
||||||
|
@ -617,6 +635,7 @@ gst_clock_id_wait_async (GstClockID id,
|
||||||
|
|
||||||
res = cclass->wait_async (clock, entry);
|
res = cclass->wait_async (clock, entry);
|
||||||
|
|
||||||
|
gst_object_unref (clock);
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -625,13 +644,20 @@ invalid_time:
|
||||||
(func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
|
(func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
|
||||||
"invalid time requested, returning _BADTIME");
|
"invalid time requested, returning _BADTIME");
|
||||||
|
gst_object_unref (clock);
|
||||||
return GST_CLOCK_BADTIME;
|
return GST_CLOCK_BADTIME;
|
||||||
}
|
}
|
||||||
not_supported:
|
not_supported:
|
||||||
{
|
{
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported");
|
GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported");
|
||||||
|
gst_object_unref (clock);
|
||||||
return GST_CLOCK_UNSUPPORTED;
|
return GST_CLOCK_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
invalid_entry:
|
||||||
|
{
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "clock entry %p lost its clock", id);
|
||||||
|
return GST_CLOCK_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -655,12 +681,23 @@ gst_clock_id_unschedule (GstClockID id)
|
||||||
g_return_if_fail (id != NULL);
|
g_return_if_fail (id != NULL);
|
||||||
|
|
||||||
entry = (GstClockEntry *) id;
|
entry = (GstClockEntry *) id;
|
||||||
clock = entry->clock;
|
clock = g_weak_ref_get (&entry->ABI.clock);
|
||||||
|
if (G_UNLIKELY (clock == NULL))
|
||||||
|
goto invalid_entry;
|
||||||
|
|
||||||
cclass = GST_CLOCK_GET_CLASS (clock);
|
cclass = GST_CLOCK_GET_CLASS (clock);
|
||||||
|
|
||||||
if (G_LIKELY (cclass->unschedule))
|
if (G_LIKELY (cclass->unschedule))
|
||||||
cclass->unschedule (clock, entry);
|
cclass->unschedule (clock, entry);
|
||||||
|
|
||||||
|
gst_object_unref (clock);
|
||||||
|
return;
|
||||||
|
|
||||||
|
invalid_entry:
|
||||||
|
{
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "clock entry %p lost its clock", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1338,6 +1375,63 @@ gst_clock_get_master (GstClock * clock)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_clock_id_get_clock:
|
||||||
|
* @id: a #GstClockID
|
||||||
|
*
|
||||||
|
* This function returns the underlying clock.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full) (nullable): a #GstClock or %NULL when the
|
||||||
|
* underlying clock has been freed. Unref after usage.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
|
*/
|
||||||
|
GstClock *
|
||||||
|
gst_clock_id_get_clock (GstClockID id)
|
||||||
|
{
|
||||||
|
GstClockEntry *entry;
|
||||||
|
|
||||||
|
g_return_val_if_fail (id != NULL, NULL);
|
||||||
|
|
||||||
|
entry = (GstClockEntry *) id;
|
||||||
|
return g_weak_ref_get (&entry->ABI.clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_clock_id_uses_clock:
|
||||||
|
* @id: a #GstClockID to check
|
||||||
|
* @clock: a #GstClock to compare against
|
||||||
|
*
|
||||||
|
* This function returns whether @id uses @clock as the underlying clock.
|
||||||
|
* @clock can be NULL, in which case the return value indicates whether
|
||||||
|
* the underlying clock has been freed. If this is the case, the @id is
|
||||||
|
* no longer usable and should be freed.
|
||||||
|
*
|
||||||
|
* Returns: whether the clock @id uses the same underlying #GstClock @clock.
|
||||||
|
*
|
||||||
|
* MT safe.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_clock_id_uses_clock (GstClockID id, GstClock * clock)
|
||||||
|
{
|
||||||
|
GstClockEntry *entry;
|
||||||
|
GstClock *entry_clock;
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail (id != NULL, FALSE);
|
||||||
|
|
||||||
|
entry = (GstClockEntry *) id;
|
||||||
|
entry_clock = g_weak_ref_get (&entry->ABI.clock);
|
||||||
|
if (entry_clock == clock)
|
||||||
|
ret = TRUE;
|
||||||
|
|
||||||
|
if (G_LIKELY (entry_clock != NULL))
|
||||||
|
gst_object_unref (entry_clock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_clock_add_observation:
|
* gst_clock_add_observation:
|
||||||
* @clock: a #GstClock
|
* @clock: a #GstClock
|
||||||
|
|
|
@ -339,13 +339,18 @@ typedef enum {
|
||||||
* Cast to a clock entry
|
* Cast to a clock entry
|
||||||
*/
|
*/
|
||||||
#define GST_CLOCK_ENTRY(entry) ((GstClockEntry *)(entry))
|
#define GST_CLOCK_ENTRY(entry) ((GstClockEntry *)(entry))
|
||||||
|
|
||||||
|
#ifndef GST_DISABLE_DEPRECATED
|
||||||
/**
|
/**
|
||||||
* GST_CLOCK_ENTRY_CLOCK:
|
* GST_CLOCK_ENTRY_CLOCK:
|
||||||
* @entry: the entry to query
|
* @entry: the entry to query
|
||||||
*
|
*
|
||||||
* Get the owner clock of the entry
|
* Get the owner clock of the entry
|
||||||
|
*
|
||||||
|
* Deprecated: Use gst_clock_id_get_clock() instead.
|
||||||
*/
|
*/
|
||||||
#define GST_CLOCK_ENTRY_CLOCK(entry) ((entry)->clock)
|
#define GST_CLOCK_ENTRY_CLOCK(entry) ((entry)->clock)
|
||||||
|
#endif
|
||||||
/**
|
/**
|
||||||
* GST_CLOCK_ENTRY_TYPE:
|
* GST_CLOCK_ENTRY_TYPE:
|
||||||
* @entry: the entry to query
|
* @entry: the entry to query
|
||||||
|
@ -387,7 +392,9 @@ typedef enum {
|
||||||
struct _GstClockEntry {
|
struct _GstClockEntry {
|
||||||
gint refcount;
|
gint refcount;
|
||||||
/*< protected >*/
|
/*< protected >*/
|
||||||
|
#ifndef GST_DISABLE_DEPRECATED
|
||||||
GstClock *clock;
|
GstClock *clock;
|
||||||
|
#endif
|
||||||
GstClockEntryType type;
|
GstClockEntryType type;
|
||||||
GstClockTime time;
|
GstClockTime time;
|
||||||
GstClockTime interval;
|
GstClockTime interval;
|
||||||
|
@ -399,7 +406,10 @@ struct _GstClockEntry {
|
||||||
gboolean woken_up;
|
gboolean woken_up;
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
|
union {
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
|
GWeakRef clock;
|
||||||
|
} ABI;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <gst/gstobject.h>
|
#include <gst/gstobject.h>
|
||||||
|
@ -600,6 +610,12 @@ void gst_clock_id_unref (GstClockID id);
|
||||||
GST_API
|
GST_API
|
||||||
gint gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2);
|
gint gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2);
|
||||||
|
|
||||||
|
GST_API
|
||||||
|
GstClock * gst_clock_id_get_clock (GstClockID id);
|
||||||
|
|
||||||
|
GST_API
|
||||||
|
gboolean gst_clock_id_uses_clock (GstClockID id, GstClock * clock);
|
||||||
|
|
||||||
GST_API
|
GST_API
|
||||||
GstClockTime gst_clock_id_get_time (GstClockID id);
|
GstClockTime gst_clock_id_get_time (GstClockID id);
|
||||||
|
|
||||||
|
|
|
@ -2286,11 +2286,8 @@ gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time,
|
||||||
time += base_time;
|
time += base_time;
|
||||||
|
|
||||||
/* Re-use existing clockid if available */
|
/* Re-use existing clockid if available */
|
||||||
/* FIXME: Casting to GstClockEntry only works because the types
|
|
||||||
* are the same */
|
|
||||||
if (G_LIKELY (sink->priv->cached_clock_id != NULL
|
if (G_LIKELY (sink->priv->cached_clock_id != NULL
|
||||||
&& GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink->
|
&& gst_clock_id_uses_clock (sink->priv->cached_clock_id, clock))) {
|
||||||
priv->cached_clock_id) == clock)) {
|
|
||||||
if (!gst_clock_single_shot_id_reinit (clock, sink->priv->cached_clock_id,
|
if (!gst_clock_single_shot_id_reinit (clock, sink->priv->cached_clock_id,
|
||||||
time)) {
|
time)) {
|
||||||
gst_clock_id_unref (sink->priv->cached_clock_id);
|
gst_clock_id_unref (sink->priv->cached_clock_id);
|
||||||
|
|
Loading…
Reference in a new issue