qvm: recover method counter updates
Browse files- docs/ASSET_PIPELINE_TODO.md +3 -0
- docs/FINDINGS.md +3 -0
- docs/PROVISIONAL_TODO.md +3 -0
- docs/RESEARCH_LEDGER.md +5 -0
- docs/REVERSE_ENGINEERING_TODO.md +3 -0
- docs/research/QVM_METHOD_STAT_UPDATES.md +7 -0
- docs/research/README.md +3 -0
- docs/research/qvm-method-stat-updates.json +0 -0
- scripts/analyze_qvm_method_stat_updates.py +16 -0
- scripts/qvm_stat_update_support.py +22 -0
- scripts/test_qvm_method_stat_updates.py +30 -0
- xtask/checks.tsv +3 -0
docs/ASSET_PIPELINE_TODO.md
CHANGED
|
@@ -910,3 +910,6 @@ Research progress: RE-748 [report](research/QVM_CLIENT_NOTIFICATIONS.md); origin
|
|
| 910 |
|
| 911 |
|
| 912 |
Research progress: RE-749 [report](research/QVM_METHOD_STAT_SLOTS.md); original assets unchanged.
|
|
|
|
|
|
|
|
|
|
|
|
| 910 |
|
| 911 |
|
| 912 |
Research progress: RE-749 [report](research/QVM_METHOD_STAT_SLOTS.md); original assets unchanged.
|
| 913 |
+
|
| 914 |
+
|
| 915 |
+
Research progress: RE-750 [report](research/QVM_METHOD_STAT_UPDATES.md); original assets unchanged.
|
docs/FINDINGS.md
CHANGED
|
@@ -1256,3 +1256,6 @@ RE-725–734 batch: [health, contact and Rust impulse findings](research/QVM_HEA
|
|
| 1256 |
|
| 1257 |
|
| 1258 |
**RE-749 — Complete method to statistic slot classification:** 278733 maps19 selected methods into statistic slots0..18 using the original jump table; all other tested methods return-1. [Evidence](research/QVM_METHOD_STAT_SLOTS.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 1256 |
|
| 1257 |
|
| 1258 |
**RE-749 — Complete method to statistic slot classification:** 278733 maps19 selected methods into statistic slots0..18 using the original jump table; all other tested methods return-1. [Evidence](research/QVM_METHOD_STAT_SLOTS.md).
|
| 1259 |
+
|
| 1260 |
+
|
| 1261 |
+
**RE-750 — Complete method counter mutation aliases and notifications:** 278834 updates per-method or fallback counters with wrapping increments, distinct self cases, and ordered aggregate/report requests. [Evidence](research/QVM_METHOD_STAT_UPDATES.md).
|
docs/PROVISIONAL_TODO.md
CHANGED
|
@@ -1248,3 +1248,6 @@ Research progress: RE-748 [report](research/QVM_CLIENT_NOTIFICATIONS.md); full n
|
|
| 1248 |
|
| 1249 |
|
| 1250 |
Research progress: RE-749 [report](research/QVM_METHOD_STAT_SLOTS.md); full native/platform/game scope remains open.
|
|
|
|
|
|
|
|
|
|
|
|
| 1248 |
|
| 1249 |
|
| 1250 |
Research progress: RE-749 [report](research/QVM_METHOD_STAT_SLOTS.md); full native/platform/game scope remains open.
|
| 1251 |
+
|
| 1252 |
+
|
| 1253 |
+
Research progress: RE-750 [report](research/QVM_METHOD_STAT_UPDATES.md); full native/platform/game scope remains open.
|
docs/RESEARCH_LEDGER.md
CHANGED
|
@@ -1395,3 +1395,8 @@ Exactly ten task commits follow baseline `e1f7eb5a`. Each task passed focused `c
|
|
| 1395 |
## 2026-10-21 — RE-749 Complete method to statistic slot classification
|
| 1396 |
|
| 1397 |
278733 maps19 selected methods into statistic slots0..18 using the original jump table; all other tested methods return-1. Focused `cargo xtask test-group stat-slots` passes (3 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 19282 bytes. Full-suite validation is deferred to the tenth batch commit. No original assets, Rust runtime or shared VM evaluator changed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1395 |
## 2026-10-21 — RE-749 Complete method to statistic slot classification
|
| 1396 |
|
| 1397 |
278733 maps19 selected methods into statistic slots0..18 using the original jump table; all other tested methods return-1. Focused `cargo xtask test-group stat-slots` passes (3 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 19282 bytes. Full-suite validation is deferred to the tenth batch commit. No original assets, Rust runtime or shared VM evaluator changed.
|
| 1398 |
+
|
| 1399 |
+
|
| 1400 |
+
## 2026-10-21 — RE-750 Complete method counter mutation aliases and notifications
|
| 1401 |
+
|
| 1402 |
+
278834 updates per-method or fallback counters with wrapping increments, distinct self cases, and ordered aggregate/report requests. Focused `cargo xtask test-group stat-updates` passes (3 Python tests); selected reports regenerate twice byte-identically, with storage, links and whitespace guards. New report: 956970 bytes. Full-suite validation is deferred to the tenth batch commit. No original assets, Rust runtime or shared VM evaluator changed.
|
docs/REVERSE_ENGINEERING_TODO.md
CHANGED
|
@@ -1291,3 +1291,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
|
|
| 1291 |
|
| 1292 |
|
| 1293 |
- [x] RE-749 Complete method to statistic slot classification ([report](research/QVM_METHOD_STAT_SLOTS.md)).
|
|
|
|
|
|
|
|
|
|
|
|
| 1291 |
|
| 1292 |
|
| 1293 |
- [x] RE-749 Complete method to statistic slot classification ([report](research/QVM_METHOD_STAT_SLOTS.md)).
|
| 1294 |
+
|
| 1295 |
+
|
| 1296 |
+
- [x] RE-750 Complete method counter mutation aliases and notifications ([report](research/QVM_METHOD_STAT_UPDATES.md)).
|
docs/research/QVM_METHOD_STAT_UPDATES.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Complete method counter mutation aliases and notifications
|
| 2 |
+
|
| 3 |
+
RE-750. Reproduce with `python3 scripts/analyze_qvm_method_stat_updates.py`; validate with `cargo xtask test-group stat-updates`. See the [machine report](qvm-method-stat-updates.json).
|
| 4 |
+
|
| 5 |
+
Recovered complete278834 across205 fixtures with actual278733, every method-1..49, self aliases, absent actor and zero/max counter values. Independent offset and callback oracles cover table/fallback dispatch.279720/279586/285227/283622 internals stay captured; invalid victim/null low-page accesses and semantic stat names remain open.
|
| 6 |
+
|
| 7 |
+
No original executable/full VM/native world collision or rendering runs. Supplied callback/native responses and fixture domains remain explicit; complete macOS/Linux Rust/Bevy/Solari gameplay remains open.
|
docs/research/README.md
CHANGED
|
@@ -846,3 +846,6 @@ The extension collector adds five focused tests for native tail calls, command-r
|
|
| 846 |
|
| 847 |
|
| 848 |
[RE-749: Complete method to statistic slot classification](QVM_METHOD_STAT_SLOTS.md).
|
|
|
|
|
|
|
|
|
|
|
|
| 846 |
|
| 847 |
|
| 848 |
[RE-749: Complete method to statistic slot classification](QVM_METHOD_STAT_SLOTS.md).
|
| 849 |
+
|
| 850 |
+
|
| 851 |
+
[RE-750: Complete method counter mutation aliases and notifications](QVM_METHOD_STAT_UPDATES.md).
|
docs/research/qvm-method-stat-updates.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
scripts/analyze_qvm_method_stat_updates.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Complete278834 counter writes, aliasing and notification requests."""
|
| 3 |
+
import itertools
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from qvm_research_support import source
|
| 6 |
+
from qvm_stat_update_support import seed,update,OFFSETS
|
| 7 |
+
from analyze_qvm import write_json
|
| 8 |
+
|
| 9 |
+
def main():
|
| 10 |
+
q,raw,h,ins=source();rows=[]
|
| 11 |
+
cases=[dict(method=m,self=s,initial=v) for m,s,v in itertools.product([-1,*range(50)],[False,True],[0,0xffffffff])];cases += [dict(method=20,self=False,initial=0,actor_absent=True)]
|
| 12 |
+
for a in cases:
|
| 13 |
+
actor=-1 if a.get('actor_absent') else 1;victim=1 if a['self'] else 2
|
| 14 |
+
_,_,p=update(ins,seed(raw,h,**a),{8:actor,12:a['method'],16:victim});p['input']=a;rows.append(p)
|
| 15 |
+
write_json(Path('docs/research/qvm-method-stat-updates.json'),{'source':q['source'],'sha256':q['sha256'],'tracked_offsets':OFFSETS,'probes':rows,'limits':'Complete278834 finite methods-1..49, actor1/victim2 or self1, absent actor-1, zero/max counters. Actual278733;279720/279586/285227/283622 captured. Invalid victim/null low-page domains excluded; no aggregate/report/native effect execution.'})
|
| 16 |
+
if __name__=='__main__':main()
|
scripts/qvm_stat_update_support.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""278834 counters with actual278733; reporting/aggregate children captured."""
|
| 2 |
+
from qvm_health_effects_support import seed as health_seed,H,CLIENT,A_CLIENT
|
| 3 |
+
from qvm_research_support import constants
|
| 4 |
+
from qvm_trace_support import resume,captured
|
| 5 |
+
from qvm_method_stats_support import method_seed,classify
|
| 6 |
+
from qvm_notification_support import POOL
|
| 7 |
+
T=H+0xf0000
|
| 8 |
+
OFFSETS=sorted(set([856+76*j+k for j in range(19) for k in [60,64]]+list(range(2376,2516,4))))
|
| 9 |
+
|
| 10 |
+
def seed(raw,h,**a):
|
| 11 |
+
m=health_seed(raw,h);m.update(method_seed(raw,h));m.update(constants(raw,h,range(31532,31684,4)));m[POOL+880+520]=A_CLIENT;m[POOL+1760+520]=CLIENT
|
| 12 |
+
for c in [CLIENT,A_CLIENT]:
|
| 13 |
+
for o in OFFSETS:m[c+o]=a.get('initial',0)
|
| 14 |
+
return m
|
| 15 |
+
|
| 16 |
+
def update(ins,m,args):
|
| 17 |
+
for o,v in args.items():m[T+52+o]=v
|
| 18 |
+
addresses=sorted({c+o for c in [CLIENT,A_CLIENT] for o in OFFSETS});before={a:m[a]&0xffffffff for a in addresses};requests=[]
|
| 19 |
+
hs={c:captured(c,requests) for c in [279720,279586,285227,283622]};hs[278733]=classify
|
| 20 |
+
m,e=resume(ins,278835,279584,m,T,handlers=hs)
|
| 21 |
+
changes=[{'client':'actor' if a>=A_CLIENT and a<A_CLIENT+7000 else 'victim','offset':a-(A_CLIENT if a>=A_CLIENT and a<A_CLIENT+7000 else CLIENT),'before':before[a],'after':m[a]&0xffffffff} for a in addresses if before[a]!=(m[a]&0xffffffff)]
|
| 22 |
+
return m,0,{'arguments':args,'changes':changes,'requests':requests,'execution':e}
|
scripts/test_qvm_method_stat_updates.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json,unittest
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from test_qvm_method_stat_slots import SLOTS
|
| 4 |
+
from qvm_notification_support import POOL
|
| 5 |
+
|
| 6 |
+
def expected(a):
|
| 7 |
+
if a.get('actor_absent'):return [],[]
|
| 8 |
+
method=a['method'];slot=SLOTS.get(method,-1);items=[];pair=False;self_hit=a['self'];victim='actor' if self_hit else 'victim'
|
| 9 |
+
if slot>=0:items=[('actor',916+76*slot),(victim,920+76*slot)];pair=True
|
| 10 |
+
elif method in [0,1,2,3,4,5,8,9]:items=[(victim,2512)]
|
| 11 |
+
elif method in {6:2488,7:2492,31:2504,32:2508,33:2508,35:2508,47:2496}:items=[(victim,{6:2488,7:2492,31:2504,32:2508,33:2508,35:2508,47:2496}[method])]
|
| 12 |
+
elif method in [22,25] and self_hit:items=[(victim,2460 if method==22 else 2452)]
|
| 13 |
+
elif method in [12,13,22,23,24,25,34,37,48]:
|
| 14 |
+
x,y={12:(2396,2468),13:(2400,2472),22:(2384,2456),23:(2408,2480),24:(2404,2476),25:(2376,2448),34:(2428,2500),37:(2392,2464),48:(2412,2484)}[method];items=[('actor',x),(victim,y)];pair=method!=34
|
| 15 |
+
changes=[{'client':c,'offset':o,'before':a['initial'],'after':(a['initial']+1)&0xffffffff} for c,o in items];changes.sort(key=lambda r:(0 if r['client']=='victim' else 1,r['offset']))
|
| 16 |
+
return changes,([279720] if pair else [])+[279586,279586,285227,283622]
|
| 17 |
+
class MethodStatUpdateTests(unittest.TestCase):
|
| 18 |
+
@classmethod
|
| 19 |
+
def setUpClass(cls):cls.ps=json.loads(Path('docs/research/qvm-method-stat-updates.json').read_text())['probes']
|
| 20 |
+
def test_independent_counter_and_callback_oracle(self):
|
| 21 |
+
for p in self.ps:
|
| 22 |
+
changes,calls=expected(p['input']);self.assertEqual(p['changes'],changes,p['input']);self.assertEqual([c['target'] for c in p['requests']],calls,p['input'])
|
| 23 |
+
def test_self_alias_and_unsigned_wrap_coverage(self):
|
| 24 |
+
self.assertEqual(len(self.ps),205);self.assertTrue(any(p['input']['self'] and p['changes'] for p in self.ps));self.assertTrue(any(c['after']==0 for p in self.ps for c in p['changes']))
|
| 25 |
+
def test_complete_exit_and_identifier_notification_abi(self):
|
| 26 |
+
for p in self.ps:
|
| 27 |
+
self.assertEqual(p['execution']['stop'],279584)
|
| 28 |
+
for c in p['requests']:
|
| 29 |
+
if c['target']==285227:self.assertEqual(c['arguments'],{'8':1 if p['input']['self'] else 2,'12':1})
|
| 30 |
+
if __name__=='__main__':unittest.main()
|
xtask/checks.tsv
CHANGED
|
@@ -1230,3 +1230,6 @@ group notifications scripts/analyze_qvm_client_notifications.py
|
|
| 1230 |
report scripts/analyze_qvm_method_stat_slots.py docs/research/qvm-method-stat-slots.json
|
| 1231 |
edge docs/research/qvm-method-stat-slots.json scripts/test_qvm_method_stat_slots.py
|
| 1232 |
group stat-slots scripts/analyze_qvm_method_stat_slots.py
|
|
|
|
|
|
|
|
|
|
|
|
| 1230 |
report scripts/analyze_qvm_method_stat_slots.py docs/research/qvm-method-stat-slots.json
|
| 1231 |
edge docs/research/qvm-method-stat-slots.json scripts/test_qvm_method_stat_slots.py
|
| 1232 |
group stat-slots scripts/analyze_qvm_method_stat_slots.py
|
| 1233 |
+
report scripts/analyze_qvm_method_stat_updates.py docs/research/qvm-method-stat-updates.json
|
| 1234 |
+
edge docs/research/qvm-method-stat-updates.json scripts/test_qvm_method_stat_updates.py
|
| 1235 |
+
group stat-updates scripts/analyze_qvm_method_stat_updates.py
|