Skip to content

Commit b04a57d

Browse files
authored
gh-139748: fix leaks in AC error paths when using unicode FS-based converters (#139765)
1 parent 570d172 commit b04a57d

File tree

14 files changed

+88
-46
lines changed

14 files changed

+88
-46
lines changed

Lib/test/test_clinic.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2980,6 +2980,8 @@ def test_cli_converters(self):
29802980
"uint64",
29812981
"uint8",
29822982
"unicode",
2983+
"unicode_fs_decoded",
2984+
"unicode_fs_encoded",
29832985
"unsigned_char",
29842986
"unsigned_int",
29852987
"unsigned_long",

Lib/test/test_compile.py

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

654+
def test_compile_filename_refleak(self):
655+
# Regression tests for reference leak in PyUnicode_FSDecoder.
656+
# See https://github.com/python/cpython/issues/139748.
657+
mortal_str = 'this is a mortal string'
658+
# check error path when 'mode' AC conversion failed
659+
self.assertRaises(TypeError, compile, b'', mortal_str, mode=1234)
660+
# check error path when 'optimize' AC conversion failed
661+
self.assertRaises(OverflowError, compile, b'', mortal_str,
662+
'exec', optimize=1 << 1000)
663+
# check error path when 'dont_inherit' AC conversion failed
664+
class EvilBool:
665+
def __bool__(self): raise ValueError
666+
self.assertRaises(ValueError, compile, b'', mortal_str,
667+
'exec', dont_inherit=EvilBool())
668+
654669
@support.cpython_only
655670
def test_same_filename_used(self):
656671
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
@@ -579,6 +579,13 @@ def test_nested_genexpr(self):
579579
self.assertEqual(sorted(st.get_identifiers()), [".0", "y"])
580580
self.assertEqual(st.get_children(), [])
581581

582+
def test__symtable_refleak(self):
583+
# Regression test for reference leak in PyUnicode_FSDecoder.
584+
# See https://github.com/python/cpython/issues/139748.
585+
mortal_str = 'this is a mortal string'
586+
# check error path when 'compile_type' AC conversion failed
587+
self.assertRaises(TypeError, symtable.symtable, '', mortal_str, 1)
588+
582589

583590
class ComprehensionTests(unittest.TestCase):
584591
def get_identifiers_recursive(self, st, res):
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
@@ -1858,14 +1858,14 @@ _certificate_to_der(_sslmodulestate *state, X509 *certificate)
18581858

18591859
/*[clinic input]
18601860
_ssl._test_decode_cert
1861-
path: object(converter="PyUnicode_FSConverter")
1861+
path: unicode_fs_encoded
18621862
/
18631863
18641864
[clinic start generated code]*/
18651865

18661866
static PyObject *
18671867
_ssl__test_decode_cert_impl(PyObject *module, PyObject *path)
1868-
/*[clinic end generated code: output=96becb9abb23c091 input=cdeaaf02d4346628]*/
1868+
/*[clinic end generated code: output=96becb9abb23c091 input=cb4988d5e651a4f8]*/
18691869
{
18701870
PyObject *retval = NULL;
18711871
X509 *x=NULL;
@@ -1895,7 +1895,6 @@ _ssl__test_decode_cert_impl(PyObject *module, PyObject *path)
18951895
X509_free(x);
18961896

18971897
fail0:
1898-
Py_DECREF(path);
18991898
if (cert != NULL) BIO_free(cert);
19001899
return retval;
19011900
}

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/socketmodule.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
@@ -3137,17 +3137,6 @@ class dev_t_return_converter(unsigned_long_return_converter):
31373137
conversion_fn = '_PyLong_FromDev'
31383138
unsigned_cast = '(dev_t)'
31393139
3140-
class FSConverter_converter(CConverter):
3141-
type = 'PyObject *'
3142-
converter = 'PyUnicode_FSConverter'
3143-
def converter_init(self):
3144-
if self.default is not unspecified:
3145-
fail("FSConverter_converter does not support default values")
3146-
self.c_default = 'NULL'
3147-
3148-
def cleanup(self):
3149-
return "Py_XDECREF(" + self.name + ");\n"
3150-
31513140
class pid_t_converter(CConverter):
31523141
type = 'pid_t'
31533142
format_unit = '" _Py_PARSE_PID "'
@@ -3211,7 +3200,7 @@ class confname_converter(CConverter):
32113200
""", argname=argname, converter=self.converter, table=self.table)
32123201
32133202
[python start generated code]*/
3214-
/*[python end generated code: output=da39a3ee5e6b4b0d input=8189d5ae78244626]*/
3203+
/*[python end generated code: output=da39a3ee5e6b4b0d input=d2759f2332cd39b3]*/
32153204

32163205
/*[clinic input]
32173206
@@ -6135,14 +6124,14 @@ os_system_impl(PyObject *module, const wchar_t *command)
61356124
/*[clinic input]
61366125
os.system -> long
61376126
6138-
command: FSConverter
6127+
command: unicode_fs_encoded
61396128
61406129
Execute the command in a subshell.
61416130
[clinic start generated code]*/
61426131

61436132
static long
61446133
os_system_impl(PyObject *module, PyObject *command)
6145-
/*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/
6134+
/*[clinic end generated code: output=290fc437dd4f33a0 input=47c6f24b6dc92881]*/
61466135
{
61476136
long result;
61486137
const char *bytes = PyBytes_AsString(command);
@@ -9328,7 +9317,7 @@ os_getgroups_impl(PyObject *module)
93289317
/*[clinic input]
93299318
os.initgroups
93309319
9331-
username as oname: FSConverter
9320+
username as oname: unicode_fs_encoded
93329321
gid: int
93339322
/
93349323
@@ -9341,12 +9330,12 @@ group id.
93419330

93429331
static PyObject *
93439332
os_initgroups_impl(PyObject *module, PyObject *oname, int gid)
9344-
/*[clinic end generated code: output=7f074d30a425fd3a input=df3d54331b0af204]*/
9333+
/*[clinic end generated code: output=7f074d30a425fd3a input=984e60c7fed88cb4]*/
93459334
#else
93469335
/*[clinic input]
93479336
os.initgroups
93489337
9349-
username as oname: FSConverter
9338+
username as oname: unicode_fs_encoded
93509339
gid: gid_t
93519340
/
93529341
@@ -9359,7 +9348,7 @@ group id.
93599348

93609349
static PyObject *
93619350
os_initgroups_impl(PyObject *module, PyObject *oname, gid_t gid)
9362-
/*[clinic end generated code: output=59341244521a9e3f input=0cb91bdc59a4c564]*/
9351+
/*[clinic end generated code: output=59341244521a9e3f input=17d8fbe2dea42ca4]*/
93639352
#endif
93649353
{
93659354
const char *username = PyBytes_AS_STRING(oname);
@@ -13115,16 +13104,16 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
1311513104
/*[clinic input]
1311613105
os.putenv
1311713106
13118-
name: FSConverter
13119-
value: FSConverter
13107+
name: unicode_fs_encoded
13108+
value: unicode_fs_encoded
1312013109
/
1312113110
1312213111
Change or add an environment variable.
1312313112
[clinic start generated code]*/
1312413113

1312513114
static PyObject *
1312613115
os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
13127-
/*[clinic end generated code: output=d29a567d6b2327d2 input=a97bc6152f688d31]*/
13116+
/*[clinic end generated code: output=d29a567d6b2327d2 input=84fcd30f873c8c45]*/
1312813117
{
1312913118
const char *name_string = PyBytes_AS_STRING(name);
1313013119
const char *value_string = PyBytes_AS_STRING(value);
@@ -13167,15 +13156,15 @@ os_unsetenv_impl(PyObject *module, PyObject *name)
1316713156
#else
1316813157
/*[clinic input]
1316913158
os.unsetenv
13170-
name: FSConverter
13159+
name: unicode_fs_encoded
1317113160
/
1317213161
1317313162
Delete an environment variable.
1317413163
[clinic start generated code]*/
1317513164

1317613165
static PyObject *
1317713166
os_unsetenv_impl(PyObject *module, PyObject *name)
13178-
/*[clinic end generated code: output=54c4137ab1834f02 input=2bb5288a599c7107]*/
13167+
/*[clinic end generated code: output=54c4137ab1834f02 input=78ff12e505ade80a]*/
1317913168
{
1318013169
if (PySys_Audit("os.unsetenv", "(O)", name) < 0) {
1318113170
return NULL;
@@ -15229,14 +15218,14 @@ os_urandom_impl(PyObject *module, Py_ssize_t size)
1522915218
/*[clinic input]
1523015219
os.memfd_create
1523115220
15232-
name: FSConverter
15221+
name: unicode_fs_encoded
1523315222
flags: unsigned_int(bitwise=True, c_default="MFD_CLOEXEC") = MFD_CLOEXEC
1523415223
1523515224
[clinic start generated code]*/
1523615225

1523715226
static PyObject *
1523815227
os_memfd_create_impl(PyObject *module, PyObject *name, unsigned int flags)
15239-
/*[clinic end generated code: output=6681ede983bdb9a6 input=a42cfc199bcd56e9]*/
15228+
/*[clinic end generated code: output=6681ede983bdb9a6 input=cd0eb092cfac474b]*/
1524015229
{
1524115230
int fd;
1524215231
const char *bytes = PyBytes_AS_STRING(name);

Modules/socketmodule.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7278,15 +7278,15 @@ Returns a list of network interface information (index, name) tuples.");
72787278

72797279
/*[clinic input]
72807280
_socket.if_nametoindex
7281-
oname: object(converter="PyUnicode_FSConverter")
7281+
oname: unicode_fs_encoded
72827282
/
72837283
72847284
Returns the interface index corresponding to the interface name if_name.
72857285
[clinic start generated code]*/
72867286

72877287
static PyObject *
72887288
_socket_if_nametoindex_impl(PyObject *module, PyObject *oname)
7289-
/*[clinic end generated code: output=289a411614f30244 input=01e0f1205307fb77]*/
7289+
/*[clinic end generated code: output=289a411614f30244 input=6125dc20683560cf]*/
72907290
{
72917291
#ifdef MS_WINDOWS
72927292
NET_IFINDEX index;
@@ -7295,7 +7295,6 @@ _socket_if_nametoindex_impl(PyObject *module, PyObject *oname)
72957295
#endif
72967296

72977297
index = if_nametoindex(PyBytes_AS_STRING(oname));
7298-
Py_DECREF(oname);
72997298
if (index == 0) {
73007299
/* if_nametoindex() doesn't set errno */
73017300
PyErr_SetString(PyExc_OSError, "no interface with this name");

0 commit comments

Comments
 (0)