[vala] Fix memory leak with owned property getters and g_object_get



commit 8974eb665656a24a8efee29f963a84c82ecbac44
Author: Jürg Billeter <j bitron ch>
Date:   Sun Mar 21 19:03:52 2010 +0100

    Fix memory leak with owned property getters and g_object_get
    
    Fixes bug 576152.

 codegen/valaccodebasemodule.vala |   12 +++++
 codegen/valaccodemodule.vala     |    4 ++
 codegen/valagobjectmodule.vala   |    6 ++-
 codegen/valagtypemodule.vala     |   83 ++++++++++++++++++++++++++++++++++++++
 vala/valaclass.vala              |   20 +++++++++
 vala/valatypesymbol.vala         |   12 +++++-
 vapi/glib-2.0.vapi               |    2 +-
 vapi/gobject-2.0.vapi            |    6 +-
 8 files changed, 138 insertions(+), 7 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index ded33db..d25ba87 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -478,6 +478,18 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 		}
 	}
 
+	public override CCodeIdentifier get_value_taker_function (DataType type_reference) {
+		var array_type = type_reference as ArrayType;
+		if (type_reference.data_type != null) {
+			return new CCodeIdentifier (type_reference.data_type.get_take_value_function ());
+		} else if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
+			// G_TYPE_STRV
+			return new CCodeIdentifier ("g_value_take_boxed");
+		} else {
+			return new CCodeIdentifier ("g_value_set_pointer");
+		}
+	}
+
 	CCodeIdentifier get_value_getter_function (DataType type_reference) {
 		var array_type = type_reference as ArrayType;
 		if (type_reference.data_type != null) {
diff --git a/codegen/valaccodemodule.vala b/codegen/valaccodemodule.vala
index 939c49f..d8e88e3 100644
--- a/codegen/valaccodemodule.vala
+++ b/codegen/valaccodemodule.vala
@@ -351,6 +351,10 @@ public abstract class Vala.CCodeModule {
 		return next.get_value_setter_function (type_reference);
 	}
 
+	public virtual CCodeIdentifier get_value_taker_function (DataType type_reference) {
+		return next.get_value_taker_function (type_reference);
+	}
+
 	public virtual CCodeExpression get_construct_property_assignment (CCodeConstant canonical_cconstant, DataType property_type, CCodeExpression value) {
 		return next.get_construct_property_assignment (canonical_cconstant, property_type, value);
 	}
diff --git a/codegen/valagobjectmodule.vala b/codegen/valagobjectmodule.vala
index 6290a68..bf5c94d 100644
--- a/codegen/valagobjectmodule.vala
+++ b/codegen/valagobjectmodule.vala
@@ -243,7 +243,11 @@ internal class Vala.GObjectModule : GTypeModule {
 				ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name)));
 				ccall.add_argument (cself);
 				var csetcall = new CCodeFunctionCall ();
-				csetcall.call = head.get_value_setter_function (prop.property_type);
+				if (prop.get_accessor.value_type.value_owned) {
+					csetcall.call = head.get_value_taker_function (prop.property_type);
+				} else {
+					csetcall.call = head.get_value_setter_function (prop.property_type);
+				}
 				csetcall.add_argument (new CCodeIdentifier ("value"));
 				csetcall.add_argument (ccall);
 				cswitch.add_statement (new CCodeExpressionStatement (csetcall));
diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala
index 7f6de7e..7353e66 100644
--- a/codegen/valagtypemodule.vala
+++ b/codegen/valagtypemodule.vala
@@ -136,6 +136,18 @@ internal class Vala.GTypeModule : GErrorModule {
 
 			decl_space.add_type_member_declaration (function);
 
+			function = new CCodeFunction (cl.get_take_value_function (), "void");
+			function.add_parameter (new CCodeFormalParameter ("value", "GValue*"));
+			function.add_parameter (new CCodeFormalParameter ("v_object", "gpointer"));
+
+			if (cl.access == SymbolAccessibility.PRIVATE) {
+				function.modifiers = CCodeModifiers.STATIC;
+				// avoid C warning as this function is not always used
+				function.attributes = "G_GNUC_UNUSED";
+			}
+
+			decl_space.add_type_member_declaration (function);
+
 			function = new CCodeFunction (cl.get_get_value_function (), "gpointer");
 			function.add_parameter (new CCodeFormalParameter ("value", "const GValue*"));
 
@@ -537,6 +549,7 @@ internal class Vala.GTypeModule : GErrorModule {
 				add_g_param_spec_type_function (cl);
 				add_g_value_get_function (cl);
 				add_g_value_set_function (cl);
+				add_g_value_take_function (cl);
 
 				var ref_count = new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "ref_count"), new CCodeConstant ("1"));
 				instance_init_fragment.append (new CCodeExpressionStatement (ref_count));
@@ -994,6 +1007,76 @@ internal class Vala.GTypeModule : GErrorModule {
 		source_type_member_definition.append (function);
 	}
 
