diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2013-09-09 14:12:05 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2013-09-09 14:12:05 (GMT) |
commit | ba7223881b8ae57b0edb93eae8dd280190dfd78e (patch) | |
tree | b5636b91856852a868140af8910b834288bcd06b | |
parent | 991ddbd26c7c24de6598ff9fe61a1d9f13186548 (diff) | |
parent | 6652de82ba5502a042b2be29a5cf7e04b73fca4b (diff) | |
download | tcl-ba7223881b8ae57b0edb93eae8dd280190dfd78e.zip tcl-ba7223881b8ae57b0edb93eae8dd280190dfd78e.tar.gz tcl-ba7223881b8ae57b0edb93eae8dd280190dfd78e.tar.bz2 |
[3609693] Must strip the internal representation of procedure-like methods in
order to ensure that any bound references to instance variables are removed.
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | generic/tclOOMethod.c | 50 | ||||
-rw-r--r-- | tests/oo.test | 30 |
3 files changed, 84 insertions, 2 deletions
@@ -1,3 +1,9 @@ +2013-09-09 Donal Fellows <dkf@users.sf.net> + + * generic/tclOOMethod.c (CloneProcedureMethod): [Bug 3609693]: Strip + the internal representation of method bodies during cloning in order + to ensure that any bound references to instance variables are removed. + 2013-09-01 Donal Fellows <dkf@users.sf.net> * generic/tclBinary.c (BinaryDecodeHex): [Bug b98fa55285]: Ensure that diff --git a/generic/tclOOMethod.c b/generic/tclOOMethod.c index 81293c7..61215de 100644 --- a/generic/tclOOMethod.c +++ b/generic/tclOOMethod.c @@ -1290,11 +1290,57 @@ CloneProcedureMethod( ClientData *newClientData) { ProcedureMethod *pmPtr = clientData; - ProcedureMethod *pm2Ptr = ckalloc(sizeof(ProcedureMethod)); + ProcedureMethod *pm2Ptr; + Tcl_Obj *bodyObj, *argsObj; + CompiledLocal *localPtr; + /* + * Copy the argument list. + */ + + argsObj = Tcl_NewObj(); + for (localPtr=pmPtr->procPtr->firstLocalPtr; localPtr!=NULL; + localPtr=localPtr->nextPtr) { + if (TclIsVarArgument(localPtr)) { + Tcl_Obj *argObj = Tcl_NewObj(); + + Tcl_ListObjAppendElement(NULL, argObj, + Tcl_NewStringObj(localPtr->name, -1)); + if (localPtr->defValuePtr != NULL) { + Tcl_ListObjAppendElement(NULL, argObj, localPtr->defValuePtr); + } + Tcl_ListObjAppendElement(NULL, argsObj, argObj); + } + } + + /* + * Must strip the internal representation in order to ensure that any + * bound references to instance variables are removed. [Bug 3609693] + */ + + bodyObj = Tcl_DuplicateObj(pmPtr->procPtr->bodyPtr); + TclFreeIntRep(bodyObj); + + /* + * Create the actual copy of the method record, manufacturing a new proc + * record. + */ + + pm2Ptr = ckalloc(sizeof(ProcedureMethod)); memcpy(pm2Ptr, pmPtr, sizeof(ProcedureMethod)); pm2Ptr->refCount = 1; - pm2Ptr->procPtr->refCount++; + Tcl_IncrRefCount(argsObj); + Tcl_IncrRefCount(bodyObj); + if (TclCreateProc(interp, NULL, "", argsObj, bodyObj, + &pm2Ptr->procPtr) != TCL_OK) { + Tcl_DecrRefCount(argsObj); + Tcl_DecrRefCount(bodyObj); + ckfree(pm2Ptr); + return TCL_ERROR; + } + Tcl_DecrRefCount(argsObj); + Tcl_DecrRefCount(bodyObj); + if (pmPtr->cloneClientdataProc) { pm2Ptr->clientData = pmPtr->cloneClientdataProc(pmPtr->clientData); } diff --git a/tests/oo.test b/tests/oo.test index e0e0791..054bc46 100644 --- a/tests/oo.test +++ b/tests/oo.test @@ -1839,6 +1839,36 @@ test oo-15.9 {ensemble rewriting must not bleed through oo::copy} -setup { } -returnCodes error -cleanup { Foo destroy } -result {wrong # args: should be "::bar <cloned> a b"} +test oo-15.10 {variable binding must not bleed through oo::copy} -setup { + oo::class create FooClass + set result {} +} -body { + set obj1 [FooClass new] + oo::objdefine $obj1 { + variable var + method m {} { + set var foo + } + method get {} { + return $var + } + export eval + } + + $obj1 m + lappend result [$obj1 get] + set obj2 [oo::copy $obj1] + $obj2 eval { + set var bar + } + lappend result [$obj2 get] + $obj1 eval { + set var grill + } + lappend result [$obj1 get] [$obj2 get] +} -cleanup { + FooClass destroy +} -result {foo bar grill bar} test oo-16.1 {OO: object introspection} -body { info object |