Skip to content

Commit 90cd009

Browse files
[3.14] gh-139748: fix leaks in AC error paths when using unicode FS-b… (#139789)
* [3.14] 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 077652b commit 90cd009

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
@@ -2833,6 +2833,8 @@ def test_cli_converters(self):
28332833
"uint64",
28342834
"uint8",
28352835
"unicode",
2836+
"unicode_fs_decoded",
2837+
"unicode_fs_encoded",
28362838
"unsigned_char",
28372839
"unsigned_int",
28382840
"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
@@ -527,6 +527,13 @@ def test_symtable_entry_repr(self):
527527
expected = f"<symtable entry top({self.top.get_id()}), line {self.top.get_lineno()}>"
528528
self.assertEqual(repr(self.top._table), expected)
529529

530+
def test__symtable_refleak(self):
531+
# Regression test for reference leak in PyUnicode_FSDecoder.
532+
# See https://github.com/python/cpython/issues/139748.
533+
mortal_str = 'this is a mortal string'
534+
# check error path when 'compile_type' AC conversion failed
535+
self.assertRaises(TypeError, symtable.symtable, '', mortal_str, 1)
536+
530537

531538
class ComprehensionTests(unittest.TestCase):
532539
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
@@ -1831,14 +1831,14 @@ _certificate_to_der(_sslmodulestate *state, X509 *certificate)
18311831

18321832
/*[clinic input]
18331833
_ssl._test_decode_cert
1834-
path: object(converter="PyUnicode_FSConverter")
1834+
path: unicode_fs_encoded
18351835
/
18361836
18371837
[clinic start generated code]*/
18381838

18391839
static PyObject *
18401840
_ssl__test_decode_cert_impl(PyObject *module, PyObject *path)
1841-
/*[clinic end generated code: output=96becb9abb23c091 input=cdeaaf02d4346628]*/
1841+
/*[clinic end generated code: output=96becb9abb23c091 input=cb4988d5e651a4f8]*/
18421842
{
18431843
PyObject *retval = NULL;
18441844
X509 *x=NULL;
@@ -1868,7 +1868,6 @@ _ssl__test_decode_cert_impl(PyObject *module, PyObject *path)
18681868
X509_free(x);
18691869

18701870
fail0:
1871-
Py_DECREF(path);
18721871
if (cert != NULL) BIO_free(cert);
18731872
return retval;
18741873
}

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
@@ -3122,17 +3122,6 @@ class dev_t_return_converter(unsigned_long_return_converter):
31223122
conversion_fn = '_PyLong_FromDev'
31233123
unsigned_cast = '(dev_t)'
31243124
3125-
class FSConverter_converter(CConverter):
3126-
type = 'PyObject *'
3127-
converter = 'PyUnicode_FSConverter'
3128-
def converter_init(self):
3129-
if self.default is not unspecified:
3130-
fail("FSConverter_converter does not support default values")
3131-
self.c_default = 'NULL'
3132-
3133-
def cleanup(self):
3134-
return "Py_XDECREF(" + self.name + ");\n"
3135-
31363125
class pid_t_converter(CConverter):
31373126
type = 'pid_t'
31383127
format_unit = '" _Py_PARSE_PID "'
@@ -3196,7 +3185,7 @@ class confname_converter(CConverter):
31963185
""", argname=argname, converter=self.converter, table=self.table)
31973186
31983187
[python start generated code]*/
3199-
/*[python end generated code: output=da39a3ee5e6b4b0d input=8189d5ae78244626]*/
3188+
/*[python end generated code: output=da39a3ee5e6b4b0d input=d2759f2332cd39b3]*/
32003189

32013190
/*[clinic input]
32023191
@@ -6098,14 +6087,14 @@ os_system_impl(PyObject *module, const wchar_t *command)
60986087
/*[clinic input]
60996088
os.system -> long
61006089
6101-
command: FSConverter
6090+
command: unicode_fs_encoded
61026091
61036092
Execute the command in a subshell.
61046093
[clinic start generated code]*/
61056094

61066095
static long
61076096
os_system_impl(PyObject *module, PyObject *command)
6108-
/*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/
6097+
/*[clinic end generated code: output=290fc437dd4f33a0 input=47c6f24b6dc92881]*/
61096098
{
61106099
long result;
61116100
const char *bytes = PyBytes_AsString(command);
@@ -9285,7 +9274,7 @@ os_getgroups_impl(PyObject *module)
92859274
/*[clinic input]
92869275
os.initgroups
92879276
9288-
username as oname: FSConverter
9277+
username as oname: unicode_fs_encoded
92899278
gid: int
92909279
/
92919280
@@ -9298,12 +9287,12 @@ group id.
92989287

92999288
static PyObject *
93009289
os_initgroups_impl(PyObject *module, PyObject *oname, int gid)
9301-
/*[clinic end generated code: output=7f074d30a425fd3a input=df3d54331b0af204]*/
9290+
/*[clinic end generated code: output=7f074d30a425fd3a input=984e60c7fed88cb4]*/
93029291
#else
93039292
/*[clinic input]
93049293
os.initgroups
93059294
9306-
username as oname: FSConverter
9295+
username as oname: unicode_fs_encoded
93079296
gid: gid_t
93089297
/
93099298
@@ -9316,7 +9305,7 @@ group id.
93169305

93179306
static PyObject *
93189307
os_initgroups_impl(PyObject *module, PyObject *oname, gid_t gid)
9319-
/*[clinic end generated code: output=59341244521a9e3f input=0cb91bdc59a4c564]*/
9308+
/*[clinic end generated code: output=59341244521a9e3f input=17d8fbe2dea42ca4]*/
93209309
#endif
93219310
{
93229311
const char *username = PyBytes_AS_STRING(oname);
@@ -13067,16 +13056,16 @@ os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
1306713056
/*[clinic input]
1306813057
os.putenv
1306913058
13070-
name: FSConverter
13071-
value: FSConverter
13059+
name: unicode_fs_encoded
13060+
value: unicode_fs_encoded
1307213061
/
1307313062
1307413063
Change or add an environment variable.
1307513064
[clinic start generated code]*/
1307613065

1307713066
static PyObject *
1307813067
os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
13079-
/*[clinic end generated code: output=d29a567d6b2327d2 input=a97bc6152f688d31]*/
13068+
/*[clinic end generated code: output=d29a567d6b2327d2 input=84fcd30f873c8c45]*/
1308013069
{
1308113070
const char *name_string = PyBytes_AS_STRING(name);
1308213071
const char *value_string = PyBytes_AS_STRING(value);
@@ -13119,15 +13108,15 @@ os_unsetenv_impl(PyObject *module, PyObject *name)
1311913108
#else
1312013109
/*[clinic input]
1312113110
os.unsetenv
13122-
name: FSConverter
13111+
name: unicode_fs_encoded
1312313112
/
1312413113
1312513114
Delete an environment variable.
1312613115
[clinic start generated code]*/
1312713116

1312813117
static PyObject *
1312913118
os_unsetenv_impl(PyObject *module, PyObject *name)
13130-
/*[clinic end generated code: output=54c4137ab1834f02 input=2bb5288a599c7107]*/
13119+
/*[clinic end generated code: output=54c4137ab1834f02 input=78ff12e505ade80a]*/
1313113120
{
1313213121
if (PySys_Audit("os.unsetenv", "(O)", name) < 0) {
1313313122
return NULL;
@@ -15185,14 +15174,14 @@ os_urandom_impl(PyObject *module, Py_ssize_t size)
1518515174
/*[clinic input]
1518615175
os.memfd_create
1518715176
15188-
name: FSConverter
15177+
name: unicode_fs_encoded
1518915178
flags: unsigned_int(bitwise=True, c_default="MFD_CLOEXEC") = MFD_CLOEXEC
1519015179
1519115180
[clinic start generated code]*/
1519215181

1519315182
static PyObject *
1519415183
os_memfd_create_impl(PyObject *module, PyObject *name, unsigned int flags)
15195-
/*[clinic end generated code: output=6681ede983bdb9a6 input=a42cfc199bcd56e9]*/
15184+
/*[clinic end generated code: output=6681ede983bdb9a6 input=cd0eb092cfac474b]*/
1519615185
{
1519715186
int fd;
1519815187
const char *bytes = PyBytes_AS_STRING(name);

Modules/socketmodule.c

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

72627262
/*[clinic input]
72637263
_socket.if_nametoindex
7264-
oname: object(converter="PyUnicode_FSConverter")
7264+
oname: unicode_fs_encoded
72657265
/
72667266
72677267
Returns the interface index corresponding to the interface name if_name.
72687268
[clinic start generated code]*/
72697269

72707270
static PyObject *
72717271
_socket_if_nametoindex_impl(PyObject *module, PyObject *oname)
7272-
/*[clinic end generated code: output=289a411614f30244 input=01e0f1205307fb77]*/
7272+
/*[clinic end generated code: output=289a411614f30244 input=6125dc20683560cf]*/
72737273
{
72747274
#ifdef MS_WINDOWS
72757275
NET_IFINDEX index;
@@ -7278,7 +7278,6 @@ _socket_if_nametoindex_impl(PyObject *module, PyObject *oname)
72787278
#endif
72797279

72807280
index = if_nametoindex(PyBytes_AS_STRING(oname));
7281-
Py_DECREF(oname);
72827281
if (index == 0) {
72837282
/* if_nametoindex() doesn't set errno */
72847283
PyErr_SetString(PyExc_OSError, "no interface with this name");

0 commit comments

Comments
 (0)