Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object destructor not called when reassigning after a try-except block. #24103

Open
darkestpigeon opened this issue Sep 13, 2024 · 2 comments
Open

Comments

@darkestpigeon
Copy link

darkestpigeon commented Sep 13, 2024

Description

Object destructor not called when reassigning after a try-except block.

Minimal example:

import std/os


type MyObj = object
  data: pointer
  size: int

proc initMyObj(size: int): MyObj =
  assert size > 0
  result.data = allocShared0(size)
  result.size = size
  
  # imitate work
  let p = cast[ptr UncheckedArray[uint8]](result.data)
  for i in 0..<size:
    p[i] = i.uint8

proc `=destroy`(x: MyObj) =
  if not x.data.isNil:
    deallocShared(x.data)

proc `=wasMoved`(x: var MyObj) =
  x.data = nil
  x.size = 0

proc `=copy`(x: var MyObj, y: MyObj) {.error.}


proc main() =
  while true:
    var obj: MyObj
    try:
      obj = initMyObj(10_000_000)
    except:
    # except FloatOverflowError: also causes a leak, although it is never raised
      break

    # discard obj

    obj = MyObj()
    sleep(20)

    echo getOccupiedMem()


main()

Uncommenting the discard obj line removes the issue.

Nim Version

Both on

Nim Compiler Version 2.0.8 [Linux: amd64]
Compiled at 2024-07-03
Copyright (c) 2006-2023 by Andreas Rumpf

git hash: 5935c3bfa9fec6505394867b23510eb5cbab3dbf
active boot switches: -d:release

and

Nim Compiler Version 2.1.99 [Linux: amd64]
Compiled at 2024-09-12
Copyright (c) 2006-2024 by Andreas Rumpf

git hash: 793cee4de1934fd1f6271cf5fed46f01c5abb19b
active boot switches: -d:release

Current Output

10223616                                                                                  
20447232                                                                                  
30670848                                     
40894464                                                                                  
51118080                                                                                                                                                                            
61341696                                                                                  
71565312                                                                                                                                                                            
81788928                                     
92012544                                     
102236160                                                                                                                                                                           
112459776                                                                                 
122683392                                                                                                                                                                           
132907008                                                                                                                                                                           
143130624                                                                                                                                                                           
153354240
...

Expected Output

0                                            
0                                            
0                                                                                                                                                                                   
0                                                                                         
0                                                                                                                                                                                   
0                                                                                                                                                                                   
0                                                                                                                                                                                   
0                                                                                                                                                                                   
0                                                                                         
0                                                                                         
0                                                                                         
0                                                                                         
0                                                                                         
0                                                                                         
0                                                                                         
0    
...

Known Workarounds

In the example above, uncommenting the discard obj line removes the issue.

Additional Information

No response

@darkestpigeon darkestpigeon changed the title Think about the title, twice. Object destructor not called when reassigning after a try-except block. Sep 13, 2024
@forchid
Copy link

forchid commented Sep 25, 2024

It's also ok if access obj before try:, such as,

The test source

import std/os


type MyObj = object
  data: pointer
  size: int

proc initMyObj(size: int): MyObj =
  assert size > 0
  result.data = allocShared0(size)
  result.size = size
  
  # imitate work
  let p = cast[ptr UncheckedArray[uint8]](result.data)
  for i in 0..<size:
    p[i] = i.uint8

proc `=destroy`(x: MyObj) =
  if not x.data.isNil:
    deallocShared(x.data)

proc `=wasMoved`(x: var MyObj) =
  x.data = nil
  x.size = 0

proc `=copy`(x: var MyObj, y: MyObj) {.error.}


proc main() =
  while true:
    var obj: MyObj
    discard obj
    try:
      obj = initMyObj(10_000_000)
    except:
    # except FloatOverflowError: also causes a leak, although it is never raised
      break

    # discard obj

    obj = MyObj()
    sleep(20)

    echo getOccupiedMem()


main()

The test result

>except
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0

@forchid
Copy link

forchid commented Sep 25, 2024

@darkestpigeon I find that this problem doesn't exist in nim-1.6.20 with --mm:orc or --mm:orc, but memory leak 48 bytes
with --mm:refc.

Test test source

import std/os


type MyObj = object
  data: pointer
  size: int

proc initMyObj(size: int): MyObj =
  assert size > 0
  result.data = allocShared0(size)
  result.size = size
  
  # imitate work
  let p = cast[ptr UncheckedArray[uint8]](result.data)
  for i in 0..<size:
    p[i] = i.uint8

proc `=destroy`(x: var MyObj) = # Using `var` in nim-1.6.20
  if not x.data.isNil:
    deallocShared(x.data)

proc `=wasMoved`(x: var MyObj) =
  x.data = nil
  x.size = 0

proc `=copy`(x: var MyObj, y: MyObj) {.error.}


proc main() =
  while true:
    var obj: MyObj
    try:
      obj = initMyObj(10_000_000)
    except:
    # except FloatOverflowError: also causes a leak, although it is never raised
      break

    # discard obj

    obj = MyObj()
    sleep(20)

    echo getOccupiedMem()


main()

The test resul

>except
0
0
0
0
0
0
0
0
0
0
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants