[macruby-changes] [216] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Sat May 24 00:55:27 PDT 2008


Revision: 216
          http://trac.macosforge.org/projects/ruby/changeset/216
Author:   lsansonetti at apple.com
Date:     2008-05-24 00:55:26 -0700 (Sat, 24 May 2008)

Log Message:
-----------
fixing memory leaks after bs parsing and when setting generic ivars (#23)

Modified Paths:
--------------
    MacRuby/trunk/bs.c
    MacRuby/trunk/gc.c
    MacRuby/trunk/hash.c
    MacRuby/trunk/include/ruby/intern.h
    MacRuby/trunk/objc.m
    MacRuby/trunk/variable.c

Modified: MacRuby/trunk/bs.c
===================================================================
--- MacRuby/trunk/bs.c	2008-05-24 04:54:44 UTC (rev 215)
+++ MacRuby/trunk/bs.c	2008-05-24 07:55:26 UTC (rev 216)
@@ -694,6 +694,8 @@
         
         case BS_XML_INFORMAL_PROTOCOL: 
         {
+	  if (protocol_name != NULL)
+	    free(protocol_name);
           protocol_name = get_attribute(reader, "name");
           CHECK_ATTRIBUTE(protocol_name, "name");
           break;
@@ -825,6 +827,9 @@
               func_ptr = bs_arg->function_pointer;
               func_ptr_arg_depth = xmlTextReaderDepth(reader);
             }
+	    else {
+              bs_arg->function_pointer = NULL;
+	    }
           }
           else {
             BAIL("argument defined outside of a " \
@@ -897,6 +902,9 @@
               func_ptr = bs_retval->function_pointer;
               func_ptr_arg_depth = xmlTextReaderDepth(reader);
             }
+	    else {
+              bs_retval->function_pointer = NULL;
+	    }
           }
           else {
             BAIL("return value defined outside a function/method");
@@ -926,7 +934,7 @@
             bs_informal_method->class_method = 
               get_boolean_attribute(reader, "class_method", false);
             bs_informal_method->type = method_type;
-            bs_informal_method->protocol_name = protocol_name;
+            bs_informal_method->protocol_name = strdup(protocol_name);
 
             bs_element = bs_informal_method;
             bs_element_type = BS_ELEMENT_INFORMAL_PROTOCOL_METHOD;
@@ -942,6 +950,7 @@
             ASSERT_ALLOC(method);
 
             method->name = sel_registerName(selector);
+	    free(selector);
             method->class_method = 
               get_boolean_attribute(reader, "class_method", false);
             method->variadic = 
@@ -1083,6 +1092,9 @@
   success = true;
 
 bails:
+  if (protocol_name != NULL)
+    free(protocol_name);
+
   xmlFreeTextReader(reader);
   
   return success;
@@ -1108,10 +1120,165 @@
   return status;
 }
 
