[libglnx] glnx-errors.h: add glnx_null_throw[_*] variants



commit 0c52d85e69310c6499a70a360a03fba2b4532677
Author: Jonathan Lebon <jlebon redhat com>
Date:   Thu Mar 2 13:55:30 2017 -0500

    glnx-errors.h: add glnx_null_throw[_*] variants
    
    These are equivalent to the non-null throw, except that the returned
    value is a NULL pointer. They can be used in functions where one wants
    to return a pointer. E.g.:
    
        GKeyFile *foo(GError **error) {
                return glnx_null_throw (error, "foobar");
        }
    
    The function call redirections are wrapped around a compound statement
    expression[1] so that they represent a single top-level expression. This
    allows us to avoid -Wunused-value warnings vs using a comma operator if
    the return value isn't used.
    
    I made the 'args...' absorb the fmt argument as well so that callers can
    still use it without always having to specify at least one additional
    variadic argument. I had to check to be sure that the expansion is all
    done by the preprocessor, so we don't need to worry about stack
    intricacies.
    
    [1] https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

 glnx-errors.h               |   11 +++++++++
 glnx-fdio.c                 |   11 ++-------
 tests/test-libglnx-errors.c |   48 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 8 deletions(-)
---
diff --git a/glnx-errors.h b/glnx-errors.h
index 8f9cad8..b891f96 100644
--- a/glnx-errors.h
+++ b/glnx-errors.h
@@ -49,6 +49,9 @@ glnx_throw (GError **error, const char *fmt, ...)
   return FALSE;
 }
 
+/* Like glnx_throw(), but yields a NULL pointer. */
+#define glnx_null_throw(error, args...) \
+  ({glnx_throw (error, args); NULL;})
 
 /* Set @error using the value of `g_strerror (errno)`.
  *
@@ -79,6 +82,10 @@ glnx_throw_errno (GError **error)
   return FALSE;
 }
 
+/* Like glnx_throw_errno(), but yields a NULL pointer. */
+#define glnx_null_throw_errno(error) \
+  ({glnx_throw_errno (error); NULL;})
+
 /* Implementation detail of glnx_throw_errno_prefix() */
 void glnx_real_set_prefix_error_from_errno_va (GError     **error,
                                                gint         errsv,
@@ -108,6 +115,10 @@ glnx_throw_errno_prefix (GError **error, const char *fmt, ...)
   return FALSE;
 }
 
+/* Like glnx_throw_errno_prefix(), but yields a NULL pointer. */
+#define glnx_null_throw_errno_prefix(error, args...) \
+  ({glnx_throw_errno_prefix (error, args); NULL;})
+
 /* BEGIN LEGACY APIS */
 
 #define glnx_set_error_from_errno(error)                \
diff --git a/glnx-fdio.c b/glnx-fdio.c
index 68704cb..de3955c 100644
--- a/glnx-fdio.c
+++ b/glnx-fdio.c
@@ -555,25 +555,20 @@ glnx_readlinkat_malloc (int            dfd,
 
   for (;;)
     {
-      char *c;
+      g_autofree char *c = NULL;
       ssize_t n;
 
       c = g_malloc (l);
       n = TEMP_FAILURE_RETRY (readlinkat (dfd, subpath, c, l-1));
       if (n < 0)
-        {
-          glnx_set_error_from_errno (error);
-          g_free (c);
-          return FALSE;
-        }
+        return glnx_null_throw_errno (error);
 
       if ((size_t) n < l-1)
         {
           c[n] = 0;
-          return c;
+          return g_steal_pointer (&c);
         }
 
-      g_free (c);
       l *= 2;
     }
 
diff --git a/tests/test-libglnx-errors.c b/tests/test-libglnx-errors.c
index 8d109cd..7c7459c 100644
--- a/tests/test-libglnx-errors.c
+++ b/tests/test-libglnx-errors.c
@@ -33,6 +33,19 @@ test_error_throw (void)
   g_assert (!glnx_throw (&error, "foo: %s %d", "hello", 42));
   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
   g_assert_cmpstr (error->message, ==, "foo: hello 42");
+  g_clear_error (&error);
+
+  gpointer dummy = glnx_null_throw (&error, "literal foo");
+  g_assert (dummy == NULL);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
+  g_assert_cmpstr (error->message, ==, "literal foo");
+  g_clear_error (&error);
+
+  gpointer dummy2 = glnx_null_throw (&error, "foo: %s %d", "hola", 24);
+  g_assert (dummy2 == NULL);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
+  g_assert_cmpstr (error->message, ==, "foo: hola 24");
+  g_clear_error (&error);
 }
 
 static void
@@ -55,6 +68,17 @@ test_error_errno (void)
   fd = open (noent_path, O_RDONLY);
   if (fd < 0)
     {
+      gpointer dummy = glnx_null_throw_errno (&error);
+      g_assert (dummy == NULL);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+      g_clear_error (&error);
+    }
+  else
+    g_assert_cmpint (fd, ==, -1);
+
+  fd = open (noent_path, O_RDONLY);
+  if (fd < 0)
+    {
       g_assert (!glnx_throw_errno_prefix (&error, "Failed to open %s", noent_path));
       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
       g_assert (g_str_has_prefix (error->message, glnx_strjoina ("Failed to open ", noent_path)));
@@ -62,6 +86,30 @@ test_error_errno (void)
     }
   else
     g_assert_cmpint (fd, ==, -1);
+
+  fd = open (noent_path, O_RDONLY);
+  if (fd < 0)
+    {
+      gpointer dummy = glnx_null_throw_errno_prefix (&error, "Failed to open file");
+      g_assert (dummy == NULL);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+      g_assert (g_str_has_prefix (error->message, "Failed to open file"));
+      g_clear_error (&error);
+    }
+  else
+    g_assert_cmpint (fd, ==, -1);
+
+  fd = open (noent_path, O_RDONLY);
+  if (fd < 0)
+    {
+      gpointer dummy = glnx_null_throw_errno_prefix (&error, "Failed to open %s", noent_path);
+      g_assert (dummy == NULL);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+      g_assert (g_str_has_prefix (error->message, glnx_strjoina ("Failed to open ", noent_path)));
+      g_clear_error (&error);
+    }
+  else
+    g_assert_cmpint (fd, ==, -1);
 }
 
 int main (int argc, char **argv)


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