+	private void add_g_value_take_function (Class cl) {
+		var function = new CCodeFunction (cl.get_take_value_function (), "void");
+		function.add_parameter (new CCodeFormalParameter ("value", "GValue*"));
+		function.add_parameter (new CCodeFormalParameter ("v_object", "gpointer"));
+
+		if (cl.access == SymbolAccessibility.PRIVATE) {
+			function.modifiers = CCodeModifiers.STATIC;
+		}
+
+		var vpointer = new CCodeMemberAccess(new CCodeMemberAccess.pointer (new CCodeIdentifier ("value"), "data[0]"),"v_pointer");
+
+		var init_block = new CCodeBlock ();
+		function.block = init_block;
+
+		var ctypedecl = new CCodeDeclaration (cl.get_cname()+"*");
+		ctypedecl.add_declarator ( new CCodeVariableDeclarator ("old"));
+		init_block.add_statement (ctypedecl);
+
+		var ccall_typecheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_VALUE_TYPE"));
+		ccall_typecheck.add_argument (new CCodeIdentifier ( "value" ));
+		ccall_typecheck.add_argument (new CCodeIdentifier ( cl.get_type_id() ));
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
+		ccall.add_argument (ccall_typecheck);
+		init_block.add_statement (new CCodeExpressionStatement (ccall));
+
+		init_block.add_statement(new CCodeExpressionStatement (new CCodeAssignment (new CCodeConstant ("old"), vpointer, CCodeAssignmentOperator.SIMPLE)));
+
+		var true_stmt = new CCodeBlock ();
+		var false_stmt = new CCodeBlock ();
+		var if_statement = new CCodeIfStatement (new CCodeIdentifier ("v_object"), true_stmt, false_stmt);
+		init_block.add_statement (if_statement);
+
+
+		ccall_typecheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
+		ccall_typecheck.add_argument (new CCodeIdentifier ( "v_object" ));
+		ccall_typecheck.add_argument (new CCodeIdentifier ( cl.get_type_id() ));
+
+		ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
+		ccall.add_argument (ccall_typecheck);
+		true_stmt.add_statement (new CCodeExpressionStatement (ccall));
+
+		var ccall_typefrominstance = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
+		ccall_typefrominstance.add_argument (new CCodeIdentifier ( "v_object" ));
+
+		var ccall_gvaluetype = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
+		ccall_gvaluetype.add_argument (new CCodeIdentifier ( "value" ));
+
+		var ccall_typecompatible = new CCodeFunctionCall (new CCodeIdentifier ("g_value_type_compatible"));
+		ccall_typecompatible.add_argument (ccall_typefrominstance);
+		ccall_typecompatible.add_argument (ccall_gvaluetype);
+
+		ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
+		ccall.add_argument (ccall_typecompatible);
+		true_stmt.add_statement (new CCodeExpressionStatement (ccall));
+
+		true_stmt.add_statement(new CCodeExpressionStatement (new CCodeAssignment (vpointer, new CCodeConstant ("v_object"), CCodeAssignmentOperator.SIMPLE)));
+
+		false_stmt.add_statement(new CCodeExpressionStatement (new CCodeAssignment (vpointer, new CCodeConstant ("NULL"), CCodeAssignmentOperator.SIMPLE)));
+
+		true_stmt = new CCodeBlock ();
+		if_statement = new CCodeIfStatement (new CCodeIdentifier ("old"), true_stmt);
+		init_block.add_statement (if_statement);
+
+		ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_unref_function ()));
+		ccall.add_argument (new CCodeIdentifier ("old"));
+		true_stmt.add_statement (new CCodeExpressionStatement (ccall));
+		source_type_member_definition.append (function);
+	}
+
 	private void add_g_value_get_function (Class cl) {
 		var function = new CCodeFunction (cl.get_get_value_function (), "gpointer");
 		function.add_parameter (new CCodeFormalParameter ("value", "const GValue*"));
diff --git a/vala/valaclass.vala b/vala/valaclass.vala
index 4fc73a2..eceedf3 100644
--- a/vala/valaclass.vala
+++ b/vala/valaclass.vala
@@ -123,6 +123,7 @@ public class Vala.Class : ObjectTypeSymbol {
 	private string marshaller_type_name;
 	private string get_value_function;
 	private string set_value_function;
+	private string take_value_function;
 	private bool _is_compact;
 	private bool _is_immutable;
 
@@ -633,6 +634,9 @@ public class Vala.Class : ObjectTypeSymbol {
 		if (a.has_argument ("set_value_function")) {
 			set_value_function = a.get_string ("set_value_function");
 		}
+		if (a.has_argument ("take_value_function")) {
+			take_value_function = a.get_string ("take_value_function");
+		}
 
 		if (a.has_argument ("const_cname")) {
 			const_cname = a.get_string ("const_cname");
@@ -755,6 +759,22 @@ public class Vala.Class : ObjectTypeSymbol {
 		return set_value_function;
 	}
 
+	public override string? get_take_value_function () {
+		if (take_value_function == null) {
+			if (is_fundamental ()) {
+				take_value_function = get_lower_case_cname ("value_take_");
+			} else if (base_class != null) {
+				take_value_function = base_class.get_take_value_function ();
+			} else if (get_type_id () == "G_TYPE_POINTER") {
+				take_value_function = "g_value_set_pointer";
+			} else {
+				take_value_function = "g_value_take_boxed";
+			}
+		}
+
+		return take_value_function;
+	}
+
 	public override bool is_reference_counting () {
 		return get_ref_function () != null;
 	}
diff --git a/vala/valatypesymbol.vala b/vala/valatypesymbol.vala
index 7be7b97..996e5dc 100644
--- a/vala/valatypesymbol.vala
+++ b/vala/valatypesymbol.vala
@@ -1,6 +1,7 @@
 /* valatypesymbol.vala
  *
- * Copyright (C) 2006-2008  Jürg Billeter, Raffaele Sandrini
+ * Copyright (C) 2006-2010  Jürg Billeter
+ * Copyright (C) 2006-2008  Raffaele Sandrini
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -195,7 +196,14 @@ public abstract class Vala.TypeSymbol : Symbol {
 	public virtual string? get_set_value_function () {
 		return null;
 	}
-	
+
+	/**
+	 * Returns the cname of the GValue taker function.
+	 */
+	public virtual string? get_take_value_function () {
+		return null;
+	}
+
 	/**
 	 * Returns the C name of this data type in upper case. Words are
 	 * separated by underscores. The upper case C name of the namespace is
diff --git a/vapi/glib-2.0.vapi b/vapi/glib-2.0.vapi
index e6d2e34..18872b0 100644
--- a/vapi/glib-2.0.vapi
+++ b/vapi/glib-2.0.vapi
@@ -818,7 +818,7 @@ public enum NormalizeMode {
 
 [Compact]
 [Immutable]
-[CCode (cname = "char", const_cname = "const char", copy_function = "g_strdup", free_function = "g_free", cheader_filename = "stdlib.h,string.h,glib.h", type_id = "G_TYPE_STRING", marshaller_type_name = "STRING", param_spec_function = "g_param_spec_string", get_value_function = "g_value_get_string", set_value_function = "g_value_set_string", type_signature = "s")]
+[CCode (cname = "char", const_cname = "const char", copy_function = "g_strdup", free_function = "g_free", cheader_filename = "stdlib.h,string.h,glib.h", type_id = "G_TYPE_STRING", marshaller_type_name = "STRING", param_spec_function = "g_param_spec_string", get_value_function = "g_value_get_string", set_value_function = "g_value_set_string", take_value_function = "g_value_take_string", type_signature = "s")]
 public class string {
 	[CCode (cname = "strstr")]
 	public unowned string? str (string needle);
diff --git a/vapi/gobject-2.0.vapi b/vapi/gobject-2.0.vapi
index ec9378a..2f08988 100644
--- a/vapi/gobject-2.0.vapi
+++ b/vapi/gobject-2.0.vapi
@@ -109,7 +109,7 @@ namespace GLib {
 		public virtual void unload ();
 	}
 
-	[CCode (type_id = "G_TYPE_PARAM", ref_function = "g_param_spec_ref", unref_function = "g_param_spec_unref", param_spec_function = "g_param_spec_param", get_value_function = "g_value_get_param", set_value_function = "g_value_set_param")]
+	[CCode (type_id = "G_TYPE_PARAM", ref_function = "g_param_spec_ref", unref_function = "g_param_spec_unref", param_spec_function = "g_param_spec_param", get_value_function = "g_value_get_param", set_value_function = "g_value_set_param", take_value_function = "g_value_take_param")]
 	public class ParamSpec {
 		public string name;
 		public ParamFlags flags;
@@ -288,7 +288,7 @@ namespace GLib {
 	[CCode (instance_pos = 0)]
 	public delegate void WeakNotify (Object object);
 
-	[CCode (ref_function = "g_object_ref", unref_function = "g_object_unref", marshaller_type_name = "OBJECT", get_value_function = "g_value_get_object", set_value_function = "g_value_set_object", param_spec_function = "g_param_spec_object", cheader_filename = "glib-object.h")]
+	[CCode (ref_function = "g_object_ref", unref_function = "g_object_unref", marshaller_type_name = "OBJECT", get_value_function = "g_value_get_object", set_value_function = "g_value_set_object", take_value_function = "g_value_take_object", param_spec_function = "g_param_spec_object", cheader_filename = "glib-object.h")]
 	public class Object {
 		public uint ref_count;
 
@@ -401,7 +401,7 @@ namespace GLib {
 	[CCode (has_target = false)]
 	public delegate void ValueTransform (Value src_value, out Value dest_value);
 
-	[CCode (copy_function = "g_value_copy", destroy_function = "g_value_unset", type_id = "G_TYPE_VALUE", marshaller_type_name = "BOXED", get_value_function = "g_value_get_boxed", set_value_function = "g_value_set_boxed", type_signature = "v")]
+	[CCode (copy_function = "g_value_copy", destroy_function = "g_value_unset", type_id = "G_TYPE_VALUE", marshaller_type_name = "BOXED", get_value_function = "g_value_get_boxed", set_value_function = "g_value_set_boxed", take_value_function = "g_value_take_boxed", type_signature = "v")]
 	public struct Value {
 		[CCode (cname = "G_VALUE_HOLDS")]
 		public bool holds (Type type);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]