Merge pull request #2899 from harfbuzz/ci-fix

[ci] Don’t install meson from its master branch
diff --git a/.circleci/config.yml b/.circleci/config.yml
index d5e7de2..46bb0f8 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -117,11 +117,7 @@
       - image: ubuntu:20.04
     steps:
       - checkout
-      - run: apt update || true; DEBIAN_FRONTEND=noninteractive apt install -y wget gnupg
-      #- run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
-      #- run: echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main" > /etc/apt/sources.list.d/llvmdev.list
-      #- run: echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main" > /etc/apt/sources.list.d/llvmdevsrc.list
-      #- run: apt update || true
+      - run: apt update || true
       - run: DEBIAN_FRONTEND=noninteractive apt install -y clang lld git binutils meson pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
       # asan+ubsan
       - run: rm -rf build && meson build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
@@ -132,9 +128,7 @@
       # msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least
       - run: rm -rf build && meson build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true
       - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
-      # test -std=c++2a and -Weverything of nightly clang builds
       - run: clang -c src/harfbuzz.cc src/hb-subset*.cc -DHB_NO_MT -Werror -std=c++2a
-      - run: clang -c src/hb-*.cc -DHB_NO_MT -Werror -Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code -Wno-unused-template -DHB_WITH_WIN1256
 
   crossbuild-win32:
     executor: win32-executor
diff --git a/src/gen-vowel-constraints.py b/src/gen-vowel-constraints.py
index 55a9ecf..184ec29 100755
--- a/src/gen-vowel-constraints.py
+++ b/src/gen-vowel-constraints.py
@@ -101,7 +101,7 @@
 						self._indent (depth + 2), cp, index + i, ')' if i == len (self._c) - 1 else ' &&'))
 				s.append ('{}{{\n'.format (indent))
 				for i in range (index):
-					s.append ('{}buffer->next_glyph ();\n'.format (self._indent (depth + 1)))
+					s.append ('{}(void) buffer->next_glyph ();\n'.format (self._indent (depth + 1)))
 				s.append ('{}matched = true;\n'.format (self._indent (depth + 1)))
 				s.append ('{}}}\n'.format (indent))
 		else:
@@ -171,15 +171,15 @@
 print ('static void')
 print ('_output_dotted_circle (hb_buffer_t *buffer)')
 print ('{')
-print ('  hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);')
-print ('  _hb_glyph_info_reset_continuation (&dottedcircle);')
+print ('  (void) buffer->output_glyph (0x25CCu);')
+print ('  _hb_glyph_info_reset_continuation (&buffer->prev());')
 print ('}')
 print ()
 print ('static void')
 print ('_output_with_dotted_circle (hb_buffer_t *buffer)')
 print ('{')
 print ('  _output_dotted_circle (buffer);')
-print ('  buffer->next_glyph ();')
+print ('  (void) buffer->next_glyph ();')
 print ('}')
 print ()
 
@@ -211,7 +211,7 @@
 	print ('      {')
 	print ('\tbool matched = false;')
 	write (str (constraints))
-	print ('\tbuffer->next_glyph ();')
+	print ('\t(void) buffer->next_glyph ();')
 	print ('\tif (matched) _output_with_dotted_circle (buffer);')
 	print ('      }')
 	print ('      break;')
diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh
index d8223dc..98ed20d 100644
--- a/src/hb-aat-layout-common.hh
+++ b/src/hb-aat-layout-common.hh
@@ -831,7 +831,7 @@
 	break;
 
       if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
     }
 
     if (!c->in_place)
diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index cf6766b..e3bc268 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -499,7 +499,7 @@
 	  }
 
 	  DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
-	  buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]);
+	  if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
 
 	  if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
 	  action = *actionData;
@@ -525,25 +525,25 @@
 	    hb_codepoint_t lig = ligatureData;
 
 	    DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
