luvit / luv

Bare libuv bindings for lua
Apache License 2.0
822 stars 185 forks source link

fs_scandir iterator causes memory leak with early break #600

Closed gpanders closed 2 years ago

gpanders commented 2 years ago

Using fs_scandir and fs_scandir_next as an iterator results in a memory leak if the iterator is not fully drained. Example:

local luv = require 'luv'

local function dir(d)
  return function(fs)
    return luv.fs_scandir_next(fs)
  end, luv.fs_scandir(d)
end

for name in dir('.') do
  print(name)
  break
end

This results in a memory leak. This happens because the uv_fs_req is only cleaned up when the iterator reaches a UV_EOF:

https://github.com/luvit/luv/blob/c51e7052ec4f0a25058f70c1b4ee99dd36180e59/src/fs.c#L600-L605

However, when the iteration loop breaks early this condition is never hit and uv_fs_req_cleanup is never called.

It does not seem possible to manually cleanup the fs handles either: fs:close() does not exist.

squeek502 commented 2 years ago

Thanks for the report, I'll look into it.

squeek502 commented 2 years ago

Here's an even simpler reproduction:

local uv = require('luv')
local req = uv.fs_scandir('.')

As pointed out in the OP, we currently only handle cleanup when we fully iterate with scandir_next.