Index: TODO =================================================================== diff -u -r90109eff5d9639f5385296e58ba9f78ffb9cecf3 -rb876f2df8715159b566727e3c240b5bcca7bacab --- TODO (.../TODO) (revision 90109eff5d9639f5385296e58ba9f78ffb9cecf3) +++ TODO (.../TODO) (revision b876f2df8715159b566727e3c240b5bcca7bacab) @@ -2254,6 +2254,11 @@ - added regression test - removed NSF_INFO +- fixed potential access to freed memory (actually when checking if + namespace was removed by Tcl); found this problem when compiling Tcl + with SYSTEM_MALLOC (own modified version of tclThreadAlloc.c) +- fixed memory leak (namespace names and structures) + TODO: - object parameter type forward: Index: generic/nsf.c =================================================================== diff -u -rbc86c5d5cba70c6f5db2b184c143a7dde00cca4c -rb876f2df8715159b566727e3c240b5bcca7bacab --- generic/nsf.c (.../nsf.c) (revision bc86c5d5cba70c6f5db2b184c143a7dde00cca4c) +++ generic/nsf.c (.../nsf.c) (revision b876f2df8715159b566727e3c240b5bcca7bacab) @@ -224,6 +224,8 @@ static Tcl_Namespace *NSGetFreshNamespace(Tcl_Interp *interp, ClientData clientData, CONST char *name); static Tcl_Namespace *RequireObjNamespace(Tcl_Interp *interp, NsfObject *object); +static void NSNamespacePreserve(Tcl_Namespace *nsPtr); +static void NSNamespaceRelease(Tcl_Namespace *nsPtr); /* prototypes for filters and mixins */ static void FilterComputeDefined(Tcl_Interp *interp, NsfObject *object); @@ -3160,7 +3162,55 @@ /* * Namespace related commands */ +/* + *---------------------------------------------------------------------- + * NSNamespacePreserve -- + * + * Increment namespace refcount + * + * Results: + * void + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static void +NSNamespacePreserve(Tcl_Namespace *nsPtr) { + Tcl_Namespace_refCount(nsPtr)++; +} +/* + *---------------------------------------------------------------------- + * NSNamespaceRelease -- + * + * Decrement namespace refcount and free namespace if necessary + * + * Results: + * void + * + * Side effects: + * Free pot. memory + * + *---------------------------------------------------------------------- + */ +static void +NSNamespaceRelease(Tcl_Namespace *nsPtr) { + Tcl_Namespace_refCount(nsPtr)--; + if (Tcl_Namespace_refCount(nsPtr) == 0 && (Tcl_Namespace_flags(nsPtr) & NS_DEAD)) { + /* + * The namespace refcount has reached 0, we have to free + * it. unfortunately, NamespaceFree() is not exported + */ + /* fprintf(stderr, "HAVE TO FREE %p\n", nsPtr); */ + /*NamespaceFree(nsPtr);*/ + ckfree(nsPtr->fullName); + ckfree(nsPtr->name); + ckfree((char*)nsPtr); + } +} + /* *---------------------------------------------------------------------- * NSDeleteCmd -- @@ -9347,7 +9397,7 @@ fprintf(stderr, "... procName %s paramDefs %p\n", ObjStr(tcd->procName), tcd->paramDefs);*/ DECR_REF_COUNT(tcd->procName); - /* ParamDefsFree(tcd->paramDefs); */ /* seems not neccessary */ + /* tcd->paramDefs is freed by NsfProcDeleteProc() */ FREE(NsfProcClientData, tcd); } @@ -9503,7 +9553,7 @@ * Tcl return code. * * Side effects: - * Adding 1 Tcl and 1 Tcl proc + * Adding one Tcl command and one Tcl proc * *---------------------------------------------------------------------- */ @@ -10867,6 +10917,9 @@ * different object system). */ + //fprintf(stderr, "nsPtr %p\n", nsPtr); + //fprintf(stderr, "nsPtr->flags %.6x\n", nsPtr ? (((Namespace *)nsPtr)->flags) : 0); + if (nsPtr && (((Namespace *)nsPtr)->flags & NS_DYING)) { Tcl_Namespace *dummy1Ptr, *dummy2Ptr; const char *dummy; @@ -10916,13 +10969,20 @@ assert(isAbsolutePath(nameString)); nsPtr = NSCheckNamespace(interp, nameString, parentNsPtr, cl); + if (nsPtr) { + NSNamespacePreserve(nsPtr); + } object->id = Tcl_CreateObjCommand(interp, nameString, NsfObjDispatch, (ClientData)object, TclDeletesObject); /*fprintf(stderr, "cmd alloc %p %d (%s)\n", object->id, Tcl_Command_refCount(object->id), nameString);*/ PrimitiveOInit(object, interp, nameString, nsPtr, cl); + if (nsPtr) { + NSNamespaceRelease(nsPtr); + } + object->cmdName = nameObj; /* convert cmdName to Tcl Obj of type cmdName */ /*Tcl_GetCommandFromObj(interp, obj->cmdName);*/ @@ -11321,9 +11381,15 @@ fprintf(stderr, "Class alloc %p '%s'\n", cl, nameString); */ nsPtr = NSCheckNamespace(interp, nameString, parentNsPtr, cl); + if (nsPtr) { + NSNamespacePreserve(nsPtr); + } object->id = Tcl_CreateObjCommand(interp, nameString, NsfObjDispatch, - (ClientData)cl, TclDeletesObject); + (ClientData)cl, TclDeletesObject); PrimitiveOInit(object, interp, nameString, nsPtr, class); + if (nsPtr) { + NSNamespaceRelease(nsPtr); + } object->cmdName = nameObj; /* convert cmdName to Tcl Obj of type cmdName */ Index: generic/nsfAccessInt.h =================================================================== diff -u -r9be296c7be8b0c04eaedd9f96c36d626aa7c2c97 -rb876f2df8715159b566727e3c240b5bcca7bacab --- generic/nsfAccessInt.h (.../nsfAccessInt.h) (revision 9be296c7be8b0c04eaedd9f96c36d626aa7c2c97) +++ generic/nsfAccessInt.h (.../nsfAccessInt.h) (revision b876f2df8715159b566727e3c240b5bcca7bacab) @@ -27,6 +27,8 @@ #define Tcl_Namespace_parentPtr(nsPtr) ((Namespace *)nsPtr)->parentPtr #define Tcl_Namespace_commandPathLength(nsPtr) ((Namespace *)nsPtr)->commandPathLength #define Tcl_Namespace_commandPathArray(nsPtr) ((Namespace *)nsPtr)->commandPathArray +#define Tcl_Namespace_refCount(nsPtr) ((Namespace *)nsPtr)->refCount +#define Tcl_Namespace_flags(nsPtr) ((Namespace *)nsPtr)->flags #define Tcl_Command_refCount(cmd) ((Command *)cmd)->refCount Index: generic/nsfStack.c =================================================================== diff -u -red4062dcf28f3ea391fa629ad79a55ec8fc10a04 -rb876f2df8715159b566727e3c240b5bcca7bacab --- generic/nsfStack.c (.../nsfStack.c) (revision ed4062dcf28f3ea391fa629ad79a55ec8fc10a04) +++ generic/nsfStack.c (.../nsfStack.c) (revision b876f2df8715159b566727e3c240b5bcca7bacab) @@ -868,8 +868,10 @@ nsPtr, nsPtr->fullName, nsPtr->refCount, cl->object.nsPtr,cl->object.nsPtr ? ((Namespace*)cl->object.nsPtr)->parentPtr : NULL);*/ - /* incremement the namespace ptr in case tcl tries to delete this namespace - during the invocation */ + /* + * Incremement the namespace ptr in case Tcl tries to delete + * this namespace during the invocation + */ nsPtr->refCount ++; } @@ -984,22 +986,8 @@ fprintf(stderr,"checkFree %p %s\n",object, ObjectName(object)); } #endif - // TODO do we have a leak now? - if (0 && nsPtr) { - nsPtr->refCount--; - /*fprintf(stderr, "CscFinish parent %s activationCount %d flags %.4x refCount %d\n", - nsPtr->fullName, nsPtr->activationCount, nsPtr->flags, nsPtr->refCount);*/ - - if ((nsPtr->refCount == 0) && (nsPtr->flags & NS_DEAD)) { - /* the namespace refcount has reached 0, we have to free - it. unfortunately, NamespaceFree() is not exported */ - /* TODO: remove me finally */ - fprintf(stderr, "HAVE TO FREE %p\n",nsPtr); - /*NamespaceFree(nsPtr);*/ - ckfree(nsPtr->fullName); - ckfree(nsPtr->name); - ckfree((char*)nsPtr); - } + if (nsPtr) { + NSNamespaceRelease(nsPtr); } } } Index: tests/object-system.test =================================================================== diff -u -rfc4e3f5f6a94ef7324baffab90d58cd7eb513907 -rb876f2df8715159b566727e3c240b5bcca7bacab --- tests/object-system.test (.../object-system.test) (revision fc4e3f5f6a94ef7324baffab90d58cd7eb513907) +++ tests/object-system.test (.../object-system.test) (revision b876f2df8715159b566727e3c240b5bcca7bacab) @@ -120,9 +120,14 @@ #? {X::slot info vars} __parameter ? {X info attributes} {{x 1} {y 2}} +# actually, we want c1 to test below the recreation of c1 in another +# object system +? {C create c1} ::c1 +? {C create c2 {:method foo {} {;}}} ::c2 + # # tests for the dispatch command - +# Object create o o method foo {} {return goo} o method bar {x} {return goo-$x} @@ -196,12 +201,16 @@ ? {::nsf::is metaclass ::c1} 0 ? {::nsf::relation ::c1 class} ::C -# destroy instance and class +# destroy instance c1 - ? {::nsf::isobject ::c1} 0 ? {::nsf::is class ::C} 1 +# recreate an nx object with a namespace +C + c2 + +# destroy class C - ? {::nsf::isobject ::C} 0