Files
spoopyghosty0--frameport/tests/test_audio_geometry.py
T
spoopyghosty0 feb4658dde Batman audio hooks: publish detours with one atomic branch (#389, #34)
The detour helper from PR #34 (used by the metadata hook and PR #389's two geometry hooks) wrote a 16-byte
branch + literal in two steps while game threads may run the function (installation is retried from
xrPollEvent). Each hook now publishes a single aligned release-atomic AArch64 B to a stub within +-128 MiB;
the trampoline replays the one verified instruction and returns to entry+4. Every mprotect is checked;
failures before publication free the stub and trampoline and leave the function untouched; no stub in range =
no hook. Adapter artifacts rebuilt by us (the PR's binary isn't shipped).
2026-10-17 16:47:06 -04:00

56 lines
2.8 KiB
Python

"""Batman audio ownership and the scope of the adapter update."""
import os
import shutil
import subprocess
import sys
from pathlib import Path
import pytest
@pytest.mark.parametrize("fixture", ["audio_geometry_test.c", "audio_geometry_target_test.c", "audio_detour_test.c"])
def test_audio_geometry_native(tmp_path, fixture):
cc = shutil.which("cc") or shutil.which("gcc") or shutil.which("clang")
if not cc or os.name == "nt":
pytest.skip("Native ownership regression requires a POSIX C compiler with pthreads")
if fixture == "audio_geometry_target_test.c" and sys.platform != "linux":
pytest.skip("Installer regression models Linux ELF loading")
root = Path(__file__).resolve().parents[1]
binary = tmp_path / "audio-geometry-test"
subprocess.run([cc, "-std=c11", "-Wall", "-Wextra", "-Werror", "-pthread",
"-I", str(root / "native/adapter"),
str(root / "tests/fixtures/src" / fixture), "-o", str(binary)], check=True)
subprocess.run([str(binary)], check=True)
def test_audio_geometry_update_outdates_batman_only(monkeypatch):
from frameport.patches.base import get, recipe_fingerprint
patch = get("frame.adapter")
recipe = {"patches": {"frame.adapter": {}}}
packages = ("com.camouflaj.manta", "com.Armature.VR4", "com.crytek.climb2", "com.example.other")
current = {p: recipe_fingerprint(recipe, p) for p in packages}
assert patch.revision_for(packages[0]) == 3
assert all(patch.revision_for(p) == 2 for p in packages[1:])
monkeypatch.setattr(patch, "package_revisions", {})
assert current[packages[0]] != recipe_fingerprint(recipe, packages[0])
assert all(current[p] == recipe_fingerprint(recipe, p) for p in packages[1:])
def test_audio_geometry_allocation_triage_is_specific_to_batman():
from frameport.validate.triage import triage
log = ("package com.camouflaj.manta\n"
"E Unity : Could not allocate memory: System out of memory!\n"
"E Unity : Trying to allocate: 26388238103B with 16 alignment. MemoryLabel: NativePlugin\n"
"E Unity : Allocation happened at: MetaXRAudioUnityMemoryAllocator.cpp\n"
"F libc : Fatal signal 5 (SIGTRAP)\n")
result = triage(log, "EXITED")
finding = next(f for f in result.findings if f.id == "batman-audio-geometry-allocation")
assert finding.severity == "fatal" and finding.suggest == ["frame.adapter"]
assert "native-crash" not in {f.id for f in result.findings}
for ordinary in (log.replace("com.camouflaj.manta", "com.example.other"),
log.replace("26388238103B", "4096B"),
log.replace("MetaXRAudioUnityMemoryAllocator.cpp", "OtherAllocator.cpp")):
assert "batman-audio-geometry-allocation" not in {f.id for f in triage(ordinary, "EXITED").findings}