@@ -111,7 +111,7 @@ struct HandlerInfo {
111
111
static struct HandlerInfo handler_info [64 ];
112
112
113
113
static int
114
- set_error_code (PyObject * err , enum XML_Error code )
114
+ set_xml_error_attr_code (PyObject * err , enum XML_Error code )
115
115
{
116
116
PyObject * v = PyLong_FromLong ((long )code );
117
117
int ok = v != NULL && PyObject_SetAttr (err , & _Py_ID (code ), v ) != -1 ;
@@ -123,7 +123,7 @@ set_error_code(PyObject *err, enum XML_Error code)
123
123
* false on an exception.
124
124
*/
125
125
static int
126
- set_error_location (PyObject * err , const char * name , XML_Size value )
126
+ set_xml_error_attr_location (PyObject * err , const char * name , XML_Size value )
127
127
{
128
128
PyObject * v = PyLong_FromSize_t ((size_t )value );
129
129
int ok = v != NULL && PyObject_SetAttrString (err , name , v ) != -1 ;
@@ -132,32 +132,32 @@ set_error_location(PyObject *err, const char *name, XML_Size value)
132
132
}
133
133
134
134
135
- static PyObject *
136
- format_xml_error (enum XML_Error code , XML_Size lineno , XML_Size column )
137
- {
138
- const char * errmsg = XML_ErrorString (code );
139
- return PyUnicode_FromFormat ("%s: line %zu, column %zu" ,
140
- errmsg , (size_t )lineno , (size_t )column );
141
- }
142
-
143
135
static PyObject *
144
136
set_xml_error (pyexpat_state * state ,
145
137
enum XML_Error code , XML_Size lineno , XML_Size column ,
146
138
const char * errmsg )
147
139
{
148
- PyObject * arg = errmsg == NULL
149
- ? format_xml_error (code , lineno , column )
150
- : PyUnicode_FromStringAndSize (errmsg , strlen (errmsg ));
140
+ PyObject * arg ;
141
+ if (errmsg == NULL ) {
142
+ arg = PyUnicode_FromFormat (
143
+ "%s: line %zu, column %zu" ,
144
+ XML_ErrorString (code ),
145
+ (size_t )lineno , (size_t )column
146
+ );
147
+ }
148
+ else {
149
+ arg = PyUnicode_FromStringAndSize (errmsg , strlen (errmsg ));
150
+ }
151
151
if (arg == NULL ) {
152
152
return NULL ;
153
153
}
154
154
PyObject * res = PyObject_CallOneArg (state -> error , arg );
155
155
Py_DECREF (arg );
156
156
if (
157
157
res != NULL
158
- && set_error_code (res , code )
159
- && set_error_location (res , "lineno" , lineno )
160
- && set_error_location (res , "offset" , column )
158
+ && set_xml_error_attr_code (res , code )
159
+ && set_xml_error_attr_location (res , "lineno" , lineno )
160
+ && set_xml_error_attr_location (res , "offset" , column )
161
161
) {
162
162
PyErr_SetObject (state -> error , res );
163
163
}
@@ -1134,6 +1134,50 @@ pyexpat_xmlparser_UseForeignDTD_impl(xmlparseobject *self, PyTypeObject *cls,
1134
1134
}
1135
1135
#endif
1136
1136
1137
+ #if XML_COMBINED_VERSION >= 20702
1138
+ static PyObject *
1139
+ set_activation_threshold (xmlparseobject * self ,
1140
+ PyTypeObject * cls ,
1141
+ unsigned long long threshold ,
1142
+ XML_Bool (* setter )(XML_Parser , unsigned long long ))
1143
+ {
1144
+ assert (self -> itself != NULL );
1145
+ if (setter (self -> itself , threshold ) == XML_TRUE ) {
1146
+ Py_RETURN_NONE ;
1147
+ }
1148
+ // The setter fails if self->itself is NULL (which is not possible here)
1149
+ // or is a non-root parser, which currently only happens for parsers
1150
+ // created by ExternalEntityParserCreate().
1151
+ pyexpat_state * state = PyType_GetModuleState (cls );
1152
+ return set_invalid_arg (state , self , "parser must be a root parser" );
1153
+ }
1154
+
1155
+ static PyObject *
1156
+ set_maximum_amplification (xmlparseobject * self ,
1157
+ PyTypeObject * cls ,
1158
+ float max_factor ,
1159
+ XML_Bool (* setter )(XML_Parser , float ))
1160
+ {
1161
+ assert (self -> itself != NULL );
1162
+ if (setter (self -> itself , max_factor ) == XML_TRUE ) {
1163
+ Py_RETURN_NONE ;
1164
+ }
1165
+ // The setter fails if self->itself is NULL (which is not possible here),
1166
+ // is a non-root parser, which currently only happens for parsers created
1167
+ // by ExternalEntityParserCreate(), or if 'max_factor' is NaN or < 1.0.
1168
+ pyexpat_state * state = PyType_GetModuleState (cls );
1169
+ // Note: Expat has no API to determine whether a parser is a root parser,
1170
+ // and since the Expat functions for defining the various maximum allowed
1171
+ // amplifcation factors fail when a bad parser or an out-of-range factor
1172
+ // is given without specifying which check failed, we check whether the
1173
+ // factor is out-of-range to improve the error message. See also gh-90949.
1174
+ const char * message = (isnan (max_factor ) || max_factor < 1.0f )
1175
+ ? "'max_factor' must be at least 1.0"
1176
+ : "parser must be a root parser" ;
1177
+ return set_invalid_arg (state , self , message );
1178
+ }
1179
+ #endif
1180
+
1137
1181
#if XML_COMBINED_VERSION >= 20702
1138
1182
/*[clinic input]
1139
1183
pyexpat.xmlparser.SetAllocTrackerActivationThreshold
@@ -1153,15 +1197,10 @@ pyexpat_xmlparser_SetAllocTrackerActivationThreshold_impl(xmlparseobject *self,
1153
1197
unsigned long long threshold )
1154
1198
/*[clinic end generated code: output=bed7e93207ba08c5 input=9c706b75c18e4ea1]*/
1155
1199
{
1156
- assert (self -> itself != NULL );
1157
- if (XML_SetAllocTrackerActivationThreshold (self -> itself , threshold ) == XML_TRUE ) {
1158
- Py_RETURN_NONE ;
1159
- }
1160
- // XML_SetAllocTrackerActivationThreshold() can only fail if self->itself
1161
- // is not a root parser (currently, this is equivalent to be created
1162
- // by ExternalEntityParserCreate()).
1163
- pyexpat_state * state = PyType_GetModuleState (cls );
1164
- return set_invalid_arg (state , self , "parser must be a root parser" );
1200
+ return set_activation_threshold (
1201
+ self , cls , threshold ,
1202
+ XML_SetAllocTrackerActivationThreshold
1203
+ );
1165
1204
}
1166
1205
#endif
1167
1206
@@ -1194,24 +1233,10 @@ pyexpat_xmlparser_SetAllocTrackerMaximumAmplification_impl(xmlparseobject *self,
1194
1233
float max_factor )
1195
1234
/*[clinic end generated code: output=6e44bd48c9b112a0 input=918b9266b490a722]*/
1196
1235
{
1197
- assert (self -> itself != NULL );
1198
- if (XML_SetAllocTrackerMaximumAmplification (self -> itself , max_factor ) == XML_TRUE ) {
1199
- Py_RETURN_NONE ;
1200
- }
1201
- // XML_SetAllocTrackerMaximumAmplification() can fail if self->itself
1202
- // is not a root parser (currently, this is equivalent to be created
1203
- // by ExternalEntityParserCreate()) or if 'max_factor' is NaN or < 1.0.
1204
- //
1205
- // Expat does not provide a way to determine whether a parser is a root
1206
- // or not, nor does it provide a way to distinguish between failures in
1207
- // XML_SetAllocTrackerMaximumAmplification() (see gh-90949), we manually
1208
- // detect the factor out-of-range issue here so that users have a better
1209
- // error message.
1210
- pyexpat_state * state = PyType_GetModuleState (cls );
1211
- const char * message = (isnan (max_factor ) || max_factor < 1.0f )
1212
- ? "'max_factor' must be at least 1.0"
1213
- : "parser must be a root parser" ;
1214
- return set_invalid_arg (state , self , message );
1236
+ return set_maximum_amplification (
1237
+ self , cls , max_factor ,
1238
+ XML_SetAllocTrackerMaximumAmplification
1239
+ );
1215
1240
}
1216
1241
#endif
1217
1242
0 commit comments