[glib] gbase64: Fix base-64 stepped encoding with small chunks



commit 35c0dd2755dbcea2539117cf33959a1a9e497f12
Author: Philip Withnall <withnall endlessm com>
Date:   Fri Mar 17 11:30:47 2017 +0000

    gbase64: Fix base-64 stepped encoding with small chunks
    
    If encoding with small chunks such that the call to
    g_base64_encode_close() has to deal with 0 < x < 24 bits of remaining
    state, the encoding code would not correctly use zeroes to pad out the
    state — it would use left-over state from an earlier iteration in the
    encoding process.
    
    This resulted in invalid base-64 encodings.
    
    Add a unit test for incremental encoding using different sized chunks
    too.
    
    Thanks to Rainier Perske for reporting and analysing the bug.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=780066
    
    Signed-off-by: Philip Withnall <withnall endlessm com>

 glib/gbase64.c      |    1 +
 glib/tests/base64.c |   58 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 0 deletions(-)
---
diff --git a/glib/gbase64.c b/glib/gbase64.c
index 7bca5ab..4dc1518 100644
--- a/glib/gbase64.c
+++ b/glib/gbase64.c
@@ -222,6 +222,7 @@ g_base64_encode_close (gboolean  break_lines,
       goto skip;
     case 1:
       outptr[2] = '=';
+      c2 = 0;  /* saved state here is not relevant */
     skip:
       outptr [0] = base64_alphabet [ c1 >> 2 ];
       outptr [1] = base64_alphabet [ c2 >> 4 | ( (c1&0x3) << 4 )];
diff --git a/glib/tests/base64.c b/glib/tests/base64.c
index ffb00d5..86875a2 100644
--- a/glib/tests/base64.c
+++ b/glib/tests/base64.c
@@ -236,6 +236,58 @@ test_base64_encode (void)
     }
 }
 
+/* Test that incremental and all-in-one encoding of strings of a length which
+ * is not a multiple of 3 bytes behave the same, as the state carried over
+ * between g_base64_encode_step() calls varies depending on how the input is
+ * split up. This is like the test_base64_decode_smallblock() test, but for
+ * encoding. */
+static void
+test_base64_encode_incremental_small_block (gconstpointer block_size_p)
+{
+  gsize i;
+  struct MyRawData myraw;
+
+  g_test_bug ("780066");
+
+  generate_databuffer_for_base64 (&myraw);
+
+  for (i = 0; ok_100_encode_strs[i] != NULL; i++)
+    {
+      const guint block_size = GPOINTER_TO_UINT (block_size_p);
+      gchar *encoded_complete = NULL;
+      gchar encoded_stepped[1024];
+      gint state = 0, save = 0;
+      gsize len_written, len_read, len_to_read, input_length;
+
+      input_length = i + 1;
+
+      /* Do it all at once. */
+      encoded_complete = g_base64_encode (myraw.data, input_length);
+
+      /* Split the data up so some number of bits remain after each step. */
+      for (len_written = 0, len_read = 0; len_read < input_length; len_read += len_to_read)
+        {
+          len_to_read = MIN (block_size, input_length - len_read);
+          len_written += g_base64_encode_step (myraw.data + len_read, len_to_read,
+                                               FALSE,
+                                               encoded_stepped + len_written,
+                                               &state, &save);
+        }
+
+      len_written += g_base64_encode_close (FALSE, encoded_stepped + len_written,
+                                            &state, &save);
+      g_assert_cmpuint (len_written, <, G_N_ELEMENTS (encoded_stepped));
+
+      /* Nul-terminate to make string comparison easier. */
+      encoded_stepped[len_written] = '\0';
+
+      /* Compare results. They should be the same. */
+      g_assert_cmpstr (encoded_complete, ==, ok_100_encode_strs[i]);
+      g_assert_cmpstr (encoded_stepped, ==, encoded_complete);
+
+      g_free (encoded_complete);
+    }
+}
 
 static void
 decode_and_compare (const gchar            *datap,
@@ -361,6 +413,7 @@ main (int argc, char *argv[])
   gint i;
 
   g_test_init (&argc, &argv, NULL);
+  g_test_bug_base ("https://bugzilla.gnome.org/browse.cgi?product=";);
 
   for (i = 0; i < DATA_SIZE; i++)
     data[i] = (guchar)i;
@@ -370,6 +423,11 @@ main (int argc, char *argv[])
   g_test_add_data_func ("/base64/full/3", GINT_TO_POINTER (2), test_full);
   g_test_add_data_func ("/base64/full/4", GINT_TO_POINTER (3), test_full);
 
+  g_test_add_data_func ("/base64/encode/incremental/small-block/1", GINT_TO_POINTER (1), 
test_base64_encode_incremental_small_block);
+  g_test_add_data_func ("/base64/encode/incremental/small-block/2", GINT_TO_POINTER (2), 
test_base64_encode_incremental_small_block);
+  g_test_add_data_func ("/base64/encode/incremental/small-block/3", GINT_TO_POINTER (3), 
test_base64_encode_incremental_small_block);
+  g_test_add_data_func ("/base64/encode/incremental/small-block/4", GINT_TO_POINTER (4), 
test_base64_encode_incremental_small_block);
+
   g_test_add_data_func ("/base64/incremental/nobreak/1", GINT_TO_POINTER (DATA_SIZE), 
test_incremental_nobreak);
   g_test_add_data_func ("/base64/incremental/break/1", GINT_TO_POINTER (DATA_SIZE), test_incremental_break);
 


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