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