8000 gh-64490: Fix bugs in argument clinic varargs processing (#32092) · python/cpython@0da7283 · GitHub
[go: up one dir, main page]

Skip to content
Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0da7283

Browse files
authored
gh-64490: Fix bugs in argument clinic varargs processing (#32092)
1 parent 351842b commit 0da7283

11 files changed

+612
-11
lines changed

Include/internal/pycore_global_objects_fini_generated.h

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

Include/internal/pycore_global_strings.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ struct _Py_global_strings {
472472
STRUCT_FOR_ID(keyfile)
473473
STRUCT_FOR_ID(keys)
474474
STRUCT_FOR_ID(kind)
475+
STRUCT_FOR_ID(kw)
476+
8000 STRUCT_FOR_ID(kw1)
477+
STRUCT_FOR_ID(kw2)
475478
STRUCT_FOR_ID(lambda)
476479
STRUCT_FOR_ID(last)
477480
STRUCT_FOR_ID(last_node)
@@ -570,6 +573,8 @@ struct _Py_global_strings {
570573
STRUCT_FOR_ID(pid)
571574
STRUCT_FOR_ID(policy)
572575
STRUCT_FOR_ID(pos)
576+
STRUCT_FOR_ID(pos1)
577+
STRUCT_FOR_ID(pos2)
573578
STRUCT_FOR_ID(print_file_and_line)
574579
STRUCT_FOR_ID(priority)
575580
STRUCT_FOR_ID(progress)

Include/internal/pycore_runtime_init_generated.h

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

Include/internal/pycore_unicodeobject_generated.h

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

Lib/test/clinic.test

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3845,7 +3845,6 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
38453845
};
38463846
#undef KWTUPLE
38473847
PyObject *argsbuf[2];
3848-
Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
38493848
PyObject *a;
38503849
PyObject *__clinic_args = NULL;
38513850

@@ -3864,7 +3863,7 @@ exit:
38643863

38653864
static PyObject *
38663865
test_vararg_impl(PyObject *module, PyObject *a, PyObject *args)
3867-
/*[clinic end generated code: output=6661f3ca97d85e8c input=81d33815ad1bae6e]*/
3866+
/*[clinic end generated code: output=880365c61ae205d7 input=81d33815ad1bae6e]*/
38683867

38693868
/*[clinic input]
38703869
test_vararg_with_default
@@ -3918,7 +3917,7 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar
39183917
};
39193918
#undef KWTUPLE
39203919
PyObject *argsbuf[3];
3921-
Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
3920+
Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
39223921
PyObject *a;
39233922
PyObject *__clinic_args = NULL;
39243923
int b = 0;
@@ -3947,7 +3946,7 @@ exit:
39473946
static PyObject *
39483947
test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
39493948
int b)
3950-
/*[clinic end generated code: output=5fe3cfccb1bef781 input=6e110b54acd9b22d]*/
3949+
/*[clinic end generated code: output=291e9a5a09831128 input=6e110b54acd9b22d]*/
39513950

39523951
/*[clinic input]
39533952
test_vararg_with_only_defaults

Lib/test/test_clinic.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,15 @@ def test_parameters_not_permitted_after_slash_for_now(self):
730730
x: int
731731
""")
732732

733+
def test_parameters_no_more_than_one_vararg(self):
734+
s = self.parse_function_should_fail("""
735+
module foo
736+
foo.bar
737+
*vararg1: object
738+
*vararg2: object
739+
""")
740+
self.assertEqual(s, "Error on line 0:\nToo many var args\n")
741+
733742
def test_function_not_at_column_0(self):
734743
function = self.parse_function("""
735744
module foo
@@ -1222,13 +1231,47 @@ def test_keyword_only_parameter(self):
12221231
ac_tester.keyword_only_parameter(1)
12231232
self.assertEqual(ac_tester.keyword_only_parameter(a=1), (1,))
12241233

1234+
def test_posonly_vararg(self):
1235+
with self.assertRaises(TypeError):
1236+
ac_tester.posonly_vararg()
1237+
self.assertEqual(ac_tester.posonly_vararg(1, 2), (1, 2, ()))
1238+
self.assertEqual(ac_tester.posonly_vararg(1, b=2), (1, 2, ()))
1239+
self.assertEqual(ac_tester.posonly_vararg(1, 2, 3, 4), (1, 2, (3, 4)))
1240+
12251241
def test_vararg_and_posonly(self):
12261242
with self.assertRaises(TypeError):
12271243
ac_tester.vararg_and_posonly()
12281244
with self.assertRaises(TypeError):
12291245
ac_tester.vararg_and_posonly(1, b=2)
12301246
self.assertEqual(ac_tester.vararg_and_posonly(1, 2, 3, 4), (1, (2, 3, 4)))
12311247

1248+
def test_vararg(self):
1249+
with self.assertRaises(TypeError):
1250+
ac_tester.vararg()
1251+
with self.assertRaises(TypeError):
1252+
ac_tester.vararg(1, b=2)
1253+
self.assertEqual(ac_tester.vararg(1, 2, 3, 4), (1, (2, 3, 4)))
1254+
1255+
def test_vararg_with_default(self):
1256+
with self.assertRaises(TypeError):
1257+
ac_tester.vararg_with_default()
1258+
self.assertEqual(ac_tester.vararg_with_default(1, b=False), (1, (), False))
1259+
self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4), (1, (2, 3, 4), False))
1260+
self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4, b=True), (1, (2, 3, 4), True))
1261+
1262+
def test_vararg_with_only_defaults(self):
1263+
self.assertEqual(ac_tester.vararg_with_only_defaults(), ((), None))
1264+
self.assertEqual(ac_tester.vararg_with_only_defaults(b=2), ((), 2))
1265+
self.assertEqual(ac_tester.vararg_with_only_defaults(1, b=2), ((1, ), 2))
1266+
self.assertEqual(ac_tester.vararg_with_only_defaults(1, 2, 3, 4), ((1, 2, 3, 4), None))
1267+
self.assertEqual(ac_tester.vararg_with_only_defaults(1, 2, 3, 4, b=5), ((1, 2, 3, 4), 5))
1268+
1269+
def test_gh_32092_oob(self):
1270+
ac_tester.gh_32092_oob(1, 2, 3, 4, kw1=5, kw2=6)
1271+
1272+
def test_gh_32092_kw_pass(self):
1273+
ac_tester.gh_32092_kw_pass(1, 2, 3)
1274+
12321275
def test_gh_99233_refcount(self):
12331276
arg = '*A unique string is not referenced by anywhere else.*'
12341277
arg_refcount_origin = sys.getrefcount(arg)
@@ -1241,5 +1284,6 @@ def test_gh_99240_double_free(self):
12411284
with self.assertRaisesRegex(TypeError, expected_error):
12421285
ac_tester.gh_99240_double_free('a', '\0b')
12431286

1287+
12441288
if __name__ == "__main__":
12451289
unittest.main()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Argument Clinic varargs bugfixes
2+
3+
* Fix out-of-bounds error in :c:func:`!_PyArg_UnpackKeywordsWithVararg`.
4+
* Fix incorrect check which allowed more than one varargs in clinic.py.
5+
* Fix miscalculation of ``noptargs`` in generated code.
6+
* Do not generate ``noptargs`` when there is a vararg argument and no optional argument.
7+

Modules/_testclinic.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,25 @@ keyword_only_parameter_impl(PyObject *module, PyObject *a)
950950
}
951951

952952

953+
/*[clinic input]
954+
posonly_vararg
955+
956+
a: object
957+
/
958+
b: object
959+
*args: object
960+
961+
[clinic start generated code]*/
962+
963+
static PyObject *
964+
posonly_vararg_impl(PyObject *module, PyObject *a, PyObject *b,
965+
PyObject *args)
966+
/*[clinic end generated code: output=ee6713acda6b954e input=783427fe7ec2b67a]*/
967+
{
968+
return pack_arguments_newref(3, a, b, args);
969+
}
970+
971+
953972
/*[clinic input]
954973
vararg_and_posonly
955974
@@ -967,6 +986,100 @@ vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args)
967986
}
968987

969988

989+
/*[clinic input]
990+
vararg
991+
992+
a: object
993+
*args: object
994+
995+
[clinic start generated code]*/
996+
997+
static PyObject *
998+
vararg_impl(PyObject *module, PyObject *a, PyObject *args)
999+
/*[clinic end generated code: output=91ab7a0efc52dd5e input=02c0f772d05f591e]*/
1000+
{
1001+
return pack_arguments_newref(2, a, args);
1002+
}
1003+
1004+
1005+
/*[clinic input]
1006+
vararg_with_default
1007+
1008+
a: object
1009+
*args: object
1010+
b: bool = False
1011+
1012+
[clinic start generated code]*/
1013+
1014+
static PyObject *
1015+
vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
1016+
int b)
1017+
/*[clinic end generated code: output=182c01035958ce92 input=68cafa6a79f89e36]*/
1018+
{
1019+
PyObject *obj_b = b ? Py_True : Py_False;
1020+
return pack_arguments_newref(3, a, args, obj_b);
1021+
}
1022+
1023+
1024+
/*[clinic input]
1025+
vararg_with_only_defaults
1026+
1027+
*args: object
1028+
b: object = None
1029+
1030+
[clinic start generated code]*/
1031+
1032+
static PyObject *
1033+
vararg_with_only_defaults_impl(PyObject *module, PyObject *args, PyObject *b)
1034+
/*[clinic end generated code: output=c06b1826d91f2f7b input=678c069bc67550e1]*/
1035+
{
1036+
return pack_arguments_newref(2, args, b);
1037+
}
1038+
1039+
1040+
1041+
/*[clinic input]
1042+
gh_32092_oob
1043+
1044+
pos1: object
1045+
pos2: object
1046+
*varargs: object
1047+
kw1: object = None
1048+
kw2: object = None
1049+
1050+
Proof-of-concept of GH-32092 OOB bug.
1051+
1052+
[clinic start generated code]*/
1053+
1054+
static PyObject *
1055+
gh_32092_oob_impl(PyObject *module, PyObject *pos1, PyObject *pos2,
1056+
PyObject *varargs, PyObject *kw1, PyObject *kw2)
1057+
/*[clinic end generated code: output=ee259c130054653f input=46d15c881608f8ff]*/
1058+
{
1059+
Py_RETURN_NONE;
1060+
}
1061+
1062+
1063+
/*[clinic input]
1064+
gh_32092_kw_pass
1065+
1066+
pos: object
1067+
*args: object
1068+
kw: object = None
1069+
1070+
Proof-of-concept of GH-32092 keyword args passing bug.
1071+
1072+
[clinic start generated code]*/
1073+
1074+
static PyObject *
1075+
gh_32092_kw_pass_impl(PyObject *module, PyObject *pos, PyObject *args,
1076+
PyObject *kw)
1077+
/*[clinic end generated code: output=4a2bbe4f7c8604e9 input=5c0bd5b9079a0cce]*/
1078+
{
1079+
Py_RETURN_NONE;
1080+
}
1081+
1082+
9701083
/*[clinic input]
9711084
gh_99233_refcount
9721085
@@ -1046,7 +1159,13 @@ static PyMethodDef tester_methods[] = {
10461159
POSONLY_KEYWORDS_OPT_KWONLY_OPT_METHODDEF
10471160
POSONLY_OPT_KEYWORDS_OPT_KWONLY_OPT_METHODDEF
10481161
KEYWORD_ONLY_PARAMETER_METHODDEF
1162+
POSONLY_VARARG_METHODDEF
10491163
VARARG_AND_POSONLY_METHODDEF
1164+
VARARG_METHODDEF
1165+
VARARG_WITH_DEFAULT_METHODDEF
1166+
VARARG_WITH_ONLY_DEFAULTS_METHODDEF
1167+
GH_32092_OOB_METHODDEF
1168+
GH_32092_KW_PASS_METHODDEF
10501169
GH_99233_REFCOUNT_METHODDEF
10511170
GH_99240_DOUBLE_FREE_METHODDEF
10521171
{NULL, NULL}

0 commit comments

Comments
 (0)
0