Nim icon indicating copy to clipboard operation
Nim copied to clipboard

Asyncdispatch leaks under --mm:arc

Open PhilippMDoerner opened this issue 5 months ago • 0 comments

Description

I opened a nim forum thread about this yesterday. It appears that using async creates a circular data-structure with its futures and that leads to leaks under arc. These become nicely visible when using address sanitizers.

I quote what I learned about this from the thread:

The problem here appears to be a cycle. I don't fully understand that myself, but leorize tried to explain it to me: The asyncCheck callback appears to construct a closure-callback, which holds on to a ref to the future being constructed by stuff(). The callback is then placed into the future itself (?), causing a cycle that arc can no longer deal with.

the worst problem in asyncdispatch is that every async call creates a cyclic reference between the future and the closure environment of the iterator whose body is generated by the async macro

Below a minimal example that demonstrates the problem:

# thefile.nim
import std/asyncdispatch

var count: int

proc stuff() {.async.} =
  echo count, 1
  await sleepAsync(500)
  echo count, 2
  count.inc

for _ in 0..<10:
  asyncCheck stuff()

while hasPendingOperations(): poll()

doAssert count == 10

Compile the above with this command:

nim r --panics:on --define:danger --mm:arc --cc:clang --debugger:native --threads:on -d:butlerThreading -d:chronicles_enabled=off -d:useMalloc --debuginfo:on --linedir:on --passC:'-fno-omit-frame-pointer' --passC:'-mno-omit-leaf-frame-pointer' --passC:"-fsanitize=address" --passL:"-fsanitize=address" thefile.nim

Nim Version

Nim Compiler Version 2.0.2 [Linux: amd64] Compiled at 2023-12-15 Copyright (c) 2006-2023 by Andreas Rumpf

git hash: c4c44d10df8a14204a75c34e499def200589cb7c active boot switches: -d:release

Replicated also on:

Nim Compiler Version 2.1.1 [Linux: amd64] Compiled at 2024-01-14 Copyright (c) 2006-2024 by Andreas Rumpf

git hash: ab4278d2179639f19967431a7aa1be858046f7a7 active boot switches: -d:release

Current Output

=================================================================
==38206==ERROR: LeakSanitizer: detected memory leaks

Indirect leak of 720 byte(s) in 10 object(s) allocated from:
    #0 0x55bb1ac5dcc1 in __interceptor_calloc (/home/philipp/.cache/nim/playground_r/playground_BAE78A16A6FDEA0E7101B2FCA8902C5FEC652390+0x10ecc1) (BuildId: 101922d28e23ebf8139937838107a944a4c1ccfd)
    #1 0x55bb1aca7763 in alloc0Impl__system_u1763 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/mm/malloc.nim:11:11
    #2 0x55bb1aca7763 in allocShared0Impl__system_u1776 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/mm/malloc.nim:37:11
    #3 0x55bb1aca7763 in alignedAlloc0__system_u1941 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/memalloc.nim:351:12
    #4 0x55bb1aca7763 in nimNewObj /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/arc.nim:81:24
    #5 0x55bb1acb2da2 in newFuture__pureZasyncdispatch_u5397 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/pure/asyncfutures.nim:113:70
    #6 0x55bb1acc0472 in stuff__playground_u10 /home/philipp/dev/playground/src/playground.nim:5:23
    #7 0x55bb1acc07b1 in NimMainModule /home/philipp/dev/playground/src/playground.nim:11:172
    #8 0x55bb1acc08f1 in NimMainInner /home/philipp/dev/playground/src/playground.nim:29:2
    #9 0x55bb1acc08f1 in NimMain /home/philipp/dev/playground/src/playground.nim:40:2
    #10 0x55bb1acc08f1 in main /home/philipp/dev/playground/src/playground.nim:48:2
    #11 0x7ff62eb9accf  (/usr/lib/libc.so.6+0x27ccf) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)

Indirect leak of 640 byte(s) in 10 object(s) allocated from:
    #0 0x55bb1ac5dcc1 in __interceptor_calloc (/home/philipp/.cache/nim/playground_r/playground_BAE78A16A6FDEA0E7101B2FCA8902C5FEC652390+0x10ecc1) (BuildId: 101922d28e23ebf8139937838107a944a4c1ccfd)
    #1 0x55bb1aca7763 in alloc0Impl__system_u1763 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/mm/malloc.nim:11:11
    #2 0x55bb1aca7763 in allocShared0Impl__system_u1776 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/mm/malloc.nim:37:11
    #3 0x55bb1aca7763 in alignedAlloc0__system_u1941 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/memalloc.nim:351:12
    #4 0x55bb1aca7763 in nimNewObj /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/arc.nim:81:24
    #5 0x55bb1acc0492 in stuff__playground_u10 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/pure/asyncmacro.nim:293:102
    #6 0x55bb1acc07b1 in NimMainModule /home/philipp/dev/playground/src/playground.nim:11:172
    #7 0x55bb1acc08f1 in NimMainInner /home/philipp/dev/playground/src/playground.nim:29:2
    #8 0x55bb1acc08f1 in NimMain /home/philipp/dev/playground/src/playground.nim:40:2
    #9 0x55bb1acc08f1 in main /home/philipp/dev/playground/src/playground.nim:48:2
    #10 0x7ff62eb9accf  (/usr/lib/libc.so.6+0x27ccf) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)

