-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Improve Buffer.MemoryCopy documentation (or fix a bug) #6419
Comments
I agree that this sentence should be deleted. Instead, it should say the same thing as C++ memmove documentation: "If some regions of the source area and the destination overlap, both functions ensure that the original source bytes in the overlapping region are copied before being overwritten." @mairaw What is the best way to get API documentation bugs like this one fixed?
The output is different because of MemoryCopy takes source as first argument, and memmove takes destination as the first argument. Once the test is fixed to pass the arguments in the right order, the output will be the same. Also, PInvoke declaration for msvcrt memmove should have |
I missed the different argument order and indeed that makes the difference in this particular case go away. But I think there are actual differences:
Prints:
I hope I didn't mess it up again. Here's a concrete case which looks like a true bug to me:
And I think it's due to copying in chunks bigger than one byte in the overlapping case. If I exclude overlapping ranges by uncommenting the respective check I get no failures. I think this exhaustive test case should be added to the test suite. I'm a big fan of exhaustive tests in cases where they are applicable. Writing an exhaustive test can be faster than adding big amounts of manual test cases. It can give a lot of confidence in correctness. |
One question remains: What about negative lengths? It should be documented what is supposed to happen. Is it just undefined behavior? Another question: What does the function do if length == 0 but the pointers are invalid (e.g. null). Is this defined? This should be clarified as well. |
I don't get that result when I run your code,
That would mean that VC++'s
Yeah, it should be documented. You get an overflow exception instead of an argument exception. It's unusual but at least bad stuff doesn't happen if you accidentally pass it a negative length. |
I made a mistake when copying out the MemoryCopy code to my project. Indeed, zero failures when correcting that... I guess that's good news: No bug! Now provably so thanks to exhaustive testing. :) |
From what I read above seems like this issue is resolved now so I'll go ahead and close it for now. Feel free to reopen if that is not the case and there is still something we can fix in the documentation side. |
Use the same wording as documentation for memmove C API. Fixes dotnet/runtime#6419 (comment)
Use the same wording as documentation for memmove C API. Fixes dotnet/runtime#6419 (comment)
(1)
The documentation should be clarified:
It is not clear what reverse order means (I understood that part only because I'm familiar with the overlapping buffers problem with memcpy). Also, "buffers overlap" is unclear because nowhere is it defined what a buffer is. We are talking about ranges of addresses here. Interpreting them as a buffer is out of scope for this API. The wording could be "memory regions specified by
source
andsourceBytesToCopy
as well asdestination
anddestinationSizeInBytes
". Or it could be what the native version says.I would have suggest a text but I wasn't sure if I was causing any licensing issues with that. I'd be willing to contribute a documentation fix if this is helping.
(2) Please clarify what a negative length or a negative destination size cause. Is that valid? What does it do?
(3) I'm actually unclear on what the function is supposed to do. It behaves differently depending on whether src and dest are ascending or descending in memory (where the ranges overlap in both cases). The behavior deviates from native
memmove
. Is this supposed to happen? If no, it's a bug. If yes, the documentation should spell that out.The output is different because the check
if ((ulong)dest - (ulong)src < len) goto PInvoke;
is sometimes false, sometimes true. And if it's false the unsafe managed version behaves questionably.Ideally, the function would mirror
memmove
.Maybe it's a good solution to call the bytewise managed loop for small overlapping buffers. For big overlapping buffers call the native code.
The text was updated successfully, but these errors were encountered: