-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Closed
Labels
Description
Test case
type
SPInner[T] = tuple[atomicCounter: int, value: T]
SharedPtr[T] = object
val: ptr SPInner[T]
proc `=destroy`*[T](p: var SharedPtr[T]) =
mixin `=destroy`
debugecho "=destroy SharedPtr[", $type(T), "]"
if p.val != nil:
let c = atomicDec(p.val.atomicCounter)
if c == 0:
`=destroy`(p.val.value)
deallocshared(p.val)
p.val = nil
proc `=`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) {.inline.} =
if dest.val != nil:
`=destroy`(dest)
if src.val != nil:
discard atomicInc(src.val[].atomicCounter)
dest.val = src.val
proc `=sink`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) {.inline.} =
if dest.val != nil:
`=destroy`(dest)
dest.val = src.val
proc newSharedPtr*[T](val: sink T): SharedPtr[T] =
result.val = cast[ptr SPInner[T]]( allocShared0( sizeof(SPInner[T]) ) )
result.val.atomicCounter = 1
result.val.value = val
func `$`*[T](p: SharedPtr[T]): string =
mixin `$`
if p.val == nil: "nil"
else: "SharedPtr(" & $p.val.value & ")"
#------------------------------------------------------------
#------------------------------------------------------------
#------------------------------------------------------------
type
TopObject = object
internal: SharedPtr[int]
proc deleteTop(p: ptr TopObject) =
if p != nil:
`=destroy`(p[]) # !!! this operation leak the integer
deallocshared(p)
proc createTop(): ptr TopObject =
result = cast[ptr TopObject](allocShared0(sizeof(TopObject)))
result.internal = newSharedPtr(1)
#------------------------------------------------------------
#------------------------------------------------------------
#------------------------------------------------------------
proc main() = # little tester code
let x = createTop()
echo $x.internal
deleteTop(x)
echo "app begin"
main()
echo "app end"The test case expected output is
app begin
SharedPtr(1)
=destroy SharedPtr[int]
app end
But actual output is:
app begin
SharedPtr(1)
app end
After a bit of analysis I can say what is going on. createTypeBoundOps for object type TopObject is not invoked early enough hence destructor is not generated while line =destroy(p[]) needs it. Generated destructor needs to be a candidate in overloaded call resolution but it doesn't exist yet.
Clearly invoking createTypeBoundOps in sempass2 is too late, destructor needs to be generated before semOverloadedCallAnalyseEffects for explicit =destroy call in sempass.