-
Notifications
You must be signed in to change notification settings - Fork 169
Add reference to .NET Memory Model #367
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,7 @@ The overall goal is to ensure .NET code is "valid" with respect to certain prope | |
|
|
||
| * Memory safety | ||
| * No access to uninitialized memory | ||
| * The [.NET Memory Model](https://github.com/dotnet/runtime/blob/main/docs/design/specs/Memory-model.md) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doc explains the expected behavior of memory access (in the presence of multithreading). I am not sure what it means for the .NET code to be valid with respect to the properties explained in this doc. I think the most immediate interpretation of this statement would be that we want to guarantee race conditions free code, but that's not what we are doing here.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternative proposals - add the following towards the end of "Global invariants" chapter: These properties interact with other .NET runtime behaviors, such as .NET Memory Model. For example, it is invalid for safe code to be able to trigger undefined behavior caused by misaligned memory accesses.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The linked doc explains the guaranteed behaviors of managed code. These are properties that must be maintained by all unsafe code. For example, the doc says:
If unsafe code is used to create a managed reference that is either unaligned or where access is not atomic, that would be invalid code and the unsafe code would be in error.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This talks about the alignment of storage for the managed reference. It does not talk about the location where the managed reference points to. For example, situation like this: This is invalid type layout. The runtime will refuse to load this type, unsafe code won't help you to get around that.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, but isn't that something that should be in the .NET Memory model doc? Basically, shouldn't there be a list of all the guaranteed properties in the .NET model, irrespective of the safety model? Or do you think that we should move all the guarantees into this document?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A few different concerns:
It works fine today, the ECMA-335 indirectly suggests that misaligned byrefs are fine through defining
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I put a basic draft of what the rules could look like, we can fill it in with whatever data we want. I do think we have to think about ways that unsafe might produce unaligned refs though. For example, ref struct S
{
ref int x;
}
Span<byte> arr = ...;
var s = Unsafe.As<byte, S>(ref arr[3]);Obviously the big problem there is a completely invalid pointer, but it's also misaligned |
||
|
|
||
| The complete definition of these properties is in [Global invariants](#global-invariants). | ||
|
|
||
|
|
@@ -114,10 +115,11 @@ public sealed class RequiresUnsafeAttribute : System.Attribute | |
|
|
||
| ### Global invariants | ||
|
|
||
| Two properties which should always hold in .NET programs are: | ||
| Three properties which should always hold in .NET programs are: | ||
|
|
||
| * Memory safety | ||
| * No access to uninitialized memory | ||
| * Alignment with the .NET Memory Model | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. .NET memory model is just one of many feature areas that the safe subset must be aligned with. I do not think it makes sense to single out the memory model here, without going into details of what "Alignment with the .NET Memory Model" actually means. I have submitted #368 with my proposed edit that should address what you are trying to achieve here with better clarity. |
||
|
|
||
| The "safe" subset of C# must guarantee these properties by construction. The unsafe subset cannot be guaranteed entirely by the system -- it needs external validation by the user or other tooling. | ||
|
|
||
|
|
@@ -133,6 +135,12 @@ These properties are guaranteed by "safe" code through a combination of compiler | |
|
|
||
| `unsafe` members are used to identify the places that cannot be automatically checked by the compiler and runtime for validity. Inside unsafe blocks, the programmer is responsible for ensuring that all requirements of the unsafe code are met, and that all code outside the block will have validity properly enforced by the system. | ||
|
|
||
| #### .NET Memory Model Alignment | ||
|
|
||
| The .NET memory model contains guarantees which must not be violated by unsafe code: | ||
|
|
||
| * Managed references must always be aligned | ||
|
|
||
| ### Non-goals | ||
|
|
||
| The new definition of `unsafe` is centered around memory safety, specifically ensuring access to valid memory and avoiding memory corruption. There are some properties that may be desirable but are not covered by memory safety. This includes: | ||
|
|
||
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.
Should we have a sub-bullet for "language specific memory model additions"?
i.e. C# (abstract language) has its own memory model that is disconnected from .NET, then Roslyn (specific implementation of the language targeting .NET) has potential addendums to the language. So safe C# code also needs to respect any such stipulations or variants in there.
The same would apply to safe F# targeting other safe F#, etc.
We can't really easily define the bounds for interlanguage interop (i.e. C# calling F# or vice versa), but I think we could call out that within a single language and we expect languages to at least be compatible with the .NET memory model