Track arg_type_info ownership properly
diff --git a/ChangeLog b/ChangeLog
index b31c0df..45512e4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2012-01-06  Petr Machata  <pmachata@redhat.com>
 
+	* common.h (struct Function.own_return_info): New field
+	* output.c (build_default_prototype): Initialize it
+	* read_config_file.c: Use it throughout.  Now that it's tracked,
+	also init other ownership bits properly.
+
+2012-01-06  Petr Machata  <pmachata@redhat.com>
+
 	* read_config_file.c (list_of_pt, arg_type_prototypes): Drop
 	(lookup_prototype, str2type): Drop
 	(parse_arg_type): New function, similar in spirit to str2type
diff --git a/common.h b/common.h
index 9f0e8e0..2741662 100644
--- a/common.h
+++ b/common.h
@@ -55,6 +55,7 @@
 	const char * name;
 	struct param *params;
 	struct arg_type_info *return_info;
+	int own_return_info;
 	size_t num_params;
 	Function * next;
 };
diff --git a/output.c b/output.c
index 59e02b7..0276b25 100644
--- a/output.c
+++ b/output.c
@@ -142,6 +142,7 @@
 	struct arg_type_info *unknown_type = type_get_simple(ARGTYPE_UNKNOWN);
 
 	ret->return_info = unknown_type;
+	ret->own_return_info = 0;
 
 	ret->num_params = 4;
 	ret->params = malloc(sizeof(*ret->params) * ret->num_params);
diff --git a/read_config_file.c b/read_config_file.c
index d55201d..08f94ba 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -40,7 +40,7 @@
 static int line_no;
 static char *filename;
 
-static struct arg_type_info *parse_type(char **str);
+static struct arg_type_info *parse_type(char **str, int *ownp);
 
 Function *list_of_functions = NULL;
 
@@ -337,6 +337,7 @@
 struct typedef_node_t {
 	char *name;
 	struct arg_type_info *info;
+	int own_type;
 	struct typedef_node_t *next;
 } *typedefs = NULL;
 
@@ -365,6 +366,7 @@
 	struct typedef_node_t *binding = malloc(sizeof(*binding));
 	binding->name = name;
 	binding->info = info;
+	binding->own_type = own_type;
 	binding->next = typedefs;
 	typedefs = binding;
 	return binding;
@@ -388,9 +390,25 @@
 	eat_spaces(str);
 
 	// Parse the type
-	info = parse_type(str);
+	int own;
+	info = parse_type(str, &own);
 
-	insert_typedef(name, info, 0);
+	insert_typedef(name, info, own);
+}
+
+static void
+destroy_fun(Function *fun)
+{
+	size_t i;
+	if (fun == NULL)
+		return;
+	if (fun->own_return_info) {
+		type_destroy(fun->return_info);
+		free(fun->return_info);
+	}
+	for (i = 0; i < fun->num_params; ++i)
+		param_destroy(&fun->params[i]);
+	free(fun->params);
 }
 
 /* Syntax: struct ( type,type,type,... ) */
@@ -417,8 +435,8 @@
 			parse_char(str, ',');
 
 		eat_spaces(str);
-		int own = 0;
-		struct arg_type_info *field = parse_type(str);
+		int own;
+		struct arg_type_info *field = parse_type(str, &own);
 		if (field == NULL || type_struct_add(info, field, own)) {
 			type_destroy(info);
 			return -1;
@@ -596,17 +614,17 @@
 }
 
 static struct arg_type_info *
-parse_nonpointer_type(char **str) {
-
-	int own;
+parse_nonpointer_type(char **str, int *ownp)
+{
 	enum arg_type type;
 	if (parse_arg_type(str, &type) < 0) {
 		struct arg_type_info *simple;
-		if (parse_alias(str, &simple, &own) < 0)
+		if (parse_alias(str, &simple, ownp) < 0)
 			return NULL;
 		if (simple == NULL)
 			simple = lookup_typedef(str);
 		if (simple != NULL) {
+			*ownp = 0;
 			return simple;
 		}
 		report_error(filename, line_no,
@@ -630,6 +648,7 @@
 	case ARGTYPE_FLOAT:
 	case ARGTYPE_DOUBLE:
 	case ARGTYPE_FORMAT:
+		*ownp = 0;
 		return type_get_simple(type);
 
 	case ARGTYPE_ARRAY:
@@ -664,8 +683,8 @@
 			     "malloc: %s", strerror(errno));
 		return NULL;
 	}
+	*ownp = 1;
 
-	assert(parser != NULL);
 	if (parser(str, info) < 0) {
 		free(info);
 		return NULL;
@@ -675,8 +694,9 @@
 }
 
 static struct arg_type_info *
-parse_type(char **str) {
-	struct arg_type_info *info = parse_nonpointer_type(str);
+parse_type(char **str, int *ownp)
+{
+	struct arg_type_info *info = parse_nonpointer_type(str, ownp);
 	if (info == NULL)
 		return NULL;
 
@@ -685,11 +705,16 @@
 		if (**str == '*') {
 			struct arg_type_info *outer = malloc(sizeof(*outer));
 			if (outer == NULL) {
+				if (*ownp) {
+					type_destroy(info);
+					free(info);
+				}
 				report_error(filename, line_no,
 					     "malloc: %s", strerror(errno));
 				return NULL;
 			}
-			type_init_pointer(outer, info, 0);
+			type_init_pointer(outer, info, *ownp);
+			*ownp = 1;
 			(*str)++;
 			info = outer;
 		} else
@@ -740,11 +765,12 @@
 		return NULL;
 	}
 
-	fun->return_info = parse_type(&str);
+	fun->return_info = parse_type(&str, &fun->own_return_info);
 	if (fun->return_info == NULL
 	    || fun->return_info->type == ARGTYPE_UNKNOWN) {
 	err:
 		debug(3, " Skipping line %d", line_no);
+		destroy_fun(fun);
 		return NULL;
 	}
 	debug(4, " return_type = %d", fun->return_info->type);
@@ -789,7 +815,8 @@
 			goto err;
 		}
 
-		struct arg_type_info *type = parse_type(&str);
+		int own;
+		struct arg_type_info *type = parse_type(&str, &own);
 		if (type == NULL) {
 			report_error(filename, line_no,
 				     "unknown argument type");
@@ -805,10 +832,15 @@
 		if (type->type == ARGTYPE_VOID) {
 			report_warning(filename, line_no,
 				       "void parameter assumed to be 'int'");
+			if (own) {
+				type_destroy(type);
+				free(type);
+			}
 			type = type_get_simple(ARGTYPE_INT);
+			own = 0;
 		}
 
-		param_init_type(&fun->params[fun->num_params++], type, 0);
+		param_init_type(&fun->params[fun->num_params++], type, own);
 
 		eat_spaces(&str);
 		if (*str == ',') {