utf8: report allocation error
authorMarc-André Lureau <marcandre.lureau@gmail.com>
Wed, 6 Nov 2013 11:21:58 +0000 (12:21 +0100)
committerMarc-André Lureau <marcandre.lureau@gmail.com>
Mon, 25 Nov 2013 11:07:57 +0000 (12:07 +0100)
Make some of the conversion functions a bit more friendly to allocation
failure.

Even though the glib policy is to abort() on allocation failure by
default, it can be quite helpful to return an allocation error for
functions already providing a GError.

I needed a safer g_utf16_to_utf8() to solve crash on big clipboard
operations with win32, related to rhbz#1017250 (and coming gdk handling
bug).

https://bugzilla.gnome.org/show_bug.cgi?id=711546

glib/gconvert.h
glib/gutf8.c

index 1945c07d6505f5c52cc52e929f57b51235b1628d..3df66ce151d0e97340f7218f2ce641b99201d6b7 100644 (file)
@@ -44,6 +44,7 @@ G_BEGIN_DECLS
  * @G_CONVERT_ERROR_PARTIAL_INPUT: Partial character sequence at end of input.
  * @G_CONVERT_ERROR_BAD_URI: URI is invalid.
  * @G_CONVERT_ERROR_NOT_ABSOLUTE_PATH: Pathname is not an absolute path.
+ * @G_CONVERT_ERROR_NO_MEMORY: No memory available. Since: 2.40
  *
  * Error codes returned by character set conversion routines.
  */
@@ -54,7 +55,8 @@ typedef enum
   G_CONVERT_ERROR_FAILED,
   G_CONVERT_ERROR_PARTIAL_INPUT,
   G_CONVERT_ERROR_BAD_URI,
-  G_CONVERT_ERROR_NOT_ABSOLUTE_PATH
+  G_CONVERT_ERROR_NOT_ABSOLUTE_PATH,
+  G_CONVERT_ERROR_NO_MEMORY
 } GConvertError;
 
 /**
index 9244fe8c4419337e3484bf95a4bf8c3bdc950a44..149eeef4466d1e92738399152018aee3a41f52e5 100644 (file)
@@ -776,6 +776,16 @@ g_utf8_to_ucs4_fast (const gchar *str,
   return result;
 }
 
+static gpointer
+try_malloc (gsize n_bytes, GError **error)
+{
+    gpointer ptr = g_try_malloc (n_bytes);
+    if (ptr == NULL)
+      g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_MEMORY,
+                           _("Failed to allocate memory"));
+    return ptr;
+}
+
 /**
  * g_utf8_to_ucs4:
  * @str: a UTF-8 encoded string
@@ -840,8 +850,10 @@ g_utf8_to_ucs4 (const gchar *str,
       in = g_utf8_next_char (in);
     }
 
-  result = g_new (gunichar, n_chars + 1);
-  
+  result = try_malloc (sizeof (gunichar) * (n_chars + 1), error);
+  if (result == NULL)
+      goto err_out;
+
   in = str;
   for (i=0; i < n_chars; i++)
     {
@@ -911,7 +923,10 @@ g_ucs4_to_utf8 (const gunichar *str,
       result_length += UTF8_LENGTH (str[i]);
     }
 
-  result = g_malloc (result_length + 1);
+  result = try_malloc (result_length + 1, error);
+  if (result == NULL)
+      goto err_out;
+
   p = result;
 
   i = 0;
@@ -1043,8 +1058,10 @@ g_utf16_to_utf8 (const gunichar2  *str,
   /* At this point, everything is valid, and we just need to convert
    */
   /********** DIFFERENT for UTF8/UCS4 **********/
-  result = g_malloc (n_bytes + 1);
-  
+  result = try_malloc (n_bytes + 1, error);
+  if (result == NULL)
+      goto err_out;
+
   high_surrogate = 0;
   out = result;
   in = str;
@@ -1180,8 +1197,10 @@ g_utf16_to_ucs4 (const gunichar2  *str,
   /* At this point, everything is valid, and we just need to convert
    */
   /********** DIFFERENT for UTF8/UCS4 **********/
-  result = g_malloc (n_bytes + 4);
-  
+  result = try_malloc (n_bytes + 4, error);
+  if (result == NULL)
+      goto err_out;
+
   high_surrogate = 0;
   out = result;
   in = str;
@@ -1310,8 +1329,10 @@ g_utf8_to_utf16 (const gchar *str,
       in = g_utf8_next_char (in);
     }
 
-  result = g_new (gunichar2, n16 + 1);
-  
+  result = try_malloc (sizeof (gunichar2) * (n16 + 1), error);
+  if (result == NULL)
+      goto err_out;
+
   in = str;
   for (i = 0; i < n16;)
     {
@@ -1405,9 +1426,11 @@ g_ucs4_to_utf16 (const gunichar  *str,
 
       i++;
     }
-  
-  result = g_new (gunichar2, n16 + 1);
-  
+
+  result = try_malloc (sizeof (gunichar2) * (n16 + 1), error);
+  if (result == NULL)
+      goto err_out;
+
   for (i = 0, j = 0; j < n16; i++)
     {
       gunichar wc = str[i];