[gnome-maps] overpass, placeBubble: Avoid use-after-free



commit af4994cf82d4201e88d0a71841dbb52169e49ad4
Author: Marcus Lundblad <ml update uu se>
Date:   Fri Oct 19 12:28:54 2018 +0200

    overpass, placeBubble: Avoid use-after-free
    
    Use bound properties to avoid JS accessing finalized GObject.
    
    Fixes #134

 src/overpass.js    | 28 ++++++++++++++++++++--------
 src/placeBubble.js | 40 +++++++++++++++++++++++++++++-----------
 2 files changed, 49 insertions(+), 19 deletions(-)
---
diff --git a/src/overpass.js b/src/overpass.js
index b8307ca..cf5cba3 100644
--- a/src/overpass.js
+++ b/src/overpass.js
@@ -19,6 +19,7 @@
 
 const Format = imports.format;
 const Geocode = imports.gi.GeocodeGlib;
+const GObject = imports.gi.GObject;
 const Soup = imports.gi.Soup;
 
 const Place = imports.place;
@@ -33,11 +34,22 @@ const _DEFAULT_OUTPUT_SORT_ORDER = 'qt';
 
 const BASE_URL = 'https://overpass-api.de/api/interpreter';
 
-var Overpass = class Overpass {
+var Overpass = GObject.registerClass({
+    Properties: {
+        'place': GObject.ParamSpec.object('place',
+                                          'Place',
+                                          'Place with added information',
+                                          GObject.ParamFlags.READABLE |
+                                          GObject.ParamFlags.WRITABLE,
+                                          Geocode.Place)
+    }
+}, class Overpass extends GObject.Object {
 
-    constructor(params) {
+    _init(params) {
         params = params || { };
 
+        super._init();
+
         // maximum allowed runtime for the query in seconds
         this.timeout = params.timeout || _DEFAULT_TIMEOUT;
 
@@ -60,7 +72,7 @@ var Overpass = class Overpass {
         this._session = new Soup.Session();
     }
 
-    addInfo(place, callback) {
+    addInfo(place) {
         let url = this._getQueryUrl(place);
         let uri = new Soup.URI(url);
         let request = new Soup.Message({ method: 'GET',
@@ -68,16 +80,16 @@ var Overpass = class Overpass {
 
         this._session.queue_message(request, (obj, message) => {
             if (message.status_code !== Soup.KnownStatusCode.OK) {
-                callback(false, message.status_code, null);
+                Utils.debug('Failed to fetch Overpass result: ' + message.status_code);
                 return;
             }
             try {
                 let jsonObj = JSON.parse(message.response_body.data);
                 this._populatePlace(place, jsonObj);
-                callback(true,
-                         message.status_code);
+                this.place = place;
+                this.notify('place');
             } catch(e) {
-                callback(false, message.status_code);
+                Utils.debug('Failed to parse Overpass result');
             }
         });
     }
@@ -143,4 +155,4 @@ var Overpass = class Overpass {
                                                 this.outputSortOrder,
                                                 this.outputCount ]);
     }
-};
+});
diff --git a/src/placeBubble.js b/src/placeBubble.js
index 1bdf47d..720fbbb 100644
--- a/src/placeBubble.js
+++ b/src/placeBubble.js
@@ -20,6 +20,7 @@
  */
 
 const GdkPixbuf = imports.gi.GdkPixbuf;
+const Geocode = imports.gi.GeocodeGlib;
 const GLib = imports.gi.GLib;
 const GObject = imports.gi.GObject;
 const Gtk = imports.gi.Gtk;
@@ -43,8 +44,16 @@ const THUMBNAIL_FETCH_SIZE = 128;
 // final scaled size of cropped thumnail
 const THUMBNAIL_FINAL_SIZE = 70;
 
-var PlaceBubble = GObject.registerClass(
-class PlaceBubble extends MapBubble.MapBubble {
+var PlaceBubble = GObject.registerClass({
+    Properties: {
+        'overpass-place': GObject.ParamSpec.object('overpass-place',
+                                                   'Overpass Place',
+                                                   'The place as filled in by Overpass',
+                                                   GObject.ParamFlags.READABLE |
+                                                   GObject.ParamFlags.WRITABLE,
+                                                   Geocode.Place)
+    }
+}, class PlaceBubble extends MapBubble.MapBubble {
 
     _init(params) {
         let ui = Utils.getUIObject('place-bubble', [ 'stack',
@@ -75,24 +84,25 @@ class PlaceBubble extends MapBubble.MapBubble {
         this._revealer = ui.contentRevealer;
 
         let overpass = new Overpass.Overpass();
+
+        /* use a property binding from the Overpass instance to avoid
+         * accessing accessing this object after the underlying GObject has
+         * been finalized */
+        overpass.bind_property('place', this, 'overpass-place',
+                               GObject.BindingFlags.DEFAULT);
+        this.connect('notify::overpass-place', () => this._onInfoAdded());
+
         if (Application.placeStore.exists(this.place, null)) {
 
             // If the place is stale, update from Overpass.
             if (Application.placeStore.isStale(this.place)) {
-                overpass.addInfo(this.place, (status, code) => {
-                    this._populate(this.place);
-                    Application.placeStore.updatePlace(this.place);
-                });
+                overpass.addInfo(this.place);
             } else {
                 let place = Application.placeStore.get(this.place);
                 this._populate(place);
             }
         } else if (this.place.store) {
-            overpass.addInfo(this.place, (status, code) => {
-                this._populate(this.place);
-                Application.placeStore.addPlace(this.place,
-                                                PlaceStore.PlaceType.RECENT);
-            });
+            overpass.addInfo(this.place);
         } else {
             this._populate(this.place);
         }
@@ -107,6 +117,14 @@ class PlaceBubble extends MapBubble.MapBubble {
         this._initExpandButton();
     }
 
+    _onInfoAdded() {
+        this._populate(this.place);
+        if (Application.placeStore.exists(this.place, null))
+            Application.placeStore.updatePlace(this.place);
+        else
+            Application.placeStore.addPlace(this.place, PlaceStore.PlaceType.RECENT);
+    }
+
     _formatWikiLink(wiki) {
         let lang = Wikipedia.getLanguage(wiki);
         let article = Wikipedia.getArticle(wiki);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]