@@ -125,7 +125,7 @@ CALL_XML_HANDLER_SETTER(const struct HandlerInfo *handler_info,
125125}
126126
127127static int
128- set_error_code (PyObject * err , enum XML_Error code )
128+ set_xml_error_attr_code (PyObject * err , enum XML_Error code )
129129{
130130 PyObject * v = PyLong_FromLong ((long )code );
131131 int ok = v != NULL && PyObject_SetAttr (err , & _Py_ID (code ), v ) != -1 ;
@@ -137,7 +137,7 @@ set_error_code(PyObject *err, enum XML_Error code)
137137 * false on an exception.
138138 */
139139static int
140- set_error_location (PyObject * err , const char * name , XML_Size value )
140+ set_xml_error_attr_location (PyObject * err , const char * name , XML_Size value )
141141{
142142 PyObject * v = PyLong_FromSize_t ((size_t )value );
143143 int ok = v != NULL && PyObject_SetAttrString (err , name , v ) != -1 ;
@@ -146,42 +146,32 @@ set_error_location(PyObject *err, const char *name, XML_Size value)
146146}
147147
148148
149- static PyObject *
150- format_xml_error (enum XML_Error code , XML_Size lineno , XML_Size column )
151- {
152- const char * errmsg = XML_ErrorString (code );
153- PyUnicodeWriter * writer = PyUnicodeWriter_Create (strlen (errmsg ) + 1 );
154- if (writer == NULL ) {
155- return NULL ;
156- }
157- if (PyUnicodeWriter_Format (writer ,
158- "%s: line %zu, column %zu" ,
159- errmsg , (size_t )lineno , (size_t )column ) < 0 )
160- {
161- PyUnicodeWriter_Discard (writer );
162- return NULL ;
163- }
164- return PyUnicodeWriter_Finish (writer );
165- }
166-
167149static PyObject *
168150set_xml_error (pyexpat_state * state ,
169151 enum XML_Error code , XML_Size lineno , XML_Size column ,
170152 const char * errmsg )
171153{
172- PyObject * arg = errmsg == NULL
173- ? format_xml_error (code , lineno , column )
174- : PyUnicode_FromStringAndSize (errmsg , strlen (errmsg ));
154+ PyObject * arg ;
155+ if (errmsg == NULL ) {
156+ arg = PyUnicode_FromFormat (
157+ "%s: line %zu, column %zu" ,
158+ XML_ErrorString (code ),
159+ (size_t )lineno , (size_t )column
160+ );
161+ }
162+ else {
163+ arg = PyUnicode_FromStringAndSize (errmsg , strlen (errmsg ));
164+ }
175165 if (arg == NULL ) {
176166 return NULL ;
177167 }
178168 PyObject * res = PyObject_CallOneArg (state -> error , arg );
179169 Py_DECREF (arg );
180170 if (
181171 res != NULL
182- && set_error_code (res , code )
183- && set_error_location (res , "lineno" , lineno )
184- && set_error_location (res , "offset" , column )
172+ && set_xml_error_attr_code (res , code )
173+ && set_xml_error_attr_location (res , "lineno" , lineno )
174+ && set_xml_error_attr_location (res , "offset" , column )
185175 ) {
186176 PyErr_SetObject (state -> error , res );
187177 }
@@ -1294,6 +1284,50 @@ pyexpat_xmlparser_SetBillionLaughsAttackProtectionMaximumAmplification_impl(xmlp
12941284}
12951285#endif
12961286
1287+ #if XML_COMBINED_VERSION >= 20702
1288+ static PyObject *
1289+ set_activation_threshold (xmlparseobject * self ,
1290+ PyTypeObject * cls ,
1291+ unsigned long long threshold ,
1292+ XML_Bool (* setter )(XML_Parser , unsigned long long ))
1293+ {
1294+ assert (self -> itself != NULL );
1295+ if (setter (self -> itself , threshold ) == XML_TRUE ) {
1296+ Py_RETURN_NONE ;
1297+ }
1298+ // The setter fails if self->itself is NULL (which is not possible here)
1299+ // or is a non-root parser, which currently only happens for parsers
1300+ // created by ExternalEntityParserCreate().
1301+ pyexpat_state * state = PyType_GetModuleState (cls );
1302+ return set_invalid_arg (state , self , "parser must be a root parser" );
1303+ }
1304+
1305+ static PyObject *
1306+ set_maximum_amplification (xmlparseobject * self ,
1307+ PyTypeObject * cls ,
1308+ float max_factor ,
1309+ XML_Bool (* setter )(XML_Parser , float ))
1310+ {
1311+ assert (self -> itself != NULL );
1312+ if (setter (self -> itself , max_factor ) == XML_TRUE ) {
1313+ Py_RETURN_NONE ;
1314+ }
1315+ // The setter fails if self->itself is NULL (which is not possible here),
1316+ // is a non-root parser, which currently only happens for parsers created
1317+ // by ExternalEntityParserCreate(), or if 'max_factor' is NaN or < 1.0.
1318+ pyexpat_state * state = PyType_GetModuleState (cls );
1319+ // Note: Expat has no API to determine whether a parser is a root parser,
1320+ // and since the Expat functions for defining the various maximum allowed
1321+ // amplifcation factors fail when a bad parser or an out-of-range factor
1322+ // is given without specifying which check failed, we check whether the
1323+ // factor is out-of-range to improve the error message. See also gh-90949.
1324+ const char * message = (isnan (max_factor ) || max_factor < 1.0f )
1325+ ? "'max_factor' must be at least 1.0"
1326+ : "parser must be a root parser" ;
1327+ return set_invalid_arg (state , self , message );
1328+ }
1329+ #endif
1330+
12971331#if XML_COMBINED_VERSION >= 20702
12981332/*[clinic input]
12991333@permit_long_summary
0 commit comments