@@ -190,11 +190,16 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
190190 return NULL ;
191191 }
192192
193- /* keyword Placeholder prohibition */
193+ /* keyword Placeholder prohibition and key type validation */
194194 if (kw != NULL ) {
195195 PyObject * key , * val ;
196196 Py_ssize_t pos = 0 ;
197197 while (PyDict_Next (kw , & pos , & key , & val )) {
198+ if (!PyUnicode_Check (key )) {
199+ PyErr_SetString (PyExc_TypeError ,
200+ "keywords must be strings" );
201+ return NULL ;
202+ }
198203 if (val == phold ) {
199204 PyErr_SetString (PyExc_TypeError ,
200205 "Placeholder cannot be passed as a keyword argument" );
@@ -493,18 +498,27 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
493498 PyTuple_SET_ITEM (tot_kwnames , pto_nkwds + i , key );
494499 }
495500
496- /* Copy pto_keywords with overlapping call keywords merged
497- * Note, tail is already coppied. */
498501 Py_ssize_t pos = 0 , i = 0 ;
499502 PyObject * keyword_dict = n_merges ? pto_kw_merged : pto -> kw ;
503+ int valid_keys = 1 ;
500504 Py_BEGIN_CRITICAL_SECTION (keyword_dict );
501505 while (PyDict_Next (keyword_dict , & pos , & key , & val )) {
506+ if (!PyUnicode_Check (key )) {
507+ valid_keys = 0 ;
508+ break ;
509+ }
502510 assert (i < pto_nkwds );
503511 PyTuple_SET_ITEM (tot_kwnames , i , Py_NewRef (key ));
504512 stack [tot_nargs + i ] = val ;
505513 i ++ ;
506514 }
507515 Py_END_CRITICAL_SECTION ();
516+ if (!valid_keys ) {
517+ PyErr_SetString (PyExc_TypeError , "keywords must be strings" );
518+ Py_XDECREF (pto_kw_merged );
519+ Py_DECREF (tot_kwnames );
520+ goto error ;
521+ }
508522 assert (i == pto_nkwds );
509523 Py_XDECREF (pto_kw_merged );
510524
0 commit comments