[iter] Fix mystery crash
authorBehdad Esfahbod <behdad@behdad.org>
Thu, 31 Jan 2019 00:03:16 +0000 (16:03 -0800)
committerBehdad Esfahbod <behdad@behdad.org>
Thu, 31 Jan 2019 00:03:16 +0000 (16:03 -0800)
Fuzzer caught it:

==14==ERROR: AddressSanitizer: stack-use-after-return on address 0x7fca2ed7a3e0 at pc 0x0000006057aa bp 0x7ffc3290f1d0 sp 0x7ffc3290f1c8
READ of size 4 at 0x7fca2ed7a3e0 thread T0
SCARINESS: 55 (4-byte-read-stack-use-after-return)
    #0 0x6057a9 in OT::SingleSubstFormat2::subset(hb_subset_context_t*) const /src/harfbuzz/src/./hb-ot-layout-gsub-table.hh:194:40
    #1 0x5ff921 in hb_subset_context_t::return_t OT::SingleSubst::dispatch<hb_subset_context_t>(hb_subset_context_t*) const /src/harfbuzz/src/./hb-ot-layout-gsub-table.hh:256:13

I can't reproduce locally, but many of the bots are failing because of this
as well.

It's a pity that operator-> must return pointer.  Ugh.  Why?!

src/hb-iter.hh
src/hb-ot-layout-gsub-table.hh

index 105379e..290e6af 100644 (file)
@@ -71,6 +71,10 @@ struct hb_iter_t
   iter_t operator + () const { return *thiz(); }
   explicit_operator bool () const { return thiz()->__more__ (); }
   unsigned len () const { return thiz()->__len__ (); }
+  /* The following can only be enabled if item_t is reference type.  Otherwise
+   * it will be returning pointer to temporary rvalue. */
+  template <typename T = item_t,
+           hb_enable_if (hb_is_reference (T))>
   hb_remove_reference (item_t)* operator -> () const { return hb_addressof (**thiz()); }
   item_t operator * () const { return thiz()->__item__ (); }
   item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
index 518afaa..dd6f017 100644 (file)
@@ -191,8 +191,8 @@ struct SingleSubstFormat2
     for (auto it = hb_zip (this+coverage, substitute)
                 | hb_filter (glyphset, hb_first); it; ++it)
     {
-      from.push ()->set (glyph_map[it->first]);
-      to.push ()->set (glyph_map[it->second]);
+      from.push ()->set (glyph_map[(*it).first]);
+      to.push ()->set (glyph_map[(*it).second]);
     }
     c->serializer->propagate_error (from, to);
     SingleSubst_serialize (c->serializer, from, to);