https://github.com/python/cpython/commit/5a1559d9493dd298a08c4be32b52295aa3eb89e5
commit: 5a1559d9493dd298a08c4be32b52295aa3eb89e5
branch: main
author: Pierre Ossman (ThinLinc team) <[email protected]>
committer: gvanrossum <[email protected]>
date: 2024-02-27T17:39:08-08:00
summary:
gh-112997: Don't log arguments in asyncio unless debugging (#115667)
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.
files:
A Misc/NEWS.d/next/Library/2024-02-19-16-53-48.gh-issue-112997.sYBXRZ.rst
M Lib/asyncio/events.py
M Lib/asyncio/format_helpers.py
M Lib/test/test_asyncio/test_events.py
diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py
index 072a99fee123c3..680749325025db 100644
--- a/Lib/asyncio/events.py
+++ b/Lib/asyncio/events.py
@@ -54,7 +54,8 @@ def _repr_info(self):
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 @@ def _run(self):
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,
diff --git a/Lib/asyncio/format_helpers.py b/Lib/asyncio/format_helpers.py
index 27d11fd4fa9553..93737b7708a67b 100644
--- a/Lib/asyncio/format_helpers.py
+++ b/Lib/asyncio/format_helpers.py
@@ -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
diff --git a/Lib/test/test_asyncio/test_events.py
b/Lib/test/test_asyncio/test_events.py
index c92c88bd5b2429..5b9c871e1d1b5a 100644
--- a/Lib/test/test_asyncio/test_events.py
+++ b/Lib/test/test_asyncio/test_events.py
@@ -2250,7 +2250,7 @@ def test_handle_repr(self):
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 @@ def test_handle_repr(self):
# 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 @@ def test_handle_repr_debug(self):
'<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
index 00000000000000..4f97b2d6085ba0
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-02-19-16-53-48.gh-issue-112997.sYBXRZ.rst
@@ -0,0 +1,2 @@
+Stop logging potentially sensitive callback arguments in :mod:`asyncio`
+unless debug mode is active.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]