diff options
author | Daniel P. Berrangé <berrange@redhat.com> | 2022-03-25 11:44:52 +0000 |
---|---|---|
committer | Daniel P. Berrangé <berrange@redhat.com> | 2022-04-21 15:00:29 +0000 |
commit | 6feb31a7a10267e14183495915b191ecdf4ea3e8 (patch) | |
tree | fd24148856bf77ddb93253d5b69dcf8938354b28 | |
parent | 3551c04ecb34540810a6cca629eb94b257b02db3 (diff) | |
download | libvirt-python-6feb31a7a10267e14183495915b191ecdf4ea3e8.tar.gz |
sanitytest: skip tests when seeing broken lxml implementation
The python lxml registers some global callbacks with libxml2. As a
result when another user of libxml2 calls APIs, it can trigger the
python callbacks that lxml previously registered. Execution of the
python callbacks in this case is often unsafe and leads to SEGVs.
This hasn't been a problem since the sanitytest.py test has been
a standalone program we execute. When it gets turned into a real
python unit test, it will run in the same process as all the other
tests and trigger the crash.
A mitigation was added in lxml 4.5.2 which is good enough to let
us continuing using lxml.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
-rw-r--r-- | sanitytest.py | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/sanitytest.py b/sanitytest.py index f3f925c..8f02cdf 100644 --- a/sanitytest.py +++ b/sanitytest.py @@ -1,8 +1,6 @@ #!/usr/bin/env python3 import sys -import lxml -import lxml.etree from typing import Dict, List, Set, Tuple # noqa F401 import libvirt import unittest @@ -373,17 +371,55 @@ def validate_c_api_bindings_present(finalklassmap): except AttributeError: raise Exception("libvirt.libvirtmod.%s (C binding does not exist)" % pyname) +# Historically python lxml is incompatible with any other +# use of libxml2 in the same process. Merely importing +# 'lxml.etree' will result in libvirt's use of libxml2 +# triggering a SEGV: +# +# https://bugs.launchpad.net/lxml/+bug/1748019 +# +# per the last comment though, it was somewhat improved by +# +# https://github.com/lxml/lxml/commit/fa1d856cad369d0ac64323ddec14b02281491706 +# +# so if we have version >= 4.5.2, we are safe to import +# lxml.etree for the purposes of unit tests at least +def broken_lxml(): + import lxml + + if not hasattr(lxml, "__version__"): + return True + + digits = [int(d) for d in lxml.__version__.split(".")] + + # We have 3 digits in versions today, but be paranoid + # for possible future changes. + if len(digits) != 3: + return False + + version = (digits[0] * 1000 * 1000) + (digits[1] * 1000) + digits[2] + if version < 4005002: + return True + + return False api_test_flag = unittest.skipUnless( os.environ.get('LIBVIRT_API_COVERAGE', False), "API coverage test is only for upstream maintainers", ) +lxml_broken_flag = unittest.skipIf( + broken_lxml(), + "lxml version clashes with libxml usage from libvirt" +) + @api_test_flag +@lxml_broken_flag class LibvirtAPICoverage(unittest.TestCase): def test_libvirt_api(self): xml = get_libvirt_api_xml_path() + import lxml.etree with open(xml, "r") as fp: tree = lxml.etree.parse(fp) |