]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-112997: Don't log arguments in asyncio unless debugging (#115667)
authorPierre Ossman (ThinLinc team) <ossman@cendio.se>
Wed, 28 Feb 2024 01:39:08 +0000 (02:39 +0100)
committerGitHub <noreply@github.com>
Wed, 28 Feb 2024 01:39:08 +0000 (17:39 -0800)
Nothing else in Python generally logs the contents of variables, so this
can be very unexpected for developers and could leak sensitive
information in to terminals and log files.

Lib/asyncio/events.py
Lib/asyncio/format_helpers.py
Lib/test/test_asyncio/test_events.py
Misc/NEWS.d/next/Library/2024-02-19-16-53-48.gh-issue-112997.sYBXRZ.rst [new file with mode: 0644]

index 072a99fee123c393d6114c229bade63700d0edaf..680749325025db3ddfea5a414285af51fcee01e5 100644 (file)
@@ -54,7 +54,8 @@ class Handle:
             info.append('cancelled')
         if self._callback is not None:
             info.append(format_helpers._format_callback_source(
-                self._callback, self._args))
+                self._callback, self._args,
+                debug=self._loop.get_debug()))
         if self._source_traceback:
             frame = self._source_traceback[-1]
             info.append(f'created at {frame[0]}:{frame[1]}')
@@ -90,7 +91,8 @@ class Handle:
             raise
         except BaseException as exc:
             cb = format_helpers._format_callback_source(
-                self._callback, self._args)
+                self._callback, self._args,
+                debug=self._loop.get_debug())
             msg = f'Exception in callback {cb}'
             context = {
                 'message': msg,
index 27d11fd4fa9553e21077bd4a93c523dbcb1d32cb..93737b7708a67b6cdcd07284f21a1b698923bf44 100644 (file)
@@ -19,19 +19,26 @@ def _get_function_source(func):
     return None
 
 
-def _format_callback_source(func, args):
-    func_repr = _format_callback(func, args, None)
+def _format_callback_source(func, args, *, debug=False):
+    func_repr = _format_callback(func, args, None, debug=debug)
     source = _get_function_source(func)
     if source:
         func_repr += f' at {source[0]}:{source[1]}'
     return func_repr
 
 
-def _format_args_and_kwargs(args, kwargs):
+def _format_args_and_kwargs(args, kwargs, *, debug=False):
     """Format function arguments and keyword arguments.
 
     Special case for a single parameter: ('hello',) is formatted as ('hello').
+
+    Note that this function only returns argument details when
+    debug=True is specified, as arguments may contain sensitive
+    information.
     """
+    if not debug:
+        return '()'
+
     # use reprlib to limit the length of the output
     items = []
     if args:
@@ -41,10 +48,11 @@ def _format_args_and_kwargs(args, kwargs):
     return '({})'.format(', '.join(items))
 
 
-def _format_callback(func, args, kwargs, suffix=''):
+def _format_callback(func, args, kwargs, *, debug=False, suffix=''):
     if isinstance(func, functools.partial):
-        suffix = _format_args_and_kwargs(args, kwargs) + suffix
-        return _format_callback(func.func, func.args, func.keywords, suffix)
+        suffix = _format_args_and_kwargs(args, kwargs, debug=debug) + suffix
+        return _format_callback(func.func, func.args, func.keywords,
+                                debug=debug, suffix=suffix)
 
     if hasattr(func, '__qualname__') and func.__qualname__:
         func_repr = func.__qualname__
@@ -53,7 +61,7 @@ def _format_callback(func, args, kwargs, suffix=''):
     else:
         func_repr = repr(func)
 
-    func_repr += _format_args_and_kwargs(args, kwargs)
+    func_repr += _format_args_and_kwargs(args, kwargs, debug=debug)
     if suffix:
         func_repr += suffix
     return func_repr
index c92c88bd5b2429c90a0c00963ad29ad74f82d188..5b9c871e1d1b5a0c1d2e64427186db12025b8b36 100644 (file)
@@ -2250,7 +2250,7 @@ class HandleTests(test_utils.TestCase):
         h = asyncio.Handle(noop, (1, 2), self.loop)
         filename, lineno = test_utils.get_function_source(noop)
         self.assertEqual(repr(h),
-                        '<Handle noop(1, 2) at %s:%s>'
+                        '<Handle noop() at %s:%s>'
                         % (filename, lineno))
 
         # cancelled handle
@@ -2268,14 +2268,14 @@ class HandleTests(test_utils.TestCase):
         # partial function
         cb = functools.partial(noop, 1, 2)
         h = asyncio.Handle(cb, (3,), self.loop)
-        regex = (r'^<Handle noop\(1, 2\)\(3\) at %s:%s>$'
+        regex = (r'^<Handle noop\(\)\(\) at %s:%s>$'
                  % (re.escape(filename), lineno))
         self.assertRegex(repr(h), regex)
 
         # partial function with keyword args
         cb = functools.partial(noop, x=1)
         h = asyncio.Handle(cb, (2, 3), self.loop)
-        regex = (r'^<Handle noop\(x=1\)\(2, 3\) at %s:%s>$'
+        regex = (r'^<Handle noop\(\)\(\) at %s:%s>$'
                  % (re.escape(filename), lineno))
         self.assertRegex(repr(h), regex)
 
@@ -2316,6 +2316,24 @@ class HandleTests(test_utils.TestCase):
             '<Handle cancelled noop(1, 2) at %s:%s created at %s:%s>'
             % (filename, lineno, create_filename, create_lineno))
 
+        # partial function
+        cb = functools.partial(noop, 1, 2)
+        create_lineno = sys._getframe().f_lineno + 1
+        h = asyncio.Handle(cb, (3,), self.loop)
+        regex = (r'^<Handle noop\(1, 2\)\(3\) at %s:%s created at %s:%s>$'
+                 % (re.escape(filename), lineno,
+                    re.escape(create_filename), create_lineno))
+        self.assertRegex(repr(h), regex)
+
+        # partial function with keyword args
+        cb = functools.partial(noop, x=1)
+        create_lineno = sys._getframe().f_lineno + 1
+        h = asyncio.Handle(cb, (2, 3), self.loop)
+        regex = (r'^<Handle noop\(x=1\)\(2, 3\) at %s:%s created at %s:%s>$'
+                 % (re.escape(filename), lineno,
+                    re.escape(create_filename), create_lineno))
+        self.assertRegex(repr(h), regex)
+
     def test_handle_source_traceback(self):
         loop = asyncio.get_event_loop_policy().new_event_loop()
         loop.set_debug(True)
diff --git a/Misc/NEWS.d/next/Library/2024-02-19-16-53-48.gh-issue-112997.sYBXRZ.rst b/Misc/NEWS.d/next/Library/2024-02-19-16-53-48.gh-issue-112997.sYBXRZ.rst
new file mode 100644 (file)
index 0000000..4f97b2d
--- /dev/null
@@ -0,0 +1,2 @@
+Stop logging potentially sensitive callback arguments in :mod:`asyncio`
+unless debug mode is active.