diff options
author | Milan Plzik <milan.plzik@streamunlimited.com> | 2015-02-20 10:27:32 +0100 |
---|---|---|
committer | Jens Georg <mail@jensge.org> | 2015-03-16 22:35:07 +0100 |
commit | 44b0b299e296a392c4a10aba8492b0b512565248 (patch) | |
tree | e89c2bcc21401a9251cd2856262d3c7c8e9b5ef0 /src | |
parent | 8a0a0b1002fe6d2b67d4f2b1e1bd940de4f6f360 (diff) | |
download | rygel-44b0b299e296a392c4a10aba8492b0b512565248.tar.gz |
renderer: Do not capture 'this' pointer in lambdas.
In Vala, 'this' pointer is captures in lambdas by default. This causes issues
with a buggy C code, which depends on the order of object destruction (e.g.
AVTransport is destroyed much later than the rest of services, causing it to
use already-freed objects).
Signed-off-by: Milan Plzik <milan.plzik@streamunlimited.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/librygel-renderer/rygel-av-transport.vala | 50 |
1 files changed, 43 insertions, 7 deletions
diff --git a/src/librygel-renderer/rygel-av-transport.vala b/src/librygel-renderer/rygel-av-transport.vala index 8a13d538..5fcd819f 100644 --- a/src/librygel-renderer/rygel-av-transport.vala +++ b/src/librygel-renderer/rygel-av-transport.vala @@ -793,6 +793,25 @@ internal class Rygel.AVTransport : Service { bool head_faked; + // HACK ALERT: This work around vala's feature of capturing 'this' pointer + // for all lambdas introduced in a class instance, even if 'this' is never + // used. Captured 'this' extends lifetime of an AVTransport instance beyond + // time expected by GUPnP. Due to GUPnP not using weak pointers at some + // places (e.g. xmlNode property of GUPnPServiceInfo), a crash happens when + // AVTransport is freed. + private static void setup_check_resource_callback (AVTransport instance, Soup.Message message) { + var weakme = WeakRef (instance); + var weakmsg = WeakRef (message); + message.got_headers.connect( () => { + Rygel.AVTransport? me = (Rygel.AVTransport?)weakme.get(); + Soup.Message? msg = (Soup.Message?)weakmsg.get(); + if (me == null || msg == null) + return; + me.head_faked = true; + me.session.cancel_message (msg, msg.status_code); + }); + } + private void check_resource (Soup.Message msg, string _uri, string _metadata, @@ -810,10 +829,7 @@ internal class Rygel.AVTransport : Service { // Fake HEAD request by cancelling the message after the headers // were received, then restart the message - msg.got_headers.connect ((msg) => { - this.head_faked = true; - this.session.cancel_message (msg, msg.status_code); - }); + setup_check_resource_callback (this, msg); this.session.queue_message (msg, null); @@ -856,6 +872,27 @@ internal class Rygel.AVTransport : Service { } } + // HACK ALERT: This work around vala's feature of capturing 'this' pointer + // for all lambdas introduced in a class instance, even if 'this' is never + // used. Captured 'this' extends lifetime of an AVTransport instance beyond + // time expected by GUPnP. Due to GUPnP not using weak pointers at some + // places (e.g. xmlNode property of GUPnPServiceInfo), a crash happens when + // AVTransport is freed. + private static void setup_handle_new_transport_uri_callback(AVTransport instance, + Message message, string uri, string metadata, GUPnP.ServiceAction action) { + var weakme = WeakRef(instance); + var weakmsg = WeakRef(message); + //var weakact = WeakRef(action); + message.finished.connect( () => { + Rygel.AVTransport? me = (Rygel.AVTransport?)weakme.get(); + Soup.Message? msg = (Soup.Message?)weakmsg.get(); + //GUPnP.ServiceAction? act = (GUPnP.ServiceAction?)weakact.get(); + if (me == null || msg == null) + return; + me.check_resource (msg, uri, metadata, action); + }); + } + private void handle_new_transport_uri (ServiceAction action, string uri, string metadata) { @@ -865,9 +902,8 @@ internal class Rygel.AVTransport : Service { "1"); message.request_headers.append ("Connection", "close"); this.head_faked = false; - message.finished.connect ((msg) => { - this.check_resource (msg, uri, metadata, action); - }); + setup_handle_new_transport_uri_callback(this, message, uri, + metadata, action); this.session.queue_message (message, null); } else { |