+#define SAFE_FREE(x) do { if ((x) != NULL) free(x); } while (0)
+
+static void bs_free_retval(bs_element_retval_t *bs_retval);
+static void bs_free_arg(bs_element_arg_t *bs_arg);
+
+static void
+bs_free_function_pointer(bs_element_function_pointer_t *bs_func_ptr)
+{
+  if (bs_func_ptr != NULL) {
+    unsigned i;
+    for (i = 0; i < bs_func_ptr->args_count; i++)
+      bs_free_arg(&bs_func_ptr->args[i]);
+    SAFE_FREE(bs_func_ptr->args);
+    bs_free_retval(bs_func_ptr->retval);
+    SAFE_FREE(bs_func_ptr);
+  }
+}
+
+static void
+bs_free_retval(bs_element_retval_t *bs_retval)
+{
+  if (bs_retval == NULL)
+    return;
+  SAFE_FREE(bs_retval->type);
+  bs_free_function_pointer(bs_retval->function_pointer);
+}
+
+static void
+bs_free_arg(bs_element_arg_t *bs_arg)
+{
+  SAFE_FREE(bs_arg->type);
+  SAFE_FREE(bs_arg->sel_of_type);
+  bs_free_function_pointer(bs_arg->function_pointer);
+}
+
+static void 
+bs_free_method(bs_element_method_t *bs_method)
+{
+  unsigned i;
+  for (i = 0; i < bs_method->args_count; i++)
+    bs_free_arg(&bs_method->args[i]);
+  SAFE_FREE(bs_method->args);
+  bs_free_retval(bs_method->retval);
+  SAFE_FREE(bs_method->suggestion); 
+}
+
 void 
 bs_element_free(bs_element_type_t type, void *value)
 {
-  /* TODO */
+  assert(value != NULL);
+
+  switch (type) {
+    case BS_ELEMENT_STRUCT:
+    {
+      bs_element_struct_t *bs_struct = (bs_element_struct_t *)value;
+      unsigned i;
+      SAFE_FREE(bs_struct->name);
+      SAFE_FREE(bs_struct->type);
+      for (i = 0; i < bs_struct->fields_count; i++) {
+        SAFE_FREE(bs_struct->fields[i].name);
+        SAFE_FREE(bs_struct->fields[i].type);
+      }
+      SAFE_FREE(bs_struct->fields);
+      break;
+    }
+
+    case BS_ELEMENT_CFTYPE:
+    {
+      bs_element_cftype_t *bs_cftype = (bs_element_cftype_t *)value;
+      SAFE_FREE(bs_cftype->name);
+      SAFE_FREE(bs_cftype->type);
+      SAFE_FREE(bs_cftype->tollfree);
+      break;
+    }
+
+    case BS_ELEMENT_OPAQUE:
+    {
+      bs_element_opaque_t *bs_opaque = (bs_element_opaque_t *)value;
+      SAFE_FREE(bs_opaque->name);
+      SAFE_FREE(bs_opaque->type);
+      break;    
+    }
+
+    case BS_ELEMENT_CONSTANT:
+    {
+      bs_element_constant_t *bs_const = (bs_element_constant_t *)value;
+      SAFE_FREE(bs_const->name);
+      SAFE_FREE(bs_const->type);
+      SAFE_FREE(bs_const->suggestion);
+      break;
+    }
+
+    case BS_ELEMENT_STRING_CONSTANT:
+    {
+      bs_element_string_constant_t *bs_str_const = 
+        (bs_element_string_constant_t *)value;
+      SAFE_FREE(bs_str_const->name);
+      SAFE_FREE(bs_str_const->value);
+      break;
+    }
+
+    case BS_ELEMENT_ENUM:
+    {
+      bs_element_enum_t *bs_enum = (bs_element_enum_t *)value;
+      SAFE_FREE(bs_enum->name);
+      SAFE_FREE(bs_enum->value);
+      SAFE_FREE(bs_enum->suggestion);
+      break;
+    }
+
+    case BS_ELEMENT_FUNCTION:
+    {
+      unsigned i;
+      bs_element_function_t *bs_func = (bs_element_function_t *)value;
+      free(bs_func->name);
+      for (i = 0; i < bs_func->args_count; i++)
+        bs_free_arg(&bs_func->args[i]);
+      SAFE_FREE(bs_func->args);
+      bs_free_retval(bs_func->retval);
+      break;
+    }
+
+    case BS_ELEMENT_FUNCTION_ALIAS:
+    {
+      bs_element_function_alias_t *bs_func_alias = 
+        (bs_element_function_alias_t *)value;
+      SAFE_FREE(bs_func_alias->name);
+      SAFE_FREE(bs_func_alias->original);
+      break;
+    }
+
+    case BS_ELEMENT_CLASS:
+    {
+      bs_element_class_t *bs_class = (bs_element_class_t *)value;
+      unsigned i;
+      free(bs_class->name);
+      for (i = 0; i < bs_class->class_methods_count; i++)
+        bs_free_method(&bs_class->class_methods[i]);
+      SAFE_FREE(bs_class->class_methods);
+      for (i = 0; i < bs_class->instance_methods_count; i++)
+        bs_free_method(&bs_class->instance_methods[i]);
+      SAFE_FREE(bs_class->instance_methods);
+      break;
+    }
+
+    case BS_ELEMENT_INFORMAL_PROTOCOL_METHOD:
+    {
+      bs_element_informal_protocol_method_t *bs_iprotm = 
+        (bs_element_informal_protocol_method_t *)value;
+      SAFE_FREE(bs_iprotm->protocol_name);
+      SAFE_FREE(bs_iprotm->type);
+      break;
+    }
+
+    default:
+      fprintf(stderr, "unknown value %p of type %d passed to bs_free()", 
+	      value, type);
+  }
+  free(value);
 }
 
 #if 0

