[AudioOut2] Write a single size_t from sceAudioOut2ContextQueryMemory
The export returns the context memory size through one size_t. For heap output it also wrote a second qword (an alignment) after it, and titles keep other locals there: Octopath Traveler II's allocator reads the dword at +12 of that block as a divisor, so it faulted with #DE during boot. Write only the size, wherever the output lives.
This commit is contained in:
parent
4d65ff6d51
commit
066df8e754
|
|
@ -247,31 +247,13 @@ public static class AudioOut2Exports
|
|||
contextMemorySize = checked(0x10000UL + (queueDepth * 0x590UL));
|
||||
}
|
||||
|
||||
// Heap: {size, alignment} (16 bytes), matching sceAudioPropagationSystemQueryMemory.
|
||||
// Stack: SIZE ONLY as a full ulong (8 bytes). Writing alignment at +8 is how
|
||||
// [rbp-0x30] became 0x100 on GTA V Enhanced. Do NOT shrink this to uint32 —
|
||||
// Main reads the out as a 64-bit size; a 4-byte write leaves a garbage high
|
||||
// dword (observed 0x7<<32|0x4000) and the allocator aborts with int 0x41.
|
||||
if (IsGuestStackAddress(memoryInfoAddress))
|
||||
{
|
||||
Span<byte> sizeOnly = stackalloc byte[sizeof(ulong)];
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(sizeOnly, contextMemorySize);
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] audio_out2.context-query-memory stack-size-only " +
|
||||
$"out=0x{memoryInfoAddress:X} size=0x{contextMemorySize:X}");
|
||||
return ctx.Memory.TryWrite(memoryInfoAddress, sizeOnly)
|
||||
? SetReturn(ctx, 0)
|
||||
: SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||
}
|
||||
|
||||
Span<byte> memoryInfo = stackalloc byte[0x10];
|
||||
memoryInfo.Clear();
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(memoryInfo[0x00..], contextMemorySize);
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(memoryInfo[0x08..], AudioOut2ContextMemoryAlignment);
|
||||
// The output is a single size_t wherever it lives. Titles keep other locals right after it
|
||||
// (Octopath Traveler II divides by the dword at +12), so nothing else may be written.
|
||||
Span<byte> memorySize = stackalloc byte[sizeof(ulong)];
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(memorySize, contextMemorySize);
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] audio_out2.context-query-memory out=0x{memoryInfoAddress:X} " +
|
||||
$"size=0x{contextMemorySize:X} align=0x{AudioOut2ContextMemoryAlignment:X}");
|
||||
return ctx.Memory.TryWrite(memoryInfoAddress, memoryInfo)
|
||||
$"[LOADER][TRACE] audio_out2.context-query-memory out=0x{memoryInfoAddress:X} size=0x{contextMemorySize:X}");
|
||||
return ctx.Memory.TryWrite(memoryInfoAddress, memorySize)
|
||||
? SetReturn(ctx, 0)
|
||||
: SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
using System.Buffers.Binary;
|
||||
using SharpEmu.HLE;
|
||||
using SharpEmu.Libs.Audio;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpEmu.Libs.Tests.Audio;
|
||||
|
||||
public sealed class AudioOut2ContextQueryMemoryTests
|
||||
{
|
||||
private const ulong MemoryBase = 0x1_0000_0000;
|
||||
private const ulong ParamAddress = MemoryBase + 0x100;
|
||||
private const ulong SizeAddress = MemoryBase + 0x200;
|
||||
|
||||
[Fact]
|
||||
public void ContextQueryMemory_WritesOneSizeAndNothingAfterIt()
|
||||
{
|
||||
var memory = new FakeCpuMemory(MemoryBase, 0x1000);
|
||||
var ctx = new CpuContext(memory, Generation.Gen5);
|
||||
Span<byte> param = stackalloc byte[0x40];
|
||||
param.Clear();
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(param[0x0C..], 8);
|
||||
Assert.True(memory.TryWrite(ParamAddress, param));
|
||||
Span<byte> paint = stackalloc byte[0x20];
|
||||
paint.Fill(0xAB);
|
||||
Assert.True(memory.TryWrite(SizeAddress, paint));
|
||||
|
||||
ctx[CpuRegister.Rdi] = ParamAddress;
|
||||
ctx[CpuRegister.Rsi] = SizeAddress;
|
||||
|
||||
Assert.Equal(0, AudioOut2Exports.AudioOut2ContextQueryMemory(ctx));
|
||||
Span<byte> written = stackalloc byte[0x20];
|
||||
Assert.True(memory.TryRead(SizeAddress, written));
|
||||
Assert.Equal(0x10000UL + (8 * 0x590UL), BinaryPrimitives.ReadUInt64LittleEndian(written));
|
||||
// The caller's locals after the size_t stay untouched.
|
||||
Assert.True(written[8..].ToArray().All(static value => value == 0xAB));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue