THRIFT-3968: Deserializing empty string/binary fields
Client: C (GLib)
Patch: Simon South <simonsouth@apache.org>

Deserialize empty strings as they are instead of returning NULL.
Expand test cases to clarify existing behavior when deserializing empty
binary fields.
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c
index 48a2c5c..7c2d017 100644
--- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c
@@ -784,11 +784,18 @@
   }
   xfer += ret;
 
-  if (read_len > 0)
-  {
-    /* allocate the memory for the string */
-    len = (guint32) read_len + 1; /* space for null terminator */
-    *str = g_new0 (gchar, len);
+  if (read_len < 0) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+                 "got negative size of %d", read_len);
+    *str = NULL;
+    return -1;
+  }
+
+  /* allocate the memory for the string */
+  len = (guint32) read_len + 1; /* space for null terminator */
+  *str = g_new0 (gchar, len);
+  if (read_len > 0) {
     if ((ret =
          thrift_transport_read_all (protocol->transport,
                                     *str, read_len, error)) < 0)
@@ -800,7 +807,7 @@
     }
     xfer += ret;
   } else {
-    *str = NULL;
+    **str = 0;
   }
 
   return xfer;
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c
index 87b6b30..a0dd3cc 100644
--- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c
@@ -1388,9 +1388,17 @@
     return -1;
   }
 
+  if (read_len < 0) {
+    g_set_error (error, THRIFT_PROTOCOL_ERROR,
+                 THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+                 "got negative size of %d", read_len);
+    *str = NULL;
+    return -1;
+  }
+
+  /* allocate the memory as an array of unsigned char for binary data */
+  *str = g_new0 (gchar, read_len + 1);
   if (read_len > 0) {
-    /* allocate the memory as an array of unsigned char for binary data */
-    *str = g_new0 (gchar, read_len + 1);
     if ((ret =
          thrift_transport_read_all (protocol->transport,
                                     *str, read_len, error)) < 0) {
@@ -1399,16 +1407,8 @@
       return -1;
     }
     xfer += ret;
-
-  } else if (read_len == 0) {
-    *str = NULL;
-
   } else {
-    g_set_error (error, THRIFT_PROTOCOL_ERROR,
-                 THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
-                 "got negative size of %d", read_len);
-    *str = NULL;
-    return -1;
+    **str = 0;
   }
 
   return xfer;
diff --git a/lib/c_glib/test/testbinaryprotocol.c b/lib/c_glib/test/testbinaryprotocol.c
index 7ca5150..58f4df8 100755
--- a/lib/c_glib/test/testbinaryprotocol.c
+++ b/lib/c_glib/test/testbinaryprotocol.c
@@ -173,6 +173,7 @@
                                                  TEST_DOUBLE, NULL) > 0);
     assert (thrift_binary_protocol_write_string (protocol,
                                                  TEST_STRING, NULL) > 0);
+    assert (thrift_binary_protocol_write_string (protocol, "", NULL) > 0);
     assert (thrift_binary_protocol_write_binary (protocol, binary, 
                                                  len, NULL) > 0);
     assert (thrift_binary_protocol_write_binary (protocol, NULL, 0, NULL) > 0);
@@ -456,6 +457,8 @@
     assert (thrift_binary_protocol_write_string (protocol,
                                                  TEST_STRING, NULL) > 0);
     thrift_transport_flush (transport, NULL);
+    assert (thrift_binary_protocol_write_string (protocol, "", NULL) > 0);
+    thrift_transport_flush (transport, NULL);
     assert (thrift_binary_protocol_write_binary (protocol, binary,
                                                  len, NULL) > 0);
     thrift_transport_flush (transport, NULL);
@@ -491,6 +494,7 @@
   gint64 value_64 = 0;
   gdouble value_double = 0;
   gchar *string = NULL;
+  gchar *empty_string = NULL;
   gpointer binary = NULL;
   guint32 len = 0;
   void *comparator = (void *) TEST_STRING;
@@ -515,6 +519,8 @@
   assert (thrift_binary_protocol_read_double (protocol,
                                               &value_double, NULL) > 0);
   assert (thrift_binary_protocol_read_string (protocol, &string, NULL) > 0);
+  assert (thrift_binary_protocol_read_string (protocol, &empty_string,
+                                              NULL) > 0);
   assert (thrift_binary_protocol_read_binary (protocol, &binary,
                                               &len, NULL) > 0);
 
@@ -525,12 +531,17 @@
   assert (value_64 == TEST_I64);
   assert (value_double == TEST_DOUBLE);
   assert (strcmp (TEST_STRING, string) == 0);
+  assert (strcmp ("", empty_string) == 0);
   assert (memcmp (comparator, binary, len) == 0);
 
   g_free (string);
+  g_free (empty_string);
   g_free (binary);
 
-  thrift_binary_protocol_read_binary (protocol, &binary, &len, NULL);
+  assert (thrift_binary_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) > 0);
+  assert (binary == NULL);
+  assert (len == 0);
   g_free (binary);
 
   transport_read_count = 0;
@@ -768,6 +779,7 @@
   gint64 value_64 = 0;
   gdouble value_double = 0;
   gchar *string = NULL;
+  gchar *empty_string = NULL;
   gpointer binary = NULL;
   guint32 len = 0;
   void *comparator = (void *) TEST_STRING;
@@ -795,6 +807,8 @@
   assert (thrift_binary_protocol_read_double (protocol,
                                               &value_double, NULL) > 0);
   assert (thrift_binary_protocol_read_string (protocol, &string, NULL) > 0);
+  assert (thrift_binary_protocol_read_string (protocol, &empty_string,
+                                              NULL) > 0);
   assert (thrift_binary_protocol_read_binary (protocol, &binary,
                                               &len, NULL) > 0);
 
@@ -805,9 +819,17 @@
   assert (value_64 == TEST_I64);
   assert (value_double == TEST_DOUBLE);
   assert (strcmp (TEST_STRING, string) == 0);
+  assert (strcmp ("", empty_string) == 0);
   assert (memcmp (comparator, binary, len) == 0);
 
   g_free (string);
+  g_free (empty_string);
+  g_free (binary);
+
+  assert (thrift_binary_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) > 0);
+  assert (binary == NULL);
+  assert (len == 0);
   g_free (binary);
 
   thrift_transport_read_end (client, NULL);
diff --git a/lib/c_glib/test/testcompactprotocol.c b/lib/c_glib/test/testcompactprotocol.c
index 9b57a8c..03bc226 100755
--- a/lib/c_glib/test/testcompactprotocol.c
+++ b/lib/c_glib/test/testcompactprotocol.c
@@ -189,6 +189,7 @@
                                                  TEST_DOUBLE, NULL) > 0);
     assert (thrift_compact_protocol_write_string (protocol,
                                                  TEST_STRING, NULL) > 0);
+    assert (thrift_compact_protocol_write_string (protocol, "", NULL) > 0);
     assert (thrift_compact_protocol_write_binary (protocol, binary,
                                                  len, NULL) > 0);
     assert (thrift_compact_protocol_write_binary (protocol, NULL, 0, NULL) > 0);
@@ -636,6 +637,8 @@
     assert (thrift_compact_protocol_write_string (protocol,
                                                  TEST_STRING, NULL) > 0);
     thrift_transport_flush (transport, NULL);
+    assert (thrift_compact_protocol_write_string (protocol, "", NULL) > 0);
+    thrift_transport_flush (transport, NULL);
     assert (thrift_compact_protocol_write_binary (protocol, binary,
                                                  len, NULL) > 0);
     thrift_transport_flush (transport, NULL);
@@ -677,6 +680,7 @@
   gint64 value_n64 = 0;
   gdouble value_double = 0;
   gchar *string = NULL;
+  gchar *empty_string = NULL;
   gpointer binary = NULL;
   guint32 len = 0;
   void *comparator = (void *) TEST_STRING;
@@ -710,6 +714,8 @@
   assert (thrift_compact_protocol_read_double (protocol,
                                               &value_double, NULL) > 0);
   assert (thrift_compact_protocol_read_string (protocol, &string, NULL) > 0);
+  assert (thrift_compact_protocol_read_string (protocol, &empty_string,
+                                               NULL) > 0);
   assert (thrift_compact_protocol_read_binary (protocol, &binary,
                                               &len, NULL) > 0);
 
@@ -729,12 +735,17 @@
   assert (zigzag_n64 == 3);
   assert (value_double == TEST_DOUBLE);
   assert (strcmp (TEST_STRING, string) == 0);
+  assert (strcmp ("", empty_string) == 0);
   assert (memcmp (comparator, binary, len) == 0);
 
   g_free (string);
+  g_free (empty_string);
   g_free (binary);
 
-  thrift_compact_protocol_read_binary (protocol, &binary, &len, NULL);
+  assert (thrift_compact_protocol_read_binary (protocol, &binary,
+                                               &len, NULL) > 0);
+  assert (binary == NULL);
+  assert (len == 0);
   g_free (binary);
 
   transport_read_count = 0;
@@ -1181,6 +1192,7 @@
   gint64 value_n64 = 0;
   gdouble value_double = 0;
   gchar *string = NULL;
+  gchar *empty_string = NULL;
   gpointer binary = NULL;
   guint32 len = 0;
   void *comparator = (void *) TEST_STRING;
@@ -1217,6 +1229,8 @@
   assert (thrift_compact_protocol_read_double (protocol,
                                               &value_double, NULL) > 0);
   assert (thrift_compact_protocol_read_string (protocol, &string, NULL) > 0);
+  assert (thrift_compact_protocol_read_string (protocol, &empty_string,
+                                               NULL) > 0);
   assert (thrift_compact_protocol_read_binary (protocol, &binary,
                                               &len, NULL) > 0);
 
@@ -1236,9 +1250,17 @@
   assert (zigzag_n64 == 3);
   assert (value_double == TEST_DOUBLE);
   assert (strcmp (TEST_STRING, string) == 0);
+  assert (strcmp ("", empty_string) == 0);
   assert (memcmp (comparator, binary, len) == 0);
 
   g_free (string);
+  g_free (empty_string);
+  g_free (binary);
+
+  assert (thrift_compact_protocol_read_binary (protocol, &binary,
+                                               &len, NULL) > 0);
+  assert (binary == NULL);
+  assert (len == 0);
   g_free (binary);
 
   thrift_transport_read_end (client, NULL);