Skip to content

Commit 50e518e

Browse files
authored
gh-132097: allow AC to disable fastcall convention to avoid UBSan failures (#131605)
1 parent ea23c89 commit 50e518e

File tree

5 files changed

+246
-134
lines changed

5 files changed

+246
-134
lines changed

Modules/_testclinic.c

+107-58
Original file line numberDiff line numberDiff line change
@@ -1443,25 +1443,69 @@ _testclinic_TestClass_defclass_posonly_varpos_impl(PyObject *self,
14431443
}
14441444

14451445

1446-
/*[clinic input]
1446+
/*
1447+
* # Do NOT use __new__ to generate this method. Compare:
1448+
*
1449+
* [1] With __new__ (METH_KEYWORDS must be added even if we don't want to)
1450+
*
1451+
* varpos_no_fastcall(PyTypeObject *type, PyObject *args, PyObject *kwargs)
1452+
* varpos_no_fastcall_impl(PyTypeObject *type, PyObject *args)
1453+
* no auto-generated METHODDEF macro
1454+
*
1455+
* [2] Without __new__ (automatically METH_FASTCALL, not good for this test)
1456+
*
1457+
* varpos_no_fastcall_impl(PyObject *type, PyObject *args)
1458+
* varpos_no_fastcall(PyObject *type, PyObject *const *args, Py_ssize_t nargs)
1459+
* flags = METH_FASTCALL|METH_CLASS
1460+
*
1461+
* [3] Without __new__ + "@disable fastcall" (what we want)
1462+
*
1463+
* varpos_no_fastcall(PyObject *type, PyObject *args)
1464+
* varpos_no_fastcall_impl(PyTypeObject *type, PyObject *args)
1465+
* flags = METH_VARARGS|METH_CLASS
1466+
*
1467+
* We want to test a non-fastcall class method but without triggering an
1468+
* undefined behaviour at runtime in cfunction_call().
1469+
*
1470+
* At runtime, a METH_VARARGS method called in cfunction_call() must be:
1471+
*
1472+
* (PyObject *, PyObject *) -> PyObject *
1473+
* (PyObject *, PyObject *, PyObject *) -> PyObject *
1474+
*
1475+
* depending on whether METH_KEYWORDS is present or not.
1476+
*
1477+
* AC determines whether a method is a __new__-like method solely bsaed
1478+
* on the method name, and not on its usage or its c_basename, and those
1479+
* methods must always be used with METH_VARARGS|METH_KEYWORDS|METH_CLASS.
1480+
*
1481+
* In particular, using [1] forces us to add METH_KEYWORDS even though
1482+
* the test shouldn't be expecting keyword arguments. Using [2] is also
1483+
* not possible since we want to test non-fastcalls. This is the reason
1484+
* why we need to be able to disable the METH_FASTCALL flag.
1485+
*/
1486+
1487+
/*[clinic input]
1488+
@disable fastcall
14471489
@classmethod
1448-
_testclinic.TestClass.__new__ as varpos_no_fastcall
1490+
_testclinic.TestClass.varpos_no_fastcall
14491491
14501492
*args: tuple
14511493
14521494
[clinic start generated code]*/
14531495

14541496
static PyObject *
1455-
varpos_no_fastcall_impl(PyTypeObject *type, PyObject *args)
1456-
/*[clinic end generated code: output=04e94f2898bb2dde input=c5d3d30a6589f97f]*/
1497+
_testclinic_TestClass_varpos_no_fastcall_impl(PyTypeObject *type,
1498+
PyObject *args)
1499+
/*[clinic end generated code: output=edfacec733aeb9c5 input=3f298d143aa98048]*/
14571500
{
14581501
return Py_NewRef(args);
14591502
}
14601503

14611504

14621505
/*[clinic input]
1506+
@disable fastcall
14631507
@classmethod
1464-
_testclinic.TestClass.__new__ as posonly_varpos_no_fastcall
1508+
_testclinic.TestClass.posonly_varpos_no_fastcall
14651509
14661510
a: object
14671511
b: object
@@ -1471,17 +1515,20 @@ _testclinic.TestClass.__new__ as posonly_varpos_no_fastcall
14711515
[clinic start generated code]*/
14721516

14731517
static PyObject *
1474-
posonly_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a, PyObject *b,
1475-
PyObject *args)
1476-
/*[clinic end generated code: output=b0a0425719f69f5a input=10f29f2c2c6bfdc4]*/
1518+
_testclinic_TestClass_posonly_varpos_no_fastcall_impl(PyTypeObject *type,
1519+
PyObject *a,
1520+
PyObject *b,
1521+
PyObject *args)
1522+
/*[clinic end generated code: output=2c5184aebe020085 input=3621dd172c5193d8]*/
14771523
{
14781524
return pack_arguments_newref(3, a, b, args);
14791525
}
14801526

14811527

14821528
/*[clinic input]
1529+
@disable fastcall
14831530
@classmethod
1484-
_testclinic.TestClass.__new__ as posonly_req_opt_varpos_no_fastcall
1531+
_testclinic.TestClass.posonly_req_opt_varpos_no_fastcall
14851532
14861533
a: object
14871534
b: object = False
@@ -1491,17 +1538,20 @@ _testclinic.TestClass.__new__ as posonly_req_opt_varpos_no_fastcall
14911538
[clinic start generated code]*/
14921539

14931540
static PyObject *
1494-
posonly_req_opt_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a,
1495-
PyObject *b, PyObject *args)
1496-
/*[clinic end generated code: output=3c44915b1a554e2d input=d319302a8748147c]*/
1541+
_testclinic_TestClass_posonly_req_opt_varpos_no_fastcall_impl(PyTypeObject *type,
1542+
PyObject *a,
1543+
PyObject *b,
1544+
PyObject *args)
1545+
/*[clinic end generated code: output=08e533d59bceadf6 input=922fa7851b32e2dd]*/
14971546
{
14981547
return pack_arguments_newref(3, a, b, args);
14991548
}
15001549

15011550

15021551
/*[clinic input]
1552+
@disable fastcall
15031553
@classmethod
1504-
_testclinic.TestClass.__new__ as posonly_poskw_varpos_no_fastcall
1554+
_testclinic.TestClass.posonly_poskw_varpos_no_fastcall
15051555
15061556
a: object
15071557
/
@@ -1511,34 +1561,39 @@ _testclinic.TestClass.__new__ as posonly_poskw_varpos_no_fastcall
15111561
[clinic start generated code]*/
15121562

15131563
static PyObject *
1514-
posonly_poskw_varpos_no_fastcall_impl(PyTypeObject *type, PyObject *a,
1515-
PyObject *b, PyObject *args)
1516-
/*[clinic end generated code: output=6ad74bed4bdc7f96 input=1f8c113e749414a3]*/
1564+
_testclinic_TestClass_posonly_poskw_varpos_no_fastcall_impl(PyTypeObject *type,
1565+
PyObject *a,
1566+
PyObject *b,
1567+
PyObject *args)
1568+
/*[clinic end generated code: output=8ecfda20850e689f input=60443fe0bb8fe3e0]*/
15171569
{
15181570
return pack_arguments_newref(3, a, b, args);
15191571
}
15201572

15211573

15221574
/*[clinic input]
1575+
@disable fastcall
15231576
@classmethod
1524-
_testclinic.TestClass.__new__ as varpos_array_no_fastcall
1577+
_testclinic.TestClass.varpos_array_no_fastcall
15251578
15261579
*args: array
15271580
15281581
[clinic start generated code]*/
15291582

15301583
static PyObject *
1531-
varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject * const *args,
1532-
Py_ssize_t args_length)
1533-
/*[clinic end generated code: output=f99d984346c60d42 input=368d8eea6de48c12]*/
1584+
_testclinic_TestClass_varpos_array_no_fastcall_impl(PyTypeObject *type,
1585+
PyObject * const *args,
1586+
Py_ssize_t args_length)
1587+
/*[clinic end generated code: output=27c9da663e942617 input=9ba5ae1f1eb58777]*/
15341588
{
15351589
return _PyTuple_FromArray(args, args_length);
15361590
}
15371591

15381592

15391593
/*[clinic input]
1594+
@disable fastcall
15401595
@classmethod
1541-
_testclinic.TestClass.__new__ as posonly_varpos_array_no_fastcall
1596+
_testclinic.TestClass.posonly_varpos_array_no_fastcall
15421597
15431598
a: object
15441599
b: object
@@ -1548,18 +1603,21 @@ _testclinic.TestClass.__new__ as posonly_varpos_array_no_fastcall
15481603
[clinic start generated code]*/
15491604

15501605
static PyObject *
1551-
posonly_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a,
1552-
PyObject *b, PyObject * const *args,
1553-
Py_ssize_t args_length)
1554-
/*[clinic end generated code: output=1eec4da1fb5b5978 input=7330c8d819a23548]*/
1606+
_testclinic_TestClass_posonly_varpos_array_no_fastcall_impl(PyTypeObject *type,
1607+
PyObject *a,
1608+
PyObject *b,
1609+
PyObject * const *args,
1610+
Py_ssize_t args_length)
1611+
/*[clinic end generated code: output=71e676f1870b5a7e input=18eadf4c6eaab613]*/
15551612
{
15561613
return pack_arguments_2pos_varpos(a, b, args, args_length);
15571614
}
15581615

15591616

15601617
/*[clinic input]
1618+
@disable fastcall
15611619
@classmethod
1562-
_testclinic.TestClass.__new__ as posonly_req_opt_varpos_array_no_fastcall
1620+
_testclinic.TestClass.posonly_req_opt_varpos_array_no_fastcall
15631621
15641622
a: object
15651623
b: object = False
@@ -1569,19 +1627,21 @@ _testclinic.TestClass.__new__ as posonly_req_opt_varpos_array_no_fastcall
15691627
[clinic start generated code]*/
15701628

