-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
I'm seeing an (unfortunately non-deterministic) access violation early in the NativeAOT-compiled System.Runtime.Tests startup on Windows ARM64:
> System.Runtime.Tests.exe!S_P_CoreLib_System_IO_StreamWriter__Flush_0() Line 308 Unknown
System.Runtime.Tests.exe!System_Console_System_Console__CreateOutputWriter() Line 237 Unknown
System.Runtime.Tests.exe!System_Console_System_Console___get_Out_g__EnsureInitialized_26_0() Line 207 Unknown
System.Runtime.Tests.exe!System_Console_System_Console__WriteLine_12() Line 807 Unknown
System.Runtime.Tests.exe!System_Runtime_Tests_SingleFileTestRunner__Main() Line 26 Unknown
System.Runtime.Tests.exe!System_Runtime_Tests__Module___StartupCodeMain() Unknown
System.Runtime.Tests.exe!wmain(int argc, wchar_t * * argv) Line 205 C++
The crash happens as the code is trying to touch an SP-relative address a "little bit" (less than a page) further away from the current and obviously written to SP:
00007FF751DB86FC B94403FF ldr wzr,[sp,#0x400]
Click here to see full disassembly - the problem instruction is highlighted
private void Flush(bool flushStream, bool flushEncoder)
{
// flushEncoder should be true at the end of the file and if
// the user explicitly calls Flush (though not if AutoFlush is true).
// This is required to flush any dangling characters from our UTF-7
// and UTF-8 encoders.
ThrowIfDisposed();
00007FF751DB85E0 D10103FF sub sp,sp,S_P_CoreLib_System_IO_StreamWriter__Flush_0 (00h)
00007FF751DB85E4 A900D3F3 stp x19,x20,[sp,#8]
00007FF751DB85E8 A901DBF5 stp x21,x22,[sp,#0x18]
00007FF751DB85EC F90017F7 str x23,[sp,#0x28]
00007FF751DB85F0 A9037BFD stp fp,lr,[sp,#0x30]
00007FF751DB85F4 9100C3FD add fp,sp,#0x30
00007FF751DB85F8 D28D2903 mov x3,#0x6948
00007FF751DB85FC F2A40583 movk x3,#0x202C,lsl #0x10
00007FF751DB8600 F2CDEDA3 movk x3,#0x6F6D,lsl #0x20
00007FF751DB8604 F2E42DA3 movk x3,#0x216D,lsl #0x30
00007FF751DB8608 F81D03A3 stur x3,[fp,#-0x30]
00007FF751DB860C AA0003F3 mov x19,x0
00007FF751DB8610 2A0103F4 mov w20,w1
00007FF751DB8614 2A0203F5 mov w21,w2
00007FF751DB8618 39416E60 ldrb w0,[x19,#0x5B]
00007FF751DB861C 35001040 cbnz w0,S_P_CoreLib_System_IO_StreamWriter__Flush_0+244h (07FF751DB8824h)
// Perf boost for Flush on non-dirty writers.
if (_charPos == 0 && !flushStream && !flushEncoder)
00007FF751DB8620 B9405260 ldr w0,[x19,#0x50]
00007FF751DB8624 53001E81 uxtb w1,w20
00007FF751DB8628 2A010000 orr w0,w0,w1
00007FF751DB862C 53001EA1 uxtb w1,w21
00007FF751DB8630 2A010000 orr w0,w0,w1
00007FF751DB8634 35000200 cbnz w0,S_P_CoreLib_System_IO_StreamWriter__Flush_0+94h (07FF751DB8674h)
{
return;
00007FF751DB8638 D28D2909 mov x9,#0x6948
00007FF751DB863C F2A40589 movk x9,#0x202C,lsl #0x10
00007FF751DB8640 F2CDEDA9 movk x9,#0x6F6D,lsl #0x20
00007FF751DB8644 F2E42DA9 movk x9,#0x216D,lsl #0x30
00007FF751DB8648 F85D03AA ldur x10,[fp,#-0x30]
00007FF751DB864C EB0A013F cmp x9,x10
00007FF751DB8650 54000040 beq S_P_CoreLib_System_IO_StreamWriter__Flush_0+78h (07FF751DB8658h)
00007FF751DB8654 97DFCA9B bl RhpFallbackFailFast (07FF7515AB0C0h)
00007FF751DB8658 D100C3BF sub sp,fp,#0x30
00007FF751DB865C A9437BFD ldp fp,lr,[sp,#0x30]
00007FF751DB8660 F94017F7 ldr x23,[sp,#0x28]
00007FF751DB8664 A941DBF5 ldp x21,x22,[sp,#0x18]
00007FF751DB8668 A940D3F3 ldp x19,x20,[sp,#8]
00007FF751DB866C 910103FF add sp,sp,#0x40
00007FF751DB8670 D65F03C0 ret
}
if (!_haveWrittenPreamble)
00007FF751DB8674 39416660 ldrb w0,[x19,#0x59]
00007FF751DB8678 35000220 cbnz w0,S_P_CoreLib_System_IO_StreamWriter__Flush_0+0DCh (07FF751DB86BCh)
{
_haveWrittenPreamble = true;
00007FF751DB867C 52800020 mov w0,#1
00007FF751DB8680 39016660 strb w0,[x19,#0x59]
00007FF751DB8684 F9401660 ldr x0,[x19,#0x28]
00007FF751DB8688 F9400001 ldr x1,[x0]
00007FF751DB868C F9402021 ldr x1,[x1,#0x40]
00007FF751DB8690 D63F0020 blr x1
00007FF751DB8694 AA0003E2 mov x2,x0
00007FF751DB8698 2A0103E3 mov w3,w1
ReadOnlySpan<byte> preamble = _encoding.Preamble;
if (preamble.Length > 0)
00007FF751DB869C 7100007F cmp w3,#0
00007FF751DB86A0 540000ED ble S_P_CoreLib_System_IO_StreamWriter__Flush_0+0DCh (07FF751DB86BCh)
{
_stream.Write(preamble);
00007FF751DB86A4 F9401260 ldr x0,[x19,#0x20]
00007FF751DB86A8 AA0203E1 mov x1,x2
00007FF751DB86AC 2A0303E2 mov w2,w3
00007FF751DB86B0 F9400003 ldr x3,[x0]
00007FF751DB86B4 F940A063 ldr x3,[x3,#0x140]
00007FF751DB86B8 D63F0060 blr x3
}
}
// For sufficiently small char data being flushed, try to encode to the stack.
// For anything else, fall back to allocating the byte[] buffer.
Span<byte> byteBuffer = stackalloc byte[0];
00007FF751DB86BC F9401E60 ldr x0,[x19,#0x38]
00007FF751DB86C0 B4000100 cbz x0,S_P_CoreLib_System_IO_StreamWriter__Flush_0+100h (07FF751DB86E0h)
if (_byteBuffer is not null)
{
byteBuffer = _byteBuffer;
00007FF751DB86C4 B5000080 cbnz x0,S_P_CoreLib_System_IO_StreamWriter__Flush_0+0F4h (07FF751DB86D4h)
00007FF751DB86C8 AA1F03F6 mov x22,xzr
00007FF751DB86CC 2A1F03F7 mov w23,wzr
00007FF751DB86D0 14000003 b S_P_CoreLib_System_IO_StreamWriter__Flush_0+0FCh (07FF751DB86DCh)
00007FF751DB86D4 91004016 add x22,x0,#0x10
00007FF751DB86D8 B9400817 ldr w23,[x0,#8]
00007FF751DB86DC 1400001C b S_P_CoreLib_System_IO_StreamWriter__Flush_0+16Ch (07FF751DB874Ch)
}
else
{
int maxBytesForCharPos = _encoding.GetMaxByteCount(_charPos);
byteBuffer = maxBytesForCharPos <= 1024 ? // arbitrary threshold
00007FF751DB86E0 F9401660 ldr x0,[x19,#0x28]
00007FF751DB86E4 B9405261 ldr w1,[x19,#0x50]
00007FF751DB86E8 F9400002 ldr x2,[x0]
00007FF751DB86EC F940B442 ldr x2,[x2,#0x168]
00007FF751DB86F0 D63F0040 blr x2
00007FF751DB86F4 7110001F cmp w0,#0x400
00007FF751DB86F8 540000CC bgt S_P_CoreLib_System_IO_StreamWriter__Flush_0+130h (07FF751DB8710h)
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////
////
//// AV at the next instruction
////
////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
00007FF751DB86FC B94403FF ldr wzr,[sp,#0x400]
00007FF751DB8700 D11003FF sub sp,sp,#0x400
00007FF751DB8704 910003F6 mov x22,sp
00007FF751DB8708 52808017 mov w23,#0x400
00007FF751DB870C 14000010 b S_P_CoreLib_System_IO_StreamWriter__Flush_0+16Ch (07FF751DB874Ch)
00007FF751DB8710 F9401660 ldr x0,[x19,#0x28]
00007FF751DB8714 F9402261 ldr x1,[x19,#0x40]
00007FF751DB8718 B9400821 ldr w1,[x1,#8]
00007FF751DB871C F9400002 ldr x2,[x0]
00007FF751DB8720 F940B442 ldr x2,[x2,#0x168]
00007FF751DB8724 D63F0040 blr x2
00007FF751DB8728 93407C01 sxtw x1,w0
00007FF751DB872C F000DD60 adrp x0,__Array<System_ComponentModel_System_ComponentModel_IEditableObject>::`vftable'+40h (07FF753967000h)
00007FF751DB8730 91304000 add x0,x0,#0xC10
00007FF751DB8734 97DFC140 bl RhpNewArray (07FF7515A8C34h)
00007FF751DB8738 9100E26E add x14,x19,#0x38
00007FF751DB873C AA0003EF mov x15,x0
00007FF751DB8740 94285230 bl RhpAssignRefAVLocation (07FF7527CD000h)
00007FF751DB8744 91004016 add x22,x0,#0x10
00007FF751DB8748 B9400817 ldr w23,[x0,#8]
00007FF751DB874C F9401A60 ldr x0,[x19,#0x30]
00007FF751DB8750 F9402261 ldr x1,[x19,#0x40]
00007FF751DB8754 B9405262 ldr w2,[x19,#0x50]
00007FF751DB8758 B50000A1 cbnz x1,S_P_CoreLib_System_IO_StreamWriter__Flush_0+18Ch (07FF751DB876Ch)
00007FF751DB875C 350006A2 cbnz w2,S_P_CoreLib_System_IO_StreamWriter__Flush_0+250h (07FF751DB8830h)
00007FF751DB8760 AA1F03E1 mov x1,xzr
00007FF751DB8764 2A1F03E2 mov w2,wzr
00007FF751DB8768 14000006 b S_P_CoreLib_System_IO_StreamWriter__Flush_0+1A0h (07FF751DB8780h)
00007FF751DB876C B9400823 ldr w3,[x1,#8]
00007FF751DB8770 2A0203E4 mov w4,w2
00007FF751DB8774 EB04007F cmp x3,x4
00007FF751DB8778 540005C3 blo S_P_CoreLib_System_IO_StreamWriter__Flush_0+250h (07FF751DB8830h)
00007FF751DB877C 91004021 add x1,x1,#0x10
00007FF751DB8780 AA1603E3 mov x3,x22
00007FF751DB8784 2A1703E4 mov w4,w23
00007FF751DB8788 53001EA5 uxtb w5,w21
00007FF751DB878C F9400006 ldr x6,[x0]
00007FF751DB8790 F9402CC6 ldr x6,[x6,#0x58]
00007FF751DB8794 D63F00C0 blr x6
stackalloc byte[1024] :
(_byteBuffer = new byte[_encoding.GetMaxByteCount(_charBuffer.Length)]);
}
int count = _encoder.GetBytes(new ReadOnlySpan<char>(_charBuffer, 0, _charPos), byteBuffer, flushEncoder);
_charPos = 0;
00007FF751DB8798 B900527F str wzr,[x19,#0x50]
if (count > 0)
00007FF751DB879C 7100001F cmp w0,#0
00007FF751DB87A0 5400018D ble S_P_CoreLib_System_IO_StreamWriter__Flush_0+1F0h (07FF751DB87D0h)
{
_stream.Write(byteBuffer.Slice(0, count));
00007FF751DB87A4 F9401263 ldr x3,[x19,#0x20]
00007FF751DB87A8 2A0003E1 mov w1,w0
00007FF751DB87AC 2A1703E2 mov w2,w23
00007FF751DB87B0 EB02003F cmp x1,x2
00007FF751DB87B4 540003E8 bhi S_P_CoreLib_System_IO_StreamWriter__Flush_0+250h (07FF751DB8830h)
00007FF751DB87B8 AA1603E1 mov x1,x22
00007FF751DB87BC 2A0003E2 mov w2,w0
00007FF751DB87C0 AA0303E0 mov x0,x3
00007FF751DB87C4 F9400063 ldr x3,[x3]
00007FF751DB87C8 F940A063 ldr x3,[x3,#0x140]
00007FF751DB87CC D63F0060 blr x3
}
if (flushStream)
00007FF751DB87D0 72001E9F tst w20,#0xFF
00007FF751DB87D4 540000A0 beq S_P_CoreLib_System_IO_StreamWriter__Flush_0+208h (07FF751DB87E8h)
{
_stream.Flush();
00007FF751DB87D8 F9401260 ldr x0,[x19,#0x20]
00007FF751DB87DC F9400001 ldr x1,[x0]
00007FF751DB87E0 F9405C21 ldr x1,[x1,#0xB8]
00007FF751DB87E4 D63F0020 blr x1
}
}
00007FF751DB87E8 D28D2909 mov x9,#0x6948
00007FF751DB87EC F2A40589 movk x9,#0x202C,lsl #0x10
00007FF751DB87F0 F2CDEDA9 movk x9,#0x6F6D,lsl #0x20
00007FF751DB87F4 F2E42DA9 movk x9,#0x216D,lsl #0x30
00007FF751DB87F8 F85D03AA ldur x10,[fp,#-0x30]
00007FF751DB87FC EB0A013F cmp x9,x10
00007FF751DB8800 54000040 beq S_P_CoreLib_System_IO_StreamWriter__Flush_0+228h (07FF751DB8808h)
00007FF751DB8804 97DFCA2F bl RhpFallbackFailFast (07FF7515AB0C0h)
00007FF751DB8808 D100C3BF sub sp,fp,#0x30
00007FF751DB880C A9437BFD ldp fp,lr,[sp,#0x30]
00007FF751DB8810 F94017F7 ldr x23,[sp,#0x28]
00007FF751DB8814 A941DBF5 ldp x21,x22,[sp,#0x18]
00007FF751DB8818 A940D3F3 ldp x19,x20,[sp,#8]
00007FF751DB881C 910103FF add sp,sp,#0x40
00007FF751DB8820 D65F03C0 ret
}
private void Flush(bool flushStream, bool flushEncoder)
{
// flushEncoder should be true at the end of the file and if
// the user explicitly calls Flush (though not if AutoFlush is true).
// This is required to flush any dangling characters from our UTF-7
// and UTF-8 encoders.
ThrowIfDisposed();
00007FF751DB8824 AA1303E0 mov x0,x19
00007FF751DB8828 940005D2 bl S_P_CoreLib_System_IO_StreamWriter___ThrowIfDisposed_g__ThrowObjectDisposedException_76_0 (07FF751DB9F70h)
00007FF751DB882C D43E0000 brk #0xF000
{
_stream.Write(byteBuffer.Slice(0, count));
00007FF751DB8830 97FD31A8 bl S_P_CoreLib_System_ThrowHelper__ThrowArgumentOutOfRangeException (07FF751D04ED0h)
00007FF751DB8834 D43E0000 brk #0xF000
The SP looks legit at the time of crash and the relative address seems to be on the next page but for some reason it doesn't appear to be triggering the guard page logic within the OS and we get an AV instead.
Looking at __chkstk implementation in the VC++ runtime it seems to be touching things at page-aligned boundaries instead of just blindly reaching into the middle of the next page 4 kB away from the current SP. Aligning to the page boundary looks like "unnecessary extra work" so maybe it has a meaning.
Crash dump, symbols, and EXE here: https://github.com/MichalStrehovsky/NativeAOT5/releases/download/vBlah/System.Runtime.Tests.zip
Note this is NativeAOT, so no SOS extensions needed, and the EXE is fully self contained and can be executed under debugger as-is. The issue is non-deterministic and happens before anything gets written to the console. Once you see console output, you missed it.