Modified: MacRuby/trunk/gc.c
===================================================================
--- MacRuby/trunk/gc.c	2008-05-24 04:54:44 UTC (rev 215)
+++ MacRuby/trunk/gc.c	2008-05-24 07:55:26 UTC (rev 216)
@@ -2923,12 +2923,14 @@
     if (rb_objc_is_non_native((VALUE)obj)) {
 	static SEL sel = NULL;
 	rb_objc_remove_keys(obj);
+	rb_free_generic_ivar((VALUE)obj, true);
 	if (sel == NULL)
 	    sel = sel_registerName("finalize");
 	objc_msgSend(obj, sel);
     }
     else {
-	/* TODO: call ObjectSpace finalizers, if any */
+	if (FL_TEST(obj, FL_EXIVAR))
+	    rb_free_generic_ivar((VALUE)obj, false);
     }
 }
 

Modified: MacRuby/trunk/hash.c
===================================================================
--- MacRuby/trunk/hash.c	2008-05-24 04:54:44 UTC (rev 215)
+++ MacRuby/trunk/hash.c	2008-05-24 07:55:26 UTC (rev 216)
@@ -263,14 +263,14 @@
     return (CFHashCode)rb_any_hash((VALUE)v); 
 }
 
-static const void *
+const void *
 rb_cfdictionary_retain_cb(CFAllocatorRef allocator, const void *v)
 {
     rb_objc_retain(v);
     return v;
 }
 
-static void
+void
 rb_cfdictionary_release_cb(CFAllocatorRef allocator, const void *v)
 {
     rb_objc_release(v);

Modified: MacRuby/trunk/include/ruby/intern.h
===================================================================
--- MacRuby/trunk/include/ruby/intern.h	2008-05-24 04:54:44 UTC (rev 215)
+++ MacRuby/trunk/include/ruby/intern.h	2008-05-24 07:55:26 UTC (rev 216)
@@ -656,7 +656,7 @@
 void rb_copy_generic_ivar(VALUE,VALUE);
 void rb_mark_generic_ivar(VALUE);
 void rb_mark_generic_ivar_tbl(void);
-void rb_free_generic_ivar(VALUE);
+void rb_free_generic_ivar(VALUE,bool);
 VALUE rb_ivar_get(VALUE, ID);
 VALUE rb_ivar_set(VALUE, ID, VALUE);
 VALUE rb_ivar_defined(VALUE, ID);

Modified: MacRuby/trunk/objc.m
===================================================================
--- MacRuby/trunk/objc.m	2008-05-24 04:54:44 UTC (rev 215)
+++ MacRuby/trunk/objc.m	2008-05-24 07:55:26 UTC (rev 216)
@@ -2109,6 +2109,7 @@
 	case BS_ELEMENT_STRUCT:
 	{
 	    setup_bs_boxed_type(type, value);
+	    do_not_free = true;
 	    break;
 	}
 
@@ -2121,7 +2122,7 @@
 	    bs_class_new = (bs_element_indexed_class_t *)
 		malloc(sizeof(bs_element_indexed_class_t));
 
-	    bs_class_new->name = strdup(bs_class->name);
+	    bs_class_new->name = bs_class->name;
 
 #define INDEX_METHODS(table, ary, len) \
     do { \
@@ -2150,6 +2151,8 @@
 	    st_insert(bs_classes, (st_data_t)bs_class_new->name, 
 		(st_data_t)bs_class_new);
 
+	    free(bs_class);
+	    do_not_free = true;
 	    break;
 	}
 
@@ -2164,6 +2167,9 @@
 	    st_insert(t, (st_data_t)bs_inf_prot_method->name,
 		(st_data_t)bs_inf_prot_method->type);
 
+	    free(bs_inf_prot_method->protocol_name);
+	    free(bs_inf_prot_method);
+	    do_not_free = true;
 	    break;
 	}
 
