[girepository] Actually verify header of loaded typelibs in g_irepository_require
authorColin Walters <walters@verbum.org>
Wed, 14 Jul 2010 15:59:11 +0000 (11:59 -0400)
committerColin Walters <walters@verbum.org>
Wed, 14 Jul 2010 15:59:11 +0000 (11:59 -0400)
Take a GError * for typelib loading code, validate the header.  This
fixes bizarre errors from gjs where g_irepository_require would happily
load old typelibs.

girepository/girepository.c
girepository/girmodule.c
girepository/gitypelib.c
girepository/gitypelib.h
tools/compiler.c
tools/generate.c

index ba6756e..ef3d6d2 100644 (file)
@@ -1221,7 +1221,9 @@ g_irepository_require (GIRepository  *repository,
       goto out;
     }
 
-  typelib = g_typelib_new_from_mapped_file (mfile);
+  typelib = g_typelib_new_from_mapped_file (mfile, error);
+  if (!typelib)
+    goto out;
   header = (Header *) typelib->data;
   typelib_namespace = g_typelib_get_string (typelib, header->namespace);
   typelib_version = g_typelib_get_string (typelib, header->nsversion);
index 1c62319..066d516 100644 (file)
@@ -206,6 +206,7 @@ GTypelib *
 g_ir_module_build_typelib (GIrModule  *module,
                             GList       *modules)
 {
+  GError *error = NULL;
   GTypelib *typelib;
   gsize length;
   guint i;
@@ -434,7 +435,12 @@ g_ir_module_build_typelib (GIrModule  *module,
   data = g_realloc (data, offset2);
   header = (Header*) data;
   length = header->size = offset2;
-  typelib = g_typelib_new_from_memory (data, length);
+  typelib = g_typelib_new_from_memory (data, length, &error);
+  if (!typelib)
+    {
+      g_error ("error building typelib: %s",
+              error->message);
+    }
 
   g_hash_table_destroy (strings);
   g_hash_table_destroy (types);
index 0741bcb..5469e8b 100644 (file)
@@ -260,30 +260,30 @@ validate_name (GTypelib   *typelib,
   return TRUE;
 }
 
+/* Fast path sanity check, operates on a memory blob */
 static gboolean
-validate_header (ValidateContext  *ctx,
-                GError          **error)
+validate_header_basic (const guint8   *memory,
+                      gsize           len,
+                      GError        **error)
 {
-  GTypelib *typelib = ctx->typelib;
-  Header *header;
+  Header *header = (Header *)memory;
 
-  if (typelib->len < sizeof (Header))
+  if (len < sizeof (Header))
     {
       g_set_error (error,
                   G_TYPELIB_ERROR,
                   G_TYPELIB_ERROR_INVALID,
-                  "The buffer is too short");
+                  "The specified typelib length %" G_GSIZE_FORMAT " is too short",
+                  len);
       return FALSE;
     }
 
-  header = (Header *)typelib->data;
-
   if (strncmp (header->magic, G_IR_MAGIC, 16) != 0)
     {
       g_set_error (error,
                   G_TYPELIB_ERROR,
                   G_TYPELIB_ERROR_INVALID_HEADER,
-                  "Magic string not found");
+                  "Invalid magic header");
       return FALSE;
 
     }
@@ -293,7 +293,7 @@ validate_header (ValidateContext  *ctx,
       g_set_error (error,
                   G_TYPELIB_ERROR,
                   G_TYPELIB_ERROR_INVALID_HEADER,
-                  "Version mismatch; expected 3, found %d",
+                  "Typelib version mismatch; expected 3, found %d",
                   header->major_version);
       return FALSE;
 
@@ -308,12 +308,13 @@ validate_header (ValidateContext  *ctx,
       return FALSE;
     }
 
-  if (header->size != typelib->len)
+  if (header->size != len)
     {
       g_set_error (error,
                   G_TYPELIB_ERROR,
                   G_TYPELIB_ERROR_INVALID_HEADER,
-                  "Typelib size mismatch");
+                  "Typelib size %" G_GSIZE_FORMAT " does not match %" G_GSIZE_FORMAT,
+                  header->size, len);
       return FALSE;
     }
 
@@ -378,9 +379,24 @@ validate_header (ValidateContext  *ctx,
       return FALSE;
     }
 
-  if (!validate_name (typelib, "namespace", typelib->data, header->namespace, error))
+  return TRUE;
+}
+
+static gboolean
+validate_header (ValidateContext  *ctx,
+                GError          **error)
+{
+  GTypelib *typelib = ctx->typelib;
+  
+  if (!validate_header_basic (typelib->data, typelib->len, error))
     return FALSE;
 
+  {
+    Header *header = (Header*)typelib->data;
+    if (!validate_name (typelib, "namespace", typelib->data, header->namespace, error))
+      return FALSE;
+  }
+
   return TRUE;
 }
 
@@ -2056,6 +2072,7 @@ _g_typelib_ensure_open (GTypelib *typelib)
  * g_typelib_new_from_memory:
  * @memory: address of memory chunk containing the typelib
  * @len: length of memory chunk containing the typelib
+ * @error: a #GError
  *
  * Creates a new #GTypelib from a memory location.  The memory block
  * pointed to by @typelib will be automatically g_free()d when the
@@ -2064,10 +2081,15 @@ _g_typelib_ensure_open (GTypelib *typelib)
  * Return value: the new #GTypelib
  **/
 GTypelib *
-g_typelib_new_from_memory (guchar *memory, gsize len)
+g_typelib_new_from_memory (guint8  *memory, 
+                          gsize    len,
+                          GError **error)
 {
   GTypelib *meta;
 
+  if (!validate_header_basic (memory, len, error))
+    return NULL;
+
   meta = g_slice_new0 (GTypelib);
   meta->data = memory;
   meta->len = len;
@@ -2081,16 +2103,22 @@ g_typelib_new_from_memory (guchar *memory, gsize len)
  * g_typelib_new_from_const_memory:
  * @memory: address of memory chunk containing the typelib
  * @len: length of memory chunk containing the typelib
+ * @error: A #GError
  *
  * Creates a new #GTypelib from a memory location.
  *
  * Return value: the new #GTypelib
  **/
 GTypelib *
-g_typelib_new_from_const_memory (const guchar *memory, gsize len)
+g_typelib_new_from_const_memory (const guchar *memory, 
+                                gsize         len,
+                                GError      **error)
 {
   GTypelib *meta;
 
+  if (!validate_header_basic (memory, len, error))
+    return NULL;
+
   meta = g_slice_new0 (GTypelib);
   meta->data = (guchar *) memory;
   meta->len = len;
@@ -2103,21 +2131,28 @@ g_typelib_new_from_const_memory (const guchar *memory, gsize len)
 /**
  * g_typelib_new_from_mapped_file:
  * @mfile: a #GMappedFile, that will be free'd when the repository is destroyed
+ * @error: a #GError
  *
  * Creates a new #GTypelib from a #GMappedFile.
  *
  * Return value: the new #GTypelib
  **/
 GTypelib *
-g_typelib_new_from_mapped_file (GMappedFile *mfile)
+g_typelib_new_from_mapped_file (GMappedFile  *mfile,
+                               GError      **error)
 {
   GTypelib *meta;
+  guint8 *data = (guint8 *) g_mapped_file_get_contents (mfile);
+  gsize len = g_mapped_file_get_length (mfile);
+
+  if (!validate_header_basic (data, len, error))
+    return NULL;
 
   meta = g_slice_new0 (GTypelib);
   meta->mfile = mfile;
   meta->owns_memory = FALSE;
-  meta->data = (guchar *) g_mapped_file_get_contents (mfile);
-  meta->len = g_mapped_file_get_length (mfile);
+  meta->data = data; 
+  meta->len = len;
 
   return meta;
 }
index 5d5eda5..0a61008 100644 (file)
@@ -34,11 +34,14 @@ G_BEGIN_DECLS
 
 typedef struct _GTypelib GTypelib;
 
-GTypelib *    g_typelib_new_from_memory       (guchar       *memory,
-                                               gsize         len);
-GTypelib *    g_typelib_new_from_const_memory (const guchar *memory,
-                                               gsize         len);
-GTypelib *    g_typelib_new_from_mapped_file  (GMappedFile  *mfile);
+GTypelib *    g_typelib_new_from_memory       (guint8        *memory,
+                                               gsize          len,
+                                              GError       **error);
+GTypelib *    g_typelib_new_from_const_memory (const guint8  *memory,
+                                               gsize          len,
+                                              GError       **error);
+GTypelib *    g_typelib_new_from_mapped_file  (GMappedFile   *mfile,
+                                              GError       **error);
 void          g_typelib_free                  (GTypelib     *typelib);
 
 gboolean      g_typelib_symbol                (GTypelib     *typelib,
index e6cddb8..d066428 100644 (file)
@@ -54,6 +54,7 @@ format_output (GTypelib *typelib)
 
   result = g_string_sized_new (6 * typelib->len);
 
+  g_string_append_printf (result, "/* GENERATED CODE - DO NOT EDIT */\n");
   g_string_append_printf (result, "#include <stdlib.h>\n");
   g_string_append_printf (result, "#include <girepository.h>\n\n");
   
@@ -84,7 +85,8 @@ format_output (GTypelib *typelib)
                              "register_typelib (void)\n"
                              "{\n"
                              "\tGTypelib *typelib;\n"
-                             "\ttypelib = g_typelib_new_from_const_memory (_G_TYPELIB, _G_TYPELIB_SIZE);\n"
+                             "\ttypelib = g_typelib_new_from_const_memory (_G_TYPELIB, _G_TYPELIB_SIZE, NULL);\n"
+                             "\tg_assert (typelib != NULL);\n"
                              "\tg_irepository_load_typelib (NULL, typelib, G_IREPOSITORY_LOAD_FLAG_LAZY, NULL);\n"
                              "}\n\n");
     }
index cd1fedc..b456901 100644 (file)
 #include "girepository.h"
 #include "gitypelib-internal.h"
 
-static const guchar *
-load_typelib (const gchar  *filename,
-             GModule     **dlhandle,
-             gsize        *len)
-{
-  guchar *typelib;
-  gsize *typelib_size;
-  GModule *handle;
-
-  handle = g_module_open (filename, G_MODULE_BIND_LOCAL|G_MODULE_BIND_LAZY);
-  if (handle == NULL)
-    {
-      g_printerr ("Could not load typelib from '%s': %s\n",
-                 filename, g_module_error ());
-      return NULL;
-    }
-
-  if (!g_module_symbol (handle, "_G_TYPELIB", (gpointer *) &typelib))
-    {
-      g_printerr ("Could not load typelib from '%s': %s\n",
-                 filename, g_module_error ());
-      return NULL;
-    }
-
-  if (!g_module_symbol (handle, "_G_TYPELIB_SIZE", (gpointer *) &typelib_size))
-    {
-      g_printerr ("Could not load typelib from '%s': %s\n",
-                 filename, g_module_error ());
-      return NULL;
-    }
-
-  *len = *typelib_size;
-
-  if (dlhandle)
-    *dlhandle = handle;
-
-  return typelib;
-}
-
 int
 main (int argc, char *argv[])
 {
@@ -114,62 +75,31 @@ main (int argc, char *argv[])
 
   for (i = 0; input[i]; i++)
     {
-      GModule *dlhandle = NULL;
-      const guchar *typelib;
-      gsize len;
+      GError *error = NULL;
       const char *namespace;
+      GMappedFile *mfile;
+      GTypelib *typelib;
 
-      if (!shlib)
-       {
-         if (!g_file_get_contents (input[i], (gchar **)&typelib, &len, &error))
-           {
-             g_fprintf (stderr, "failed to read '%s': %s\n",
-                        input[i], error->message);
-             g_clear_error (&error);
-             continue;
-           }
-       }
-      else
-       {
-         typelib = load_typelib (input[i], &dlhandle, &len);
-         if (!typelib)
-           {
-             g_fprintf (stderr, "failed to load typelib from '%s'\n",
-                        input[i]);
-             continue;
-           }
-       }
+      mfile = g_mapped_file_new (input[i], FALSE, &error);
+      if (!mfile)
+       g_error ("failed to read '%s': %s", input[i], error->message);
 
       if (input[i + 1] && output)
        needs_prefix = TRUE;
       else
        needs_prefix = FALSE;
 
-      data = g_typelib_new_from_const_memory (typelib, len);
-      {
-        GError *error = NULL;
-        if (!g_typelib_validate (data, &error)) {
-          g_printerr ("typelib not valid: %s\n", error->message);
-          g_clear_error (&error);
-         return 1;
-        }
-      }
-      namespace = g_irepository_load_typelib (g_irepository_get_default (), data, 0,
+      typelib = g_typelib_new_from_mapped_file (mfile, &error);
+      if (!typelib)
+       g_error ("failed to create typelib '%s': %s", input[i], error->message);
+
+      namespace = g_irepository_load_typelib (g_irepository_get_default (), typelib, 0,
                                              &error);
       if (namespace == NULL)
-       {
-         g_printerr ("failed to load typelib: %s\n", error->message);
-         return 1;
-       }
-
+       g_error ("failed to load typelib: %s", error->message);
+      
       gir_writer_write (output, namespace, needs_prefix, show_all);
 
-      if (dlhandle)
-       {
-         g_module_close (dlhandle);
-         dlhandle = NULL;
-       }
-
       /* when writing to stdout, stop after the first module */
       if (input[i + 1] && !output)
        {