[vala] Fix memory leak when freeing arrays of structs



commit 87b90ea71c7c07f18715972266cf881c69bc6f13
Author: Jürg Billeter <j bitron ch>
Date:   Sat Aug 1 20:06:32 2009 +0200

    Fix memory leak when freeing arrays of structs
    
    Fixes bug 589144.

 codegen/valaccodearraymodule.vala |   53 +++++++++++++++++++++++++++++++++++++
 codegen/valaccodebasemodule.vala  |   21 ++++++++++----
 2 files changed, 68 insertions(+), 6 deletions(-)
---
diff --git a/codegen/valaccodearraymodule.vala b/codegen/valaccodearraymodule.vala
index fbc17a6..4137a94 100644
--- a/codegen/valaccodearraymodule.vala
+++ b/codegen/valaccodearraymodule.vala
@@ -378,6 +378,59 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule {
 		}
 	}
 
+	private CCodeForStatement get_struct_array_free_loop (Struct st) {
+		var cbody = new CCodeBlock ();
+		var cptrarray = new CCodeIdentifier ("array");
+		var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
+
+		var cfreecall = new CCodeFunctionCall (get_destroy_func_expression (new StructValueType (st)));
+		cfreecall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cea));
+
+		var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
+		cbody.add_statement (new CCodeExpressionStatement (cfreecall));
+
+		var cfor = new CCodeForStatement (cforcond, cbody);
+		cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
+		cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1"))));
+
+		return cfor;
+	}
+
+	public override string? append_struct_array_free (Struct st) {
+		string cname = "_vala_%s_array_free".printf (st.get_cname ());;
+
+		if (source_declarations.add_declaration (cname)) {
+			return cname;
+		}
+
+		var fun = new CCodeFunction (cname, "void");
+		fun.modifiers = CCodeModifiers.STATIC;
+		fun.add_parameter (new CCodeFormalParameter ("array", "%s*".printf (st.get_cname ())));
+		fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
+		source_declarations.add_type_member_declaration (fun.copy ());
+
+		var cdofree = new CCodeBlock ();
+
+		var citdecl = new CCodeDeclaration ("int");
+		citdecl.add_declarator (new CCodeVariableDeclarator ("i"));
+		cdofree.add_statement (citdecl);
+
+		cdofree.add_statement (get_struct_array_free_loop (st));
+
+		var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
+		var cif = new CCodeIfStatement (ccondarr, cdofree);
+		fun.block = new CCodeBlock ();
+		fun.block.add_statement (cif);
+
+		var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
+		carrfree.add_argument (new CCodeIdentifier ("array"));
+		fun.block.add_statement (new CCodeExpressionStatement (carrfree));
+
+		source_type_member_definition.append (fun);
+
+		return cname;
+	}
+
 	private CCodeForStatement get_vala_array_free_loop () {
 		var cbody = new CCodeBlock ();
 		var cptrarray = new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*");
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index ca28952..3351119 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -2106,6 +2106,10 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 		return destroy_func;
 	}
 
+	public virtual string? append_struct_array_free (Struct st) {
+		return null;
+	}
+
 	public virtual CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr) {
 		var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
 
@@ -2159,9 +2163,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 			ccall.add_argument (new CCodeConstant ("TRUE"));
 		} else if (type is ArrayType) {
 			var array_type = (ArrayType) type;
-			if (array_type.element_type.data_type == null || array_type.element_type.data_type.is_reference_type ()) {
-				requires_array_free = true;
-
+			if (requires_destroy (array_type.element_type)) {
 				CCodeExpression csizeexpr = null;
 				bool first = true;
 				for (int dim = 1; dim <= array_type.rank; dim++) {
@@ -2173,9 +2175,16 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 					}
 				}
 
-				ccall.call = new CCodeIdentifier ("_vala_array_free");
-				ccall.add_argument (csizeexpr);
-				ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
+				var st = array_type.element_type.data_type as Struct;
+				if (st != null && !array_type.element_type.nullable) {
+					ccall.call = new CCodeIdentifier (append_struct_array_free (st));
+					ccall.add_argument (csizeexpr);
+				} else {
+					requires_array_free = true;
+					ccall.call = new CCodeIdentifier ("_vala_array_free");
+					ccall.add_argument (csizeexpr);
+					ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
+				}
 			}
 		}
 		



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