Skip to content

Memory leak in tryRecv #91

Open
Open

Description

@arnetheduck
var m: string
for i in 0..100:
  c.send("test")
  discard c.tryRecv(m)

the above example will leak ~100 string instances because m is not destroyed before being overwritten with a new value:

proc tryRecv*[T](c: Chan[T], dst: var T): bool {.inline.} =
  channelReceive(c.d, dst.addr, sizeof(T), false)

Here we can see that the channel just blindly overwrites dst.

Some of the the options (all pretty unattractive):

  • destroy dst inside the channel, iff there is an item - makes channelReceive generic, runs the destructor inside the lock
  • use a temporary: var tmp: T; if channelReceive(..., addr tmp, ...): dst = move(tmp) - defeats the efficiency gains of using this somewhat quirky API
  • =destroy and =wasMoved the item unconditionally - inefficient when channel is empty, weird post-condition for the function in general - post-state is undefined because =wasMoved itself is not well-defined for this purpose
  • change the api back to tryRecv(...): tuple[bool, T] - ugly api because T is default-inited on every loop, even when empty - also inefficient because it's zeroed twice and then gets a value and typically needs to be moved/copied out of the tuple
  • change the api to Option[T] or Result[T, EmptyOrClosed] - clean api, doesn't init T on empty in theory - practically however, a lot of zeroing again, needs a copy to extract T from Option/Result, same as above but now there's a union involved - emptyorclosed because Split channel into sender/receiver #88 has "all senders gone" support

Of all of these, perhaps the last one is the best to start with - it's semantically unambiguous at least.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions