summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Holejsovsky <pavel.holejsovsky@gmail.com>2012-05-12 07:44:57 +0200
committerPavel Holejsovsky <pavel.holejsovsky@gmail.com>2012-05-12 20:48:55 +0200
commitd055d35a873be5978d82df3955d859399c2e30d9 (patch)
treed9cb3ae43fc09d363958ee8712983fab00c6d9d3
parent39fc1013ba84d885272123e954b2aea27d5117cd (diff)
downloadgobject-introspection-d055d35a873be5978d82df3955d859399c2e30d9.tar.gz
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
-rw-r--r--girepository/gitypelib-internal.h2
-rw-r--r--girepository/gitypelib.c6
-rw-r--r--girepository/gthash-test.c8
-rw-r--r--girepository/gthash.c10
-rw-r--r--tests/repository/gitypelibtest.c11
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);
}