Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Correctly release the underlying file mapping. #9340

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/ruby/io/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ enum rb_io_buffer_flags {

// The buffer is read-only and cannot be modified.
RB_IO_BUFFER_READONLY = 128,

// The buffer is backed by a file.
RB_IO_BUFFER_FILE = 256,
};

// Represents the endian of the data types.
Expand Down
40 changes: 22 additions & 18 deletions io_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,17 +155,7 @@ io_buffer_map_file(struct rb_io_buffer *buffer, int descriptor, size_t size, rb_
buffer->size = size;

buffer->flags |= RB_IO_BUFFER_MAPPED;
}

// Release the memory associated with a mapped buffer.
static inline void
io_buffer_unmap(void* base, size_t size)
{
#ifdef _WIN32
VirtualFree(base, 0, MEM_RELEASE);
#else
munmap(base, size);
#endif
buffer->flags |= RB_IO_BUFFER_FILE;
}

static void
Expand Down Expand Up @@ -234,7 +224,16 @@ io_buffer_free(struct rb_io_buffer *buffer)
}

if (buffer->flags & RB_IO_BUFFER_MAPPED) {
io_buffer_unmap(buffer->base, buffer->size);
#ifdef _WIN32
if (buffer->flags & RB_IO_BUFFER_FILE) {
UnmapViewOfFile(buffer->base);
}
else {
VirtualFree(buffer->base, 0, MEM_RELEASE);
}
#else
munmap(buffer->base, buffer->size);
#endif
}

// Previously we had this, but we found out due to the way GC works, we
Expand All @@ -245,19 +244,20 @@ io_buffer_free(struct rb_io_buffer *buffer)

buffer->base = NULL;

#if defined(_WIN32)
if (buffer->mapping) {
CloseHandle(buffer->mapping);
buffer->mapping = NULL;
}
#endif
buffer->size = 0;
buffer->flags = 0;
buffer->source = Qnil;

return 1;
}

#if defined(_WIN32)
if (buffer->mapping) {
CloseHandle(buffer->mapping);
buffer->mapping = NULL;
}
#endif

return 0;
}

Expand Down Expand Up @@ -926,6 +926,10 @@ rb_io_buffer_to_s(VALUE self)
rb_str_cat2(result, " MAPPED");
}

if (buffer->flags & RB_IO_BUFFER_FILE) {
rb_str_cat2(result, " FILE");
}

if (buffer->flags & RB_IO_BUFFER_SHARED) {
rb_str_cat2(result, " SHARED");
}
Expand Down
15 changes: 7 additions & 8 deletions test/ruby/test_io_buffer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -519,23 +519,22 @@ def test_shared
end

def test_private
omit if RUBY_PLATFORM =~ /mswin|mingw/
tmpdir = Dir.tmpdir
buffer_path = File.join(tmpdir, "buffer.txt")
File.write(buffer_path, "Hello World")

Tempfile.create("buffer.txt") do |io|
io.write("Hello World")

buffer = IO::Buffer.map(io, nil, 0, IO::Buffer::PRIVATE)
File.open(buffer_path) do |file|
buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
assert buffer.private?
refute buffer.readonly?

buffer.set_string("J")

# It was not changed because the mapping was private:
io.seek(0)
assert_equal "Hello World", io.read
file.seek(0)
assert_equal "Hello World", file.read
ensure
buffer&.free
io&.close
end
end
end