Skip to content

Commit dac827c

Browse files
[3.13] gh-139748: fix leaks in AC error paths when using unicode FS-b… (#139792)
* [3.13] gh-139748: fix leaks in AC error paths when using unicode FS-based converters (GH-139765) (cherry picked from commit b04a57d) Co-authored-by: Bénédikt Tran <[email protected]>
1 parent d8971c2 commit dac827c

File tree

13 files changed

+81
-42
lines changed

13 files changed

+81
-42
lines changed

Lib/test/test_clinic.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2827,6 +2827,8 @@ def test_cli_converters(self):
28272827
"slice_index",
28282828
"str",
28292829
"unicode",
2830+
"unicode_fs_decoded",
2831+
"unicode_fs_encoded",
28302832
"unsigned_char",
28312833
"unsigned_int",
28322834
"unsigned_long",

Lib/test/test_compile.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,21 @@ def test_compile_filename(self):
643643
compile('pass', filename, 'exec')
644644
self.assertRaises(TypeError, compile, 'pass', list(b'file.py'), 'exec')
645645

646+
def test_compile_filename_refleak(self):
647+
# Regression tests for reference leak in PyUnicode_FSDecoder.
648+
# See https://github.com/python/cpython/issues/139748.
649+
mortal_str = 'this is a mortal string'
650+
# check error path when 'mode' AC conversion failed
651+
self.assertRaises(TypeError, compile, b'', mortal_str, mode=1234)
652+
# check error path when 'optimize' AC conversion failed
653+
self.assertRaises(OverflowError, compile, b'', mortal_str,
654+
'exec', optimize=1 << 1000)
655+
# check error path when 'dont_inherit' AC conversion failed
656+
class EvilBool:
657+
def __bool__(self): raise ValueError
658+
self.assertRaises(ValueError, compile, b'', mortal_str,
659+
'exec', dont_inherit=EvilBool())
660+
646661
@support.cpython_only
647662
def test_same_filename_used(self):
648663
s = """def f(): pass\ndef g(): pass"""

Lib/test/test_symtable.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,13 @@ def test_symtable_entry_repr(self):
493493
expected = f"<symtable entry top({self.top.get_id()}), line {self.top.get_lineno()}>"
494494
self.assertEqual(repr(self.top._table), expected)
495495

496+
def test__symtable_refleak(self):
497+
# Regression test for reference leak in PyUnicode_FSDecoder.
498+
# See https://github.com/python/cpython/issues/139748.
499+
mortal_str = 'this is a mortal string'
500+
# check error path when 'compile_type' AC conversion failed
501+
self.assertRaises(TypeError, symtable.symtable, '', mortal_str, 1)
502+
496503

497504
class CommandLineTest(unittest.TestCase):
498505
maxDiff = None
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix reference leaks in error branches of functions accepting path strings or
2+
bytes such as :func:`compile` and :func:`os.system`. Patch by Bénédikt Tran.

Modules/_ssl.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,14 +1782,14 @@ _certificate_to_der(_sslmodulestate *state, X509 *certificate)
17821782

17831783
/*[clinic input]
17841784
_ssl._test_decode_cert
1785-
path: object(converter="PyUnicode_FSConverter")
1785+
path: unicode_fs_encoded
17861786
/
17871787
17881788
[clinic start generated code]*/
17891789

17901790
static PyObject *
17911791
_ssl__test_decode_cert_impl(PyObject *module, PyObject *path)
1792-
/*[clinic end generated code: output=96becb9abb23c091 input=cdeaaf02d4346628]*/
1792+
/*[clinic end generated code: output=96becb9abb23c091 input=cb4988d5e651a4f8]*/
17931793
{
17941794
PyObject *retval = NULL;
17951795
X509 *x=NULL;
@@ -1819,7 +1819,6 @@ _ssl__test_decode_cert_impl(PyObject *module, PyObject *path)
18191819
X509_free(x);
18201820

18211821
fail0:
1822-
Py_DECREF(path);
18231822
if (cert != NULL) BIO_free(cert);
18241823
return retval;
18251824
}

Modules/clinic/_ssl.c.h

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/clinic/symtablemodule.c.h

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/posixmodule.c

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3044,17 +3044,6 @@ class dev_t_return_converter(unsigned_long_return_converter):
30443044
conversion_fn = '_PyLong_FromDev'
30453045
unsigned_cast = '(dev_t)'
30463046
3047-
class FSConverter_converter(CConverter):
3048-
type = 'PyObject *'
3049-
converter = 'PyUnicode_FSConverter'
3050-
def converter_init(self):
3051-
if self.default is not unspecified:
3052-
fail("FSConverter_converter does not support default values")
3053-
self.c_default = 'NULL'
3054-
3055-
def cleanup(self):
3056-
return "Py_XDECREF(" + self.name + ");\n"
3057-
30583047
class pid_t_converter(CConverter):
30593048
type = 'pid_t'
30603049
format_unit = '" _Py_PARSE_PID "'
@@ -3093,7 +3082,7 @@ class confname_converter(CConverter):
30933082
""", argname=argname, converter=self.converter, table=self.table)
30943083
30953084
[python start generated code]*/
3096-
/*[python end generated code: output=da39a3ee5e6b4b0d input=a6199b1618d73f53]*/
3085+
/*[python end generated code: output=da39a3ee5e6b4b0d input=1a078a0f42a586c1]*/
30973086

30983087
/*[clinic input]
30993088
@@ -6013,14 +6002,14 @@ os_system_impl(PyObject *module, const wchar_t *command)
60136002
/*[clinic input]
60146003
os.system -> long
60156004
6016-
command: FSConverter
6005+
command: unicode_fs_encoded
60176006
60186007
Execute the command in a subshell.
60196008
[clinic start generated code]*/
60206009

60216010
static long
60226011
os_system_impl(PyObject *module, PyObject *command)
6023-
/*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/
6012+
/*[clinic end generated code: output=290fc437dd4f33a0 input=47c6f24b6dc92881]*/
60246013
{
60256014
long result;
60266015
const char *bytes = PyBytes_AsString(command);
@@ -9200,7 +9189,7 @@ os_getgroups_impl(PyObject *module)
92009189
/*[clinic input]
92019190
os.initgroups
92029191
9203-
username as oname: FSConverter
9192+
username as oname: unicode_fs_encoded
92049193
gid: int
92059194
/
92069195
@@ -9213,12 +9202,12 @@ group id.
92139202

92149203
static PyObject *
92159204
os_initgroups_impl(PyObject *module, PyObject *oname, int gid)
9216-
/*[clinic end generated code: output=7f074d30a425fd3a input=df3d54331b0af204]*/
9205+
/*[clinic end generated code: output=7f074d30a425fd3a input=984e60c7fed88cb4]*/
92179206
#else
92189207
/*[clinic input]
92199208
os.initgroups
92209209
9221-
username as oname: FSConverter
9210+
username as oname: unicode_fs_encoded
92229211
gid: gid_t
92239212
/
92249213
@@ -9231,7 +9220,7 @@ group id.
92319220

92329221
static PyObject *
92339222
os_initgroups_impl(PyObject *module, PyObject *oname, gid_t gid)
9234-
/*[clinic end generated code: output=59341244521a9e3f input=0cb91bdc59a4c564]*/
9223+
/*[clinic end generated code: output=59341244521a9e3f input=17d8fbe2dea42ca4]*/
92359224
#endif
92369225
{
92379226
const char *username = PyBytes_AS_STRING(oname);
@@ -12956,16 +12945,16 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
1295612945
/*[clinic input]
1295712946
os.putenv
1295812947
12959-
name: FSConverter
12960-
value: FSConverter
12948+
name: unicode_fs_encoded
12949+
value: unicode_fs_encoded
1296112950
/
1296212951
1296312952
Change or add an environment variable.
1296412953
[clinic start generated code]*/
1296512954

1296612955
static PyObject *
1296712956
os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
12968-
/*[clinic end generated code: output=d29a567d6b2327d2 input=a97bc6152f688d31]*/
12957+
/*[clinic end generated code: output=d29a567d6b2327d2 input=84fcd30f873c8c45]*/
1296912958
{
1297012959
const char *name_string = PyBytes_AS_STRING(name);
1297112960
const char *value_string = PyBytes_AS_STRING(value);
@@ -13008,15 +12997,15 @@ os_unsetenv_impl(PyObject *module, PyObject *name)
1300812997
#else
1300912998
/*[clinic input]
1301012999
os.unsetenv
13011-
name: FSConverter
13000+
name: unicode_fs_encoded
1301213001
/
1301313002
1301413003
Delete an environment variable.
1301513004
[clinic start generated code]*/
1301613005

1301713006
static PyObject *
1301813007
os_unsetenv_impl(PyObject *module, PyObject *name)
13019-
/*[clinic end generated code: output=54c4137ab1834f02 input=2bb5288a599c7107]*/
13008+
/*[clinic end generated code: output=54c4137ab1834f02 input=78ff12e505ade80a]*/
1302013009
{
1302113010
if (PySys_Audit("os.unsetenv", "(O)", name) < 0) {
1302213011
return NULL;
@@ -15074,14 +15063,14 @@ os_urandom_impl(PyObject *module, Py_ssize_t size)
1507415063
/*[clinic input]
1507515064
os.memfd_create
1507615065
15077-
name: FSConverter
15066+
name: unicode_fs_encoded
1507815067
flags: unsigned_int(bitwise=True, c_default="MFD_CLOEXEC") = MFD_CLOEXEC
1507915068
1508015069
[clinic start generated code]*/
1508115070

1508215071
static PyObject *
1508315072
os_memfd_create_impl(PyObject *module, PyObject *name, unsigned int flags)
15084-
/*[clinic end generated code: output=6681ede983bdb9a6 input=a42cfc199bcd56e9]*/
15073+
/*[clinic end generated code: output=6681ede983bdb9a6 input=cd0eb092cfac474b]*/
1508515074
{
1508615075
int fd;
1508715076
const char *bytes = PyBytes_AS_STRING(name);

Modules/socketmodule.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7115,7 +7115,6 @@ _socket_socket_if_nametoindex_impl(PySocketSockObject *self, PyObject *oname)
71157115
#endif
71167116

71177117
index = if_nametoindex(PyBytes_AS_STRING(oname));
7118-
Py_DECREF(oname);
71197118
if (index == 0) {
71207119
/* if_nametoindex() doesn't set errno */
71217120
PyErr_SetString(PyExc_OSError, "no interface with this name");

Modules/symtablemodule.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module _symtable
1313
_symtable.symtable
1414
1515
source: object
16-
filename: object(converter='PyUnicode_FSDecoder')
16+
filename: unicode_fs_decoded
1717
startstr: str
1818
/
1919
@@ -23,7 +23,7 @@ Return symbol and scope dictionaries used internally by compiler.
2323
static PyObject *
2424
_symtable_symtable_impl(PyObject *module, PyObject *source,
2525
PyObject *filename, const char *startstr)
26-
/*[clinic end generated code: output=59eb0d5fc7285ac4 input=9dd8a50c0c36a4d7]*/
26+
/*[clinic end generated code: output=59eb0d5fc7285ac4 input=436ffff90d02e4f6]*/
2727
{
2828
struct symtable *st;
2929
PyObject *t;
@@ -47,12 +47,10 @@ _symtable_symtable_impl(PyObject *module, PyObject *source,
4747
else {
4848
PyErr_SetString(PyExc_ValueError,
4949
"symtable() arg 3 must be 'exec' or 'eval' or 'single'");
50-
Py_DECREF(filename);
5150
Py_XDECREF(source_copy);
5251
return NULL;
5352
}
5453
st = _Py_SymtableStringObjectFlags(str, filename, start, &cf);
55-
Py_DECREF(filename);
5654
Py_XDECREF(source_copy);
5755
if (st == NULL) {
5856
return NULL;

0 commit comments

Comments
 (0)