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

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

devnexen
Copy link
Contributor

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

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
Contributor 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 179
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
Contributor 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
Contributor 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?

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