8000 gh-133157: remove usage of `_Py_NO_SANITIZE_UNDEFINED` in `pyexpat` (… · python/cpython@845263a · GitHub
[go: up one dir, main page]

Skip to content
  • Commit 845263a

    Browse files
    encukoupicnixz
    andauthored
    gh-133157: remove usage of _Py_NO_SANITIZE_UNDEFINED in pyexpat (#135346)
    This was the last usage, so the macro is removed as well. Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
    1 parent 23caccf commit 845263a

    File tree

    4 files changed

    +96
    -29
    lines changed

    4 files changed

    +96
    -29
    lines changed

    Include/pyport.h

    Lines changed: 0 additions & 19 deletions
    Original file line numberDiff line numberDiff line change
    @@ -667,25 +667,6 @@ extern "C" {
    667667
    #endif
    668668

    669669

    670-
    // _Py_NO_SANITIZE_UNDEFINED(): Disable Undefined Behavior sanitizer (UBsan)
    671-
    // on a function.
    672-
    //
    673-
    // Clang and GCC 9.0+ use __attribute__((no_sanitize("undefined"))).
    674-
    // GCC 4.9+ uses __attribute__((no_sanitize_undefined)).
    675-
    #if defined(__has_feature)
    676-
    # if __has_feature(undefined_behavior_sanitizer)
    677-
    # define _Py_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
    678-
    # endif
    679-
    #endif
    680-
    #if !defined(_Py_NO_SANITIZE_UNDEFINED) && defined(__GNUC__) \
    681-
    && ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9))
    682-
    # define _Py_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
    683-
    #endif
    684-
    #ifndef _Py_NO_SANITIZE_UNDEFINED
    685-
    # define _Py_NO_SANITIZE_UNDEFINED
    686-
    #endif
    687-
    688-
    689670
    // _Py_NONSTRING: The nonstring variable attribute specifies that an object or
    690671
    // member declaration with type array of char, signed char, or unsigned char,
    691672
    // or pointer to such a type is intended to store character arrays that do not

    Lib/test/test_pyexpat.py

    Lines changed: 16 additions & 4 deletions
    Original file line numberDiff line numberDiff line change
    @@ -9,12 +9,11 @@
    99
    from io import BytesIO
    1010
    from test import support
    1111
    from test.support import os_helper
    12-
    12+
    from test.support import sortdict
    13+
    from unittest import mock
    1314
    from xml.parsers import expat
    1415
    from xml.parsers.expat import errors
    1516

    16-
    from test.support import sortdict
    17-
    1817

    1918
    class SetAttributeTest(unittest.TestCase):
    2019
    def setUp(self):
    @@ -436,6 +435,19 @@ def test7(self):
    436435
    "<!--abc-->", "4", "<!--def-->", "5", "</a>"],
    437436
    "buffered text not properly split")
    438437

    438+
    def test_change_character_data_handler_in_callback(self):
    439+
    # Test that xmlparse_handler_setter() properly handles
    440+
    # the special case "parser.CharacterDataHandler = None".
    441+
    def handler(*args):
    442+
    parser.CharacterDataHandler = None
    443+
    444+
    handler_wrapper = mock.Mock(wraps=handler)
    445+
    parser = expat.ParserCreate()
    446+
    parser.CharacterDataHandler = handler_wrapper
    447+
    parser.Parse(b"<a>1<b/>2<c></c>3<!--abc-->4<!--def-->5</a> ", True)
    448+
    handler_wrapper.assert_called_once()
    449+
    self.assertIsNone(parser.CharacterDataHandler)
    450+
    439451

    440452
    # Test handling of exception from callback:
    441453
    class HandlerExceptionTest(unittest.TestCase):
    @@ -595,7 +607,7 @@ def test_unchanged_size(self):
    595607
    def test_disabling_buffer(self):
    596608
    xml1 = b"<?xml version='1.0' encoding='iso8859'?><a>" + b'a' * 512
    597609
    xml2 = b'b' * 1024
    598-
    xml3 = b'c' * 1024 + b'</a>';
    610+
    xml3 = b'c' * 1024 + b'</a>'
    599611
    parser = expat.ParserCreate()
    600612
    parser.CharacterDataHandler = self.counting_handler
    601613
    parser.buffer_text = 1
    Lines changed: 1 addition & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1 @@
    1+
    Remove the private, undocumented macro :c:macro:`!_Py_NO_SANITIZE_UNDEFINED`.

    Modules/pyexpat.c

    Lines changed: 79 additions & 6 deletions
    Original file line numberDiff line numberDiff line change
    @@ -98,7 +98,11 @@ typedef struct {
    9898

    9999
    #define CHARACTER_DATA_BUFFER_SIZE 8192
    100100

    101-
    typedef const void *xmlhandler;
    101+
    // A generic function type for storage.
    102+
    // To avoid undefined behaviors, a handler must be cast to the correct
    103+
    // function type before it's called; see SETTER_WRAPPER below.
    104+
    typedef void (*xmlhandler)(void);
    105+
    102106
    typedef void (*xmlhandlersetter)(XML_Parser self, xmlhandler handler);
    103107

    104108
    struct HandlerInfo {
    @@ -110,9 +114,7 @@ struct HandlerInfo {
    110114

    111115
    static struct HandlerInfo handler_info[64];
    112116

    113-
    // gh-111178: Use _Py_NO_SANITIZE_UNDEFINED, rather than using the exact
    114-
    // handler API for each handler.
    115-
    static inline void _Py_NO_SANITIZE_UNDEFINED
    117+
    static inline void
    116118
    CALL_XML_HANDLER_SETTER(const struct HandlerInfo *handler_info,
    117119
    XML_Parser xml_parser, xmlhandler xml_handler)
    118120
    {
    @@ -1365,7 +1367,7 @@ xmlparse_handler_setter(PyObject *op, PyObject *v, void *closure)
    13651367
    elaborate system of handlers and state could remove the
    13661368
    C handler more effectively. */
    13671369
    if (handlernum == CharacterData && self->in_callback) {
    1368-
    c_handler = noop_character_data_handler;
    1370+
    c_handler = (xmlhandler)noop_character_data_handler;
    13691371
    }
    13701372
    v = NULL;
    13711373
    }
    @@ -2222,13 +2224,84 @@ clear_handlers(xmlparseobject *self, int initial)
    22222224
    }
    22232225
    }
    22242226

    2227+
    /* To avoid undefined behaviors, a function must be *called* via a function
    2228+
    * pointer of the correct type.
    2229+
    * So, for each `XML_Set*` function, we define a wrapper that calls `XML_Set*`
    2230+
    * with its argument cast to the appropriate type.
    2231+
    */
    2232+
    2233+
    typedef void (*parser_only)(void *);
    2234+
    typedef int (*not_standalone)(void *);
    2235+
    typedef void (*parser_and_data)(void *, const XML_Char *);
    2236+
    typedef void (*parser_and_data_and_int)(void *, const XML_Char *, int);
    2237+
    typedef void (*parser_and_data_and_data)(
    2238+
    void *, const XML_Char *, const XML_Char *);
    2239+
    typedef void (*start_element)(void *, const XML_Char *, const XML_Char **);
    2240+
    typedef void (*element_decl)(void *, const XML_Char *, XML_Content *);
    2241+
    typedef void (*xml_decl)(
    2242+
    void *, const XML_Char *, const XML_Char *, int);
    2243+
    typedef void (*start_doctype_decl)(
    2244+
    void *, const XML_Char *, const XML_Char *, const XML_Char *, int);
    2245+
    typedef void (*notation_decl)(
    2246+
    void *,
    2247+
    const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *);
    2248+
    typedef void (*attlist_decl)(
    2249+
    void *,
    2250+
    const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *,
    2251+
    int);
    2252+
    typedef void (*unparsed_entity_decl)(
    2253+
    void *,
    2254+
    const XML_Char *, const XML_Char *,
    2255+
    const XML_Char *, const XML_Char *, const XML_Char *);
    2256+
    typedef void (*entity_decl)(
    2257+
    void *,
    2258+
    const XML_Char *, int,
    2259+
    const XML_Char *, int,
    2260+
    const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *);
    2261+
    typedef int (*external_entity_ref)(
    2262+
    XML_Parser,
    2263+
    const XML_Char *, const XML_Char *, const XML_Char *, const XML_Char *);
    2264+
    2265+
    #define SETTER_WRAPPER(NAME, TYPE) \
    2266+
    static inline void \
    2267+
    pyexpat_Set ## NAME (XML_Parser parser, xmlhandler handler) \
    2268+
    { \
    2269+
    (void)XML_Set ## NAME (parser, (TYPE)handler); \
    2270+
    }
    2271+
    2272+
    SETTER_WRAPPER(StartElementHandler, start_element)
    2273+
    SETTER_WRAPPER(EndElementHandler, parser_and_data)
    2274+
    SETTER_WRAPPER(ProcessingInstructionHandler, parser_and_data_and_data)
    2275+
    SETTER_WRAPPER(CharacterDataHandler, parser_and_data_and_int)
    2276+
    SETTER_WRAPPER(UnparsedEntityDeclHandler, unparsed_entity_decl)
    2277+
    SETTER_WRAPPER(NotationDeclHandler, notation_decl)
    2278+
    SETTER_WRAPPER(StartNamespaceDeclHandler, parser_and_data_and_data)
    2279+
    SETTER_WRAPPER(EndNamespaceDeclHandler, parser_and_data)
    2280+
    SETTER_WRAPPER(CommentHandler, parser_and_data)
    2281+
    SETTER_WRAPPER(StartCdataSectionHandler, parser_only)
    2282+
    SETTER_WRAPPER(EndCdataSectionHandler, parser_only)
    2283+
    SETTER_WRAPPER(DefaultHandler, parser_and_data_and_int)
    2284+
    SETTER_WRAPPER(DefaultHandlerExpand, parser_and_data_and_int)
    2285+
    SETTER_WRAPPER(NotStandaloneHandler, not_standalone)
    2286+
    SETTER_WRAPPER(ExternalEntityRefHandler, external_entity_ref)
    2287+
    SETTER_WRAPPER(StartDoctypeDeclHandler, start_doctype_decl)
    2288+
    SETTER_WRAPPER(EndDoctypeDeclHandler, parser_only)
    2289+
    SETTER_WRAPPER(EntityDeclHandler, entity_decl)
    2290+
    SETTER_WRAPPER(XmlDeclHandler, xml_decl)
    2291+
    SETTER_WRAPPER(ElementDeclHandler, element_decl)
    2292+
    SETTER_WRAPPER(AttlistDeclHandler, attlist_decl)
    2293+
    #if XML_COMBINED_VERSION >= 19504
    2294+
    SETTER_WRAPPER(SkippedEntityHandler, parser_and_data_and_int)
    2295+
    #endif
    2296+
    #undef SETTER_WRAPPER
    2297+
    22252298
    static struct HandlerInfo handler_info[] = {
    22262299

    22272300
    // The cast to `xmlhandlersetter` is needed as the signature of XML
    22282301
    // handler functions is not compatible with `xmlhandlersetter` since
    22292302
    // their second parameter is narrower than a `const void *`.
    22302303
    #define HANDLER_INFO(name) \
    2231-
    {#name, (xmlhandlersetter)XML_Set##name, my_##name},
    2304+
    {#name, (xmlhandlersetter)pyexpat_Set##name, (xmlhandler)my_##name},
    22322305

    22332306
    HANDLER_INFO(StartElementHandler)
    22342307
    HANDLER_INFO(EndElementHandler)

    0 commit comments

    Comments
     (0)
    0