Skip to content

Change reinterpret_cast use to memcpy #2295

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

Merged
merged 1 commit into from
Feb 13, 2020

Conversation

josalem
Copy link
Contributor

@josalem josalem commented Jan 28, 2020

  • prevents unaligned address access on some ARM OSes that fault on that

Changes use of reinterpret_cast to memcpy in EventPipe IPC read/write operations.

resolves #2067

I'm going to be doing some local tests to convince myself that memory is still being accounted for. I'll flip the bit on PR status after that.

CC - @tommcdon

@josalem josalem added this to the 5.0 milestone Jan 28, 2020
@josalem josalem requested review from noahfalk and sywhang January 28, 2020 19:15
@josalem josalem self-assigned this Jan 28, 2020
@josalem josalem changed the title Change reinterpre_cast use to memcpy Change reinterpret_cast use to memcpy Jan 28, 2020
@@ -24,7 +24,7 @@ bool TryParse(uint8_t *&bufferCursor, uint32_t &bufferLen, T &result)

if (bufferLen < sizeof(T))
return false;
result = *(reinterpret_cast<T *>(bufferCursor));
memcpy(&result, bufferCursor, sizeof(T));
Copy link
Contributor

Choose a reason for hiding this comment

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

Might consider something like:

template <typename T>
static inline T unaligned_reinterpret_cast(const void* ptr)
{
   T tmp; 
   memcpy(&tmp, ptr, sizeof(T));
   return tmp;
}

Then just use it like:

result = unaligned_reinterpret_cast<T>(bufferCursor);

At least, for fundamental types such as int and float, this generates pretty good code that does not involve copies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure I see how refactoring that code removes the need for a copy. memcpy happens either way. Are you suggesting replacing the entirety of TryParse with the above code?

Copy link
Contributor

@lpereira lpereira Jan 28, 2020

Choose a reason for hiding this comment

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

Oh, I mean, it still calls memcpy() (which might not even copy, just load it in a register), but there's no additional copy because it's returning tmp instead of a reference or pointer.

This just wraps memcpy() in a function in such a way that it's clear from the call site that it's a reinterpret_cast that works with unaligned pointers. It's otherwise identical to the direct memcpy() call in your patch.

return false;
result = reinterpret_cast<const T *>(bufferCursor);

T *resultBuffer = new (nothrow) T[stringLen];
Copy link
Member

Choose a reason for hiding this comment

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

Does this buffer ever get deleted? I didn't notice any changes at any callsite of TryParseString.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just updated the code so that strings are held in NewHolder|NewArrayHolders so they should get deleted correctly. I'm going to see about running Valgrind over it to make sure.

@@ -24,7 +24,7 @@ bool TryParse(uint8_t *&bufferCursor, uint32_t &bufferLen, T &result)

if (bufferLen < sizeof(T))
return false;
result = *(reinterpret_cast<T *>(bufferCursor));
memcpy(&result, bufferCursor, sizeof(T));
Copy link
Contributor

Choose a reason for hiding this comment

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

Testing with this single line change, it just worked in my case.

@@ -55,17 +55,19 @@ const GenerateCoreDumpCommandPayload* GenerateCoreDumpCommandPayload::TryParse(B
return nullptr;
}

payload->incomingBuffer = lpBuffer;
uint8_t* pBufferCursor = payload->incomingBuffer;
uint8_t* pBufferCursor = lpBuffer;
Copy link
Member

Choose a reason for hiding this comment

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

Does GenerateCoreDumpCommandPayload* above need to be NewArrayHolder now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The user is expected to handle the memory new'd here. Down on line 88, the GenerateCoreDumpPayload is put into a NewHolder.

Copy link
Member

Choose a reason for hiding this comment

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

It is a good practice to assign a newly allocated memory to a holder immediately. That way, you would not need to delete it at line 65 and it is also future proof when someone might add another return path to this function. The final return in this function would then use payload->Extract() or just call SuppressRelease() before the return.

@josalem
Copy link
Contributor Author

josalem commented Feb 3, 2020

After some discussion with @noahfalk last week, I'm going top scale back the scope of this PR to just the line that @swift-kim said solved their issue. This is minimally invasive and solves the issue. Once the PR is scaled back, I'll mark the PR as ready for review.

@swift-kim
Copy link
Contributor

@josalem Is there any news?

@josalem
Copy link
Contributor Author

josalem commented Feb 10, 2020

@josalem Is there any news?

@swift-kim I was offline last week, but I should be able to modify the PR this week to only include the line that fixes your issue and mark the PR for review.

@josalem josalem force-pushed the dev/josalem/rm-reinterpretcast branch from 293b498 to b2ee74e Compare February 10, 2020 19:57
@josalem josalem marked this pull request as ready for review February 11, 2020 01:53
@josalem josalem force-pushed the dev/josalem/rm-reinterpretcast branch from b2ee74e to 0082ccd Compare February 11, 2020 19:12
@josalem
Copy link
Contributor Author

josalem commented Feb 11, 2020

/azp run runtime

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@josalem josalem requested a review from noahfalk February 12, 2020 19:49
@stephentoub stephentoub merged commit c89e275 into dotnet:master Feb 13, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 11, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bus error when parsing EventPipeProviderConfiguration
8 participants