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

[NativeAOT] Missing memory fence before bulk move of objects #90890

Merged
merged 3 commits into from
Aug 22, 2023

Conversation

VSadov
Copy link
Member

@VSadov VSadov commented Aug 21, 2023

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

@ghost
Copy link

ghost commented Aug 21, 2023

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Memory model requires that the object modifications are observable before the reference itself is observable.
It is possible that RhBulkMoveWithWriteBarrier is making the objects shared, thus needs a fence.

See similar fence in CoreCLR InlinedMemmoveGCRefsHelper

Author: VSadov
Assignees: -
Labels:

area-NativeAOT-coreclr

Milestone: -

@VSadov
Copy link
Member Author

VSadov commented Aug 21, 2023

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 dmb ishst).

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.

@VSadov VSadov requested a review from jkotas August 21, 2023 20:31
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)
Copy link
Member Author

Choose a reason for hiding this comment

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

This helper was unused.

@VSadov VSadov marked this pull request as ready for review August 21, 2023 20:34
@@ -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
Copy link
Member

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?

#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

Copy link
Member Author

@VSadov VSadov Aug 21, 2023

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
Copy link
Member

Choose a reason for hiding this comment

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

Delete this file?

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

Thanks

@VSadov VSadov merged commit 3bda6e0 into dotnet:main Aug 22, 2023
108 checks passed
@VSadov VSadov deleted the bulkBar branch August 22, 2023 03:00
@VSadov
Copy link
Member Author

VSadov commented Aug 22, 2023

Thanks!

@VSadov
Copy link
Member Author

VSadov commented Aug 22, 2023

I think we want an 8.0 backport for this.

@VSadov
Copy link
Member Author

VSadov commented Aug 22, 2023

/backport to release/8.0

@github-actions
Copy link
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/5942571566

@ghost ghost locked as resolved and limited conversation to collaborators Sep 21, 2023
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.

2 participants