changeset 51992:71658f79758a

clonebundle-digest: add recursion guards for Python 3.8 For Python 3.8 and 3.9, the read/readinto pair can recurse, so make sure the data is only hashed once.
author Joerg Sonnenberger <joerg@bec.de>
date Fri, 11 Oct 2024 14:37:59 +0200
parents f0bee30af890
children daeb85ebee48
files mercurial/url.py
diffstat 1 files changed, 14 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/url.py	Tue Oct 08 01:06:57 2024 -0400
+++ b/mercurial/url.py	Fri Oct 11 14:37:59 2024 +0200
@@ -538,18 +538,27 @@
                         )
 
             def read(self, amt=None):
+                self._digest_recursion_level += 1
                 data = super().read(amt)
-                self._digest_input(data)
+                self._digest_recursion_level -= 1
+                if self._digest_recursion_level == 0:
+                    self._digest_input(data)
                 return data
 
             def readline(self):
+                self._digest_recursion_level += 1
                 data = super().readline()
-                self._digest_input(data)
+                self._digest_recursion_level -= 1
+                if self._digest_recursion_level == 0:
+                    self._digest_input(data)
                 return data
 
             def readinto(self, dest):
+                self._digest_recursion_level += 1
                 got = super().readinto(dest)
-                self._digest_input(dest[:got])
+                self._digest_recursion_level -= 1
+                if self._digest_recursion_level == 0:
+                    self._digest_input(dest[:got])
                 return got
 
             def _close_conn(self):
@@ -560,6 +569,8 @@
         response._digest = self._digest
         response._digest_consumed = 0
         response._hasher = self._hasher.copy()
+        # Python 3.8 / 3.9 recurses internally between read/readinto.
+        response._digest_recursion_level = 0
         response._digest_finished = False
         return response