Fix possible memory leaks, which occurs when constructor components throw errors.
gfx [Sat, 12 Jun 2010 03:58:49 +0000 (12:58 +0900)]
xs-src/Mouse.xs
xs-src/MouseAccessor.xs

index 8033635..19d98c6 100644 (file)
@@ -571,26 +571,28 @@ PPCODE:
     }
 }
 
-SV*
+void
 new_object(SV* meta, ...)
 CODE:
 {
     AV* const xc   = mouse_get_xc(aTHX_ meta);
     HV* const args = mouse_buildargs(aTHX_ meta, NULL, ax, items);
+    SV* object;
 
-    RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc));
-    mouse_class_initialize_object(aTHX_ meta, RETVAL, args, FALSE);
-    mouse_buildall(aTHX_ xc, RETVAL, sv_2mortal(newRV_inc((SV*)args))); /* BUILDALL */
+    object = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc));
+    mouse_class_initialize_object(aTHX_ meta, object, args, FALSE);
+    mouse_buildall(aTHX_ xc, object, sv_2mortal(newRV_inc((SV*)args))); /* BUILDALL */
+    ST(0) = object; /* because object is mortal, we should return it as is */
+    XSRETURN(1);
 }
-OUTPUT:
-    RETVAL
 
-SV*
+void
 clone_object(SV* meta, SV* object, ...)
 CODE:
 {
     AV* const xc   = mouse_get_xc(aTHX_ meta);
     HV* const args = mouse_buildargs(aTHX_ meta, NULL, ax + 1, items - 1);
+    SV* proto;
 
     if(!mouse_is_an_instance_of(aTHX_ MOUSE_xc_stash(xc), object)) {
         mouse_throw_error(meta, object,
@@ -598,12 +600,11 @@ CODE:
             mcall0(meta, mouse_name), object);
     }
 
-    RETVAL = mouse_instance_clone(aTHX_ object);
-    mouse_class_initialize_object(aTHX_ meta, RETVAL, args, TRUE);
+    proto = mouse_instance_clone(aTHX_ object);
+    mouse_class_initialize_object(aTHX_ meta, proto, args, TRUE);
+    ST(0) = proto; /* because object is mortal, we should return it as is */
+    XSRETURN(1);
 }
-OUTPUT:
-    RETVAL
-
 
 void
 _initialize_object(SV* meta, SV* object, HV* args, bool is_cloning = FALSE)
@@ -655,7 +656,7 @@ PPCODE:
 
 MODULE = Mouse  PACKAGE = Mouse::Object
 
-SV*
+void
 new(SV* klass, ...)
 CODE:
 {
@@ -663,6 +664,7 @@ CODE:
     AV* const xc   = mouse_get_xc(aTHX_ meta);
     UV const flags = MOUSE_xc_flags(xc);
     SV* args;
+    SV* object;
 
     /* BUILDARGS */
     if(flags & MOUSEf_XC_HAS_BUILDARGS){
@@ -692,12 +694,12 @@ CODE:
     }
 
     /* new_object */
-    RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc));
-    mouse_class_initialize_object(aTHX_ meta, RETVAL, (HV*)SvRV(args), FALSE);
-    mouse_buildall(aTHX_ xc, RETVAL, args); /* BUILDALL */
+    object = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc));
+    mouse_class_initialize_object(aTHX_ meta, object, (HV*)SvRV(args), FALSE);
+    mouse_buildall(aTHX_ xc, object, args); /* BUILDALL */
+    ST(0) = object; /* because object is mortal, we should return it as is */
+    XSRETURN(1);
 }
-OUTPUT:
-    RETVAL
 
 void
 DESTROY(SV* object)
index 7fc55b6..1dad5e6 100644 (file)
@@ -1,6 +1,7 @@
 #include "mouse.h"
 
 #define CHECK_INSTANCE(instance) STMT_START{                           \
+        assert(instance);                                              \
         if(!(SvROK(instance) && SvTYPE(SvRV(instance)) == SVt_PVHV)){  \
             croak("Invalid object instance: '%"SVf"'", instance);      \
         }                                                              \
@@ -331,24 +332,26 @@ XS(XS_Mouse_simple_predicate)
 
 SV*
 mouse_instance_create(pTHX_ HV* const stash) {
+    SV* instance;
     assert(stash);
     assert(SvTYPE(stash) == SVt_PVHV);
-    return sv_bless( newRV_noinc((SV*)newHV()), stash );
+    instance = sv_bless( newRV_noinc((SV*)newHV()), stash );
+    return sv_2mortal(instance);
 }
 
 SV*
 mouse_instance_clone(pTHX_ SV* const instance) {
-    HV* proto;
-    assert(instance);
-
+    SV* proto;
     CHECK_INSTANCE(instance);
-    proto = newHVhv((HV*)SvRV(instance));
-    return sv_bless( newRV_noinc((SV*)proto), SvSTASH(SvRV(instance)) );
+    assert(SvOBJECT(SvRV(instance)));
+
+    proto = newRV_noinc((SV*)newHVhv((HV*)SvRV(instance)));
+    sv_bless(proto, SvSTASH(SvRV(instance)));
+    return sv_2mortal(proto);
 }
 
 bool
 mouse_instance_has_slot(pTHX_ SV* const instance, SV* const slot) {
-    assert(instance);
     assert(slot);
     CHECK_INSTANCE(instance);
     return hv_exists_ent((HV*)SvRV(instance), slot, 0U);
@@ -357,7 +360,6 @@ mouse_instance_has_slot(pTHX_ SV* const instance, SV* const slot) {
 SV*
 mouse_instance_get_slot(pTHX_ SV* const instance, SV* const slot) {
     HE* he;
-    assert(instance);
     assert(slot);
     CHECK_INSTANCE(instance);
     he = hv_fetch_ent((HV*)SvRV(instance), slot, FALSE, 0U);
@@ -368,7 +370,6 @@ SV*
 mouse_instance_set_slot(pTHX_ SV* const instance, SV* const slot, SV* const value) {
     HE* he;
     SV* sv;
-    assert(instance);
     assert(slot);
     assert(value);
     CHECK_INSTANCE(instance);
@@ -390,7 +391,6 @@ mouse_instance_delete_slot(pTHX_ SV* const instance, SV* const slot) {
 void
 mouse_instance_weaken_slot(pTHX_ SV* const instance, SV* const slot) {
     HE* he;
-    assert(instance);
     assert(slot);
     CHECK_INSTANCE(instance);
     he = hv_fetch_ent((HV*)SvRV(instance), slot, FALSE, 0U);