-
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
[NativeAOT] Missing memory fence before bulk move of objects #90890
Conversation
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas Issue DetailsMemory model requires that the object modifications are observable before the reference itself is observable. See similar fence in CoreCLR
|
In theory the fence could be done conditionally on whether destination is a heap location. Only a "publising" write needs a fence. Also a store fence should be sufficient. (as in I think we may want to backport this to 8.0, thus just doing the same unconditional full fence as in CoreCLR seems less risky. |
if (pDest <= pSrc || pSrc + cbDest <= pDest) | ||
InlineForwardGCSafeCopy(pDest, pSrc, cbDest); | ||
else | ||
InlineBackwardGCSafeCopy(pDest, pSrc, cbDest); | ||
|
||
InlinedBulkWriteBarrier(pDest, cbDest); | ||
} | ||
|
||
void REDHAWK_CALLCONV RhpBulkWriteBarrier(void* pMemStart, uint32_t cbMemSize) |
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 helper was unused.
@@ -36,15 +36,18 @@ COOP_PINVOKE_CDECL_HELPER(void *, RhpGcSafeZeroMemory, (void * mem, size_t size) | |||
|
|||
COOP_PINVOKE_HELPER(void, RhBulkMoveWithWriteBarrier, (uint8_t* pDest, uint8_t* pSrc, size_t cbDest)) | |||
{ | |||
#if TARGET_ARM64 |
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.
Can we define GCHeapMemoryBarrier
macro that matches what we do in CoreCLR?
runtime/src/coreclr/vm/common.h
Lines 338 to 352 in e18e4aa
#if defined(TARGET_X86) || defined(TARGET_AMD64) | |
// | |
// Strong memory model. No memory barrier necessary before writing object references into GC heap. | |
// | |
#define GCHeapMemoryBarrier() | |
#else | |
// | |
// The weak memory model forces us to raise memory barriers before writing object references into GC heap. This is required | |
// for both security and to make most managed code written against strong memory model work. Under normal circumstances, this memory | |
// barrier is part of GC write barrier. However, there are a few places in the VM that set cards manually without going through | |
// regular GC write barrier. These places need to this macro. This macro is usually used before memcpy-like operation followed | |
// by SetCardsAfterBulkCopy. | |
// | |
#define GCHeapMemoryBarrier() MemoryBarrier() | |
#endif |
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 am not sure GCHeapMemoryBarrier
should be a helper.
It sounds like something more general for use in GC, but it is used only in the bulk copy helper and that is the only place where it is applicable.
Also, ideally it should be something like
#if TARGET_ARM64
if (InHeap(dst))
{
StoreMemoryBarrier();
}
#endif
That is to not do fences when this is used to copy structs on stack.
I guess, since we are not doing that, we could match the CoreCLR pattern.
@@ -4,5 +4,3 @@ | |||
// | |||
// Unmanaged GC memory helpers |
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.
Delete this file?
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
Thanks! |
I think we want an 8.0 backport for this. |
/backport to release/8.0 |
Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/5942571566 |
Memory model requires that the modifications to an object are observable by other threads no later than the reference to the object becomes observable.
It is possible that
RhBulkMoveWithWriteBarrier
is making the objects shared, thus needs a fence.See similar fence in CoreCLR
InlinedMemmoveGCRefsHelper
runtime/src/coreclr/classlibnative/bcltype/arraynative.inl
Line 310 in e18e4aa