Reject oversized pickle lengths with OverflowError (#9040)

Preserve the wrapper-pickle regressions merged into main while refreshing the independent length checks.

Assisted-by: OpenAI Codex:model identifier unavailable
This commit is contained in:
youknowdot authored and GitHub committed 2026-10-11 00:51:40 +09:00
1 parent 9d6bf4d224
commit be52c97463
2 files changed
+33 -6

No files matched your search

+11 -6
View File
@@ -818,13 +818,18 @@ mod _pickle {
.ok()
.filter(|n| isize::try_from(*n).is_ok())
.ok_or_else(|| {
new_unpickling_error(
vm,
let message = if what == "FRAME" {
format!(
"FRAME length exceeds system's maximum of {} bytes",
isize::MAX
)
} else {
format!(
"{what} exceeds system's maximum size of {} bytes",
isize::MAX
),
)
)
};
vm.new_overflow_error(message)
})
}
@@ -1090,7 +1095,7 @@ mod _pickle {
}
Some(BINBYTES8) => {
let arr: [u8; 8] = st.read_n(8, vm)?.try_into().unwrap();
let n = read_size(&arr, vm, "BINBYTES8")?;
let n = read_size(&arr, vm, "BINBYTES")?;
let data = st.read_n(n, vm)?.to_vec();
stack.push(vm.ctx.new_bytes(data).into());
}
@@ -1129,7 +1134,7 @@ mod _pickle {
}
Some(BINUNICODE8) => {
let arr: [u8; 8] = st.read_n(8, vm)?.try_into().unwrap();
let n = read_size(&arr, vm, "BINUNICODE8")?;
let n = read_size(&arr, vm, "BINUNICODE")?;
let data = st.read_n(n, vm)?.to_vec();
stack.push(utf8_surrogatepass(&data, vm)?);
}
+22
View File
@@ -1,5 +1,8 @@
import _pickle
import io
import sys
from testutils import assert_raises
# BINPUT leaves holes; MEMOIZE uses the number of present entries.
unpickler = _pickle.Unpickler(io.BytesIO(b"\x80\x04]q\x07\x94h\x01\x86."))
@@ -13,3 +16,22 @@ assert memo[7] is left
# Slot wrapper descriptors reduce to lookup on their defining class.
assert object.__str__.__reduce__() == (getattr, (object, "__str__"))
assert _pickle.loads(_pickle.dumps(object.__str__)) is object.__str__
# Oversized advertised lengths are rejected before trying to read or allocate.
for opcode, name in (
(b"\x8e", "BINBYTES"),
(b"\x8d", "BINUNICODE"),
(b"\x95", "FRAME"),
):
data = b"\x80\x04" + opcode + (sys.maxsize + 1).to_bytes(8, "little")
for load in (
_pickle.loads,
lambda data: _pickle.Unpickler(io.BytesIO(data)).load(),
):
with assert_raises(OverflowError) as caught:
load(data)
if name == "FRAME":
expected = f"FRAME length exceeds system's maximum of {sys.maxsize} bytes"
else:
expected = f"{name} exceeds system's maximum size of {sys.maxsize} bytes"
assert str(caught.exception) == expected