-	    buffer->replace_glyph (lig);
+	    if (unlikely (!buffer->replace_glyph (lig))) return;
 
 	    unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
 	    /* Now go and delete all subsequent components. */
 	    while (match_length - 1u > cursor)
 	    {
 	      DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
-	      buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]);
-	      buffer->replace_glyph (DELETED_GLYPH);
+	      if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
+	      if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
 	    }
 
-	    buffer->move_to (lig_end);
+	    if (unlikely (!buffer->move_to (lig_end))) return;
 	    buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
 	  }
 
 	  actionData++;
 	}
 	while (!(action & LigActionLast));
-	buffer->move_to (end);
+	if (unlikely (!buffer->move_to (end))) return;
       }
     }
 
@@ -733,17 +733,16 @@
 	bool before = flags & MarkedInsertBefore;
 
 	unsigned int end = buffer->out_len;
-	buffer->move_to (mark);
+	if (unlikely (!buffer->move_to (mark))) return;
 
 	if (buffer->idx < buffer->len && !before)
-	  buffer->copy_glyph ();
+	  if (unlikely (!buffer->copy_glyph ())) return;
 	/* TODO We ignore KashidaLike setting. */
-	for (unsigned int i = 0; i < count; i++)
-	  buffer->output_glyph (glyphs[i]);
+	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
 	if (buffer->idx < buffer->len && !before)
 	  buffer->skip_glyph ();
 
-	buffer->move_to (end + count);
+	if (unlikely (!buffer->move_to (end + count))) return;
 
 	buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
       }
@@ -764,10 +763,9 @@
 	unsigned int end = buffer->out_len;
 
 	if (buffer->idx < buffer->len && !before)
-	  buffer->copy_glyph ();
+	  if (unlikely (!buffer->copy_glyph ())) return;
 	/* TODO We ignore KashidaLike setting. */
-	for (unsigned int i = 0; i < count; i++)
-	  buffer->output_glyph (glyphs[i]);
+	if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
 	if (buffer->idx < buffer->len && !before)
 	  buffer->skip_glyph ();
 
@@ -786,7 +784,7 @@
 	 *
 	 * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
 	 */
-	buffer->move_to ((flags & DontAdvance) ? end : end + count);
+	if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
       }
     }
 
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index 0e293f6..8cad6ab 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -319,7 +319,7 @@
   if (unlikely (!successful)) return;
 
   assert (idx <= len);
-  next_glyphs (len - idx);
+  if (unlikely (!next_glyphs (len - idx))) return;
 
   assert (have_output);
   have_output = false;
@@ -342,31 +342,6 @@
   idx = 0;
 }
 
