-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add metadata rules for unsafe #9814
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 | ||||
|---|---|---|---|---|---|---|
|
|
@@ -184,6 +184,43 @@ partial class C2 | |||||
|
|
||||||
| For properties, `get` and `set/init` members can be independently declared as `unsafe`; marking the entire property as `unsafe` means that both the `get` and `set/init` members are unsafe. | ||||||
|
|
||||||
| #### Metadata | ||||||
|
|
||||||
| When an assembly is compiled with the new memory safety rules, it gets marked with `MemorySafetyRulesAttribute` (detailed below), filled in with `15` as the language version. This is a signal to | ||||||
| any downstream consumers that any members defined in the assembly will be properly attributed with `RequiresUnsafeAttribute` (detailed below) if an `unsafe` context is required to call them. | ||||||
| Any member in such an assembly that is not marked with `RequiresUnsafeAttribute` does not require an `unsafe` context to be called, regardless of the types in the signature of the member. | ||||||
|
|
||||||
| When a member is marked as `unsafe`, the compiler will synthesize a `RequiresUnsafeAttribute` application on the member in metadata. When a user-facing member marked as `unsafe` generates | ||||||
| hidden members, such as an auto-property's backing field or get/set methods, both the user-facing member and any hidden members generated by that user-facing member are all marked as `unsafe`, | ||||||
| and `RequiresUnsafeAttribute` is applied to all of them. | ||||||
|
|
||||||
| ```cs | ||||||
| namespace System.Runtime.CompilerServices | ||||||
| { | ||||||
| /// <summary>Indicates the language version of the memory safety rules used when the module was compiled.</summary> | ||||||
| [AttributeUsage(AttributeTargets.Module, Inherited = false)] | ||||||
| public sealed class MemorySafetyRulesAttribute : Attribute | ||||||
|
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. Will this play well with other languages? Suppose that C# 15 adds new safety rules. Now also suppose that F# adds safety rules in version 8. Does Roslyn understand which langauge version the number is related to? Are attributes under
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. It's based on the
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. It's documented here: https://github.com/dotnet/csharplang/blob/main/proposals/csharp-11.0/low-level-struct-improvements.md#refsafetyrulesattribute. The version is actually ignored, but it could be considered in the future if there was another "ref safety rules" version.
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. @jjonescz Thanks. I don't see anything specific about the attribute and other languages though. It seems like it is implicitly a C# only attribute. This gets back to my question of, what if F# has their own ref-safety rules? or another .NET compiler decides to express their own memory safety rules? I'm not saying we should throw it all away or even add a new API or change the existing one. I think I would like to see some clear documentation on the API though say "is specifically for Roslyn" or "is specifically for C#". I'm not going to quibble about potentially other non-Roslyn C# compilers.
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. The attribute is essentially for C#. The version number in the attribute is always a C# major language version. Languages that want to interop with C#'s unsafe code, will need to recognize and understand it, and possibly even emit it themselves if they want their "unsafe methods", etc. to be understood and treated similarly as C#'s.
Other languages/compilers can simply be oblivious to this attribute. That is the default state of affairs. If another language decided to implement a divergent concept of In the past, F# did some work to check ref safety for ref structs, etc. It doesn't look like they recognize RefSafetyRulesAttribute, though, they might wish to do so in the future. That's the nature of the impact I would anticipate on other major .NET languages for this feature as well.
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.
Then that should be documented cleared on the API. |
||||||
| { | ||||||
| /// <summary>Initializes a new instance of the <see cref="MemorySafetyRulesAttribute"/> class.</summary> | ||||||
| /// <param name="version">The language version of the memory safety rules used when the module was compiled.</param> | ||||||
| public MemorySafetyRulesAttribute(int version) => Version = version; | ||||||
|
|
||||||
| /// <summary>Gets the language version of the memory safety rules used when the module was compiled.</summary> | ||||||
| public int Version { get; } | ||||||
| } | ||||||
|
|
||||||
| [AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Delegate | AttributeTargets.Constructor, AllowMultiple = false, Inherited = true)] | ||||||
|
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.
Suggested change
As discussed offline, we may want to mark delegate |
||||||
| public sealed class RequiresUnsafeAttribute : Attribute | ||||||
| { | ||||||
| } | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| #### Compat mode | ||||||
|
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. I think this compat behavior is fine to reduce virality of the feature, but we should consider offering a facility to tighten our enforcement.
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. That feels like the job of either an analyzer or even an SDK build task, imo.
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. Agreed, I'm not saying it would be implemented in the compiler. In LDM last week, we discussed the need to review the full picture with all the pieces: compiler+analyzers+guidelines+SDK to see how it all fits.
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.
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. @agocke Either you or JanK at LDM last week mentioned that the language rules would not be sufficient by themselves to deliver on the memory safety claim we're trying to offer as part of the feature, and we may need analyzers and coding guidelines to shore up some gaps. Will you be on point to update the overall design doc with things that fall outside of language/compiler?
The reason I'm asking is I'd like to capture a open question: if we design the language/compiler for more compatibility (older compilers and not-opted-into-new-rules compiler are oblivious to new "unsafecaller" modifier) then should some other part of the system allow the user to crank the enforcement to "strict"? Before discussing how this would be implemented, my question is whether that's a scenario we're trying to support. |
||||||
|
|
||||||
| For compat purposes, and to reduce the number of false negatives that occur when enabling the new rules, we have a fallback rule for modules that have not been updated to the new rules. For such modules, | ||||||
| a member is considered `unsafe` if it has a pointer or function pointer type in its signature. | ||||||
|
|
||||||
| ## Open questions | ||||||
|
|
||||||
| ### Local functions/lambda safe contexts | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.