Skip to content

Commit 52402c3

Browse files
committed
make some changes for the next PR
1 parent 8fa6bd1 commit 52402c3

File tree

4 files changed

+58
-33
lines changed

4 files changed

+58
-33
lines changed

Doc/library/pyexpat.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,8 @@ common XML vulnerabilities.
281281
.. note::
282282

283283
The maximum amplification factor is only considered if the threshold
284-
that can be adjusted :meth:`.SetAllocTrackerActivationThreshold` is
285-
exceeded.
284+
that can be adjusted by :meth:`.SetAllocTrackerActivationThreshold`
285+
is exceeded.
286286

287287
.. versionadded:: next
288288

Doc/whatsnew/3.15.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,8 @@ unittest
556556
xml.parsers.expat
557557
-----------------
558558

559-
* Add :func:`~xml.parsers.expat.xmlparser.SetAllocTrackerActivationThreshold`
560-
and :func:`~xml.parsers.expat.xmlparser.SetAllocTrackerMaximumAmplification`
559+
* Add :meth:`~xml.parsers.expat.xmlparser.SetAllocTrackerActivationThreshold`
560+
and :meth:`~xml.parsers.expat.xmlparser.SetAllocTrackerMaximumAmplification`
561561
to :ref:`xmlparser <xmlparser-objects>` objects to prevent use of
562562
disproportional amounts of dynamic memory from within an Expat parser.
563563
(Contributed by Bénédikt Tran in :gh:`90949`.)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Add :func:`~xml.parsers.expat.xmlparser.SetAllocTrackerActivationThreshold`
2-
and :func:`~xml.parsers.expat.xmlparser.SetAllocTrackerMaximumAmplification`
1+
Add :meth:`~xml.parsers.expat.xmlparser.SetAllocTrackerActivationThreshold`
2+
and :meth:`~xml.parsers.expat.xmlparser.SetAllocTrackerMaximumAmplification`
33
to :ref:`xmlparser <xmlparser-objects>` objects to prevent use of
44
disproportional amounts of dynamic memory from within an Expat parser.
55
Patch by Bénédikt Tran.

Modules/pyexpat.c

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,50 @@ pyexpat_xmlparser_UseForeignDTD_impl(xmlparseobject *self, PyTypeObject *cls,
11741174
}
11751175
#endif
11761176

1177+
#if XML_COMBINED_VERSION >= 20702
1178+
static PyObject *
1179+
set_activation_threshold(xmlparseobject *self,
1180+
PyTypeObject *cls,
1181+
unsigned long long threshold,
1182+
XML_Bool (*setter)(XML_Parser, unsigned long long))
1183+
{
1184+
assert(self->itself != NULL);
1185+
if (setter(self->itself, threshold) == XML_TRUE) {
1186+
Py_RETURN_NONE;
1187+
}
1188+
// The setter fails if self->itself is NULL (which is not possible here)
1189+
// or is a non-root parser, which currently only happens for parsers
1190+
// created by ExternalEntityParserCreate().
1191+
pyexpat_state *state = PyType_GetModuleState(cls);
1192+
return set_invalid_arg(state, self, "parser must be a root parser");
1193+
}
1194+
1195+
static PyObject *
1196+
set_maximum_amplification(xmlparseobject *self,
1197+
PyTypeObject *cls,
1198+
float max_factor,
1199+
XML_Bool (*setter)(XML_Parser, float))
1200+
{
1201+
assert(self->itself != NULL);
1202+
if (setter(self->itself, max_factor) == XML_TRUE) {
1203+
Py_RETURN_NONE;
1204+
}
1205+
// The setter fails if self->itself is NULL (which is not possible here),
1206+
// is a non-root parser, which currently only happens for parsers created
1207+
// by ExternalEntityParserCreate(), or if 'max_factor' is NaN or < 1.0.
1208+
pyexpat_state *state = PyType_GetModuleState(cls);
1209+
// Note: Expat has no API to determine whether a parser is a root parser,
1210+
// and since the Expat functions for defining the various maximum allowed
1211+
// amplifcation factors fail when a bad parser or a out-of-range factor
1212+
// is given without specifying which check failed, we check whether the
1213+
// factor is out-of-range to improve the error message. See also gh-90949.
1214+
const char *message = (isnan(max_factor) || max_factor < 1.0f)
1215+
? "'max_factor' must be at least 1.0"
1216+
: "parser must be a root parser";
1217+
return set_invalid_arg(state, self, message);
1218+
}
1219+
#endif
1220+
11771221
#if XML_COMBINED_VERSION >= 20702
11781222
/*[clinic input]
11791223
@permit_long_summary
@@ -1195,15 +1239,10 @@ pyexpat_xmlparser_SetAllocTrackerActivationThreshold_impl(xmlparseobject *self,
11951239
unsigned long long threshold)
11961240
/*[clinic end generated code: output=bed7e93207ba08c5 input=54182cd71ad69978]*/
11971241
{
1198-
assert(self->itself != NULL);
1199-
if (XML_SetAllocTrackerActivationThreshold(self->itself, threshold) == XML_TRUE) {
1200-
Py_RETURN_NONE;
1201-
}
1202-
// XML_SetAllocTrackerActivationThreshold() can only fail if self->itself
1203-
// is not a root parser (currently, this is equivalent to be created
1204-
// by ExternalEntityParserCreate()).
1205-
pyexpat_state *state = PyType_GetModuleState(cls);
1206-
return set_invalid_arg(state, self, "parser must be a root parser");
1242+
return set_activation_threshold(
1243+
self, cls, threshold,
1244+
XML_SetAllocTrackerActivationThreshold
1245+
);
12071246
}
12081247
#endif
12091248

@@ -1238,24 +1277,10 @@ pyexpat_xmlparser_SetAllocTrackerMaximumAmplification_impl(xmlparseobject *self,
12381277
float max_factor)
12391278
/*[clinic end generated code: output=6e44bd48c9b112a0 input=3544abf9dd7ae055]*/
12401279
{
1241-
assert(self->itself != NULL);
1242-
if (XML_SetAllocTrackerMaximumAmplification(self->itself, max_factor) == XML_TRUE) {
1243-
Py_RETURN_NONE;
1244-
}
1245-
// XML_SetAllocTrackerMaximumAmplification() can fail if self->itself
1246-
// is not a root parser (currently, this is equivalent to be created
1247-
// by ExternalEntityParserCreate()) or if 'max_factor' is NaN or < 1.0.
1248-
//
1249-
// Expat does not provide a way to determine whether a parser is a root
1250-
// or not, nor does it provide a way to distinguish between failures in
1251-
// XML_SetAllocTrackerMaximumAmplification() (see gh-90949), we manually
1252-
// detect the factor out-of-range issue here so that users have a better
1253-
// error message.
1254-
pyexpat_state *state = PyType_GetModuleState(cls);
1255-
const char *message = (isnan(max_factor) || max_factor < 1.0f)
1256-
? "'max_factor' must be at least 1.0"
1257-
: "parser must be a root parser";
1258-
return set_invalid_arg(state, self, message);
1280+
return set_maximum_amplification(
1281+
self, cls, max_factor,
1282+
XML_SetAllocTrackerMaximumAmplification
1283+
);
12591284
}
12601285
#endif
12611286

0 commit comments

Comments
 (0)