mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 19:55:32 +00:00
latency tracer: Fix unsafe and NULL pointer accesses
Use thread-safe accesses to pad peers and parent objects. This fixes some crashers and all the non-safe access patterns I could spot. There's still some weirdness when using the latency tracer on pipeline chains that aren't yet linked, but this at least stops it segfaulting. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/269>
This commit is contained in:
parent
cecb291263
commit
e07bb52bf7
1 changed files with 75 additions and 24 deletions
|
@ -105,12 +105,15 @@ get_real_pad_parent (GstPad * pad)
|
||||||
if (!pad)
|
if (!pad)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
parent = GST_OBJECT_PARENT (pad);
|
parent = gst_object_get_parent (GST_OBJECT_CAST (pad));
|
||||||
|
|
||||||
/* if parent of pad is a ghost-pad, then pad is a proxy_pad */
|
/* if parent of pad is a ghost-pad, then pad is a proxy_pad */
|
||||||
if (parent && GST_IS_GHOST_PAD (parent)) {
|
if (parent && GST_IS_GHOST_PAD (parent)) {
|
||||||
|
GstObject *tmp;
|
||||||
pad = GST_PAD_CAST (parent);
|
pad = GST_PAD_CAST (parent);
|
||||||
parent = GST_OBJECT_PARENT (pad);
|
tmp = gst_object_get_parent (GST_OBJECT_CAST (pad));
|
||||||
|
gst_object_unref (parent);
|
||||||
|
parent = tmp;
|
||||||
}
|
}
|
||||||
return GST_ELEMENT_CAST (parent);
|
return GST_ELEMENT_CAST (parent);
|
||||||
}
|
}
|
||||||
|
@ -176,6 +179,9 @@ log_latency (const GstStructure * data, GstElement * sink_parent,
|
||||||
const GValue *value;
|
const GValue *value;
|
||||||
gchar *sink, *element_sink, *id_element_sink;
|
gchar *sink, *element_sink, *id_element_sink;
|
||||||
|
|
||||||
|
g_return_if_fail (sink_parent);
|
||||||
|
g_return_if_fail (sink_pad);
|
||||||
|
|
||||||
value = gst_structure_id_get_value (data, latency_probe_ts);
|
value = gst_structure_id_get_value (data, latency_probe_ts);
|
||||||
src_ts = g_value_get_uint64 (value);
|
src_ts = g_value_get_uint64 (value);
|
||||||
|
|
||||||
|
@ -207,6 +213,9 @@ log_element_latency (const GstStructure * data, GstElement * parent,
|
||||||
gchar *pad_name, *element_name, *element_id;
|
gchar *pad_name, *element_name, *element_id;
|
||||||
const GValue *value;
|
const GValue *value;
|
||||||
|
|
||||||
|
g_return_if_fail (parent);
|
||||||
|
g_return_if_fail (pad);
|
||||||
|
|
||||||
element_id = g_strdup_printf ("%p", parent);
|
element_id = g_strdup_printf ("%p", parent);
|
||||||
element_name = gst_element_get_name (parent);
|
element_name = gst_element_get_name (parent);
|
||||||
pad_name = gst_pad_get_name (pad);
|
pad_name = gst_pad_get_name (pad);
|
||||||
|
@ -228,7 +237,7 @@ static void
|
||||||
send_latency_probe (GstLatencyTracer * self, GstElement * parent, GstPad * pad,
|
send_latency_probe (GstLatencyTracer * self, GstElement * parent, GstPad * pad,
|
||||||
guint64 ts)
|
guint64 ts)
|
||||||
{
|
{
|
||||||
GstPad *peer_pad = GST_PAD_PEER (pad);
|
GstPad *peer_pad = gst_pad_get_peer (pad);
|
||||||
GstElement *peer_parent = get_real_pad_parent (peer_pad);
|
GstElement *peer_parent = get_real_pad_parent (peer_pad);
|
||||||
|
|
||||||
/* allow for non-parented pads to send latency probes as used in e.g.
|
/* allow for non-parented pads to send latency probes as used in e.g.
|
||||||
|
@ -237,7 +246,7 @@ send_latency_probe (GstLatencyTracer * self, GstElement * parent, GstPad * pad,
|
||||||
gchar *pad_name, *element_name, *element_id;
|
gchar *pad_name, *element_name, *element_id;
|
||||||
GstEvent *latency_probe;
|
GstEvent *latency_probe;
|
||||||
|
|
||||||
if (self->flags & GST_LATENCY_TRACER_FLAG_PIPELINE &&
|
if (parent && self->flags & GST_LATENCY_TRACER_FLAG_PIPELINE &&
|
||||||
GST_OBJECT_FLAG_IS_SET (parent, GST_ELEMENT_FLAG_SOURCE)) {
|
GST_OBJECT_FLAG_IS_SET (parent, GST_ELEMENT_FLAG_SOURCE)) {
|
||||||
element_id = g_strdup_printf ("%p", parent);
|
element_id = g_strdup_printf ("%p", parent);
|
||||||
element_name = gst_element_get_name (parent);
|
element_name = gst_element_get_name (parent);
|
||||||
|
@ -259,7 +268,8 @@ send_latency_probe (GstLatencyTracer * self, GstElement * parent, GstPad * pad,
|
||||||
gst_pad_push_event (pad, latency_probe);
|
gst_pad_push_event (pad, latency_probe);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->flags & GST_LATENCY_TRACER_FLAG_ELEMENT) {
|
if (peer_parent && peer_pad &&
|
||||||
|
self->flags & GST_LATENCY_TRACER_FLAG_ELEMENT) {
|
||||||
element_id = g_strdup_printf ("%p", peer_parent);
|
element_id = g_strdup_printf ("%p", peer_parent);
|
||||||
element_name = gst_element_get_name (peer_parent);
|
element_name = gst_element_get_name (peer_parent);
|
||||||
pad_name = gst_pad_get_name (peer_pad);
|
pad_name = gst_pad_get_name (peer_pad);
|
||||||
|
@ -280,36 +290,44 @@ send_latency_probe (GstLatencyTracer * self, GstElement * parent, GstPad * pad,
|
||||||
g_free (element_id);
|
g_free (element_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (peer_pad)
|
||||||
|
gst_object_unref (peer_pad);
|
||||||
|
if (peer_parent)
|
||||||
|
gst_object_unref (peer_parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
calculate_latency (GstElement * parent, GstPad * pad, guint64 ts)
|
calculate_latency (GstElement * parent, GstPad * pad, guint64 ts)
|
||||||
{
|
{
|
||||||
GstElement *peer_parent = get_real_pad_parent (GST_PAD_PEER (pad));
|
|
||||||
|
|
||||||
if (parent && (!GST_IS_BIN (parent)) &&
|
if (parent && (!GST_IS_BIN (parent)) &&
|
||||||
(!GST_OBJECT_FLAG_IS_SET (parent, GST_ELEMENT_FLAG_SOURCE))) {
|
(!GST_OBJECT_FLAG_IS_SET (parent, GST_ELEMENT_FLAG_SOURCE))) {
|
||||||
GstEvent *ev;
|
GstEvent *ev;
|
||||||
|
GstPad *peer_pad = gst_pad_get_peer (pad);
|
||||||
|
GstElement *peer_parent = get_real_pad_parent (peer_pad);
|
||||||
|
|
||||||
/* FIXME unsafe use of peer */
|
/* Protect against element being unlinked */
|
||||||
if (GST_OBJECT_FLAG_IS_SET (peer_parent, GST_ELEMENT_FLAG_SINK)) {
|
if (peer_pad && peer_parent &&
|
||||||
|
GST_OBJECT_FLAG_IS_SET (peer_parent, GST_ELEMENT_FLAG_SINK)) {
|
||||||
ev = g_object_get_qdata ((GObject *) pad, latency_probe_id);
|
ev = g_object_get_qdata ((GObject *) pad, latency_probe_id);
|
||||||
GST_DEBUG ("%s_%s: Should log full lantency now (event %p)",
|
GST_DEBUG ("%s_%s: Should log full latency now (event %p)",
|
||||||
GST_DEBUG_PAD_NAME (pad), ev);
|
GST_DEBUG_PAD_NAME (pad), ev);
|
||||||
if (ev) {
|
if (ev) {
|
||||||
log_latency (gst_event_get_structure (ev), peer_parent,
|
log_latency (gst_event_get_structure (ev), peer_parent, peer_pad, ts);
|
||||||
GST_PAD_PEER (pad), ts);
|
|
||||||
g_object_set_qdata ((GObject *) pad, latency_probe_id, NULL);
|
g_object_set_qdata ((GObject *) pad, latency_probe_id, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ev = g_object_get_qdata ((GObject *) pad, sub_latency_probe_id);
|
ev = g_object_get_qdata ((GObject *) pad, sub_latency_probe_id);
|
||||||
GST_DEBUG ("%s_%s: Should log sub lantency now (event %p)",
|
GST_DEBUG ("%s_%s: Should log sub latency now (event %p)",
|
||||||
GST_DEBUG_PAD_NAME (pad), ev);
|
GST_DEBUG_PAD_NAME (pad), ev);
|
||||||
if (ev) {
|
if (ev) {
|
||||||
log_element_latency (gst_event_get_structure (ev), parent, pad, ts);
|
log_element_latency (gst_event_get_structure (ev), parent, pad, ts);
|
||||||
g_object_set_qdata ((GObject *) pad, sub_latency_probe_id, NULL);
|
g_object_set_qdata ((GObject *) pad, sub_latency_probe_id, NULL);
|
||||||
}
|
}
|
||||||
|
if (peer_pad)
|
||||||
|
gst_object_unref (peer_pad);
|
||||||
|
if (peer_parent)
|
||||||
|
gst_object_unref (peer_parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,6 +339,9 @@ do_push_buffer_pre (GstTracer * tracer, guint64 ts, GstPad * pad)
|
||||||
|
|
||||||
send_latency_probe (self, parent, pad, ts);
|
send_latency_probe (self, parent, pad, ts);
|
||||||
calculate_latency (parent, pad, ts);
|
calculate_latency (parent, pad, ts);
|
||||||
|
|
||||||
|
if (parent)
|
||||||
|
gst_object_unref (parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -331,6 +352,9 @@ do_pull_range_pre (GstTracer * tracer, guint64 ts, GstPad * pad)
|
||||||
GstElement *parent = get_real_pad_parent (peer_pad);
|
GstElement *parent = get_real_pad_parent (peer_pad);
|
||||||
|
|
||||||
send_latency_probe (self, parent, peer_pad, ts);
|
send_latency_probe (self, parent, peer_pad, ts);
|
||||||
|
|
||||||
|
if (parent)
|
||||||
|
gst_object_unref (parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -339,6 +363,9 @@ do_pull_range_post (GstTracer * self, guint64 ts, GstPad * pad)
|
||||||
GstElement *parent = get_real_pad_parent (pad);
|
GstElement *parent = get_real_pad_parent (pad);
|
||||||
|
|
||||||
calculate_latency (parent, pad, ts);
|
calculate_latency (parent, pad, ts);
|
||||||
|
|
||||||
|
if (parent)
|
||||||
|
gst_object_unref (parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstPadProbeReturn
|
static GstPadProbeReturn
|
||||||
|
@ -352,12 +379,11 @@ do_drop_sub_latency_event (GstPad * pad, GstPadProbeInfo * info,
|
||||||
const GstStructure *data = gst_event_get_structure (ev);
|
const GstStructure *data = gst_event_get_structure (ev);
|
||||||
|
|
||||||
if (gst_structure_get_name_id (data) == sub_latency_probe_id) {
|
if (gst_structure_get_name_id (data) == sub_latency_probe_id) {
|
||||||
/* FIXME unsafe peer pad usage */
|
GstPad *peer_pad = gst_pad_get_peer (pad);
|
||||||
GstPad *peer_pad = GST_PAD_PEER (pad);
|
|
||||||
GstElement *peer_parent = get_real_pad_parent (peer_pad);
|
GstElement *peer_parent = get_real_pad_parent (peer_pad);
|
||||||
const GValue *value;
|
const GValue *value;
|
||||||
gchar *element_id = g_strdup_printf ("%p", peer_parent);
|
gchar *element_id = g_strdup_printf ("%p", peer_parent);
|
||||||
gchar *pad_name = gst_pad_get_name (peer_pad);
|
gchar *pad_name = peer_pad ? gst_pad_get_name (peer_pad) : NULL;
|
||||||
const gchar *value_element_id, *value_pad_name;
|
const gchar *value_element_id, *value_pad_name;
|
||||||
|
|
||||||
/* Get the element id, element name and pad name from data */
|
/* Get the element id, element name and pad name from data */
|
||||||
|
@ -366,7 +392,8 @@ do_drop_sub_latency_event (GstPad * pad, GstPadProbeInfo * info,
|
||||||
value = gst_structure_id_get_value (data, latency_probe_pad);
|
value = gst_structure_id_get_value (data, latency_probe_pad);
|
||||||
value_pad_name = g_value_get_string (value);
|
value_pad_name = g_value_get_string (value);
|
||||||
|
|
||||||
if (!g_str_equal (value_element_id, element_id) ||
|
if (pad_name == NULL ||
|
||||||
|
!g_str_equal (value_element_id, element_id) ||
|
||||||
!g_str_equal (value_pad_name, pad_name)) {
|
!g_str_equal (value_pad_name, pad_name)) {
|
||||||
GST_DEBUG ("%s_%s: Dropping sub-latency event",
|
GST_DEBUG ("%s_%s: Dropping sub-latency event",
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_PAD_NAME (pad));
|
||||||
|
@ -375,6 +402,11 @@ do_drop_sub_latency_event (GstPad * pad, GstPadProbeInfo * info,
|
||||||
|
|
||||||
g_free (pad_name);
|
g_free (pad_name);
|
||||||
g_free (element_id);
|
g_free (element_id);
|
||||||
|
|
||||||
|
if (peer_pad)
|
||||||
|
gst_object_unref (peer_pad);
|
||||||
|
if (peer_parent)
|
||||||
|
gst_object_unref (peer_parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,13 +417,13 @@ static void
|
||||||
do_push_event_pre (GstTracer * self, guint64 ts, GstPad * pad, GstEvent * ev)
|
do_push_event_pre (GstTracer * self, guint64 ts, GstPad * pad, GstEvent * ev)
|
||||||
{
|
{
|
||||||
GstElement *parent = get_real_pad_parent (pad);
|
GstElement *parent = get_real_pad_parent (pad);
|
||||||
GstPad *peer_pad = GST_PAD_PEER (pad);
|
|
||||||
GstElement *peer_parent = get_real_pad_parent (peer_pad);
|
|
||||||
|
|
||||||
if (parent && (!GST_IS_BIN (parent)) &&
|
if (parent && (!GST_IS_BIN (parent)) &&
|
||||||
(!GST_OBJECT_FLAG_IS_SET (parent, GST_ELEMENT_FLAG_SOURCE)) &&
|
(!GST_OBJECT_FLAG_IS_SET (parent, GST_ELEMENT_FLAG_SOURCE)) &&
|
||||||
GST_EVENT_TYPE (ev) == GST_EVENT_CUSTOM_DOWNSTREAM) {
|
GST_EVENT_TYPE (ev) == GST_EVENT_CUSTOM_DOWNSTREAM) {
|
||||||
const GstStructure *data = gst_event_get_structure (ev);
|
const GstStructure *data = gst_event_get_structure (ev);
|
||||||
|
GstPad *peer_pad = gst_pad_get_peer (pad);
|
||||||
|
GstElement *peer_parent = get_real_pad_parent (peer_pad);
|
||||||
|
|
||||||
/* if not set yet, add a pad probe that prevents sub-latency event from
|
/* if not set yet, add a pad probe that prevents sub-latency event from
|
||||||
* flowing further */
|
* flowing further */
|
||||||
|
@ -406,8 +438,8 @@ do_push_event_pre (GstTracer * self, guint64 ts, GstPad * pad, GstEvent * ev)
|
||||||
(gpointer) 1);
|
(gpointer) 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME unsafe peer access */
|
if (peer_parent == NULL
|
||||||
if (GST_OBJECT_FLAG_IS_SET (peer_parent, GST_ELEMENT_FLAG_SINK)) {
|
|| GST_OBJECT_FLAG_IS_SET (peer_parent, GST_ELEMENT_FLAG_SINK)) {
|
||||||
/* store event so that we can calculate latency when the buffer that
|
/* store event so that we can calculate latency when the buffer that
|
||||||
* follows has been processed */
|
* follows has been processed */
|
||||||
g_object_set_qdata_full ((GObject *) pad, latency_probe_id,
|
g_object_set_qdata_full ((GObject *) pad, latency_probe_id,
|
||||||
|
@ -418,7 +450,7 @@ do_push_event_pre (GstTracer * self, guint64 ts, GstPad * pad, GstEvent * ev)
|
||||||
if (gst_structure_get_name_id (data) == sub_latency_probe_id) {
|
if (gst_structure_get_name_id (data) == sub_latency_probe_id) {
|
||||||
const GValue *value;
|
const GValue *value;
|
||||||
gchar *element_id = g_strdup_printf ("%p", peer_parent);
|
gchar *element_id = g_strdup_printf ("%p", peer_parent);
|
||||||
gchar *pad_name = gst_pad_get_name (peer_pad);
|
gchar *pad_name = peer_pad ? gst_pad_get_name (peer_pad) : NULL;
|
||||||
const gchar *value_element_id, *value_pad_name;
|
const gchar *value_element_id, *value_pad_name;
|
||||||
|
|
||||||
/* Get the element id, element name and pad name from data */
|
/* Get the element id, element name and pad name from data */
|
||||||
|
@ -428,7 +460,7 @@ do_push_event_pre (GstTracer * self, guint64 ts, GstPad * pad, GstEvent * ev)
|
||||||
value_pad_name = g_value_get_string (value);
|
value_pad_name = g_value_get_string (value);
|
||||||
|
|
||||||
if (!g_str_equal (value_element_id, element_id) ||
|
if (!g_str_equal (value_element_id, element_id) ||
|
||||||
!g_str_equal (value_pad_name, pad_name)) {
|
g_strcmp0 (value_pad_name, pad_name) != 0) {
|
||||||
GST_DEBUG ("%s_%s: Storing sub-latency event",
|
GST_DEBUG ("%s_%s: Storing sub-latency event",
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
GST_DEBUG_PAD_NAME (pad));
|
||||||
g_object_set_qdata_full ((GObject *) pad, sub_latency_probe_id,
|
g_object_set_qdata_full ((GObject *) pad, sub_latency_probe_id,
|
||||||
|
@ -438,7 +470,13 @@ do_push_event_pre (GstTracer * self, guint64 ts, GstPad * pad, GstEvent * ev)
|
||||||
g_free (pad_name);
|
g_free (pad_name);
|
||||||
g_free (element_id);
|
g_free (element_id);
|
||||||
}
|
}
|
||||||
|
if (peer_pad)
|
||||||
|
gst_object_unref (peer_pad);
|
||||||
|
if (peer_parent)
|
||||||
|
gst_object_unref (peer_parent);
|
||||||
}
|
}
|
||||||
|
if (parent)
|
||||||
|
gst_object_unref (parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -453,7 +491,16 @@ do_query_post (GstLatencyTracer * tracer, GstClockTime ts, GstPad * pad,
|
||||||
gchar *element_name, *element_id;
|
gchar *element_name, *element_id;
|
||||||
struct LatencyQueryTableValue *value;
|
struct LatencyQueryTableValue *value;
|
||||||
GstElement *element = get_real_pad_parent (pad);
|
GstElement *element = get_real_pad_parent (pad);
|
||||||
GstElement *peer_element = get_real_pad_parent (GST_PAD_PEER (pad));
|
GstPad *peer_pad = gst_pad_get_peer (pad);
|
||||||
|
GstElement *peer_element = get_real_pad_parent (peer_pad);
|
||||||
|
|
||||||
|
/* If something is being removed/unlinked, cleanup the stack so we can
|
||||||
|
* ignore this query in the trace. */
|
||||||
|
if (!element || !peer_element || !peer_pad) {
|
||||||
|
while ((value = local_latency_query_stack_pop ()))
|
||||||
|
latency_query_table_value_destroy (value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse the query */
|
/* Parse the query */
|
||||||
gst_query_parse_latency (query, &live, &min, &max);
|
gst_query_parse_latency (query, &live, &min, &max);
|
||||||
|
@ -485,6 +532,10 @@ do_query_post (GstLatencyTracer * tracer, GstClockTime ts, GstPad * pad,
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
g_free (element_name);
|
g_free (element_name);
|
||||||
g_free (element_id);
|
g_free (element_id);
|
||||||
|
|
||||||
|
gst_object_unref (peer_pad);
|
||||||
|
gst_object_unref (peer_element);
|
||||||
|
gst_object_unref (element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue