Repository navigation
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d9d8def-16fe-4105-9e0f-b8aad187abce
Unmodified output of the migration driver across net12.0-windows, net12.0-unix, net12.0-browser, net12.0-wasi, and net12.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d9d8def-16fe-4105-9e0f-b8aad187abce
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d9d8def-16fe-4105-9e0f-b8aad187abce
Unmodified output of the fixed migration driver across net12.0-windows, net12.0-unix, and net12.0-browser. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d9d8def-16fe-4105-9e0f-b8aad187abce
Enable the two affected consumer test projects to compile the migrated shared helper. Neither project is enrolled in unsafe-v2. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d9d8def-16fe-4105-9e0f-b8aad187abce
|
Azure Pipelines: Successfully started running 4 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @karelz, @dotnet/area-system-io-compression |
| internal static unsafe void GetCryptographicallySecureRandomBytes(byte* buffer, int length) | ||
| { | ||
| if (Sys.GetCryptographicallySecureRandomBytes(buffer, length) != 0) | ||
| if (/* SAFETY: To be audited */ unsafe(Sys.GetCryptographicallySecureRandomBytes(buffer, length)) != 0) |
There was a problem hiding this comment.
hm.. this one probably should've been unsafe{}, will check.
Try all valid block candidates before unsafe expressions, including expression-body conversions. Keep expressions as a fallback and preserve the explicit expression-first action. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d9d8def-16fe-4105-9e0f-b8aad187abce
Retain unsafe-v2 enrollment and approved consumer settings. Restore only the previous automatic migration output before regenerating contexts with the updated fixer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d9d8def-16fe-4105-9e0f-b8aad187abce
Untouched output of a full driver replay from pre-migration sources across all five library TFMs. Control-flow headers and convertible expression bodies now prefer unsafe blocks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d9d8def-16fe-4105-9e0f-b8aad187abce
Untouched output of the fixed migration driver across all three test TFMs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d9d8def-16fe-4105-9e0f-b8aad187abce
| } | ||
| } | ||
|
|
||
| public unsafe nuint SetPrefix(ReadOnlyMemory<byte> prefix) |
There was a problem hiding this comment.
A bit surprised about this change. I would have thought that we would leave unsafe on a method.
There was a problem hiding this comment.
@agocke The code fixer is not supposed to infer whether internal unsafety should be propagated to callers. We make an exception for signatures containing unmanaged pointers, because experience shows that, in 99% of cases, methods accepting unmanaged pointers end up dereferencing them.
In general, though, this is the responsibility of a human or an AI agent:
- Find all
unsafe {}orunsafe(...)contexts marked with// SAFETY: To be audited. - Fill in the safety comment.
- Decide whether the method's internal unsafety should be propagated to its callers (based on ...).
- If it should, propagate it and add a
/// <safety>comment. - Update all call sites (the code fixer can be rerun for this step).
There was a problem hiding this comment.
So the code fixer, whether invoked by a human or an AI agent, handles 90% of the heavy lifting. AI then does the more nuanced work. This could all be done in one pass, but I'm not sure I want that for the libraries. I want to keep mechanical changes that don't need careful review separate from those that do.
There was a problem hiding this comment.
NOTE: unsafe on a method is always kept by the code-fixer if the method:
- Contains unmanaged pointers in the sig - purely speculation
- Contains
/// <safety>comment - it means it was already audited.
Otherwise we assumed unsafe is just a legacy unsafe-v1 "method-wide-unsafe-context" that we can remove.
There was a problem hiding this comment.
The code fixer is not supposed to infer whether internal unsafety should be propagated to callers.
Isn't this assuming the opposite though? That any given unsafe method is actually only inner-unsafe?
I think this could work, but I want to understand the reasoning why we are pushing things down to inner unsafe. Just because it follows unsafe-v1 semantics?
There was a problem hiding this comment.
Isn't this assuming the opposite though? That any given unsafe method is actually only inner-unsafe?
@agocke I am not sure it can be done the other way. Currently in v1 unsafe is used for inner-unsafe and we convert it into inner-unsafe in v2. If we convert unsafe into caller-unsafe, we'll get an enormous cascade of unsafe contexts - at this point the output of the migration tooling will be instantly reverted. Say unsafe void Dispose() are you suggesting it should propagated into IDisposable.Dispose interface? (same for any interface/virtual/overriden method. Also, a gazillion of classes marked as unsafe, does it mean all methods are unsafe in v2? or lack of unsafe on them means they're fully caller-safe?
Also, this effectively changes Public API and should go through Public API review, while with the current workflow it won't.
Currently, the only speculation we allow ourself is that method accepting unmanaged pointers should be marked as caller-unsafe (and they were effectively caller-unsafe even in unsafe-v1).
|
PTAL @agocke @jkotas @jjonescz. It contains a small fix (and tests) for UnsafeContext injector (to prioritize statements over expressions). Tracking issue: #136664 I don't expect a PR per assembly, I think many of them could be batched. (say up to 2000 LOC of changes or more). |
|
NOTE: there are no functional changes here, it's really about agreeing on the format. |
|
@EgorBo are we as IO.Compression owners expected to review this? If so, what should we be looking for? |
I have requested the review for awareness - to make sure that the area owners are comfortable with assuming the ownership of these annotations. |
|
I see, and I assume once this is merged, it is up to us to fill in those security annotations? Is there some document/playbook summarizing the approach? I may have gaps in how unsafe-v2 is supposed to work so I could use some examples to work from. |
unsafe-v2 spec: https://github.com/dotnet/csharplang/blob/main/proposals/unsafe-evolution.md The clean up work can be done by code owners or we'll just send an AI PR that you can review. The work is:
// Compression level functions
[LibraryImport(Libraries.CompressionNative)]
internal static unsafe partial int ZSTD_minCLevel();looks like a perfect candidate for Optional: replace unsafe{} with a code that doesn't require it. |
rzikm
left a comment
There was a problem hiding this comment.
LGTM from IO.Compression perspective, I will raise the follow-up PR with the required annotations.
I chose
System.IO.Compression(and its tests) as the first target because it's relatively small and interop-heavy.This PR covers only the mechanical migration: there is no AI-driven work to fill in safety comments or decide which methods might need a caller-unsafe contract. This lets the review focus entirely on the code fixer output.
References
A prompt for reading all the relevant documentation and running the driver script:
(I also tell it where to find a prebuilt dotnet/runtime in WSL so it can handle Linux targets there.)