From 8c3baf067791dd11bed9eeec3009da512a1b4ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Cabello=20Jim=C3=A9nez?= Date: Mon, 18 Aug 2025 23:25:59 +0200 Subject: [PATCH 1/2] gh-137928: Centralize size validation in multiprocessing.heap --- Lib/multiprocessing/heap.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Lib/multiprocessing/heap.py b/Lib/multiprocessing/heap.py index 6217dfe12689b3..5ef12959f89dda 100644 --- a/Lib/multiprocessing/heap.py +++ b/Lib/multiprocessing/heap.py @@ -155,6 +155,15 @@ def _roundup(n, alignment): mask = alignment - 1 return (n + mask) & ~mask + @staticmethod + # Bind sys.maxsize once at function definition time to avoid global lookups. + def _validate_size(size, _maxsize=sys.maxsize): + """Validate requested size; raise ValueError if < 0, OverflowError if >= _maxsize.""" + if size < 0: + raise ValueError("Size {0:n} out of range".format(size)) + if _maxsize <= size: + raise OverflowError("Size {0:n} too large".format(size)) + def _new_arena(self, size): # Create a new arena with at least the given *size* length = self._roundup(max(self._size, size), mmap.PAGESIZE) @@ -295,10 +304,7 @@ def free(self, block): def malloc(self, size): # return a block of right size (possibly rounded up) - if size < 0: - raise ValueError("Size {0:n} out of range".format(size)) - if sys.maxsize <= size: - raise OverflowError("Size {0:n} too large".format(size)) + Heap._validate_size(size) if os.getpid() != self._lastpid: self.__init__() # reinitialize after fork with self._lock: @@ -324,10 +330,7 @@ class BufferWrapper(object): _heap = Heap() def __init__(self, size): - if size < 0: - raise ValueError("Size {0:n} out of range".format(size)) - if sys.maxsize <= size: - raise OverflowError("Size {0:n} too large".format(size)) + Heap._validate_size(size) block = BufferWrapper._heap.malloc(size) self._state = (block, size) util.Finalize(self, BufferWrapper._heap.free, args=(block,)) From 204d26466607295c7d601fb6969e477639f51878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Cabello=20Jim=C3=A9nez?= Date: Thu, 21 Aug 2025 10:03:26 +0200 Subject: [PATCH 2/2] gh-137928: Move size validation helper to module level in multiprocessing.heap --- Lib/multiprocessing/heap.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/Lib/multiprocessing/heap.py b/Lib/multiprocessing/heap.py index 5ef12959f89dda..f1d74d245101c0 100644 --- a/Lib/multiprocessing/heap.py +++ b/Lib/multiprocessing/heap.py @@ -20,6 +20,12 @@ __all__ = ['BufferWrapper'] +# +# Module constants +# + +_MAXSIZE = sys.maxsize + # # Inheritable class which wraps an mmap, and from which blocks can be allocated # @@ -108,6 +114,17 @@ def rebuild_arena(size, dupfd): reduction.register(Arena, reduce_arena) +# +# Validation helpers +# + +def _validate_size(size): + """Validate requested size; raise ValueError if < 0, OverflowError if >= _MAXSIZE.""" + if size < 0: + raise ValueError("Size {0:n} out of range".format(size)) + if _MAXSIZE <= size: + raise OverflowError("Size {0:n} too large".format(size)) + # # Class allowing allocation of chunks of memory from arenas # @@ -155,15 +172,6 @@ def _roundup(n, alignment): mask = alignment - 1 return (n + mask) & ~mask - @staticmethod - # Bind sys.maxsize once at function definition time to avoid global lookups. - def _validate_size(size, _maxsize=sys.maxsize): - """Validate requested size; raise ValueError if < 0, OverflowError if >= _maxsize.""" - if size < 0: - raise ValueError("Size {0:n} out of range".format(size)) - if _maxsize <= size: - raise OverflowError("Size {0:n} too large".format(size)) - def _new_arena(self, size): # Create a new arena with at least the given *size* length = self._roundup(max(self._size, size), mmap.PAGESIZE) @@ -304,7 +312,7 @@ def free(self, block): def malloc(self, size): # return a block of right size (possibly rounded up) - Heap._validate_size(size) + _validate_size(size) if os.getpid() != self._lastpid: self.__init__() # reinitialize after fork with self._lock: @@ -330,7 +338,7 @@ class BufferWrapper(object): _heap = Heap() def __init__(self, size): - Heap._validate_size(size) + _validate_size(size) block = BufferWrapper._heap.malloc(size) self._state = (block, size) util.Finalize(self, BufferWrapper._heap.free, args=(block,))