-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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] Add null checks into memcpy/memset helpers #98547
Conversation
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas Issue DetailsFixes #95517
|
...reclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MemoryHelpers.cs
Outdated
Show resolved
Hide resolved
...reclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MemoryHelpers.cs
Outdated
Show resolved
Hide resolved
...reclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MemoryHelpers.cs
Outdated
Show resolved
Hide resolved
...reclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MemoryHelpers.cs
Outdated
Show resolved
Hide resolved
...reclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/MemoryHelpers.cs
Outdated
Show resolved
Hide resolved
What is this extra wrapper going to do to the perf? It may be better to make the JIT to inline the null checks instead. |
We discussed implement this in the Jit. It is possible, but mildly involved due to the need to do the zero-length check. Additionally, these helpers are not used in scenarios with small sizes that would be most sensitive to the overhead (unless the user uses
I will note that this would make the implementation fragile in the sense of being prone to self-recursion depending on Jit implementation details (or even optimization choices). Perhaps that's not a big concern; it would be an obvious failure mode. |
Right, we have two options:
|
And only for structs without gc references. The unroll rules are listed here: runtime/src/coreclr/jit/compiler.h Lines 9215 to 9222 in d972a19
|
This kicks in for constant sizes only. Are there any important cases where these helpers are used for non-constant sizes? |
|
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.
LGTM. Thanks!
cc @VSadov We may want to do something similar for CoreCLR too. The current implementation of these helpers for CoreCLR is not GC suspend friendly. |
FYI |
Yes, it is by design. Passing invalid unmanaged buffers into BCL APIs is undefined behavior. Invalid unmanaged buffers typically signal process state corruption, buffer overrun, etc. We would not want to intentionally convert any situation where we fail fast for these cases today into something that can be caught and handled. |
I'd expect null to not be considered "corrupted process state" kind of invalid in such API? This also only reproduces with a big size, a small one throws a |
Are these generally used for small sizes like boxing/unboxing or for potentially big buffers as well? |
Right, passing invalid unmanaged buffer into BCL APIs is undefined behavior. We are not trying to detect and convert all cases into fail fasts. If we were to make the behavior more defined, it would be to detect and fail fast in more cases. It tends to come with performance overhead and it is hard to tell when to stop. For example, how far we should go with detecting This approach matches how many C/C++ libraries deal with this issue, including standard C library. For example, try calling |
I think the following answers that:
|
It turns out that we use initblk in two places in CoreLib: #98623 (comment) that are slower after this change than they need to be. I expect this to be cleaned up as this gets unified with full CoreCLR CoreLib. |
Fixes #95517