Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Lib/test/test_marshal.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import array
import io
import marshal
import struct
import sys
import unittest
import os
Expand Down Expand Up @@ -140,6 +141,29 @@ def test_different_filenames(self):
self.assertEqual(co1.co_filename, "f1")
self.assertEqual(co2.co_filename, "f2")

def test_inconsistent_code_object(self):
# localsplusnames and localspluskinds must have equal length; if
# not, marshal must raise ValueError, not SystemError (gh-151830).
co = compile("def f():\n a=1;b=2;c=3", "<test>", "exec").co_consts[0]
n = len(co.co_varnames) + len(co.co_cellvars) + len(co.co_freevars)
blob = marshal.dumps(co)
# Find the localspluskinds record: the TYPE_STRING ('s') whose payload
# is exactly n bytes long (one kind byte per localsplus name).
kinds = None
for off in range(len(blob) - 5):
if blob[off] == ord('s'):
if struct.unpack_from('<i', blob, off + 1)[0] == n:
kinds = blob[off + 5:off + 5 + n]
break
# f's locals (a, b, c) are all plain fast locals (CO_FAST_LOCAL).
self.assertEqual(kinds, bytes([0x20]) * n)
# Rewrite it with one fewer kind byte than there are names.
corrupt = (blob[:off] + b's' + struct.pack('<i', n - 1)
+ kinds[:n - 1] + blob[off + 5 + n:])
with self.assertRaisesRegex(
ValueError, r'bad marshal data \(invalid code object\)'):
marshal.loads(corrupt)

def test_no_allow_code(self):
data = {'a': [({0},)]}
dump = marshal.dumps(data, allow_code=False)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fixed :func:`marshal.loads` raising :exc:`SystemError` instead of
:exc:`ValueError` for serialized data containing a code object with
inconsistent internal fields.
4 changes: 4 additions & 0 deletions Python/marshal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1670,6 +1670,10 @@ r_object(RFILE *p)
};

if (_PyCode_Validate(&con) < 0) {
if (PyErr_ExceptionMatches(PyExc_SystemError)) {
PyErr_SetString(PyExc_ValueError,
"bad marshal data (invalid code object)");
}
goto code_error;
}

Expand Down
Loading