nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).

Home Page:https://nim-lang.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ensureMove usage leading to memory leak for JsonNode !

eagledot opened this issue · comments

Description

I was using ensureMove with custom objects to make sure compiler is doing what i expect.
I accidentally used ensureMove with a JsonNode (with kind JObject), later i pinned memory leak to usage of ensureMove .

I am not sure if i am supposed to use ensureMove anywhere , but compiler didn't give me any warning.

Following minimal code reproduces the issue for me .

# happens both with ARC and ORC mm
import std/json
proc test_something():JsonNode=

    var final_result = JsonNode(kind:JObject)
    var a = JsonNode(kind:JArray)
    for i in 0..<10000:
        a.add(JsonNode(kind:JString, str:"random string"))
    final_result["key"] = ensureMove a
    # final_result["key"] = a

    return final_result

var temp:JsonNode
for i in 0..<100000:
    temp = test_something()

Nim Version

Nim Compiler Version 2.2.0 [Windows: amd64]
Compiled at 2024-10-02
Copyright (c) 2006-2024 by Andreas Rumpf

active boot switches: -d:release

Current Output

No response

Expected Output

I think it is not supposed to do memory leak or i don't know if `ensureMove` is supposed to be used for custom objects only!

Known Workarounds

No response

Additional Information

No response

This is a bug, but JsonNode is a ref object so there is very little point in using ensureMove. Seems for refs ensureMove extends the lifetime of references and they never get collected.

yeah i thought so, i.e not using ensureMove with references , but wanted to document it just in case here.
BTW, if i use JArray kind, it doesn't leak the memory ! Does ensureMove always leak memory for every ref object?

ensureMove should be a noop for references but it accidentally does something for some reference tree.

Reduced:

type
  JsonNode = ref object

proc foo(d: JsonNode) =
  discard

proc test_something()=
  var a = JsonNode()
  foo(ensureMove(a))

test_something()