[gnome-builder] libide: ensure draft content is always \0 terminated



commit 8d3b479b8a1f42d962ee9b591d5ba12bea4cfd75
Author: Christian Hergert <chergert redhat com>
Date:   Sun Oct 11 11:36:56 2015 -0400

    libide: ensure draft content is always \0 terminated
    
    This requires knowing a bit about the GtkTextBuffer internals.
    
    We can add the trailing newline when necessary and avoid a copy to do
    so. This fixes some common "error and end of file" when using the vala
    compiler to detect errors.

 libide/ide-buffer.c |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 51 insertions(+), 1 deletions(-)
---
diff --git a/libide/ide-buffer.c b/libide/ide-buffer.c
index 8a6a1ce..0ecbdd1 100644
--- a/libide/ide-buffer.c
+++ b/libide/ide-buffer.c
@@ -1564,6 +1564,37 @@ ide_buffer_get_diagnostic_at_iter (IdeBuffer         *self,
   return NULL;
 }
 
+static gboolean
+ide_buffer_can_do_newline_hack (IdeBuffer *self,
+                                guint      len)
+{
+  guint next_pow2;
+
+  g_assert (IDE_IS_BUFFER (self));
+
+  /*
+   * If adding two bytes to our length (one for \n and one for \0) is still under the next
+   * power of two, then we can avoid making a copy of the buffer when saving the buffer
+   * to our drafts.
+   *
+   * HACK: This relies on the fact that GtkTextBuffer returns a GString allocated string
+   *       which grows the string in powers of two.
+   */
+
+  if ((len == 0) || (len & (len - 1)) == 0)
+    return FALSE;
+
+  next_pow2 = len;
+  next_pow2 |= next_pow2 >> 1;
+  next_pow2 |= next_pow2 >> 2;
+  next_pow2 |= next_pow2 >> 4;
+  next_pow2 |= next_pow2 >> 8;
+  next_pow2 |= next_pow2 >> 16;
+  next_pow2++;
+
+  return ((len + 2) < next_pow2);
+}
+
 /**
  * ide_buffer_get_content:
  *
@@ -1604,8 +1635,27 @@ ide_buffer_get_content (IdeBuffer *self)
        */
       len = strlen (text);
       if (gtk_source_buffer_get_implicit_trailing_newline (GTK_SOURCE_BUFFER (self)))
-        text [len++] = '\n';
+        {
+          if (!ide_buffer_can_do_newline_hack (self, len))
+            {
+              gchar *copy;
 
+              copy = g_malloc (len + 2);
+              memcpy (copy, text, len);
+              g_free (text);
+              text = copy;
+            }
+
+          text [len] = '\n';
+          text [++len] = '\0';
+        }
+
+      /*
+       * We pass a buffer that is longer than the length we tell GBytes about.
+       * This way, compilers that don't want to see the trailing \0 can ignore
+       * that data, but compilers that rely on valid C strings can also rely
+       * on the buffer to be valid.
+       */
       priv->content = g_bytes_new_take (text, len);
 
       if ((priv->context != NULL) &&


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