Splice by joining bytes around the original module code

A spliced module is now the original's header, a prefix, the original's marshalled code verbatim,
and a suffix. The original comes first in the stream, so its interned-string references stay
valid; the wrapper and the overrides are marshalled with version 0, which doesn't intern, so the
prefix and suffix don't depend on the original's bytes. A patcher can splice without
unmarshalling, and IMVU's code is no longer re-marshalled at all. The helper checks every spliced
module round-trips.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
dhkatzandClaude Opus 5.5 committed 2026-10-27 04:04:34 -07:00
1 parent 17527688f9
commit 63a4e31bc0
1 file changed
+39 -13
+39 -13
View File
@@ -8,8 +8,9 @@ with the class's own name, so private names mangle correctly, and are then copie
Input on stdin, JSON: {"library": <dir of patched sources>, "modules": [{"path": "imvu/account.py",
"base": <base64>, "patched": <base64>, "pyo": <base64>}]}
Output on stdout, JSON: {"modules": [{"path", "pyo": <base64> or null, "overrides": [...], "errors": [...],
"warnings": [...]}]}
Output on stdout, JSON: {"modules": [{"path", "pyo", "prefix", "suffix": <base64> or null, "overrides": [...],
"errors": [...], "warnings": [...]}]}. The spliced pyo is the original's 8-byte header + prefix + the original's
marshalled code (bytes 8 onward, verbatim) + suffix; see wrapper().
"""
from __future__ import print_function
@@ -47,6 +48,8 @@ def %(save)s(namespace, names):
namespace['%(prefix)s' + name] = namespace[name]
''' % {'patch_class': PATCH_CLASS, 'save': SAVE_ORIGINALS, 'prefix': ORIGINAL_PREFIX}
STUB = "exec 'T5DE_ORIGINAL'\nexec 'T5DE_OVERRIDES'\n"
# Stands in for the original module code while marshalling the wrapper; replaced by the original's bytes.
ORIGINAL_MARKER = '\0t5de: original module code\0'
class SpliceError(Exception):
@@ -279,15 +282,34 @@ def splice(path, base_source, patched_source, pyo):
original = marshal.loads(pyo[8:])
tree = override_tree(units, patched_source)
overrides = compile(tree, original.co_filename, 'exec', original.co_flags & FUTURE_FLAGS, True)
stub = compile(STUB, original.co_filename, 'exec', 0, True)
consts = tuple(original if c == 'T5DE_ORIGINAL' else overrides if c == 'T5DE_OVERRIDES' else c
prefix, suffix = wrapper(original.co_filename, overrides)
spliced = pyo[:8] + prefix + pyo[8:] + suffix
embedded = [c for c in marshal.loads(spliced[8:]).co_consts if isinstance(c, types.CodeType)]
assert len(embedded) == 2 and marshal.dumps(embedded[0]) == marshal.dumps(original)
# Marshal version 0 drops which strings were interned, so compare the overrides by content, not bytes.
assert same_code(embedded[1], overrides)
names = ['%s.%s' % (class_name, name) if class_name else name for _, _, class_name, name in units]
warnings = warnings + fidelity_warnings(original, base_source, patched_source, names)
return (prefix, suffix), names, errors, warnings, changed_functions
def wrapper(filename, overrides):
"""The bytes around IMVU's original module code in a spliced .pyo: header + prefix + original + suffix.
The module code object runs the original module code, then the overrides. The original is embedded as its
marshalled bytes, verbatim, and comes first in the stream, so its interned-string references stay valid; the
wrapper is marshalled with version 0, which doesn't intern (names are interned again when the code loads). So
the prefix and suffix don't depend on the original's bytes, and a patcher can splice without unmarshalling."""
stub = compile(STUB, filename, 'exec', 0, True)
consts = tuple(ORIGINAL_MARKER if c == 'T5DE_ORIGINAL' else overrides if c == 'T5DE_OVERRIDES' else c
for c in stub.co_consts)
module = types.CodeType(stub.co_argcount, stub.co_nlocals, stub.co_stacksize, stub.co_flags, stub.co_code,
consts, stub.co_names, stub.co_varnames, stub.co_filename, stub.co_name,
stub.co_firstlineno, stub.co_lnotab, stub.co_freevars, stub.co_cellvars)
names = ['%s.%s' % (class_name, name) if class_name else name for _, _, class_name, name in units]
warnings = warnings + fidelity_warnings(original, base_source, patched_source, names)
return pyo[:8] + marshal.dumps(module), names, errors, warnings, changed_functions
data, marker = marshal.dumps(module, 0), marshal.dumps(ORIGINAL_MARKER, 0)
assert data.count(marker) == 1
prefix, suffix = data.split(marker)
return prefix, suffix
def code_objects(module):
@@ -394,14 +416,18 @@ def main():
results, changed = [], {}
for module in request['modules']:
path = module['path']
result = {'path': path, 'pyo': None, 'overrides': [], 'errors': [], 'warnings': []}
result = {'path': path, 'pyo': None, 'prefix': None, 'suffix': None, 'overrides': [], 'errors': [],
'warnings': []}
try:
pyo, names, errors, warnings, changed_functions = splice(
path, base64.b64decode(module['base']), base64.b64decode(module['patched']),
base64.b64decode(module['pyo']))
pyo = base64.b64decode(module['pyo'])
parts, names, errors, warnings, changed_functions = splice(
path, base64.b64decode(module['base']), base64.b64decode(module['patched']), pyo)
result.update(overrides=names, errors=errors, warnings=warnings)
if pyo is not None:
result['pyo'] = base64.b64encode(pyo).decode('ascii')
if parts is not None:
prefix, suffix = parts
result['prefix'] = base64.b64encode(prefix).decode('ascii')
result['suffix'] = base64.b64encode(suffix).decode('ascii')
result['pyo'] = base64.b64encode(pyo[:8] + prefix + pyo[8:] + suffix).decode('ascii')
if changed_functions:
changed[module_name(path)] = (path, changed_functions)
except SpliceError as e: