fix(python): pin only the 3.14 and 3.15 magics checked locally

Keep magic 3627 (CPython 3.14.6) and 3666 (CPython 3.15.0b3), whose code
layout and inline-cache tables match those interpreters' opcode tables and
whose decoded code objects match marshal.loads across a stdlib sample. Leave
the 3.15.0a8 magic 3663 unpinned, since no 3.15.0a8 interpreter was available
to check it, and regenerate the 3.15 slice fixture with 3.15.0b3.

Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
gensokyo-devandgensokyo-dev authored and Ysopwnable committed 2026-11-14 13:37:55 +01:00
1 parent 1d08253ff2
commit 9d3eb083dd
7 files changed
+108 -148

No files matched your search

+93 -92
View File
@@ -148,19 +148,29 @@ cliTest.for([
version: "3.14.4",
pythonVersion: "3.14",
magic: 3627,
moduleConsts: [
{ kind: "code", name: "f", firstlineno: 1 },
{ kind: "none" },
{ kind: "frozenset", length: 2 },
],
encoded:
"Kw4NCgAAAAAAAAAAHwAAAOMAAAAAAAAAAAAAAAABAAAAAAAAAPMMAAAAgABSABcAdABSASMAKQNjAQAAAAAAAAAAAAAAAgAAAAMAAADzFAAAAIAAVgBSACwaAAAAAAAAAAAAACMAKQE66QEAAADpCgAAAOkCAAAAqQApAdoBYXMBAAAAJtoKZml4dHVyZS5wedoBZnIJAAAAAQAAAHMMAAAAgADYCwyIVo050AQU8wAAAABOPgIAAADjAgAAAAAAAAAAAAAAAgAAAAMAAADzHgAAAIAAVgBQAAAAAAAAAAAAAAAAAAAAAAAAAFYAMwIjAKkBTqkB2gF4qQJyBwAAANoBYnMCAAAAJiZyCAAAANoIPGxhbWJkYT5yEgAAAAEAAABzDAAAAIAAsAG3A7EDsFGpeHIKAAAA4wIAAAAAAAAAAAAAAAIAAAADAAAA8x4AAACAAFYAUAAAAAAAAAAAAAAAAAAAAAAAAABWATMCIwByDQAAAHIOAAAAchAAAABzAgAAACYmcggAAAByEgAAAHISAAAAAQAAAHMMAAAAgACQcZdzkXOYQZFocgoAAAApAXIJAAAAcgYAAAByCgAAAHIIAAAA2gg8bW9kdWxlPnIVAAAAAQAAAHMKAAAA8AMBAQH0AgEBFXIKAAAA",
},
{
version: "3.15.0a8",
version: "3.15.0b3",
pythonVersion: "3.15",
magic: 3663,
magic: 3666,
// 3.15 loads None through LOAD_COMMON_CONSTANT, so it is not a constant.
moduleConsts: [
{ kind: "code", name: "f", firstlineno: 1 },
{ kind: "frozenset", length: 2 },
],
encoded:
"Tw4NCgAAAAAAAAAAHwAAAOMAAAAAAAAAAAAAAAABAAAAAAAAAPMOAAAAgAAAAFEAFQBzAFEBIQApA2MBAAAAAAAAAAAAAAACAAAAAwAAAPMWAAAAgAAAAFUAUQAqGgAAAAAAAAAAAAAhACkBOukBAAAA6QoAAADpAgAAAKkAKQHaAWFzAQAAACbaCmZpeHR1cmUucHnaAWZyCQAAAAEAAABzDAAAAIEA2AsMiFaNOdAEFPMAAAAATj4CAAAA4wIAAAAAAAAAAAAAAAIAAAADAAAA8yAAAACAAAAAVQBPAAAAAAAAAAAAAAAAAAAAAAAAAFUAMQIhAKkBTqkB2gF4qQJyBwAAANoBYnMCAAAAJiZyCAAAANoIPGxhbWJkYT5yEgAAAAEAAABzDAAAAIEAsAG3A7EDsFGpeHIKAAAA4wIAAAAAAAAAAAAAAAIAAAADAAAA8yAAAACAAAAAVQBPAAAAAAAAAAAAAAAAAAAAAAAAAFUBMQIhAHINAAAAcg4AAAByEAAAAHMCAAAAJiZyCAAAAHISAAAAchIAAAABAAAAcwwAAACBAJBxl3ORc5hBkWhyCgAAACkBcgkAAAByBgAAAHIKAAAAcggAAADaCDxtb2R1bGU+chUAAAABAAAAcwoAAADxAwEBAfQCAQEVcgoAAAA=",
"Ug4NCgAAAAAAAAAAHwAAAOMAAAAAAAAAAAAAAAABAAAAAAAAAPMOAAAAgAAAAFEAFQBzAFAHIQApAmMBAAAAAAAAAAAAAAACAAAAAwAAAPMWAAAAgAAAAFUAUQAqGgAAAAAAAAAAAAAhACkBOukBAAAA6QoAAADpAgAAAKkAKQHaAWFzAQAAACbaCmZpeHR1cmUucHnaAWZyCQAAAAEAAABzDAAAAIEA2AsMiFaNOdAEFPMAAAAAPgIAAADjAgAAAAAAAAAAAAAAAgAAAAMAAADzIAAAAIAAAABVAE8AAAAAAAAAAAAAAAAAAAAAAAAAVQAxAiEAKQFOKQHaAXgpAnIHAAAA2gFicwIAAAAmJnIIAAAA2gg8bGFtYmRhPnIPAAAAAQAAAHMMAAAAgQCIYY9jiWOQMYlYcgoAAADjAgAAAAAAAAAAAAAAAgAAAAMAAADzIAAAAIAAAABVAE8AAAAAAAAAAAAAAAAAAAAAAAAAVQExAiEAKQFOKQFyDQAAACkCcgcAAAByDgAAAHMCAAAAJiZyCAAAAHIPAAAAcg8AAAABAAAAcwwAAACBAIhhj2OJY5AxiVhyCgAAACkBcgkAAAByBgAAAHIKAAAAcggAAADaCDxtb2R1bGU+chIAAAABAAAAcwoAAADxAwEBAfQCAQEVcgoAAAA=",
},
])(
"reads CPython $version output with a slice constant and distinct lambdas",
async ({ version, pythonVersion, magic, encoded }, { cli }) => {
async ({ version, pythonVersion, magic, moduleConsts, encoded }, { cli }) => {
// CPython marshal output of `def f(a): return a[1:10:2]` plus a frozenset
// of two same-line lambdas, `(a.x, b)` and `(a.x, a)`, whose bytecode
// differs only in the LOAD_FAST_BORROW operand after LOAD_ATTR's caches.
@@ -180,11 +190,7 @@ cliTest.for([
});
expect(evidence.normalized_result.code_objects).toHaveLength(4);
expect(evidence.normalized_result.code_objects[0]).toMatchObject({
consts: [
{ kind: "code", name: "f", firstlineno: 1 },
{ kind: "none" },
{ kind: "frozenset", length: 2 },
],
consts: moduleConsts,
nested_code: [1, 2, 3],
});
expect(evidence.normalized_result.code_objects[1]).toMatchObject({
@@ -196,88 +202,84 @@ cliTest.for([
},
);
cliTest(
"reads the final CPython 3.15.2 magic 3666 from a real release pyc",
async ({ cli }) => {
// `encodings/__pycache__/utf_8.cpython-315.pyc`, byte for byte as shipped in
// python-build-standalone cpython-3.15.2+20261026-aarch64-apple-darwin
// (install_only tarball, SHA-256 285a6b92...e64a6): the header carries magic 3666.
// The expected rows are what a CPython 3.15.0a8 interpreter's own
// `marshal.loads` reports for these bytes (qualname, first line, SHA-256 of
// `co_code`), so they are not derived from this reader. a8 and the final
// release share the 3.11 code layout; 3.15.2 itself was not executed.
const pyc = Buffer.from(
"Ug4NCgAAAAAQXd9q7QMAAOMAAAAAAAAAAAAAAAAFAAAAAAAAAPPkAAAAgAAAAFEAcwBdAFAHSARzAVwBTwQAAAAAAAAAAAAAAAAAAAAAAABzA1ELUQEVAGsBcwQTAB8AUQIVAFEDXAFPCgAAAAAAAAAAAAAAAAAAAAAAADIDAAAAAAAAcwUTAB8AUQQVAFEFXAFPDAAAAAAAAAAAAAAAAAAAAAAAADIDAAAAAAAAcwcTAB8AUQYVAFEHXAFPEAAAAAAAAAAAAAAAAAAAAAAAADIDAAAAAAAAcwgTAB8AUQgVAFEJXAFPEgAAAAAAAAAAAAAAAAAAAAAAADIDAAAAAAAAcwlRChUAcwpQByEAKQx6gFB5dGhvbiAndXRmLTgnIENvZGVjCgoKV3JpdHRlbiBieSBNYXJjLUFuZHJlIExlbWJ1cmcgKG1hbEBsZW1idXJnLmNvbSkuCgooYykgQ29weXJpZ2h0IENOUkksIEFsbCBSaWdodHMgUmVzZXJ2ZWQuIE5PIFdBUlJBTlRZLgoKYwIAAAAAAAAAAAAAAAUAAAADAAAA8zIAAACAAAAAWwAAAAAAAAAAAE8CAAAAAAAAAAAAAAAAAAAAAAAAHwBWAVAJMgMAAAAAAAAhACkBVCkC2gZjb2RlY3PaDHV0Zl84X2RlY29kZSkC2gVpbnB1dNoGZXJyb3JzcwIAAAAmJtpNL3ByaXZhdGUvdG1wL3RtcGUzY3J1Y2ZiL291dC9weXRob24vaW5zdGFsbC9saWIvcHl0aG9uMy4xNS9lbmNvZGluZ3MvdXRmXzgucHnaBmRlY29kZXIIAAAADwAAAHMVAAAAgQDcCxHXCx7SCx6Ydahk0wsz0AQz8wAAAABjAAAAAAAAAAAAAAAAAgAAAAAAAADzLAAAAGAAgAAAAFwAcwFRAHMCXRJzAxQAbgBRA1EBFQBrAXMEUQJzBVUAcwZQByEAKQTaEkluY3JlbWVudGFsRW5jb2RlcmMDAAAAAAAAAAAAAAAEAAAAAwAACPNSAAAAgAAAAFsAAAAAAAAAAABPAgAAAAAAAAAAAAAAAAAAAAAAAB8AVhBPBAAAAAAAAAAAAAAAAAAAAAAAADICAAAAAAAAXQAqGgAAAAAAAAAAAAAhACkB6QAAAAApA3IDAAAA2gx1dGZfOF9lbmNvZGVyBgAAACkD2gRzZWxmcgUAAADaBWZpbmFscwMAAAAmJiZyBwAAANoGZW5jb2Rl2hlJbmNyZW1lbnRhbEVuY29kZXIuZW5jb2RlEwAAAHMcAAAAgQDcDxXXDyLSDyKgNa8rqSvTDzawcdUPOdAIOXIJAAAAqQApAUYpB9oIX19uYW1lX1/aCl9fbW9kdWxlX1/aDF9fcXVhbG5hbWVfX9oPX19maXJzdGxpbmVub19fchEAAADaFV9fc3RhdGljX2F0dHJpYnV0ZXNfX9oRX19jbGFzc2RpY3RjZWxsX18pAdoNX19jbGFzc2RpY3RfX3MBAAAAQHIHAAAAcgsAAAByCwAAABIAAABzDwAAAPiHAIEA9wIBBTryAAEFOnIJAAAAcgsAAABjAAAAAAAAAAAAAAAAAQAAAAAAAADzMAAAAIAAAABcAHMBUQBzAl0WcwNcBE8KAAAAAAAAAAAAAAAAAAAAAAAAcwZRAXMHUAchACkC2hJJbmNyZW1lbnRhbERlY29kZXJyEwAAACkIchQAAAByFQAAAHIWAAAAchcAAAByAwAAAHIEAAAA2g5fYnVmZmVyX2RlY29kZXIYAAAAchMAAAByCQAAAHIHAAAAchwAAAByHAAAABYAAABzDQAAAIcA2BUb1xUo0RUohE5yCQAAAHIcAAAAYwAAAAAAAAAAAAAAAAEAAAAAAAAA8zAAAACAAAAAXABzAVEAcwJdGXMDXARPCgAAAAAAAAAAAAAAAAAAAAAAAHMGUQFzB1AHIQApAtoMU3RyZWFtV3JpdGVychMAAAApCHIUAAAAchUAAAByFgAAAHIXAAAAcgMAAAByDgAAAHIRAAAAchgAAAByEwAAAHIJAAAAcgcAAAByHwAAAHIfAAAAGQAAAPMNAAAAhwDYDRPXDSDRDSCERnIJAAAAch8AAABjAAAAAAAAAAAAAAAAAQAAAAAAAADzMAAAAIAAAABcAHMBUQBzAl0ccwNcBE8KAAAAAAAAAAAAAAAAAAAAAAAAcwZRAXMHUAchACkC2gxTdHJlYW1SZWFkZXJyEwAAACkIchQAAAByFQAAAHIWAAAAchcAAAByAwAAAHIEAAAAcggAAAByGAAAAHITAAAAcgkAAAByBwAAAHIiAAAAciIAAAAcAAAAciAAAAByCQAAAHIiAAAAYwAAAAAAAAAAAAAAAAoAAAADAAAA824AAACAAAAAWwAAAAAAAAAAAE8CAAAAAAAAAAAAAAAAAAAAAAAAHwBRAFsEAAAAAAAAAABbBgAAAAAAAAAAWwgAAAAAAAAAAFsKAAAAAAAAAABbDAAAAAAAAAAAWw4AAAAAAAAAAFEBNQcAAAAAAAAhACkCegV1dGYtOCkH2gRuYW1lchEAAAByCAAAANoSaW5jcmVtZW50YWxlbmNvZGVy2hJpbmNyZW1lbnRhbGRlY29kZXLaDHN0cmVhbXJlYWRlctoMc3RyZWFtd3JpdGVyKQhyAwAAANoJQ29kZWNJbmZvchEAAAByCAAAAHILAAAAchwAAAByIgAAAHIfAAAAchMAAAByCQAAAHIHAAAA2gtnZXRyZWdlbnRyeXIqAAAAIQAAAHMqAAAAgQDcCxHXCxvSCxvYDRTcDxXcDxXcGy3cGy3cFSHcFSH0DwgMBvAACAUGcgkAAAApAdoGc3RyaWN0KQvaB19fZG9jX19yAwAAAHIOAAAAchEAAAByCAAAAHILAAAA2hpCdWZmZXJlZEluY3JlbWVudGFsRGVjb2RlcnIcAAAAch8AAAByIgAAAHIqAAAAchMAAAByCQAAAHIHAAAA2gg8bW9kdWxlPnIuAAAAAQAAAHNuAAAA8QMBAQHxAgcBBPMQAAEO8AgAChDXCRzRCRyABvQEAQE09AYCATqYFtcZMtEZMvQAAgE69AgBASmYFtcZOtEZOvQAAQEp9AYBASGQNtcTJtETJvQAAQEh9AYBASGQNtcTJtETJvQAAQEh9AoJAQZyCQAAAA==",
"base64",
);
const root = await createTestTempDirectory("rea-python-pyc-final-315-");
const path = join(root, "utf_8.cpython-315.pyc");
await writeFile(path, pyc);
const result = await cli.run({
arguments: ["inspect-python-pyc", path, "--json"],
});
expect(result.exitCode, result.stderr).toBe(0);
const evidence = completePycEvidenceSchema.parse(result.json);
expect(evidence.normalized_result.header).toMatchObject({
magic: 3666,
python_version: "3.15",
code_layout: "py311",
flags: 0,
hash_based: false,
});
expect(
evidence.normalized_result.code_objects.map((code) => [
code.qualname,
code.firstlineno,
code.bytecode.sha256,
]),
).toEqual([
[
"<module>",
1,
"dec009b8d182273295bb1af2572eaf510c5a2c9b79c9ed5b5867acd3ab3f3532",
],
[
"decode",
15,
"fe1a50cda8d8510aee7c6c8a4300c4fb151a360ba9e830b7ac9bd797d4b522f6",
],
[
"IncrementalEncoder",
18,
"32afcda5f0c08dccd01a0e42c4a2b5575247c8ed5723bc704db2dd995511c73b",
],
[
"IncrementalEncoder.encode",
19,
"df5053d342e0600648ddbd48ec64a5f1c4336c6956cde360b8799c61da5d93fe",
],
[
"IncrementalDecoder",
22,
"2d2cf7a62ece3c133ac82e9d59fee2ecfd21eb1a79c31b7d4a6e64a30fc2072d",
],
[
"StreamWriter",
25,
"b77dff0cd7cf304af6ae747b34e03499353b914282cb7d782ec4d8e24e442c67",
],
[
"StreamReader",
28,
"0b21e2f77e98d3f01c2698ed2b9cff5778331afb1a8bdc12b3eb80c389d36861",
],
[
"getregentry",
33,
"98cecbb09af6594440e3caab695700c9ca4d5a1355a3e8a83e2172dd8a9fc6a5",
],
]);
expect(evidence.normalized_result.artifact.sha256).toBe(
createHash("sha256").update(pyc).digest("hex"),
);
},
);
cliTest("reads a CPython 3.15 magic 3666 stdlib pyc", async ({ cli }) => {
// `encodings/__pycache__/utf_8.cpython-315.pyc`, byte for byte as shipped in
// python-build-standalone cpython-3.15.2+20261026-aarch64-apple-darwin
// (install_only tarball, SHA-256 285a6b92...e64a6): the header carries magic 3666.
// The expected rows are what CPython 3.15.0b3 (magic 3666) reports for
// these bytes through its own `marshal.loads` (qualname, first line,
// SHA-256 of `co_code`), so they are not derived from this reader.
const pyc = Buffer.from(
"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",
"base64",
);
const root = await createTestTempDirectory("rea-python-pyc-final-315-");
const path = join(root, "utf_8.cpython-315.pyc");
await writeFile(path, pyc);
const result = await cli.run({
arguments: ["inspect-python-pyc", path, "--json"],
});
expect(result.exitCode, result.stderr).toBe(0);
const evidence = completePycEvidenceSchema.parse(result.json);
expect(evidence.normalized_result.header).toMatchObject({
magic: 3666,
python_version: "3.15",
code_layout: "py311",
flags: 0,
hash_based: false,
});
expect(
evidence.normalized_result.code_objects.map((code) => [
code.qualname,
code.firstlineno,
code.bytecode.sha256,
]),
).toEqual([
[
"<module>",
1,
"dec009b8d182273295bb1af2572eaf510c5a2c9b79c9ed5b5867acd3ab3f3532",
],
[
"decode",
15,
"fe1a50cda8d8510aee7c6c8a4300c4fb151a360ba9e830b7ac9bd797d4b522f6",
],
[
"IncrementalEncoder",
18,
"32afcda5f0c08dccd01a0e42c4a2b5575247c8ed5723bc704db2dd995511c73b",
],
[
"IncrementalEncoder.encode",
19,
"df5053d342e0600648ddbd48ec64a5f1c4336c6956cde360b8799c61da5d93fe",
],
[
"IncrementalDecoder",
22,
"2d2cf7a62ece3c133ac82e9d59fee2ecfd21eb1a79c31b7d4a6e64a30fc2072d",
],
[
"StreamWriter",
25,
"b77dff0cd7cf304af6ae747b34e03499353b914282cb7d782ec4d8e24e442c67",
],
[
"StreamReader",
28,
"0b21e2f77e98d3f01c2698ed2b9cff5778331afb1a8bdc12b3eb80c389d36861",
],
[
"getregentry",
33,
"98cecbb09af6594440e3caab695700c9ca4d5a1355a3e8a83e2172dd8a9fc6a5",
],
]);
expect(evidence.normalized_result.artifact.sha256).toBe(
createHash("sha256").update(pyc).digest("hex"),
);
});
cliTest(
"uses magic-specific cache tables for synthetic pyc bytecode equality",
@@ -293,7 +295,6 @@ cliTest(
{ magic: 3564, opcode: 58, cacheUnits: 1 },
{ magic: 3571, opcode: 82, cacheUnits: 9 },
{ magic: 3627, opcode: 80, cacheUnits: 9 },
{ magic: 3663, opcode: 79, cacheUnits: 9 },
{ magic: 3666, opcode: 128, cacheUnits: 1 },
];
for (const { magic, opcode, cacheUnits } of cases) {