-
-void
-hb_buffer_t::replace_glyphs (unsigned int num_in,
-			     unsigned int num_out,
-			     const uint32_t *glyph_data)
-{
-  if (unlikely (!make_room_for (num_in, num_out))) return;
-
-  assert (idx + num_in <= len);
-
-  merge_clusters (idx, idx + num_in);
-
-  hb_glyph_info_t orig_info = info[idx];
-  hb_glyph_info_t *pinfo = &out_info[out_len];
-  for (unsigned int i = 0; i < num_out; i++)
-  {
-    *pinfo = orig_info;
-    pinfo->codepoint = glyph_data[i];
-    pinfo++;
-  }
-
-  idx  += num_in;
-  out_len += num_out;
-}
-
 bool
 hb_buffer_t::move_to (unsigned int i)
 {
@@ -1316,7 +1291,7 @@
   if (unlikely (hb_object_is_immutable (buffer)))
     return length == 0;
 
-  if (!buffer->ensure (length))
+  if (unlikely (!buffer->ensure (length)))
     return false;
 
   /* Wipe the new space */
@@ -1546,7 +1521,10 @@
   if (item_length == -1)
     item_length = text_length - item_offset;
 
-  buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
+  if (unlikely (item_length < 0 ||
+		item_length > INT_MAX / 8 ||
+		!buffer->ensure (buffer->len + item_length * sizeof (T) / 4)))
+    return;
 
   /* If buffer is empty and pre-context provided, install it.
    * This check is written this way, to make sure people can
diff --git a/src/hb-buffer.hh b/src/hb-buffer.hh
index 9cad520..8b432b5 100644
--- a/src/hb-buffer.hh
+++ b/src/hb-buffer.hh
@@ -139,7 +139,7 @@
 
   /* Methods */
 
-  bool in_error () const { return !successful; }
+  HB_NODISCARD bool in_error () const { return !successful; }
 
   void allocate_var (unsigned int start, unsigned int count)
   {
@@ -186,7 +186,7 @@
   hb_glyph_info_t &prev ()      { return out_info[out_len ? out_len - 1 : 0]; }
   hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
 
-  bool has_separate_output () const { return info != out_info; }
+  HB_NODISCARD bool has_separate_output () const { return info != out_info; }
 
 
   HB_INTERNAL void reset ();
@@ -210,86 +210,89 @@
   HB_INTERNAL void clear_output ();
   HB_INTERNAL void clear_positions ();
 
-  HB_INTERNAL void replace_glyphs (unsigned int num_in,
-				   unsigned int num_out,
-				   const hb_codepoint_t *glyph_data);
-
-  void replace_glyph (hb_codepoint_t glyph_index)
+  template <typename T>
+  HB_NODISCARD bool replace_glyphs (unsigned int num_in,
+				    unsigned int num_out,
+				    const T *glyph_data)
   {
-    if (unlikely (out_info != info || out_len != idx)) {
-      if (unlikely (!make_room_for (1, 1))) return;
-      out_info[out_len] = info[idx];
+    if (unlikely (!make_room_for (num_in, num_out))) return false;
+
+    assert (idx + num_in <= len);
+
+    merge_clusters (idx, idx + num_in);
+
+    hb_glyph_info_t &orig_info = idx < len ? cur() : prev();
+
+    hb_glyph_info_t *pinfo = &out_info[out_len];
+    for (unsigned int i = 0; i < num_out; i++)
+    {
+      *pinfo = orig_info;
+      pinfo->codepoint = glyph_data[i];
+      pinfo++;
     }
-    out_info[out_len].codepoint = glyph_index;
 
-    idx++;
-    out_len++;
+    idx  += num_in;
+    out_len += num_out;
+    return true;
   }
+
+  HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph_index)
+  { return replace_glyphs (1, 1, &glyph_index); }
+
   /* Makes a copy of the glyph at idx to output and replace glyph_index */
-  hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
+  HB_NODISCARD bool output_glyph (hb_codepoint_t glyph_index)
+  { return replace_glyphs (0, 1, &glyph_index); }
+
+  HB_NODISCARD bool output_info (const hb_glyph_info_t &glyph_info)
   {
-    if (unlikely (!make_room_for (0, 1))) return Crap (hb_glyph_info_t);
-
-    if (unlikely (idx == len && !out_len))
-      return Crap (hb_glyph_info_t);
-
-    out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
-    out_info[out_len].codepoint = glyph_index;
-
-    out_len++;
-
-    return out_info[out_len - 1];
-  }
-  void output_info (const hb_glyph_info_t &glyph_info)
-  {
-    if (unlikely (!make_room_for (0, 1))) return;
+    if (unlikely (!make_room_for (0, 1))) return false;
 
     out_info[out_len] = glyph_info;
 
     out_len++;
+    return true;
   }
   /* Copies glyph at idx to output but doesn't advance idx */
-  void copy_glyph ()
+  HB_NODISCARD bool copy_glyph ()
   {
-    if (unlikely (!make_room_for (0, 1))) return;
-
-    out_info[out_len] = info[idx];
-
-    out_len++;
+    /* Extra copy because cur()'s return can be freed within
+     * output_info() call if buffer reallocates. */
+    return output_info (hb_glyph_info_t (cur()));
   }
+
   /* Copies glyph at idx to output and advance idx.
    * If there's no output, just advance idx. */
-  void
-  next_glyph ()
+  HB_NODISCARD bool next_glyph ()
   {
     if (have_output)
     {
       if (out_info != info || out_len != idx)
       {
-	if (unlikely (!make_room_for (1, 1))) return;
+	if (unlikely (!make_room_for (1, 1))) return false;
 	out_info[out_len] = info[idx];
       }
       out_len++;
     }
 
     idx++;
+    return true;
   }
   /* Copies n glyphs at idx to output and advance idx.
    * If there's no output, just advance idx. */
-  void
-  next_glyphs (unsigned int n)
+  HB_NODISCARD bool next_glyphs (unsigned int n)
   {
     if (have_output)
     {
       if (out_info != info || out_len != idx)
       {
-	if (unlikely (!make_room_for (n, n))) return;
+	if (unlikely (!make_room_for (n, n))) return false;
 	memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
       }
       out_len += n;
     }
 
     idx += n;
+    return true;
   }
   /* Advance idx without copying to output. */
   void skip_glyph () { idx++; }
@@ -329,14 +332,14 @@
 
 
   /* Internal methods */
-  HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
+  HB_NODISCARD HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
 
-  HB_INTERNAL bool enlarge (unsigned int size);
+  HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
 
-  bool ensure (unsigned int size)
+  HB_NODISCARD bool ensure (unsigned int size)
   { return likely (!size || size < allocated) ? true : enlarge (size); }
 
-  bool ensure_inplace (unsigned int size)
+  HB_NODISCARD bool ensure_inplace (unsigned int size)
   { return likely (!size || size < allocated); }
 
   void assert_glyphs ()
@@ -349,7 +352,7 @@
     assert ((content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) ||
 	    (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
   }
-  bool ensure_glyphs ()
+  HB_NODISCARD bool ensure_glyphs ()
   {
     if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_GLYPHS))
     {
@@ -360,7 +363,7 @@
     }
     return true;
   }
-  bool ensure_unicode ()
+  HB_NODISCARD bool ensure_unicode ()
   {
     if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_UNICODE))
     {
@@ -372,8 +375,8 @@
     return true;
   }
 
-  HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
-  HB_INTERNAL bool shift_forward (unsigned int count);
+  HB_NODISCARD HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
+  HB_NODISCARD HB_INTERNAL bool shift_forward (unsigned int count);
 
   typedef long scratch_buffer_t;
   HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index 220ba4f..9dafe65 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -289,7 +289,7 @@
     return true;
   }
 
-  buffer->ensure (glyph_count);
+  (void) buffer->ensure (glyph_count);
   scratch = buffer->get_scratch_buffer (&scratch_size);
   while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
 	  DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 7655af1..36a95ea 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -659,7 +659,7 @@
   void replace_glyph (hb_codepoint_t glyph_index) const
   {
     _set_glyph_props (glyph_index);
-    buffer->replace_glyph (glyph_index);
+    (void) buffer->replace_glyph (glyph_index);
   }
   void replace_glyph_inplace (hb_codepoint_t glyph_index) const
   {
@@ -670,13 +670,13 @@
 				    unsigned int class_guess) const
   {
     _set_glyph_props (glyph_index, class_guess, true);
-    buffer->replace_glyph (glyph_index);
+    (void) buffer->replace_glyph (glyph_index);
   }
   void output_glyph_for_component (hb_codepoint_t glyph_index,
 				   unsigned int class_guess) const
   {
     _set_glyph_props (glyph_index, class_guess, false, true);
-    buffer->output_glyph (glyph_index);
+    (void) buffer->output_glyph (glyph_index);
   }
 };
 
@@ -1043,7 +1043,7 @@
 				    hb_min (this_comp, last_num_components);
 	  _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
       }
-      buffer->next_glyph ();
+      (void) buffer->next_glyph ();
     }
 
     last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
@@ -1272,7 +1272,7 @@
       match_positions[next] += delta;
   }
 
-  buffer->move_to (end);
+  (void) buffer->move_to (end);
 
   return_trace (true);
 }
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 089c794..89df949 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -1782,7 +1782,7 @@
     if (applied)
       ret = true;
     else
