From 8af8aaa4a8b5a096a8cf6e946c7675fca2f1f233 Mon Sep 17 00:00:00 2001 From: Pavel Holejsovsky Date: Sat, 12 May 2012 07:44:57 +0200 Subject: [PATCH] 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 --- gitypelib-internal.h | 2 +- gitypelib.c | 6 +++--- gthash-test.c | 8 ++++---- gthash.c | 10 +++++++++- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/gitypelib-internal.h b/gitypelib-internal.h index ed8e6792d..04662b4a0 100644 --- a/gitypelib-internal.h +++ b/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/gitypelib.c b/gitypelib.c index ae6b84587..2af17e969 100644 --- a/gitypelib.c +++ b/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/gthash-test.c b/gthash-test.c index 7909a0c85..ea811e35a 100644 --- a/gthash-test.c +++ b/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/gthash.c b/gthash.c index 8a3529592..b50ea6f0e 100644 --- a/gthash.c +++ b/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);