Skip to content
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

Merged
merged 1 commit into from
Nov 16, 2024
Merged

Conversation

devnexen
Copy link
Collaborator

mostly like memcpy with optional bound checking but capable of handling overlapping cases thus using
reverse copy instead.

Copy link
Member

@mjp41 mjp41 left a 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.

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]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

Copy link
Member

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]));
Copy link
Member

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?

Copy link
Collaborator Author

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 :-)

Comment on lines 163 to 182
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);
Copy link
Member

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.

{
s[i] = static_cast<unsigned int>(i);
}
ptr = s + sz;
Copy link
Member

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.

Suggested change
ptr = s + sz;
auto dst = after ? s + sz : s;
auto src = after ? s : s + sz;

and then use src and dst below?

return report_fatal_bounds_error(
dst, len, "memmove with destination out of bounds of heap allocation");

if (dst > src)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would

Suggested change
if (dst > src)
if ((dst - src) < len)

be a better check? Currently it doesn't check that there is actually an overlap? @davidchisnall

Copy link
Member

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 memmoves will be slow.

Copy link
Collaborator Author

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.

Copy link
Member

@mjp41 mjp41 left a 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;
Copy link
Member

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.

Suggested change
auto sz = size / 2;
auto sz = size / 2;
auto offset = size / 3;

Then use offset in the calculations using after?

return report_fatal_bounds_error(
dst, len, "memmove with destination out of bounds of heap allocation");

if (dst > src)
Copy link
Member

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 memmoves will be slow.

@mjp41
Copy link
Member

mjp41 commented Feb 28, 2023

@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.

@devnexen
Copy link
Collaborator Author

weird as the issue seem about check_bounds about using memcpy ?
Also my clang-format(9) does not report format issue..

@mjp41
Copy link
Member

mjp41 commented Mar 1, 2023

I think it is the last line here:

Check fail: dst[u] == i in /home/runner/work/snmalloc/snmalloc/src/test/func/memcpy/func-memcpy.cc on 200  
in test void check_overlaps2(size_t) [after = false] overlap error: 0x4 0x2

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 cmake, and then the clangformat target?

@devnexen devnexen force-pushed the memmove_impl branch 2 times, most recently from be22da7 to 9065f38 Compare March 8, 2023 21:29
@devnexen devnexen force-pushed the memmove_impl branch 2 times, most recently from c14ddfd to 00f84d1 Compare March 13, 2023 21:01
@devnexen devnexen marked this pull request as ready for review November 2, 2024 15:10
mostly like memcpy with optional bound checking but
capable of handling overlapping cases thus using
reverse copy instead.
Copy link
Member

@mjp41 mjp41 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mjp41 mjp41 enabled auto-merge (squash) November 16, 2024 07:34
@mjp41 mjp41 merged commit 01885f5 into microsoft:main Nov 16, 2024
52 checks passed
devnexen added a commit to devnexen/snmalloc that referenced this pull request Nov 20, 2024
mjp41 pushed a commit that referenced this pull request Nov 20, 2024
* Revert "custom memmove implementation proposal. (#593)"

This reverts commit 01885f5.

* disable memmove fuzzing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants