Add context stack so when we get an error we can print out nicely where it

2008-08-24  Colin Walters  <walters@verbum.org>

	* girepository/gtypelib.c: Add context stack so
	when we get an error we can print out nicely
	where it is.

svn path=/trunk/; revision=482
This commit is contained in:
Colin Walters 2008-08-24 16:51:43 +00:00 committed by Colin Walters
parent ed13aae5f2
commit 1ebc6cfb7a

View File

@ -26,18 +26,83 @@
#include "gtypelib.h"
typedef struct {
GTypelib *typelib;
GSList *context_stack;
} ValidateContext;
#define ALIGN_VALUE(this, boundary) \
(( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
static void
push_context (ValidateContext *ctx, const char *name)
{
ctx->context_stack = g_slist_prepend (ctx->context_stack, (char*)name);
}
static void
pop_context (ValidateContext *ctx)
{
g_assert (ctx->context_stack != NULL);
ctx->context_stack = g_slist_delete_link (ctx->context_stack,
ctx->context_stack);
}
static gboolean
validate_interface_blob (GTypelib *typelib,
validate_interface_blob (ValidateContext *ctx,
guint32 offset,
GError **error);
DirEntry *
get_dir_entry_checked (GTypelib *typelib,
guint16 index,
GError **error)
{
Header *header = (Header *)typelib->data;
guint32 offset;
if (index == 0 || index > header->n_entries)
{
g_set_error (error,
G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID_BLOB,
"Invalid directory index %d", index);
return FALSE;
}
offset = header->directory + (index - 1) * header->entry_blob_size;
if (typelib->len < offset + sizeof (DirEntry))
{
g_set_error (error,
G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID,
"The buffer is too short");
return FALSE;
}
return (DirEntry *)&typelib->data[offset];
}
static CommonBlob *
get_blob (GTypelib *typelib,
guint32 offset,
GError **error)
{
if (typelib->len < offset + sizeof (CommonBlob))
{
g_set_error (error,
G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID,
"The buffer is too short");
return FALSE;
}
return (CommonBlob *)&typelib->data[offset];
}
static InterfaceTypeBlob *
get_type_blob (GTypelib *typelib,
const char *funcname,
SimpleTypeBlob *simple,
GError **error)
{
@ -55,20 +120,12 @@ get_type_blob (GTypelib *typelib,
g_set_error (error,
G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID,
"Expected non-basic type in function %s, got %d", funcname,
"Expected non-basic type but got %d",
simple->tag);
return FALSE;
}
if (typelib->len < simple->offset + sizeof (CommonBlob))
{
g_set_error (error,
G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID,
"The buffer is too short");
return FALSE;
}
return (InterfaceTypeBlob*) &typelib->data[simple->offset];
return (InterfaceTypeBlob*) get_blob (typelib, simple->offset, error);
}
DirEntry *
@ -144,7 +201,7 @@ get_string_nofail (GTypelib *typelib, guint32 offset)
}
static gboolean
validate_name (GTypelib *typelib,
validate_name (GTypelib *typelib,
const char *msg,
const guchar *data, guint32 offset,
GError **error)
@ -179,9 +236,10 @@ validate_name (GTypelib *typelib,
}
static gboolean
validate_header (GTypelib *typelib,
GError **error)
validate_header (ValidateContext *ctx,
GError **error)
{
GTypelib *typelib = ctx->typelib;
Header *header;
if (typelib->len < sizeof (Header))
@ -336,20 +394,16 @@ validate_iface_type_blob (GTypelib *typelib,
GError **error)
{
InterfaceTypeBlob *blob;
Header *header;
header = (Header *)typelib->data;
InterfaceBlob *target;
blob = (InterfaceTypeBlob*)&typelib->data[offset];
if (blob->interface == 0 || blob->interface > header->n_entries)
{
g_set_error (error,
G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID_BLOB,
"Invalid directory index %d", blob->interface);
return FALSE;
}
target = (InterfaceBlob*) get_dir_entry_checked (typelib, blob->interface, error);
if (!target)
return FALSE;
if (target->blob_type == 0) /* non-local */
return TRUE;
return TRUE;
}
@ -628,14 +682,14 @@ validate_signature_blob (GTypelib *typelib,
}
static gboolean
validate_function_blob (GTypelib *typelib,
validate_function_blob (ValidateContext *ctx,
guint32 offset,
guint16 container_type,
GError **error)
{
GTypelib *typelib = ctx->typelib;
FunctionBlob *blob;
SignatureBlob *sigblob;
const char *funcname;
if (typelib->len < offset + sizeof (FunctionBlob))
{
@ -660,7 +714,7 @@ validate_function_blob (GTypelib *typelib,
if (!validate_name (typelib, "function", typelib->data, blob->name, error))
return FALSE;
funcname = get_string_nofail (typelib, blob->name);
push_context (ctx, get_string_nofail (typelib, blob->name));
if (!validate_name (typelib, "function symbol", typelib->data, blob->symbol, error))
return FALSE;
@ -677,7 +731,7 @@ validate_function_blob (GTypelib *typelib,
g_set_error (error,
G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID_BLOB,
"Constructor %s not allowed", funcname);
"Constructor not allowed");
return FALSE;
}
}
@ -723,31 +777,36 @@ validate_function_blob (GTypelib *typelib,
SimpleTypeBlob *simple = return_type_from_signature (typelib,
blob->signature,
error);
InterfaceTypeBlob *iface;
InterfaceTypeBlob *iface_type;
InterfaceBlob *iface;
if (!simple)
return FALSE;
iface = get_type_blob (typelib, funcname, simple, error);
if (!iface)
iface_type = get_type_blob (typelib, simple, error);
if (!iface_type)
return FALSE;
if (!(iface->tag == GI_TYPE_TAG_INTERFACE))
if (!(iface_type->tag == GI_TYPE_TAG_INTERFACE))
{
g_set_error (error,
G_TYPELIB_ERROR,
G_TYPELIB_ERROR_INVALID,
"Invalid return type %d for constructor %s",
iface->tag, funcname);
"Invalid return type %d for constructor",
iface_type->tag);
return FALSE;
}
}
pop_context (ctx);
return TRUE;
}
static gboolean
validate_callback_blob (GTypelib *typelib,
validate_callback_blob (ValidateContext *ctx,
guint32 offset,
GError **error)
{
GTypelib *typelib = ctx->typelib;
CallbackBlob *blob;
if (typelib->len < offset + sizeof (CallbackBlob))
@ -772,9 +831,13 @@ validate_callback_blob (GTypelib *typelib,
if (!validate_name (typelib, "callback", typelib->data, blob->name, error))
return FALSE;
push_context (ctx, get_string_nofail (typelib, blob->name));
if (!validate_signature_blob (typelib, blob->signature, error))
return FALSE;
pop_context (ctx);
return TRUE;
}
@ -1068,11 +1131,12 @@ validate_vfunc_blob (GTypelib *typelib,
}
static gboolean
validate_struct_blob (GTypelib *typelib,
validate_struct_blob (ValidateContext *ctx,
guint32 offset,
guint16 blob_type,
GError **error)
{
GTypelib *typelib = ctx->typelib;
StructBlob *blob;
gint i;
@ -1108,6 +1172,8 @@ validate_struct_blob (GTypelib *typelib,
if (!validate_name (typelib, "struct", typelib->data, blob->name, error))
return FALSE;
push_context (ctx, get_string_nofail (typelib, blob->name));
if (blob_type == BLOB_TYPE_BOXED)
{
@ -1151,7 +1217,7 @@ validate_struct_blob (GTypelib *typelib,
for (i = 0; i < blob->n_methods; i++)
{
if (!validate_function_blob (typelib,
if (!validate_function_blob (ctx,
offset + sizeof (StructBlob) +
blob->n_fields * sizeof (FieldBlob) +
i * sizeof (FunctionBlob),
@ -1160,6 +1226,8 @@ validate_struct_blob (GTypelib *typelib,
return FALSE;
}
pop_context (ctx);
return TRUE;
}
@ -1260,10 +1328,11 @@ validate_enum_blob (GTypelib *typelib,
}
static gboolean
validate_object_blob (GTypelib *typelib,
validate_object_blob (ValidateContext *ctx,
guint32 offset,
GError **error)
{
GTypelib *typelib = ctx->typelib;
Header *header;
ObjectBlob *blob;
gint i;
@ -1388,7 +1457,7 @@ validate_object_blob (GTypelib *typelib,
for (i = 0; i < blob->n_methods; i++, offset2 += sizeof (FunctionBlob))
{
if (!validate_function_blob (typelib, offset2, BLOB_TYPE_OBJECT, error))
if (!validate_function_blob (ctx, offset2, BLOB_TYPE_OBJECT, error))
return FALSE;
}
@ -1414,10 +1483,11 @@ validate_object_blob (GTypelib *typelib,
}
static gboolean
validate_interface_blob (GTypelib *typelib,
validate_interface_blob (ValidateContext *ctx,
guint32 offset,
GError **error)
{
GTypelib *typelib = ctx->typelib;
Header *header;
InterfaceBlob *blob;
gint i;
@ -1510,7 +1580,7 @@ validate_interface_blob (GTypelib *typelib,
for (i = 0; i < blob->n_methods; i++, offset2 += sizeof (FunctionBlob))
{
if (!validate_function_blob (typelib, offset2, BLOB_TYPE_INTERFACE, error))
if (!validate_function_blob (ctx, offset2, BLOB_TYPE_INTERFACE, error))
return FALSE;
}
@ -1552,10 +1622,11 @@ validate_union_blob (GTypelib *typelib,
}
static gboolean
validate_blob (GTypelib *typelib,
guint32 offset,
GError **error)
validate_blob (ValidateContext *ctx,
guint32 offset,
GError **error)
{
GTypelib *typelib = ctx->typelib;
CommonBlob *common;
if (typelib->len < offset + sizeof (CommonBlob))
@ -1572,16 +1643,16 @@ validate_blob (GTypelib *typelib,
switch (common->blob_type)
{
case BLOB_TYPE_FUNCTION:
if (!validate_function_blob (typelib, offset, 0, error))
if (!validate_function_blob (ctx, offset, 0, error))
return FALSE;
break;
case BLOB_TYPE_CALLBACK:
if (!validate_callback_blob (typelib, offset, error))
if (!validate_callback_blob (ctx, offset, error))
return FALSE;
break;
case BLOB_TYPE_STRUCT:
case BLOB_TYPE_BOXED:
if (!validate_struct_blob (typelib, offset, common->blob_type, error))
if (!validate_struct_blob (ctx, offset, common->blob_type, error))
return FALSE;
break;
case BLOB_TYPE_ENUM:
@ -1590,11 +1661,11 @@ validate_blob (GTypelib *typelib,
return FALSE;
break;
case BLOB_TYPE_OBJECT:
if (!validate_object_blob (typelib, offset, error))
if (!validate_object_blob (ctx, offset, error))
return FALSE;
break;
case BLOB_TYPE_INTERFACE:
if (!validate_interface_blob (typelib, offset, error))
if (!validate_interface_blob (ctx, offset, error))
return FALSE;
break;
case BLOB_TYPE_CONSTANT:
@ -1621,9 +1692,10 @@ validate_blob (GTypelib *typelib,
}
static gboolean
validate_directory (GTypelib *typelib,
GError **error)
validate_directory (ValidateContext *ctx,
GError **error)
{
GTypelib *typelib = ctx->typelib;
Header *header = (Header *)typelib->data;
DirEntry *entry;
gint i;
@ -1674,7 +1746,7 @@ validate_directory (GTypelib *typelib,
return FALSE;
}
if (!validate_blob (typelib, entry->offset, error))
if (!validate_blob (ctx, entry->offset, error))
return FALSE;
}
else
@ -1697,9 +1769,10 @@ validate_directory (GTypelib *typelib,
}
static gboolean
validate_annotations (GTypelib *typelib,
validate_annotations (ValidateContext *ctx,
GError **error)
{
GTypelib *typelib = ctx->typelib;
Header *header = (Header *)typelib->data;
if (header->size < header->annotations + header->n_annotations * sizeof (AnnotationBlob))
@ -1714,18 +1787,59 @@ validate_annotations (GTypelib *typelib,
return TRUE;
}
static void
prefix_with_context (GError **error,
const char *section,
ValidateContext *ctx)
{
GString *str = g_string_new (NULL);
GSList *link;
char *buf;
link = ctx->context_stack;
if (!link)
{
g_prefix_error (error, "In %s:", section);
return;
}
for (; link; link = link->next)
{
g_string_append (str, link->data);
if (link->next)
g_string_append_c (str, '/');
}
g_string_append_c (str, ')');
buf = g_string_free (str, FALSE);
g_prefix_error (error, "In %s (Context: %s): ", section, buf);
g_free (buf);
}
gboolean
g_typelib_validate (GTypelib *typelib,
GError **error)
{
if (!validate_header (typelib, error))
return FALSE;
ValidateContext ctx;
ctx.typelib = typelib;
ctx.context_stack = NULL;
if (!validate_directory (typelib, error))
return FALSE;
if (!validate_header (&ctx, error))
{
prefix_with_context (error, "In header", &ctx);
return FALSE;
}
if (!validate_annotations (typelib, error))
return FALSE;
if (!validate_directory (&ctx, error))
{
prefix_with_context (error, "directory", &ctx);
return FALSE;
}
if (!validate_annotations (&ctx, error))
{
prefix_with_context (error, "annotations", &ctx);
return FALSE;
}
return TRUE;
}