15711629
static PyObject *
1572-
posonly_req_opt_varpos_array_no_fastcall_impl(PyTypeObject *type,
1573-
PyObject *a, PyObject *b,
1574-
PyObject * const *args,
1575-
Py_ssize_t args_length)
1576-
/*[clinic end generated code: output=88041c2176135218 input=7f5fd34ee5f9e0bf]*/
1630+
_testclinic_TestClass_posonly_req_opt_varpos_array_no_fastcall_impl(PyTypeObject *type,
1631+
PyObject *a,
1632+
PyObject *b,
1633+
PyObject * const *args,
1634+
Py_ssize_t args_length)
1635+
/*[clinic end generated code: output=abb395cae91d48ac input=5bf791fdad70b480]*/
15771636
{
15781637
return pack_arguments_2pos_varpos(a, b, args, args_length);
15791638
}
15801639

15811640

15821641
/*[clinic input]
1642+
@disable fastcall
15831643
@classmethod
1584-
_testclinic.TestClass.__new__ as posonly_poskw_varpos_array_no_fastcall
1644+
_testclinic.TestClass.posonly_poskw_varpos_array_no_fastcall
15851645
15861646
a: object
15871647
/
@@ -1591,11 +1651,12 @@ _testclinic.TestClass.__new__ as posonly_poskw_varpos_array_no_fastcall
15911651
[clinic start generated code]*/
15921652

15931653
static PyObject *
1594-
posonly_poskw_varpos_array_no_fastcall_impl(PyTypeObject *type, PyObject *a,
1595-
PyObject *b,
1596-
PyObject * const *args,
1597-
Py_ssize_t args_length)
1598-
/*[clinic end generated code: output=70eda18c3667681e input=2b0fcd7bd9bb865c]*/
1654+
_testclinic_TestClass_posonly_poskw_varpos_array_no_fastcall_impl(PyTypeObject *type,
1655+
PyObject *a,
1656+
PyObject *b,
1657+
PyObject * const *args,
1658+
Py_ssize_t args_length)
1659+
/*[clinic end generated code: output=aaddd9530048b229 input=9ed3842f4d472d45]*/
15991660
{
16001661
return pack_arguments_2pos_varpos(a, b, args, args_length);
16011662
}
@@ -1606,27 +1667,15 @@ static struct PyMethodDef test_class_methods[] = {
16061667
_TESTCLINIC_TESTCLASS_DEFCLASS_VARPOS_METHODDEF
16071668
_TESTCLINIC_TESTCLASS_DEFCLASS_POSONLY_VARPOS_METHODDEF
16081669

1609-
{"varpos_no_fastcall", _PyCFunction_CAST(varpos_no_fastcall),
1610-
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
1611-
{"posonly_varpos_no_fastcall", _PyCFunction_CAST(posonly_varpos_no_fastcall),
1612-
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
1613-
{"posonly_req_opt_varpos_no_fastcall", _PyCFunction_CAST(posonly_req_opt_varpos_no_fastcall),
1614-
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
1615-
{"posonly_poskw_varpos_no_fastcall", _PyCFunction_CAST(posonly_poskw_varpos_no_fastcall),
1616-
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
1617-
1618-
{"varpos_array_no_fastcall",
1619-
_PyCFunction_CAST(varpos_array_no_fastcall),
1620-
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
1621-
{"posonly_varpos_array_no_fastcall",
1622-
_PyCFunction_CAST(posonly_varpos_array_no_fastcall),
1623-
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
1624-
{"posonly_req_opt_varpos_array_no_fastcall",
1625-
_PyCFunction_CAST(posonly_req_opt_varpos_array_no_fastcall),
1626-
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
1627-
{"posonly_poskw_varpos_array_no_fastcall",
1628-
_PyCFunction_CAST(posonly_poskw_varpos_array_no_fastcall),
1629-
METH_VARARGS|METH_KEYWORDS|METH_CLASS, ""},
1670+
_TESTCLINIC_TESTCLASS_VARPOS_NO_FASTCALL_METHODDEF
1671+
_TESTCLINIC_TESTCLASS_POSONLY_VARPOS_NO_FASTCALL_METHODDEF
1672+
_TESTCLINIC_TESTCLASS_POSONLY_REQ_OPT_VARPOS_NO_FASTCALL_METHODDEF
1673+
_TESTCLINIC_TESTCLASS_POSONLY_POSKW_VARPOS_NO_FASTCALL_METHODDEF
1674+
1675+
_TESTCLINIC_TESTCLASS_VARPOS_ARRAY_NO_FASTCALL_METHODDEF
1676+
_TESTCLINIC_TESTCLASS_POSONLY_VARPOS_ARRAY_NO_FASTCALL_METHODDEF
1677+
_TESTCLINIC_TESTCLASS_POSONLY_REQ_OPT_VARPOS_ARRAY_NO_FASTCALL_METHODDEF
1678+
_TESTCLINIC_TESTCLASS_POSONLY_POSKW_VARPOS_ARRAY_NO_FASTCALL_METHODDEF
16301679

16311680
{NULL, NULL}
16321681
};

0 commit comments

Comments
 (0)