-      buffer->next_glyph ();
+      (void) buffer->next_glyph ();
   }
   return ret;
 }
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc
index 533e928..dbedd6a 100644
--- a/src/hb-ot-shape-complex-hangul.cc
+++ b/src/hb-ot-shape-complex-hangul.cc
@@ -205,7 +205,7 @@
       {
 	/* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
 	buffer->unsafe_to_break_from_outbuffer (start, buffer->idx);
-	buffer->next_glyph ();
+	if (unlikely (!buffer->next_glyph ())) break;
 	if (!is_zero_width_char (font, u))
 	{
 	  buffer->merge_out_clusters (start, end + 1);
@@ -231,12 +231,12 @@
 	    chars[0] = 0x25CCu;
 	    chars[1] = u;
 	  }
-	  buffer->replace_glyphs (1, 2, chars);
+	  (void) buffer->replace_glyphs (1, 2, chars);
 	}
 	else
 	{
 	  /* No dotted circle available in the font; just leave tone mark untouched. */
-	  buffer->next_glyph ();
+	  (void) buffer->next_glyph ();
 	}
       }
       start = end = buffer->out_len;
@@ -273,7 +273,7 @@
 	  hb_codepoint_t s = SBase + (l - LBase) * NCount + (v - VBase) * TCount + tindex;
 	  if (font->has_glyph (s))
 	  {
-	    buffer->replace_glyphs (t ? 3 : 2, 1, &s);
+	    (void) buffer->replace_glyphs (t ? 3 : 2, 1, &s);
 	    end = start + 1;
 	    continue;
 	  }
@@ -285,13 +285,13 @@
 	 * Set jamo features on the individual glyphs, and advance past them.
 	 */
 	buffer->cur().hangul_shaping_feature() = LJMO;
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	buffer->cur().hangul_shaping_feature() = VJMO;
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (t)
 	{
 	  buffer->cur().hangul_shaping_feature() = TJMO;
-	  buffer->next_glyph ();
+	  (void) buffer->next_glyph ();
 	  end = start + 3;
 	}
 	else
@@ -323,9 +323,7 @@
 	hb_codepoint_t new_s = s + new_tindex;
 	if (font->has_glyph (new_s))
 	{
-	  buffer->replace_glyphs (2, 1, &new_s);
-	  if (unlikely (!buffer->successful))
-	    break;
+	  (void) buffer->replace_glyphs (2, 1, &new_s);
 	  end = start + 1;
 	  continue;
 	}
@@ -349,14 +347,14 @@
 	    (!tindex || font->has_glyph (decomposed[2])))
 	{
 	  unsigned int s_len = tindex ? 3 : 2;
-	  buffer->replace_glyphs (1, s_len, decomposed);
+	  (void) buffer->replace_glyphs (1, s_len, decomposed);
 
 	  /* If we decomposed an LV because of a non-combining T following,
 	   * we want to include this T in the syllable.
 	   */
 	  if (has_glyph && !tindex)
 	  {
-	    buffer->next_glyph ();
+	    (void) buffer->next_glyph ();
 	    s_len++;
 	  }
 	  if (unlikely (!buffer->successful))
@@ -384,17 +382,15 @@
 
       if (has_glyph)
       {
-	/* We didn't decompose the S, so just advance past it. */
+	/* We didn't decompose the S, so just advance past it and fall through. */
 	end = start + 1;
-	buffer->next_glyph ();
-	continue;
       }
     }
 
     /* Didn't find a recognizable syllable, so we leave end <= start;
      * this will prevent tone-mark reordering happening.
      */
-    buffer->next_glyph ();
+    (void) buffer->next_glyph ();
   }
   buffer->swap_buffers ();
 }
diff --git a/src/hb-ot-shape-complex-syllabic.cc b/src/hb-ot-shape-complex-syllabic.cc
index 9f8c790..46509ab 100644
--- a/src/hb-ot-shape-complex-syllabic.cc
+++ b/src/hb-ot-shape-complex-syllabic.cc
@@ -85,13 +85,13 @@
 	while (buffer->idx < buffer->len && buffer->successful &&
 	       last_syllable == buffer->cur().syllable() &&
 	       buffer->cur().complex_var_u8_category() == (unsigned) repha_category)
