JIT: Fix too wide loads on arm64 for small structs#76341
JIT: Fix too wide loads on arm64 for small structs#76341EgorBo merged 18 commits intodotnet:mainfrom
Conversation
|
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch Issue DetailsFixes #76194 We've had similar issues in the past e.g. #64683 (reproduces even on .NET Framework)
|
11e36e3 to
64e80d3
Compare
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
src/coreclr/jit/lower.cpp
Outdated
| LIR::Use retValUse(BlockRange(), &ret->gtOp1, ret); | ||
| unsigned tmpNum = BAD_VAR_NUM; | ||
| if (structCls != NO_CLASS_HANDLE) | ||
| { | ||
| tmpNum = comp->lvaGrabTemp(true DEBUGARG("mis-sized struct return")); | ||
| comp->genReturnLocal = tmpNum; | ||
| comp->lvaSetStruct(tmpNum, structCls, true); | ||
| } |
There was a problem hiding this comment.
| LIR::Use retValUse(BlockRange(), &ret->gtOp1, ret); | |
| unsigned tmpNum = BAD_VAR_NUM; | |
| if (structCls != NO_CLASS_HANDLE) | |
| { | |
| tmpNum = comp->lvaGrabTemp(true DEBUGARG("mis-sized struct return")); | |
| comp->genReturnLocal = tmpNum; | |
| comp->lvaSetStruct(tmpNum, structCls, true); | |
| } | |
| LIR::Use retValUse(BlockRange(), &ret->gtOp1, ret); | |
| unsigned tmpNum = comp->lvaGrabTemp(true DEBUGARG("mis-sized struct return")); | |
| comp->lvaSetStruct(tmpNum, structCls, false); |
genReturnLocalhas a very specific purpose, no reason to set it here.- No unsafe value class checks needed (in principle, in practice it doesn't matter) since the address of this local won't escape.
There was a problem hiding this comment.
genReturnLocal has a very specific purpose, no reason to set it here.
Tests assert after this patch: Assertion failed 'tmp == genReturnLocal'
There was a problem hiding this comment.
I reverted some suggestions if you don't mind because we hit the path for non-structs as well (e.g. small type primitives) so now it's cleaner that we have a special case for that rare case with IND<struct>.
There was a problem hiding this comment.
We still need to handle the case with handle-less BLK nodes though.
Reproduction:
struct Sx3
{
public byte A, B, C;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static Sx3 Problem(void* s)
{
Sx3 a;
Unsafe.CopyBlock(&a, s, 3);
return a;
}There was a problem hiding this comment.
thanks, reverted the revert. @SingleAccretion does it look good to you? I assume it's just your change written with my hands 😄
Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
SingleAccretion
left a comment
There was a problem hiding this comment.
Yep, looks good!
|
@jakobbotsch could you please take a look and sign it off? CI failure is known: #78290 |
| if (realSize == 0) | ||
| { | ||
| // TODO-ADDR: delete once "IND<struct>" nodes are no more | ||
| realSize = comp->info.compCompHnd->getClassSize(structCls); |
There was a problem hiding this comment.
I assume it is guaranteed that structCls != NO_CLASS_HANDLE here or we would have hit some BADCODE previously? (e.g. returning struct in method declared to return int)
There was a problem hiding this comment.
Not that the current behavior tries to be careful in such cases, I've just tried and got an AccessViolationException in Main for it when I changed return type to int while was trying to return a small struct.
|
LLVMAOT failure was known and already fixed in Main |
| _ptr = mmap(null, 2 * PageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
| if (_ptr != null && mprotect(_ptr + PageSize, PageSize, PROT_NONE) != 0) | ||
| { | ||
| munmap(_ptr, 2 * PageSize); |
There was a problem hiding this comment.
This looks like it will result in a double free
There was a problem hiding this comment.
Ah, I see the reason now:
On success, mmap() returns a pointer to the mapped area. On
error, the value MAP_FAILED (that is, (void *) -1) is returned,
and [errno](https://man7.org/linux/man-pages/man3/errno.3.html) is set to indicate the error.So this does not correctly check that we failed to allocate the memory.
Fixes #76194
using @SingleAccretion's snippet since mine was uglier.
We've had similar issues in the past e.g. #64683 (reproduces even on .NET Framework x64)
it's just that normally it's an extremely rare case, perhaps, still worth backporting to .NET 7.0