nmarshall commited on
Commit
dd27994
·
1 Parent(s): 9c0f602

qvm: execute original string helpers

Browse files
docs/FINDINGS.md CHANGED
@@ -1409,3 +1409,6 @@ RE-791–800 adds exact Rust source-sort/ranking parity, mixed count/prefix sema
1409
 
1410
 
1411
  **RE-803:** Both bounded resumers now support validated child byte writes, coherent word mirroring and explicit word/byte/return precedence. [Evidence](research/QVM_CHILD_BYTE_EFFECTS.md).
 
 
 
 
1409
 
1410
 
1411
  **RE-803:** Both bounded resumers now support validated child byte writes, coherent word mirroring and explicit word/byte/return precedence. [Evidence](research/QVM_CHILD_BYTE_EFFECTS.md).
1412
+
1413
+
1414
+ **RE-804:** Actual strlen36038 and strcpy36185 execute against coherent bytes, preserving destination guards; bounded copy69338 retains an explicit native strncpy model. [Evidence](research/QVM_STRING_MEMORY.md).
docs/PROVISIONAL_TODO.md CHANGED
@@ -1416,3 +1416,6 @@ RE-802: Bounded tracing can now preserve byte/word coherence and execute unalign
1416
 
1417
 
1418
  RE-803: Both bounded resumers now support validated child byte writes, coherent word mirroring and explicit word/byte/return precedence. Full runtime completion remains open. [Evidence](research/QVM_CHILD_BYTE_EFFECTS.md).
 
 
 
 
1416
 
1417
 
1418
  RE-803: Both bounded resumers now support validated child byte writes, coherent word mirroring and explicit word/byte/return precedence. Full runtime completion remains open. [Evidence](research/QVM_CHILD_BYTE_EFFECTS.md).
1419
+
1420
+
1421
+ RE-804: Actual strlen36038 and strcpy36185 execute against coherent bytes, preserving destination guards; bounded copy69338 retains an explicit native strncpy model. Full runtime completion remains open. [Evidence](research/QVM_STRING_MEMORY.md).
docs/RESEARCH_LEDGER.md CHANGED
@@ -1681,3 +1681,8 @@ Bounded tracing can now preserve byte/word coherence and execute unaligned byte
1681
  ## 2026-10-26 — RE-803 Explicit child byte effects and read-only shared byte views
1682
 