-	  buffer->next_glyph ();
+	  (void) buffer->next_glyph ();
       }
 
-      buffer->output_info (ginfo);
+      (void) buffer->output_info (ginfo);
     }
     else
-      buffer->next_glyph ();
+      (void) buffer->next_glyph ();
   }
   buffer->swap_buffers ();
 }
diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc
index 347ea2e..4c30681 100644
--- a/src/hb-ot-shape-complex-thai.cc
+++ b/src/hb-ot-shape-complex-thai.cc
@@ -323,20 +323,19 @@
 
   buffer->clear_output ();
   unsigned int count = buffer->len;
-  for (buffer->idx = 0; buffer->idx < count && buffer->successful;)
+  for (buffer->idx = 0; buffer->idx < count /* No need for: && buffer->successful */;)
   {
     hb_codepoint_t u = buffer->cur().codepoint;
-    if (likely (!IS_SARA_AM (u))) {
-      buffer->next_glyph ();
+    if (likely (!IS_SARA_AM (u)))
+    {
+      if (unlikely (!buffer->next_glyph ())) break;
       continue;
     }
 
     /* Is SARA AM. Decompose and reorder. */
-    hb_glyph_info_t &nikhahit = buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
-    _hb_glyph_info_set_continuation (&nikhahit);
-    buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u));
-    if (unlikely (!buffer->successful))
-      return;
+    (void) buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
+    _hb_glyph_info_set_continuation (&buffer->prev());
+    if (unlikely (!buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u)))) break;
 
     /* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
     unsigned int end = buffer->out_len;
diff --git a/src/hb-ot-shape-complex-vowel-constraints.cc b/src/hb-ot-shape-complex-vowel-constraints.cc
index 124716e..1037626 100644
--- a/src/hb-ot-shape-complex-vowel-constraints.cc
+++ b/src/hb-ot-shape-complex-vowel-constraints.cc
@@ -23,15 +23,15 @@
 static void
 _output_dotted_circle (hb_buffer_t *buffer)
 {
-  hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);
-  _hb_glyph_info_reset_continuation (&dottedcircle);
+  (void) buffer->output_glyph (0x25CCu);
+  _hb_glyph_info_reset_continuation (&buffer->prev());
 }
 
 static void
 _output_with_dotted_circle (hb_buffer_t *buffer)
 {
   _output_dotted_circle (buffer);
-  buffer->next_glyph ();
+  (void) buffer->next_glyph ();
 }
 
 void
@@ -96,12 +96,12 @@
 		buffer->idx + 2 < count &&
 		0x0907u == buffer->cur (2).codepoint)
 	    {
-	      buffer->next_glyph ();
+	      (void) buffer->next_glyph ();
 	      matched = true;
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -122,7 +122,7 @@
 	    matched = 0x09E2u == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -158,7 +158,7 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -182,7 +182,7 @@
 	    matched = 0x0ABEu == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -200,7 +200,7 @@
 	    matched = 0x0B57u == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -214,7 +214,7 @@
 	{
 	  matched = true;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -237,7 +237,7 @@
 	    matched = 0x0C55u == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -255,7 +255,7 @@
 	    matched = 0x0CCCu == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -281,7 +281,7 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -316,7 +316,7 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -337,7 +337,7 @@
 	    matched = 0x11042u == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -358,7 +358,7 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -384,7 +384,7 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -404,7 +404,7 @@
 	    }
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
@@ -427,7 +427,7 @@
 	    matched = 0x116B2u == buffer->cur (1).codepoint;
 	    break;
 	}
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	if (matched) _output_with_dotted_circle (buffer);
       }
       break;
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 1453d2e..778b5b8 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -101,8 +101,9 @@
 static inline void
 output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
 {
+  /* This is very confusing indeed. */
   buffer->cur().glyph_index() = glyph;
-  buffer->output_glyph (unichar); /* This is very confusing indeed. */
+  (void) buffer->output_glyph (unichar);
   _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
 }
 
@@ -110,7 +111,7 @@
 next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
 {
   buffer->cur().glyph_index() = glyph;
-  buffer->next_glyph ();
+  (void) buffer->next_glyph ();
 }
 
 static inline void
@@ -229,30 +230,35 @@
       if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
       {
 	hb_codepoint_t unicode = buffer->cur().codepoint;
-	buffer->replace_glyphs (2, 1, &unicode);
+	(void) buffer->replace_glyphs (2, 1, &unicode);
       }
       else
       {
 	/* Just pass on the two characters separately, let GSUB do its magic. */
 	set_glyph (buffer->cur(), font);
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
 	set_glyph (buffer->cur(), font);
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
       }
       /* Skip any further variation selectors. */
-      while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
+      while (buffer->idx < end &&
+	     buffer->successful &&
+	     unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
       {
 	set_glyph (buffer->cur(), font);
-	buffer->next_glyph ();
+	(void) buffer->next_glyph ();
       }
-    } else {
+    }
+    else
+    {
       set_glyph (buffer->cur(), font);
-      buffer->next_glyph ();
+      (void) buffer->next_glyph ();
     }
   }
-  if (likely (buffer->idx < end)) {
+  if (likely (buffer->idx < end))
+  {
     set_glyph (buffer->cur(), font);
-    buffer->next_glyph ();
+    (void) buffer->next_glyph ();
   }
 }
 
@@ -348,7 +354,7 @@
 						      sizeof (buffer->info[0]),
 						      &buffer->cur().glyph_index(),
 						      sizeof (buffer->info[0]));
-	buffer->next_glyphs (done);
+	if (unlikely (!buffer->next_glyphs (done))) break;
       }
       while (buffer->idx < end && buffer->successful)
 	decompose_current_character (&c, might_short_circuit);
@@ -429,8 +435,8 @@
     buffer->clear_output ();
     count = buffer->len;
     unsigned int starter = 0;
-    buffer->next_glyph ();
-    while (buffer->idx < count && buffer->successful)
+    (void) buffer->next_glyph ();
+    while (buffer->idx < count /* No need for: && buffer->successful */)
     {
       hb_codepoint_t composed, glyph;
       if (/* We don't try to compose a non-mark character with it's preceding starter.
@@ -452,9 +458,7 @@
 	    font->get_nominal_glyph (composed, &glyph))
 	{
 	  /* Composes. */
-	  buffer->next_glyph (); /* Copy to out-buffer. */
-	  if (unlikely (!buffer->successful))
-	    return;
+	  if (unlikely (!buffer->next_glyph ())) break; /* Copy to out-buffer. */
 	  buffer->merge_out_clusters (starter, buffer->out_len);
 	  buffer->out_len--; /* Remove the second composable. */
 	  /* Modify starter and carry on. */
@@ -467,7 +471,7 @@
       }
 
       /* Blocked, or doesn't compose. */
-      buffer->next_glyph ();
+      if (unlikely (!buffer->next_glyph ())) break;
 
       if (info_cc (buffer->prev()) == 0)
 	starter = buffer->out_len - 1;
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 92831e0..86ab0b4 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -534,7 +534,7 @@
   hb_glyph_info_t info = dottedcircle;
   info.cluster = buffer->cur().cluster;
   info.mask = buffer->cur().mask;
-  buffer->output_info (info);
+  (void) buffer->output_info (info);
   buffer->swap_buffers ();
 }
 
diff --git a/test/shaping/run-tests.py b/test/shaping/run-tests.py
index 6dea5b9..4e9a3de 100755
--- a/test/shaping/run-tests.py
+++ b/test/shaping/run-tests.py
@@ -97,7 +97,7 @@
 
 		if not reference:
 			print ('%s "%s" %s %s --unicodes %s' %
-					 (hb_shape, fontfile, ' '.join(extra_options), options, unicodes))
+					 (hb_shape, fontfile, ' '.join(extra_options), ' '.join(options), unicodes))
 
 		if "--font-funcs=ft" in options and not have_freetype:
 			skips += 1