luvit/luv

fs_scandir iterator causes memory leak with early break

gpanders opened this issue · 2 comments

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:

luv/src/fs.c

Lines 600 to 605 in c51e705

if (ret == UV_EOF) {
luv_cleanup_req(L, (luv_req_t*)req->data);
req->data = NULL;
uv_fs_req_cleanup(req);
return 0;
}

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.

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

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.