1683
  Both bounded resumers now support validated child byte writes, coherent word mirroring and explicit word/byte/return precedence. Focused `cargo xtask test-group child-byte-effects` passes (6 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
 
 
 
 
 
 
1681
  ## 2026-10-26 — RE-803 Explicit child byte effects and read-only shared byte views
1682
 
1683
  Both bounded resumers now support validated child byte writes, coherent word mirroring and explicit word/byte/return precedence. Focused `cargo xtask test-group child-byte-effects` passes (6 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
1684
+
1685
+
1686
+ ## 2026-10-26 — RE-804 Actual QVM string helpers across aligned and unaligned memory
1687
+
1688
+ Actual strlen36038 and strcpy36185 execute against coherent bytes, preserving destination guards; bounded copy69338 retains an explicit native strncpy model. Focused `cargo xtask test-group string-memory` passes (6 Python tests); selected reports regenerate twice deterministically, with storage, documentation links and whitespace guards. Full suite deferred to task ten. Original assets unchanged; source fixtures do not establish complete native/runtime parity.
docs/REVERSE_ENGINEERING_TODO.md CHANGED
@@ -1459,3 +1459,6 @@ Purpose: turn the supplied installation into an evidence-backed specification of
1459
 
1460
 
1461
  - [x] RE-803 Explicit child byte effects and read-only shared byte views ([evidence](research/QVM_CHILD_BYTE_EFFECTS.md)).
 
 
 
 
1459
 
1460
 
1461
  - [x] RE-803 Explicit child byte effects and read-only shared byte views ([evidence](research/QVM_CHILD_BYTE_EFFECTS.md)).
1462
+
1463
+
1464
+ - [x] RE-804 Actual QVM string helpers across aligned and unaligned memory ([evidence](research/QVM_STRING_MEMORY.md)).
docs/research/QVM_STRING_MEMORY.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Actual QVM string helpers across aligned and unaligned memory
2
+
3
+ RE-804. Reproduce with `python3 scripts/analyze_qvm_string_memory.py`; focused validation: `cargo xtask test-group string-memory`. [Machine report](qvm-string-memory.json).
4
+
5
+ 128 original-instruction fixtures vary source/destination alignment, NUL positions, long names and non-UTF8 bytes.32 wrapper cases verify valid capacities1/2/4/32 and exact terminal NUL. Independent byte-string oracles check lengths, return pointers and all destination guard bytes. Source word lookahead is given initialized padding; overlap and native ABI/error paths are not claimed.
6
+
7
+ Original executable/native runtime and complete Linux/macOS Rust/Bevy/Solari acceptance remain unverified.
docs/research/README.md CHANGED
@@ -999,3 +999,6 @@ The extension collector adds five focused tests for native tail calls, command-r
999
 
1000
 
1001
  [RE-803: Explicit child byte effects and read-only shared byte views](QVM_CHILD_BYTE_EFFECTS.md).
 
 
 
 
999
 
1000
 
1001
  [RE-803: Explicit child byte effects and read-only shared byte views](QVM_CHILD_BYTE_EFFECTS.md).
1002
+
1003
+
1004
+ [RE-804: Actual QVM string helpers across aligned and unaligned memory](QVM_STRING_MEMORY.md).
docs/research/qvm-resumer-audit.json CHANGED
@@ -9371,6 +9371,42 @@
9371
  "repeated_calls_opt_in": true,
9372
  "repeated_calls_setting": "literal_true"
9373
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9374
  {
9375
  "backward_conditional_branches": [],
9376
  "calls": [
@@ -9432,8 +9468,8 @@
9432
  }
9433
  },
9434
  "summary": {
9435
- "call_expressions": 188,
9436
- "files": 146,
9437
  "legacy_expressions": 158,
9438
  "nonliteral_ranges": 24,
9439
  "unresolved_mode_expressions": 3
 
9371
  "repeated_calls_opt_in": true,
9372
  "repeated_calls_setting": "literal_true"
9373
  },
9374
+ {
9375
+ "backward_conditional_branches": [],
9376
+ "calls": [
9377
+ {
9378
+ "dynamic_store_requires_review": false,
9379
+ "implicit_local_offset": null,
9380
+ "instruction": 69348,
9381
+ "stores_result": false,
9382
+ "target": 5096
9383
+ },
9384
+ {
9385
+ "dynamic_store_requires_review": false,
9386
+ "implicit_local_offset": null,
9387
+ "instruction": 69359,
9388
+ "stores_result": false,
9389
+ "target": 5096
9390
+ },
9391
+ {
9392
+ "dynamic_store_requires_review": false,
9393
+ "implicit_local_offset": null,
9394
+ "instruction": 69373,
9395
+ "stores_result": false,
9396
+ "target": -103
9397
+ }
9398
+ ],
9399
+ "explicit_result_offsets": null,
9400
+ "helper": "qvm_trace_support.resume",
9401
+ "line": 36,
9402
+ "literal_range": [
9403
+ 69339,
9404
+ 69384
9405
+ ],
9406
+ "path": "scripts/qvm_string_memory_support.py",
9407
+ "repeated_calls_opt_in": true,
9408
+ "repeated_calls_setting": "literal_true"
9409
+ },
9410
  {
9411
  "backward_conditional_branches": [],
9412
  "calls": [
 
9468
  }
9469
  },
9470
  "summary": {
9471
+ "call_expressions": 189,
9472
+ "files": 147,
9473
  "legacy_expressions": 158,
9474
  "nonliteral_ranges": 24,
9475
  "unresolved_mode_expressions": 3
docs/research/qvm-string-memory.json ADDED
The diff for this file is too large to render. See raw diff
 
scripts/analyze_qvm_string_memory.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import itertools
3
+ from pathlib import Path
4
+ from qvm_research_support import source
5
+ from qvm_string_memory_support import strlen,strcpy,copy_bounded,L
6
+ from qvm_byte_memory_support import read_bytes
7
+ from analyze_qvm import write_json
8
+ S=L+0x4000;D=S+0x1000
9
+
10
+ def main():
11
+ q,raw,h,ins=source();rows=[];copies=[];names=[b'',b'A',b'AB',b'x'*31,b'x'*32,b'x'*63,b'AB\0suffix',bytes([255,254,253])]
12
+ for sa,da,name in itertools.product(range(4),range(4),names):
13
+ b={S+sa+j:v for j,v in enumerate(name+b'\0'+b'\xcc'*4)};b.update({D+j:0x7e for j in range(96)});m,n,e=strlen(ins,{}, {8:S+sa},b);m,value,c=strcpy(ins,m,{8:D+da,12:S+sa},b);out=read_bytes(m,{**b,**c['child_memory_bytes']},D,96);rows.append({'source_alignment':sa,'dest_alignment':da,'source_hex':name.hex(),'length':n,'result_pointer':value-D,'buffer_hex':out.hex(),'strlen_execution':e['execution'],'strcpy_execution':c['execution']})
14
+ for name,cap in itertools.product(names,[1,2,4,32]):
15
+ b={S+j:v for j,v in enumerate(name+b'\0'+b'\xcc'*4)};b.update({D+j:0x7e for j in range(40)});m,v,e=copy_bounded(ins,{}, {8:D,12:S,16:cap},b);out=read_bytes(m,{**b,**e['child_memory_bytes']},D,40);copies.append({'source_hex':name.hex(),'capacity':cap,'buffer_hex':out.hex(),'wrapper_trace_sha256':e['wrapper_trace_sha256']})
16
+ write_json(Path('docs/research/qvm-string-memory.json'),{'source':q['source'],'sha256':q['sha256'],'probes':rows,'bounded_copies':copies,'limits':'Actual36038 strlen and36185 strcpy over128 aligned/unaligned byte fixtures, plus actual69338 valid wrapper over32 cases with modeled native-103 strncpy. Source word lookahead requires initialized padding; strcpy fixtures are disjoint with initialized destination guards. Native copy/error/overlap ABI parity remains open.'})
17
+ if __name__=='__main__':main()
scripts/qvm_string_memory_support.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Actual36038/36185 and69338 with explicit modeled native strncpy bytes."""
2
+ from qvm_health_effects_support import H
3
+ from qvm_byte_memory_support import read_byte,read_bytes
4
+ from analyze_deferred_auth import trace_slice
5
+ from analyze_bsp_references import trace_fields
6
+ from qvm_trace_support import resume
7
+ L=H+0x680000
8
+ C=L+0x1000
9
+ W=L+0x2000
10
+
11
+ def cstring(m,b,address,limit=32768):
12
+ out=bytearray()
13
+ for j in range(limit):
14
+ v=read_byte(m,b,address+j)
15
+ if v==0:return bytes(out)
16
+ out.append(v)
17
+ raise ValueError('bounded string missing NUL')
18
+
19
+ def strlen(ins,m,args,b):
20
+ m=dict(m);m[L+28]=args[8];t=trace_slice(ins,36039,36121,m,{},byte_memory=b,local_base=L,coherent_memory=True,capture_stack=True,halt_on_leave=True,limit=32768)
21
+ return t['memory'],t['stack'][-1],{'execution':trace_fields(t,False),'actual_strlen':True}
22
+
23
+ def strcpy(ins,m,args,b):
24
+ n=len(cstring(m,b,args[12],1025));m=dict(m);m[C+32]=args[8];m[C+36]=args[12];t=trace_slice(ins,36186,36304,m,{},byte_memory=b,local_base=C,coherent_memory=True,capture_stack=True,halt_on_leave=True,limit=32768)
25
+ cells={args[8]+j:read_byte(t['memory'],t['byte_memory'],args[8]+j) for j in range(n+1)}
26
+ return t['memory'],t['stack'][-1],{'execution':trace_fields(t,False),'child_memory_bytes':cells,'actual_strcpy':True}
27
+
28
+ def copy_bounded(ins,m,args,b):
29
+ if args[12]==0 or not 1<=args[16]<=1024:raise ValueError('unsupported bounded copy domain')
30
+ m=dict(m)
31
+ for o,v in args.items():m[W+20+o]=v
32
+ def native(i,m,a,bs):
33
+ if not 0<=a[16]<=1023:raise ValueError('unsupported native copy count')
34
+ raw=cstring(m,bs,a[12]);data=raw[:a[16]].ljust(a[16],b'\0')
35
+ return m,a[8],{'native_strncpy_modeled':True,'child_memory_bytes':{a[8]+j:v for j,v in enumerate(data)}}
36
+ m,e=resume(ins,69339,69384,m,W,handlers={-103:native},byte_inputs=b,repeated_calls=True,sync_child_words=True,coherent_memory=True,byte_handlers=True,capture_byte_memory=True)
37
+ cells={args[8]+j:read_byte(m,e['byte_memory'],args[8]+j) for j in range(args[16])}
38
+ return m,0,{'child_memory_bytes':cells,'wrapper_trace_sha256':e['trace_sha256'],'native_strncpy_modeled':True}
scripts/test_qvm_string_memory.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json,unittest
2
+ from pathlib import Path
3
+ from qvm_string_memory_support import cstring,copy_bounded
4
+ class StringMemoryTests(unittest.TestCase):
5
+ @classmethod
6
+ def setUpClass(cls):cls.r=json.loads(Path('docs/research/qvm-string-memory.json').read_text())
7
+ def test_actual_strlen_strcpy_and_preserved_post_nul_guards(self):
8
+ self.assertEqual(len(self.r['probes']),128)
9
+ for p in self.r['probes']:
10
+ text=bytes.fromhex(p['source_hex']).split(b'\0')[0];out=bytearray(b'~'*96);start=p['dest_alignment'];out[start:start+len(text)+1]=text+b'\0';self.assertEqual(p['length'],len(text));self.assertEqual(p['result_pointer'],start);self.assertEqual(p['buffer_hex'],out.hex())
11
+ def test_actual_wrapper_terminator_and_native_copy_model(self):
12
+ self.assertEqual(len(self.r['bounded_copies']),32)
13
+ for p in self.r['bounded_copies']:
14
+ raw=bytes.fromhex(p['source_hex']).split(b'\0')[0];cap=p['capacity'];out=bytearray(b'~'*40);out[:cap]=raw[:cap-1].ljust(cap-1,b'\0')+b'\0';self.assertEqual(p['buffer_hex'],out.hex())
15
+ def test_unterminated_and_invalid_domains_reject(self):
16
+ with self.assertRaisesRegex(ValueError,'missing NUL'):cstring({},dict(enumerate(b'abc')),0,3)
17
+ with self.assertRaises(ValueError):copy_bounded([],{},{8:4,12:8,16:0},{})
18
+ if __name__=='__main__':unittest.main()
xtask/checks.tsv CHANGED
@@ -1898,3 +1898,8 @@ report scripts/analyze_qvm_child_byte_effects.py docs/research/qvm-child-byte-ef
1898
  edge docs/research/qvm-child-byte-effects.json scripts/test_qvm_child_byte_effects.py
1899
  group child-byte-effects scripts/analyze_qvm_child_byte_effects.py
1900
  edge scripts/analyze_qvm_child_byte_effects.py scripts/analyze_qvm_resumer_audit.py
 
 
 
 
 
 
1898
  edge docs/research/qvm-child-byte-effects.json scripts/test_qvm_child_byte_effects.py
1899
  group child-byte-effects scripts/analyze_qvm_child_byte_effects.py
1900
  edge scripts/analyze_qvm_child_byte_effects.py scripts/analyze_qvm_resumer_audit.py
1901
+ report scripts/analyze_qvm_string_memory.py docs/research/qvm-string-memory.json
1902
+ edge docs/research/qvm-string-memory.json scripts/test_qvm_string_memory.py
1903
+ group string-memory scripts/analyze_qvm_string_memory.py
1904
+ edge scripts/analyze_qvm_string_memory.py scripts/analyze_qvm_resumer_audit.py
1905
+ edge scripts/qvm_string_memory_support.py scripts/analyze_qvm_resumer_audit.py