From 0666071f7925f8fd41d52757906087c9a240c5c1 Mon Sep 17 00:00:00 2001 From: ParantezTech <12572227+par274@users.noreply.github.com> Date: Fri, 9 Oct 2026 01:27:52 +0300 Subject: [PATCH] [Tests] Cover backward red-zone spans, direct memory no-space results and the mount info size --- .../Kernel/KernelMemoryCompatExportsTests.cs | 44 ++++++++++++++++ .../Loader/GuestRedZonePatcherTests.cs | 51 +++++++++++++++---- .../SaveData/SaveDataExportsTests.cs | 19 +++++++ 3 files changed, 104 insertions(+), 10 deletions(-) diff --git a/tests/SharpEmu.Libs.Tests/Kernel/KernelMemoryCompatExportsTests.cs b/tests/SharpEmu.Libs.Tests/Kernel/KernelMemoryCompatExportsTests.cs index df2817c..6ca7bbe 100644 --- a/tests/SharpEmu.Libs.Tests/Kernel/KernelMemoryCompatExportsTests.cs +++ b/tests/SharpEmu.Libs.Tests/Kernel/KernelMemoryCompatExportsTests.cs @@ -436,6 +436,50 @@ public sealed class KernelMemoryCompatExportsTests } } + [Fact] + public void AvailableDirectMemorySize_FullRangeClearsOutputsAndReportsNoSpace() + { + const ulong allocationStart = 0; + const ulong allocationLength = 0x0040_0000; + var context = new CpuContext(new FakeCpuMemory(GuestMemoryBase, 0x1000), Generation.Gen5); + + try + { + AllocateDirectMemory(context, allocationStart, allocationLength); + Assert.True(context.TryWriteUInt64(SpanStartOutAddress, 0xDEAD_BEEF)); + Assert.True(context.TryWriteUInt64(SpanSizeOutAddress, 0xDEAD_BEEF)); + + context[CpuRegister.Rdi] = allocationStart; + context[CpuRegister.Rsi] = allocationStart + allocationLength; + context[CpuRegister.Rdx] = 0; + context[CpuRegister.Rcx] = SpanStartOutAddress; + context[CpuRegister.R8] = SpanSizeOutAddress; + + Assert.Equal(unchecked((int)0x8002000C), KernelMemoryCompatExports.KernelAvailableDirectMemorySize(context)); + Assert.True(context.TryReadUInt64(SpanStartOutAddress, out var spanStart)); + Assert.True(context.TryReadUInt64(SpanSizeOutAddress, out var spanSize)); + Assert.Equal(0UL, spanStart); + Assert.Equal(0UL, spanSize); + } + finally + { + ReleaseDirectMemory(context, allocationStart, allocationLength); + } + } + + [Fact] + public void AvailableDirectMemorySize_EmptySearchRangeReportsNoSpace() + { + var context = new CpuContext(new FakeCpuMemory(GuestMemoryBase, 0x1000), Generation.Gen5); + context[CpuRegister.Rdi] = 0x0010_0000; + context[CpuRegister.Rsi] = 0x0010_0000; + context[CpuRegister.Rdx] = 0; + context[CpuRegister.Rcx] = SpanStartOutAddress; + context[CpuRegister.R8] = SpanSizeOutAddress; + + Assert.Equal(unchecked((int)0x8002000C), KernelMemoryCompatExports.KernelAvailableDirectMemorySize(context)); + } + private static void AllocateDirectMemory(CpuContext context, ulong start, ulong length, ulong outputAddress = AllocationOutAddress) { context[CpuRegister.Rdi] = start; diff --git a/tests/SharpEmu.Libs.Tests/Loader/GuestRedZonePatcherTests.cs b/tests/SharpEmu.Libs.Tests/Loader/GuestRedZonePatcherTests.cs index 55de7c7..82f7105 100644 --- a/tests/SharpEmu.Libs.Tests/Loader/GuestRedZonePatcherTests.cs +++ b/tests/SharpEmu.Libs.Tests/Loader/GuestRedZonePatcherTests.cs @@ -191,7 +191,7 @@ public sealed class GuestRedZonePatcherTests } [Fact] - public unsafe void LeavesShortAccessUnchangedWhenNextInstructionIsBranchTarget() + public unsafe void PatchesShortAccessBeforeBranchTargetFromThePreviousInstruction() { if (RuntimeInformation.ProcessArchitecture != Architecture.X64) return; @@ -199,14 +199,45 @@ public sealed class GuestRedZonePatcherTests var argument = OperatingSystem.IsWindows() ? (byte)0x91 : (byte)0x97; byte[] function = [ - 0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // mov rax, value - 0x48, 0x89, 0x44, 0x24, 0xF8, // mov [rsp-8], rax - 0x48, 0x8D, argument, 0x00, 0x20, 0x00, 0x00, // lea rdx, [arg+0x2000] - 0xB8, 0xFE, 0xFF, 0xFF, 0xFF, // mov eax, 0xFFFFFFFE - 0x21, 0x02, // and [rdx], eax - 0x48, 0x8B, 0x44, 0x24, 0xF8, // target: mov rax, [rsp-8] - 0xC3, // ret - 0xEB, 0xF8, // jmp target + 0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, + 0x48, 0x89, 0x44, 0x24, 0xF8, + 0x48, 0x8D, argument, 0x00, 0x20, 0x00, 0x00, + 0xB8, 0xFE, 0xFF, 0xFF, 0xFF, + 0x21, 0x02, + 0x48, 0x8B, 0x44, 0x24, 0xF8, + 0xC3, + 0xEB, 0xF8, + ]; + + using var image = PatchedImage.Create(function, [(0x2000, 7u)]); + if (OperatingSystem.IsWindows() || OperatingSystem.IsMacOS()) + { + Assert.Equal(1, image.Result.PatchedSites); + Assert.Equal(0xE9, image.ReadByte(22)); + } + + Assert.Equal(0x1122_3344_5566_7788UL, ((delegate* unmanaged)image.Base)(image.Base)); + Assert.Equal(6u, image.ReadUInt32(0x2000)); + } + + [Fact] + public unsafe void LeavesShortAccessBeforeBranchTargetUnchangedWhenAnIndirectBranchIsUnresolved() + { + if (RuntimeInformation.ProcessArchitecture != Architecture.X64) + return; + + var argument = OperatingSystem.IsWindows() ? (byte)0x91 : (byte)0x97; + byte[] function = + [ + 0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, + 0x48, 0x89, 0x44, 0x24, 0xF8, + 0x48, 0x8D, argument, 0x00, 0x20, 0x00, 0x00, + 0xB8, 0xFE, 0xFF, 0xFF, 0xFF, + 0x21, 0x02, + 0x48, 0x8B, 0x44, 0x24, 0xF8, + 0xC3, + 0xEB, 0xF8, + 0xFF, 0xE0, ]; using var image = PatchedImage.Create(function, [(0x2000, 7u)]); @@ -215,7 +246,7 @@ public sealed class GuestRedZonePatcherTests { Assert.Equal(1, image.Result.RedZoneFunctions); Assert.Equal(1, image.Result.UnrelocatableSites); - Assert.Equal(1, image.Result.BranchTargetRefusals); + Assert.Equal(1, image.Result.IndirectBranchRefusals); } for (var index = 0; index < function.Length; index++) diff --git a/tests/SharpEmu.Libs.Tests/SaveData/SaveDataExportsTests.cs b/tests/SharpEmu.Libs.Tests/SaveData/SaveDataExportsTests.cs index 4ae3e75..93f9147 100644 --- a/tests/SharpEmu.Libs.Tests/SaveData/SaveDataExportsTests.cs +++ b/tests/SharpEmu.Libs.Tests/SaveData/SaveDataExportsTests.cs @@ -247,6 +247,25 @@ public sealed class SaveDataExportsTests : IDisposable Assert.Equal(16382UL, freeBlocks); } + [Fact] + public void GetMountInfo_WritesOnlyTheGuestStructure() + { + Assert.Equal(0, Mount()); + WriteAscii(MountPointStr, MountPoint); + Span sentinel = stackalloc byte[0x10]; + sentinel.Fill(0xCD); + Assert.True(_memory.TryWrite(MountInfo + 0x30, sentinel)); + + Assert.Equal( + 0, + SaveDataExports.SaveDataGetMountInfo( + Reg(rdi: MountPointStr, rsi: MountInfo))); + + Span after = stackalloc byte[0x10]; + Assert.True(_memory.TryRead(MountInfo + 0x30, after)); + Assert.True(after.SequenceEqual(sentinel)); + } + [Fact] public void DirNameSearch_ReportsBlockCapacityAndRemainingBlocks() {