-
Notifications
You must be signed in to change notification settings - Fork 76
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
Support zero-size Mmap
and MmapMut
#25
Conversation
I cannot easily run tests for Windows on my machine (only |
Maybe we should simply have a flag that indicates that the mmap len was created empty and return |
Do you mean for |
For both, to be more consistent. Or just for Windows + a long comment for Unix explaining why it's ok and why it's different from Win. |
Fixes danburkert#72 Previously, mapping an empty file or requesting a zero-size mapping would return an error because underlying OS APIs do not support zero-size mappings. Now, this crate instead requests a one-byte mapping (which most lilkely ends up rounded up to one memory page) but still has `Deref` return an empty slice in those cases. This is the behavior suggested for Unix in danburkert#72 (comment) On Windows, docs for `CreateFileMappingW` say: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw > `dwMaximumSizeHigh` > > The high-order DWORD of the maximum size of the file mapping object. > > `dwMaximumSizeLow` > > The low-order DWORD of the maximum size of the file mapping object. > > If this parameter and dwMaximumSizeHigh are 0 (zero), the maximum size of > the file mapping object is equal to the current size of the file that hFile > identifies. > > An attempt to map a file with a length of 0 (zero) fails with an error code > of ERROR_FILE_INVALID. Applications should test for files with a length of > 0 (zero) and reject those files. Hopefully that last paragraph only applies when `dwMaximumSize` is zero (which this PR avoids), but that is not clear to me.
@@ -119,6 +119,11 @@ extern "system" { | |||
fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO); | |||
} | |||
|
|||
/// Returns a fixed pointer that is valid for `slice::from_raw_parts::<u8>` with `len == 0`. | |||
fn empty_slice_ptr() -> *mut c_void { | |||
std::ptr::NonNull::<u8>::dangling().cast().as_ptr() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What kind of black magic is that? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NonNull::dangling
interprets align_of()
as an address to create a pointer that is not null but still correctly aligned. It is mentioned in the docs of slice::from_raw_parts
as a way to obtain an arbitrary pointer that can be used to create an empty slice.
NonNull::cast
is similar to (and based on) as
for casting for example *mut u8
to *mut c_void
. It can be turbofished, but in this case type inference fills in the destination type.
src/unix.rs
Outdated
"memory map must have a non-zero length", | ||
)); | ||
} | ||
// Ensure a non-zero length for the underlying mapping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you expand this comment a bit to explain why we have to do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’d like to also explain why the work around is correct, but I’m getting less and less convinced it actually is 😅
I don't understand the Unix logic. Is it ok to map a zero-sized file to a non-zero sized, aligned memory block? On Windows, afaik, you're simply skipping PS: I have close to zero knowledge about mmap, despite the fact I'm maintaining this crate. Therefore I want to have a good understanding and reason behind all major changes to it. |
The previous commit’s trick of creating a non-zero-size mapping for an empty file does not work on Windows like it does with `mmap` on Unix. It cause an `IoError` with code 1006 and message `The volume for a file has been externally altered so that the opened file is no longer valid.` https://github.com/RazrFalcon/memmap2-rs/pull/25/checks?check_run_id=3620122580#step:4:46 Instead, in that case skip creating a mapping entirely. We don’t need one for `Deref` to return a valid zero-size slice.
I went by this comment danburkert#72 (comment) suggesting that it is ok, but I don’t find something supporting this idea in the man page. I’ve asked that commenter: danburkert#72 (comment) To skip calling |
I’ve found POSIX defining the guarantee we need: danburkert#72 (comment) |
Looks good to me. And thanks for a detailed comment. |
Fixes danburkert#72
Fixes #23
Previously, mapping an empty file or requesting a zero-size mapping would return an error because underlying OS APIs do not support zero-size mappings. Now, this crate instead requests a one-byte mapping (which most lilkely ends up rounded up to one memory page) but still has
Deref
return an empty slice in those cases.This is the behavior suggested for Unix in danburkert#72 (comment)
On Windows, docs for
CreateFileMappingW
say:https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw
Hopefully that last paragraph only applies whendwMaximumSize
is zero (which this PR avoids), but that is not clear to me.Edit: nope: #25 (comment)