Indirect leak of 480 byte(s) in 10 object(s) allocated from:
    #0 0x55bb1ac5dcc1 in __interceptor_calloc (/home/philipp/.cache/nim/playground_r/playground_BAE78A16A6FDEA0E7101B2FCA8902C5FEC652390+0x10ecc1) (BuildId: 101922d28e23ebf8139937838107a944a4c1ccfd)
    #1 0x55bb1aca7763 in alloc0Impl__system_u1763 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/mm/malloc.nim:11:11
    #2 0x55bb1aca7763 in allocShared0Impl__system_u1776 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/mm/malloc.nim:37:11
    #3 0x55bb1aca7763 in alignedAlloc0__system_u1941 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/memalloc.nim:351:12
    #4 0x55bb1aca7763 in nimNewObj /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/arc.nim:81:24
    #5 0x55bb1acc0442 in stuff__playground_u10 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/pure/asyncmacro.nim:232:90
    #6 0x55bb1acc07b1 in NimMainModule /home/philipp/dev/playground/src/playground.nim:11:172
    #7 0x55bb1acc08f1 in NimMainInner /home/philipp/dev/playground/src/playground.nim:29:2
    #8 0x55bb1acc08f1 in NimMain /home/philipp/dev/playground/src/playground.nim:40:2
    #9 0x55bb1acc08f1 in main /home/philipp/dev/playground/src/playground.nim:48:2
    #10 0x7ff62eb9accf  (/usr/lib/libc.so.6+0x27ccf) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)

Indirect leak of 144 byte(s) in 2 object(s) allocated from:
    #0 0x55bb1ac5dcc1 in __interceptor_calloc (/home/philipp/.cache/nim/playground_r/playground_BAE78A16A6FDEA0E7101B2FCA8902C5FEC652390+0x10ecc1) (BuildId: 101922d28e23ebf8139937838107a944a4c1ccfd)
    #1 0x55bb1aca7763 in alloc0Impl__system_u1763 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/mm/malloc.nim:11:11
    #2 0x55bb1aca7763 in allocShared0Impl__system_u1776 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/mm/malloc.nim:37:11
    #3 0x55bb1aca7763 in alignedAlloc0__system_u1941 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/memalloc.nim:351:12
    #4 0x55bb1aca7763 in nimNewObj /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/system/arc.nim:81:24
    #5 0x55bb1acb2da2 in newFuture__pureZasyncdispatch_u5397 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/pure/asyncfutures.nim:113:70
    #6 0x55bb1acba14d in sleepAsync__playground_u19 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/pure/asyncdispatch.nim:1922:14
    #7 0x55bb1acbf73f in stuffX20X28AsyncX29___playground_u4 /home/philipp/dev/playground/src/playground.nim:7:29
    #8 0x55bb1acbfc95 in stuffNimAsyncContinue__playground_u6 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/pure/asyncmacro.nim:33:53
    #9 0x55bb1acc058f in stuff__playground_u10 /home/philipp/.choosenim/toolchains/nim-2.0.2/lib/pure/asyncmacro.nim:293:155
    #10 0x55bb1acc07b1 in NimMainModule /home/philipp/dev/playground/src/playground.nim:11:172
    #11 0x55bb1acc08f1 in NimMainInner /home/philipp/dev/playground/src/playground.nim:29:2
    #12 0x55bb1acc08f1 in NimMain /home/philipp/dev/playground/src/playground.nim:40:2
    #13 0x55bb1acc08f1 in main /home/philipp/dev/playground/src/playground.nim:48:2
    #14 0x7ff62eb9accf  (/usr/lib/libc.so.6+0x27ccf) (BuildId: 8bfe03f6bf9b6a6e2591babd0bbc266837d8f658)

SUMMARY: AddressSanitizer: 1984 byte(s) leaked in 32 allocation(s).

Expected Output

No stacktraces

Possible Solution

No response

Additional Information

No response

PhilippMDoerner avatar Jan 15 '24 19:01 PhilippMDoerner