@@ -2172,6 +2178,7 @@
 	    bs_element_cftype_t *bs_cftype = (bs_element_cftype_t *)value;
 	    st_insert(bs_cftypes, (st_data_t)bs_cftype->type, 
 		    (st_data_t)bs_cftype);
+	    do_not_free = true;
 	    break;
 	}
     }

Modified: MacRuby/trunk/variable.c
===================================================================
--- MacRuby/trunk/variable.c	2008-05-24 04:54:44 UTC (rev 215)
+++ MacRuby/trunk/variable.c	2008-05-24 07:55:26 UTC (rev 216)
@@ -784,23 +784,48 @@
     entry1->var = entry2->var;
 }
 
+#if WITH_OBJC
+static CFMutableDictionaryRef generic_iv_dict = NULL;
+const void * rb_cfdictionary_retain_cb(CFAllocatorRef, const void *);
+void rb_cfdictionary_release_cb(CFAllocatorRef, const void *);
+#else
 static int special_generic_ivar = 0;
 static st_table *generic_iv_tbl;
+#endif
 
 st_table*
 rb_generic_ivar_table(VALUE obj)
 {
+#if WITH_OBJC
+    return NULL;
+#else
     st_data_t tbl;
 
     if (!FL_TEST(obj, FL_EXIVAR)) return 0;
     if (!generic_iv_tbl) return 0;
     if (!st_lookup(generic_iv_tbl, obj, &tbl)) return 0;
     return (st_table *)tbl;
+#endif
 }
 
 static VALUE
 generic_ivar_get(VALUE obj, ID id, int warn)
 {
+#if WITH_OBJC
+    if (generic_iv_dict != NULL) {
+	CFDictionaryRef obj_dict;
+
+	if (CFDictionaryGetValueIfPresent(generic_iv_dict, 
+	    (const void *)obj, (const void **)&obj_dict) 
+	    && obj_dict != NULL) {
+	    VALUE val;
+
+	    if (CFDictionaryGetValueIfPresent(obj_dict, (const void *)id, 
+		(const void **)&val))
+		return val;
+	}
+    }
+#else
     st_data_t tbl;
     VALUE val;
 
@@ -811,6 +836,7 @@
 	    }
 	}
     }
+#endif
     if (warn) {
 	rb_warning("instance variable %s not initialized", rb_id2name(id));
     }
@@ -818,8 +844,45 @@
 }
 
 static void
-generic_ivar_set(VALUE obj, ID id, VALUE val)
+generic_ivar_set(VALUE obj, ID id, VALUE val, int pure)
 {
+#if WITH_OBJC
+    CFMutableDictionaryRef obj_dict;
+
+    if (rb_special_const_p(obj)) {
+	if (rb_obj_frozen_p(obj)) 
+	    rb_error_frozen("object");
+    }
+    if (generic_iv_dict == NULL) {
+	CFDictionaryValueCallBacks values_cb;
+
+	memset(&values_cb, 0, sizeof(values_cb));
+	values_cb.retain = rb_cfdictionary_retain_cb;
+	values_cb.release = rb_cfdictionary_release_cb;
+
+	generic_iv_dict = CFDictionaryCreateMutable(NULL, 0, NULL, &values_cb);
+	obj_dict = NULL;
+    }
+    else {
+	obj_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(
+	    (CFDictionaryRef)generic_iv_dict, (const void *)obj);
+    }
+    if (obj_dict == NULL) {
+	CFDictionaryValueCallBacks values_cb;
+
+	memset(&values_cb, 0, sizeof(values_cb));
+	values_cb.retain = rb_cfdictionary_retain_cb;
+	values_cb.release = rb_cfdictionary_release_cb;
+
+	obj_dict = CFDictionaryCreateMutable(NULL, 0, NULL, &values_cb);
+	CFDictionarySetValue(generic_iv_dict, (const void *)obj, 
+	    (const void *)obj_dict);
+	CFMakeCollectable(obj_dict);
+    }
+    if (!pure)
+	FL_SET(obj, FL_EXIVAR);
+    CFDictionarySetValue(obj_dict, (const void *)id, (const void *)val);
+#else
     st_table *tbl;
     st_data_t data;
 
@@ -839,11 +902,24 @@
 	return;
     }
     st_insert((st_table *)data, id, val);
+#endif
 }
 
 static VALUE
 generic_ivar_defined(VALUE obj, ID id)
 {
+#if WITH_OBJC
+    CFMutableDictionaryRef obj_dict;
+
+    if (generic_iv_dict != NULL
+	&& CFDictionaryGetValueIfPresent((CFDictionaryRef)generic_iv_dict, 
+	   (const void *)obj, (const void **)&obj_dict) && obj_dict != NULL) {
+    	if (CFDictionaryGetValueIfPresent(obj_dict, (const void *)id, NULL))
+	    return Qtrue;
+    }
+    return Qfalse;    
+
+#else
     st_table *tbl;
     st_data_t data;
     VALUE val;
@@ -855,11 +931,33 @@
 	return Qtrue;
     }
     return Qfalse;
+#endif
 }
 
 static int
 generic_ivar_remove(VALUE obj, ID id, VALUE *valp)
 {
+#if WITH_OBJC
+    CFMutableDictionaryRef obj_dict;
+    VALUE val;
+
+    if (generic_iv_dict == NULL)
+	return 0;
+
+    obj_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(
+	(CFDictionaryRef)generic_iv_dict, (const void *)obj);
+    if (obj_dict == NULL)
+	return 0;
+
+    if (CFDictionaryGetValueIfPresent(obj_dict, (const void *)id, 
+	(const void **)&val)) {
+	*valp = val;
+	CFDictionaryRemoveValue(obj_dict, (const void *)id);
+	return 1;
+    }
+
+    return 0;
+#else
     st_table *tbl;
     st_data_t data;
     int status;
@@ -873,8 +971,10 @@
 	st_free_table((st_table *)data);
     }
     return status;
+#endif
 }
 
+#if !WITH_OBJC
 void
 rb_mark_generic_ivar(VALUE obj)
 {
@@ -909,20 +1009,59 @@
     if (special_generic_ivar == 0) return;
     st_foreach_safe(generic_iv_tbl, givar_i, 0);
 }
+#endif
 
 void
-rb_free_generic_ivar(VALUE obj)
+rb_free_generic_ivar(VALUE obj, bool lookup)
 {
+#if WITH_OBJC
+    if (generic_iv_dict != NULL) {
+	if (lookup) {
+	    if (CFDictionaryGetValueIfPresent(generic_iv_dict, 
+		(const void *)obj, NULL)) {
+		CFDictionaryReplaceValue(generic_iv_dict, (const void *)obj, 
+		    NULL);
+	    }
+	}
+	else {
+	    CFDictionaryRemoveValue(generic_iv_dict, (const void *)obj);
+	}
+    }
+#else
     st_data_t tbl;
 
     if (!generic_iv_tbl) return;
     if (st_delete(generic_iv_tbl, &obj, &tbl))
 	st_free_table((st_table *)tbl);
+#endif
 }
 
 void
 rb_copy_generic_ivar(VALUE clone, VALUE obj)
 {
+#if WITH_OBJC
+    CFMutableDictionaryRef obj_dict;
+    CFMutableDictionaryRef clone_dict;
+    VALUE val;
+
+    if (generic_iv_dict == NULL)
+	return;
+
+    obj_dict = (CFMutableDictionaryRef)CFDictionaryGetValue(
+	(CFDictionaryRef)generic_iv_dict, (const void *)obj);
+    if (obj_dict == NULL)
+	return;
+
+    if (CFDictionaryGetValueIfPresent((CFDictionaryRef)generic_iv_dict, 
+	(const void *)clone, (const void **)&clone_dict) 
+	&& clone_dict != NULL)
+	CFDictionaryRemoveValue(generic_iv_dict, (const void *)clone);
+
+    clone_dict = CFDictionaryCreateMutableCopy(NULL, 0, obj_dict);
+    CFDictionarySetValue(generic_iv_dict, (const void *)clone, 
+	(const void *)clone_dict);
+    CFMakeCollectable(clone_dict);
+#else
     st_data_t data;
 
     if (!generic_iv_tbl) return;
@@ -949,6 +1088,7 @@
 	    FL_SET(clone, FL_EXIVAR);
 	}
     }
