fix: stabilize full-handler oracle fixtures

This commit is contained in:
yusufcanislek
2026-04-01 06:55:56 +03:00
parent 773e30f23c
commit 460e845aed
6 changed files with 113 additions and 6 deletions
+1
View File
@@ -57,6 +57,7 @@ Use `run_microtests.cmd --check-flags <filter>` to enforce oracle flag compariso
Use `run_microtests.cmd --build <filter>` to force rebuilding `rewrite_microtests.exe`, or `run_microtests.cmd --no-build <filter>` to skip any build step.
Set `SKIP_ORACLE_GENERATION=1` to reuse a pre-generated oracle file. Set `MERGEN_TEST_VECTORS=<path>` to point tests at a custom oracle JSON file.
Use `run_all_handlers.cmd` to exercise full handler coverage smoke tests. It writes `lifter/test_vectors/oracle_vectors_full_handlers.json` and then runs microtests against it through `run_microtests.cmd` (which now builds lazily).
Oracle vector JSON fixtures are deterministic by design; regenerating them should only change tracked files when the underlying cases change, not because of wall-clock metadata.
Full-handler vectors are expected to execute end-to-end (no default `skip: true` crash exclusions).
Use `run_flagstress.cmd` (or `python test.py flags`) for broad strict-flag validation across all handlers that explicitly write flags.
Use `python test.py semantic` to run runtime semantic regression for all samples (accepts `--filter` to narrow scope and `--input-ir` to override the IR file for a single sample).
@@ -1,6 +1,5 @@
{
"schema": "mergen-oracle-v1",
"generated_at_utc": "2026-03-23T01:08:54.375218+00:00",
"source_seed_schema": "mergen-oracle-seed-v1",
"providers": [
"unicorn"
@@ -1,6 +1,5 @@
{
"schema": "mergen-oracle-v1",
"generated_at_utc": "2026-03-23T02:39:45.593139+00:00",
"source_seed_schema": "mergen-oracle-seed-v1",
"providers": [
"unicorn"
@@ -4493,6 +4492,40 @@
}
}
},
{
"name": "smoke_scasx_scasq",
"handler": "scasx",
"oracle_mode": "none",
"instruction_bytes": [
73,
175
],
"initial": {
"registers": {
"RAX": "0x1122334455667788",
"RBX": "0x8877665544332211",
"RCX": "0x10",
"RDX": "0x2"
},
"flags": {
"FLAG_CF": 0,
"FLAG_PF": 0,
"FLAG_AF": 0,
"FLAG_ZF": 0,
"FLAG_SF": 0,
"FLAG_OF": 0,
"FLAG_DF": 0,
"FLAG_IF": 1
}
},
"expected": {
"registers": {},
"flags": {}
},
"oracle_observations": {},
"skip": true,
"skip_reason": "memory operand in 'scasq rax, qword ptr [rdi]'; needs mapped memory for emulation"
},
{
"name": "smoke_setb_setb",
"handler": "setb",
+12 -4
View File
@@ -4,7 +4,6 @@ import importlib
import json
import sys
from dataclasses import dataclass
from datetime import datetime, timezone
from pathlib import Path
from typing import Dict, List, Tuple
@@ -176,6 +175,12 @@ def load_seed(path: Path) -> dict:
return payload
def _format_register_hex(reg_name: str, value: int) -> str:
if reg_name.upper().startswith("XMM"):
return f"0x{value:032x}"
return f"0x{value:x}"
def normalize_expected(case: dict, oracle_result: OracleResult) -> dict:
expected = case.get("expected", {})
out = {
@@ -184,7 +189,9 @@ def normalize_expected(case: dict, oracle_result: OracleResult) -> dict:
}
for reg_name in expected.get("registers", {}).keys():
out["registers"][reg_name] = f"0x{oracle_result.registers[reg_name]:x}"
out["registers"][reg_name] = _format_register_hex(
reg_name, oracle_result.registers[reg_name]
)
for flag_name in expected.get("flags", {}).keys():
out["flags"][flag_name] = int(oracle_result.flags[flag_name])
@@ -218,9 +225,10 @@ def compare_results(results: Dict[str, OracleResult], case_name: str, *, strict:
def build_output(seed_payload: dict, provider_names: List[str], output_cases: List[dict]) -> dict:
# These oracle fixtures are checked into the repo, so wall-clock metadata
# would create meaningless diffs on every regeneration.
return {
"schema": "mergen-oracle-v1",
"generated_at_utc": datetime.now(timezone.utc).isoformat(),
"source_seed_schema": seed_payload["schema"],
"providers": provider_names,
"cases": output_cases,
@@ -371,7 +379,7 @@ def main():
"oracle_observations": {
provider_name: {
"registers": {
reg: f"0x{value:x}"
reg: _format_register_hex(reg, value)
for reg, value in result.registers.items()
},
"flags": result.flags,
@@ -3412,6 +3412,38 @@
"oracle": "none",
"source": "capstone-auto-discovery"
},
{
"name": "smoke_scasx_scasq",
"handler": "scasx",
"instruction_bytes": [
73,
175
],
"initial": {
"registers": {
"RAX": "0x1122334455667788",
"RBX": "0x8877665544332211",
"RCX": "0x10",
"RDX": "0x2"
},
"flags": {
"FLAG_CF": 0,
"FLAG_PF": 0,
"FLAG_AF": 0,
"FLAG_ZF": 0,
"FLAG_SF": 0,
"FLAG_OF": 0,
"FLAG_DF": 0,
"FLAG_IF": 1
}
},
"expected": {
"registers": {},
"flags": {}
},
"oracle": "none",
"source": "capstone-auto-discovery"
},
{
"name": "smoke_setb_setb",
"handler": "setb",
@@ -3786,6 +3786,40 @@
"oracle": "unicorn",
"source": "capstone-auto-discovery"
},
{
"name": "smoke_scasx_scasq",
"handler": "scasx",
"instruction_bytes": [
73,
175
],
"initial": {
"registers": {
"RAX": "0x1122334455667788",
"RBX": "0x8877665544332211",
"RCX": "0x10",
"RDX": "0x2"
},
"flags": {
"FLAG_CF": 0,
"FLAG_PF": 0,
"FLAG_AF": 0,
"FLAG_ZF": 0,
"FLAG_SF": 0,
"FLAG_OF": 0,
"FLAG_DF": 0,
"FLAG_IF": 1
}
},
"expected": {
"registers": {},
"flags": {}
},
"oracle": "none",
"source": "capstone-auto-discovery",
"skip": true,
"skip_reason": "memory operand in 'scasq rax, qword ptr [rdi]'; needs mapped memory for emulation"
},
{
"name": "smoke_setb_setb",
"handler": "setb",