From d055d35a873be5978d82df3955d859399c2e30d9 Mon Sep 17 00:00:00 2001 From: Pavel Holejsovsky Date: Sat, 12 May 2012 07:44:57 +0200 Subject: girepository: avoid crash when querying nonexistent info It appears that cmph library can return (n+1) when querying item not present in its original n-item-sized set. Adjust code so that it detects this condition and do not chase stray pointers resulting from this bogus(?) hash result. https://bugzilla.gnome.org/show_bug.cgi?id=675939 --- girepository/gitypelib-internal.h | 2 +- girepository/gitypelib.c | 6 +++--- girepository/gthash-test.c | 8 ++++---- girepository/gthash.c | 10 +++++++++- tests/repository/gitypelibtest.c | 11 +++++++++++ 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h index ed8e6792..04662b4a 100644 --- a/girepository/gitypelib-internal.h +++ b/girepository/gitypelib-internal.h @@ -1183,7 +1183,7 @@ void _gi_typelib_hash_builder_pack (GITypelibHashBuilder *builder, guint8* mem, void _gi_typelib_hash_builder_destroy (GITypelibHashBuilder *builder); -guint16 _gi_typelib_hash_search (guint8* memory, const char *str); +guint16 _gi_typelib_hash_search (guint8* memory, const char *str, guint n_entries); G_END_DECLS diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c index ae6b8458..2af17e96 100644 --- a/girepository/gitypelib.c +++ b/girepository/gitypelib.c @@ -165,15 +165,15 @@ g_typelib_get_dir_entry_by_name (GITypelib *typelib, const char *name) { Section *dirindex; - gint i; + gint i, n_entries; const char *entry_name; DirEntry *entry; dirindex = get_section_by_id (typelib, GI_SECTION_DIRECTORY_INDEX); + n_entries = ((Header *)typelib->data)->n_local_entries; if (dirindex == NULL) { - gint n_entries = ((Header *)typelib->data)->n_local_entries; for (i = 1; i <= n_entries; i++) { entry = g_typelib_get_dir_entry (typelib, i); @@ -188,7 +188,7 @@ g_typelib_get_dir_entry_by_name (GITypelib *typelib, guint8 *hash = (guint8*) &typelib->data[dirindex->offset]; guint16 index; - index = _gi_typelib_hash_search (hash, name); + index = _gi_typelib_hash_search (hash, name, n_entries); entry = g_typelib_get_dir_entry (typelib, index + 1); entry_name = g_typelib_get_string (typelib, entry->name); if (strcmp (name, entry_name) == 0) diff --git a/girepository/gthash-test.c b/girepository/gthash-test.c index 7909a0c8..ea811e35 100644 --- a/girepository/gthash-test.c +++ b/girepository/gthash-test.c @@ -47,10 +47,10 @@ test_build_retrieve (void) _gi_typelib_hash_builder_destroy (builder); - g_assert (_gi_typelib_hash_search (buf, "Action") == 0); - g_assert (_gi_typelib_hash_search (buf, "ZLibDecompressor") == 42); - g_assert (_gi_typelib_hash_search (buf, "VolumeMonitor") == 9); - g_assert (_gi_typelib_hash_search (buf, "FileMonitorFlags") == 31); + g_assert (_gi_typelib_hash_search (buf, "Action", 4) == 0); + g_assert (_gi_typelib_hash_search (buf, "ZLibDecompressor", 4) == 42); + g_assert (_gi_typelib_hash_search (buf, "VolumeMonitor", 4) == 9); + g_assert (_gi_typelib_hash_search (buf, "FileMonitorFlags", 4) == 31); } int diff --git a/girepository/gthash.c b/girepository/gthash.c index 8a352959..b50ea6f0 100644 --- a/girepository/gthash.c +++ b/girepository/gthash.c @@ -191,7 +191,7 @@ _gi_typelib_hash_builder_destroy (GITypelibHashBuilder *builder) } guint16 -_gi_typelib_hash_search (guint8* memory, const char *str) +_gi_typelib_hash_search (guint8* memory, const char *str, guint n_entries) { guint32 *mph; guint16 *table; @@ -203,6 +203,14 @@ _gi_typelib_hash_search (guint8* memory, const char *str) offset = cmph_search_packed (mph, str, strlen (str)); + /* Make sure that offset always lies in the entries array. cmph + cometimes generates offset larger than number of entries (for + 'str' argument which is not in the hashed list). In this case, + fake the correct result and depend on caller's final check that + the entry is really the one that the caller wanted. */ + if (offset >= n_entries) + offset = 0; + dirmap_offset = *((guint32*)memory); table = (guint16*) (memory + dirmap_offset); diff --git a/tests/repository/gitypelibtest.c b/tests/repository/gitypelibtest.c index c53eab29..7068ef3d 100644 --- a/tests/repository/gitypelibtest.c +++ b/tests/repository/gitypelibtest.c @@ -168,6 +168,16 @@ test_fundamental_get_ref_function_pointer (GIRepository *repo) g_base_info_unref (info); } +static void +test_hash_with_cairo_typelib (GIRepository *repo) +{ + GIBaseInfo *info; + + g_assert (g_irepository_require (repo, "cairo", NULL, 0, NULL)); + info = g_irepository_find_by_name (repo, "cairo", "region"); + g_assert (info == NULL); +} + int main(int argc, char **argv) { @@ -183,6 +193,7 @@ main(int argc, char **argv) test_size_of_gvalue (repo); test_is_pointer_for_struct_arg (repo); test_fundamental_get_ref_function_pointer (repo); + test_hash_with_cairo_typelib (repo); exit(0); } -- cgit v1.2.1