+#endif
 }
 
 static VALUE
@@ -1012,16 +1152,15 @@
     long i, len;
     int ivar_extended;
 
+    if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
+	rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
+    if (OBJ_FROZEN(obj)) rb_error_frozen("object");
 #if WITH_OBJC
     if (rb_objc_is_non_native(obj)) {
-	generic_ivar_set(obj, id, val);
+	generic_ivar_set(obj, id, val, 1);
 	return val;
     }
 #endif
-
-    if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
-	rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
-    if (OBJ_FROZEN(obj)) rb_error_frozen("object");
     switch (TYPE(obj)) {
       case T_OBJECT:
         iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
@@ -1082,7 +1221,7 @@
 	st_insert(RCLASS_IV_TBL(obj), id, val);
         break;
       default:
-	generic_ivar_set(obj, id, val);
+	generic_ivar_set(obj, id, val, 0);
 	break;
     }
     return val;
@@ -1094,6 +1233,9 @@
     VALUE val;
     struct st_table *iv_index_tbl;
     st_data_t index;
+    if (rb_objc_is_non_native(obj)) {
+	return generic_ivar_defined(obj, id);
+    }
     switch (TYPE(obj)) {
       case T_OBJECT:
         iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
@@ -1155,29 +1297,39 @@
 void rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
 {
 #if WITH_OBJC
-    if (!rb_objc_is_non_native(obj))
+    if (rb_objc_is_non_native(obj))
+	goto generic;
 #endif
     switch (TYPE(obj)) {
       case T_OBJECT:
         obj_ivar_each(obj, func, arg);
-	break;
+	return;
       case T_CLASS:
       case T_MODULE:
 	if (RCLASS_IV_TBL(obj)) {
 	    st_foreach_safe(RCLASS_IV_TBL(obj), func, arg);
 	}
-	break;
-      default:
-	if (!generic_iv_tbl) break;
-	if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
-	    st_data_t tbl;
+	return;
+    }
+generic:
+#if WITH_OBJC
+    if (generic_iv_dict != NULL) {
+	CFDictionaryRef obj_dict;
 
-	    if (st_lookup(generic_iv_tbl, obj, &tbl)) {
-		st_foreach_safe((st_table *)tbl, func, arg);
-	    }
+	obj_dict = (CFDictionaryRef)CFDictionaryGetValue((CFDictionaryRef)generic_iv_dict, (const void *)obj);
+	if (obj_dict != NULL)
+	    CFDictionaryApplyFunction(obj_dict, (CFDictionaryApplierFunction)func, (void *)arg);
+    }
+#else
+    if (!generic_iv_tbl) break;
+    if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
+	st_data_t tbl;
+
+	if (st_lookup(generic_iv_tbl, obj, &tbl)) {
+	    st_foreach_safe((st_table *)tbl, func, arg);
 	}
-	break;
     }
+#endif
 }
 
 static int

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macruby-changes/attachments/20080524/a7cb16cd/attachment-0001.htm 


More information about the macruby-changes mailing list