-
Notifications
You must be signed in to change notification settings - Fork 108
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
custom memmove implementation proposal. #593
base: main
Are you sure you want to change the base?
Conversation
mostly like memcpy with optional bound checking but capable of handling overlapping cases thus using reverse copy instead.
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.
Thanks for doing this. I think the test coverage needs a bit of work. It would be nice to vary the sizes and directions of overlap to make sure the code functions correctly.
src/test/func/memcpy/func-memcpy.cc
Outdated
my_memmove(ptr, s, sz * sizeof(unsigned int)); | ||
for (size_t i = 0; i < sz; ++i) | ||
{ | ||
EXPECT(ptr[i] == s[i], "overlap error: {} {}", ptr[i], s[i]); |
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.
EXPECT(ptr[i] == s[i], "overlap error: {} {}", ptr[i], s[i]); | |
EXPECT(ptr[i] == i, "overlap error: {} {}", ptr[i], i); |
I think s[i]
can be corrupted by the memmove
. Better to use the original value of i
here.
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.
Would be more complex if you make this test do both directions.
} | ||
my_memmove(&s[2], &s[4], sizeof(s[0])); | ||
EXPECT(s[2] == s[4], "overlap error: {} {}", s[2], s[4]); | ||
my_memmove(&s[15], &s[5], sizeof(s[0])); |
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.
Isn't s[15]
out of bounds when size == 8
?
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.
ah right I forgot to change in the beginning the sizes set were fixed :-)
src/test/func/memcpy/func-memcpy.cc
Outdated
void check_overlaps(size_t size) | ||
{ | ||
START_TEST("memmove overlaps, size {}", size); | ||
auto* s = static_cast<unsigned int*>(my_malloc(size * sizeof(unsigned int))); | ||
auto sz = size / 2; | ||
for (size_t i = 0; i < size; ++i) | ||
{ | ||
s[i] = static_cast<unsigned int>(i); | ||
} | ||
my_memmove(&s[2], &s[4], sizeof(s[0])); | ||
EXPECT(s[2] == s[4], "overlap error: {} {}", s[2], s[4]); | ||
my_memmove(&s[15], &s[5], sizeof(s[0])); | ||
EXPECT(s[15] == s[5], "overlap error: {} {}", s[15], s[5]); | ||
auto ptr = s; | ||
my_memmove(ptr, s, size * sizeof(s[0])); | ||
EXPECT(ptr == s, "overlap error: {} {}", ptr, s); | ||
my_free(s); |
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.
The first part of this test feels like it is debug to get things working. The second part has a lot of uniformity. Perhaps, just drop the first part, or make it a separate test: check_overlaps1
and check_overlaps2
.
src/test/func/memcpy/func-memcpy.cc
Outdated
{ | ||
s[i] = static_cast<unsigned int>(i); | ||
} | ||
ptr = s + sz; |
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.
This only provides an overlap in one direction.
ptr = s + sz; | |
auto dst = after ? s + sz : s; | |
auto src = after ? s : s + sz; |
and then use src
and dst
below?
src/snmalloc/global/memcpy.h
Outdated
return report_fatal_bounds_error( | ||
dst, len, "memmove with destination out of bounds of heap allocation"); | ||
|
||
if (dst > src) |
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.
Would
if (dst > src) | |
if ((dst - src) < len) |
be a better check? Currently it doesn't check that there is actually an overlap? @davidchisnall
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 guess my concern here is because you have dropped to a slow byte by byte copy. Half of all non-overlapping memmove
s will be slow.
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.
right .. I ll follow your suggestion.
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.
Thanks for fixing the tests.
void check_overlaps2(size_t size) | ||
{ | ||
START_TEST("memmove overlaps2, size {}", size); | ||
auto sz = size / 2; |
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 wonder if it would be good to separate the offset from the size being copied. The current test only covers very small overlaps.
auto sz = size / 2; | |
auto sz = size / 2; | |
auto offset = size / 3; |
Then use offset
in the calculations using after
?
src/snmalloc/global/memcpy.h
Outdated
return report_fatal_bounds_error( | ||
dst, len, "memmove with destination out of bounds of heap allocation"); | ||
|
||
if (dst > src) |
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 guess my concern here is because you have dropped to a slow byte by byte copy. Half of all non-overlapping memmove
s will be slow.
19db257
to
2aa9388
Compare
@devnexen sorry for the delay in running the CI. It looks like there are a few failures in the tests, and clangformat is not happy. |
weird as the issue seem about check_bounds about using memcpy ? |
I think it is the last line here:
https://github.com/microsoft/snmalloc/actions/runs/4256879925/jobs/7476767702#step:9:16563 The clangformat might be it has cached an old file list. If you try rerunning |
be22da7
to
9065f38
Compare
mostly like memcpy with optional bound checking but capable of handling overlapping cases thus using
reverse copy instead.