Skip to content

Commit e866d95

Browse files
committed
Prism: Close the open file once finished reading
1 parent 4009b71 commit e866d95

File tree

2 files changed

+45
-7
lines changed

2 files changed

+45
-7
lines changed

prism_compile.c

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11458,6 +11458,37 @@ pm_parse_file_script_lines(const pm_scope_node_t *scope_node, const pm_parser_t
1145811458
return lines;
1145911459
}
1146011460

11461+
struct load_from_fd_args {
11462+
VALUE path;
11463+
VALUE io;
11464+
int open_mode;
11465+
int fd;
11466+
};
11467+
11468+
static VALUE
11469+
close_file(VALUE args)
11470+
{
11471+
struct load_from_fd_args *arg = (void *)args;
11472+
if (arg->fd != -1) {
11473+
close(arg->fd);
11474+
}
11475+
else if (!NIL_P(arg->io)) {
11476+
rb_io_close(arg->io);
11477+
}
11478+
return Qnil;
11479+
}
11480+
11481+
static VALUE
11482+
load_content(VALUE args)
11483+
{
11484+
struct load_from_fd_args *arg = (void *)args;
11485+
VALUE io = rb_io_fdopen(arg->fd, arg->open_mode, RSTRING_PTR(arg->path));
11486+
arg->io = io;
11487+
arg->fd = -1;
11488+
rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
11489+
return rb_funcall(io, rb_intern("read"), 0);
11490+
}
11491+
1146111492
/**
1146211493
* Attempt to load the file into memory. Return a Ruby error if the file cannot
1146311494
* be read.
@@ -11478,13 +11509,14 @@ pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error)
1147811509
// For non-regular files (pipes, character devices), we need to read
1147911510
// through Ruby IO to properly release the GVL while waiting for data.
1148011511
if (init_result == PM_SOURCE_INIT_ERROR_NON_REGULAR) {
11481-
const int open_mode = O_RDONLY | O_NONBLOCK;
11482-
int fd = open(RSTRING_PTR(filepath), open_mode);
11483-
if (fd == -1) goto error_generic;
11484-
11485-
VALUE io = rb_io_fdopen(fd, open_mode, RSTRING_PTR(filepath));
11486-
rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
11487-
VALUE contents = rb_funcall(io, rb_intern("read"), 0);
11512+
struct load_from_fd_args args = {
11513+
.path = filepath,
11514+
.open_mode = O_RDONLY | O_NONBLOCK,
11515+
.fd = rb_cloexec_open(RSTRING_PTR(filepath), args.open_mode, 0),
11516+
.io = Qnil,
11517+
};
11518+
if (args.fd == -1) goto error_generic;
11519+
VALUE contents = rb_ensure(load_content, (VALUE)&args, close_file, (VALUE)&args);
1148811520

1148911521
if (!RB_TYPE_P(contents, T_STRING)) goto error_generic;
1149011522

test/ruby/test_compile_prism.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2721,6 +2721,12 @@ def test_parse_file
27212721
assert_raise TypeError do
27222722
RubyVM::InstructionSequence.compile_file_prism(nil)
27232723
end
2724+
2725+
assert_nothing_raised(Errno::EMFILE, Errno::ENFILE) do
2726+
10000.times do
2727+
RubyVM::InstructionSequence.compile_file_prism(File::NULL)
2728+
end
2729+
end
27242730
end
27252731

27262732
private

0 commit comments

Comments
 (0)