+2007-12-21 Wim Taymans <wim.taymans@collabora.co.uk>
+
+ * gst/gstpad.c: (gst_pad_dispose):
+ Really unlink the peer pad instead of setting the peer pointer to NULL
+ when we dispose the pad.
+ This correctly calls the unlink functions and makes sure that the peer
+ does not have a handle to invalid memory. See #504671.
+
+ * tests/check/gst/gstpad.c: (GST_START_TEST), (gst_pad_suite):
+ Add testsuite for above case.
+
2007-12-20 Tim-Philipp Müller <tim at centricular dot net>
Patch by: Peter Kjellerstedt <pkj axis com>
gst_pad_dispose (GObject * object)
{
GstPad *pad = GST_PAD (object);
+ GstPad *peer;
GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, pad, "dispose");
- /* we don't hold a ref to the peer so we can just set the
- * peer to NULL. */
- GST_PAD_PEER (pad) = NULL;
+ /* unlink the peer pad */
+ if ((peer = gst_pad_get_peer (pad))) {
+ /* window for MT unsafeness, someone else could unlink here
+ * and then we call unlink with wrong pads. The unlink
+ * function would catch this and safely return failed. */
+ if (GST_PAD_IS_SRC (pad))
+ gst_pad_unlink (pad, peer);
+ else
+ gst_pad_unlink (peer, pad);
+
+ gst_object_unref (peer);
+ }
/* clear the caps */
gst_caps_replace (&GST_PAD_CAPS (pad), NULL);
GST_END_TEST;
+/* see that an unref also unlinks the pads */
+GST_START_TEST (test_src_unref_unlink)
+{
+ GstPad *src, *sink;
+ GstCaps *caps;
+ GstPadLinkReturn plr;
+
+ sink = gst_pad_new ("sink", GST_PAD_SINK);
+ fail_if (sink == NULL);
+
+ src = gst_pad_new ("src", GST_PAD_SRC);
+ fail_if (src == NULL);
+
+ caps = gst_caps_from_string ("foo/bar");
+
+ gst_pad_set_caps (src, caps);
+ gst_pad_set_caps (sink, caps);
+
+ plr = gst_pad_link (src, sink);
+ fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
+
+ /* unref the srcpad */
+ gst_object_unref (src);
+
+ /* sink should be unlinked now */
+ fail_if (gst_pad_is_linked (sink));
+
+ /* cleanup */
+ gst_object_unref (sink);
+ gst_caps_unref (caps);
+}
+
+GST_END_TEST;
+
+/* see that an unref also unlinks the pads */
+GST_START_TEST (test_sink_unref_unlink)
+{
+ GstPad *src, *sink;
+ GstCaps *caps;
+ GstPadLinkReturn plr;
+
+ sink = gst_pad_new ("sink", GST_PAD_SINK);
+ fail_if (sink == NULL);
+
+ src = gst_pad_new ("src", GST_PAD_SRC);
+ fail_if (src == NULL);
+
+ caps = gst_caps_from_string ("foo/bar");
+
+ gst_pad_set_caps (src, caps);
+ gst_pad_set_caps (sink, caps);
+
+ plr = gst_pad_link (src, sink);
+ fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
+
+ /* unref the sinkpad */
+ gst_object_unref (sink);
+
+ /* src should be unlinked now */
+ fail_if (gst_pad_is_linked (src));
+
+ /* cleanup */
+ gst_object_unref (src);
+ gst_caps_unref (caps);
+}
+
+GST_END_TEST;
Suite *
gst_pad_suite (void)
tcase_add_test (tc_chain, test_push_linked);
tcase_add_test (tc_chain, test_flowreturn);
tcase_add_test (tc_chain, test_push_negotiation);
+ tcase_add_test (tc_chain, test_src_unref_unlink);
+ tcase_add_test (tc_chain, test_sink_unref_unlink);
return s;
}