Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Py_BuildValue("(s#O)", ...) segfaults if entered with exception raised #83094

Closed
danielen mannequin opened this issue Nov 26, 2019 · 12 comments
Closed

Py_BuildValue("(s#O)", ...) segfaults if entered with exception raised #83094

danielen mannequin opened this issue Nov 26, 2019 · 12 comments
Labels
3.8 only security fixes 3.9 only security fixes extension-modules C modules in the Modules dir release-blocker type-crash A hard crash of the interpreter, possibly with a core dump

Comments

@danielen
Copy link
Mannequin

danielen mannequin commented Nov 26, 2019

BPO 38913
Nosy @doko42, @ambv, @serhiy-storchaka, @zooba, @stratakis
PRs
  • bpo-38913: Fix segfault in Py_BuildValue("(s#O)", ...) if entered with exception raised. #18656
  • [3.8] bpo-38913: Fix segfault in Py_BuildValue("(sGH-O)", ...) if entered with exception raised. (GH-18656). #18732
  • Files
  • module.c
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2020-03-02.19:44:34.948>
    created_at = <Date 2019-11-26.06:27:21.676>
    labels = ['extension-modules', '3.8', '3.9', 'type-crash', 'release-blocker']
    title = 'Py_BuildValue("(s#O)", ...) segfaults if entered with exception raised'
    updated_at = <Date 2020-03-02.19:44:34.946>
    user = 'https://bugs.python.org/danielen'

    bugs.python.org fields:

    activity = <Date 2020-03-02.19:44:34.946>
    actor = 'serhiy.storchaka'
    assignee = 'none'
    closed = True
    closed_date = <Date 2020-03-02.19:44:34.948>
    closer = 'serhiy.storchaka'
    components = ['Extension Modules']
    creation = <Date 2019-11-26.06:27:21.676>
    creator = 'danielen'
    dependencies = []
    files = ['48743']
    hgrepos = []
    issue_num = 38913
    keywords = ['patch', '3.8regression']
    message_count = 12.0
    messages = ['357485', '357504', '357512', '357514', '357554', '358096', '362635', '363129', '363134', '363167', '363200', '363204']
    nosy_count = 6.0
    nosy_names = ['doko', 'lukasz.langa', 'serhiy.storchaka', 'steve.dower', 'cstratak', 'danielen']
    pr_nums = ['18656', '18732']
    priority = 'release blocker'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'crash'
    url = 'https://bugs.python.org/issue38913'
    versions = ['Python 3.8', 'Python 3.9']

    @danielen
    Copy link
    Mannequin Author

    danielen mannequin commented Nov 26, 2019

    The following code results in a segmentation fault in CPython 3.8 while executes fines (raises a SystemError) in CPython 3.7.

    PyObject* debug(PyObject *self, PyObject *args)
    {
            const char * debug = "debug";
            PyErr_SetString(PyExc_ValueError, "debug!");
            return Py_BuildValue("(s#O)", debug, strlen(debug), Py_None);
    }

    It seems necessary for the format string to contain both an instance of "s#" and "O" to trigger the bug.

    I'm attaching a C module that reproduces the problem.

    @danielen danielen mannequin added 3.8 only security fixes extension-modules C modules in the Modules dir labels Nov 26, 2019
    @doko42
    Copy link
    Member

    doko42 commented Nov 26, 2019

    seen with the current 3.8 branch.

    @zooba
    Copy link
    Member

    zooba commented Nov 26, 2019

    Does it depend on whether PY_SSIZE_T_CLEAN is defined?

    @danielen
    Copy link
    Mannequin Author

    danielen mannequin commented Nov 26, 2019

    It is not reproducible with PY_SSIZE_T_CLEAN defined.

    @danielen
    Copy link
    Mannequin Author

    danielen mannequin commented Nov 27, 2019

    The problem arises from this code in do_mktuple(), staring at line 394 in modsupport.c:

                if (**p_format == '#') {
                    ++*p_format;
                    if (flags & FLAG_SIZE_T)
                        n = va_arg(*p_va, Py_ssize_t);
                    else {
                        if (PyErr_WarnEx(PyExc_DeprecationWarning,
                                    "PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) {
                            return NULL;
                        }
                        n = va_arg(*p_va, int);
                    }
                }

    If this is entered with an exception raised, PyErr_WarnEx() return NULL, thus this function return NULL without consuming the argument relative to the string length for the "s#" specifier. This argument is then consumed at the next iteration for the "O" specifier, resulting in a segmentation fault when the string length is interpreted as an object pointer.

    I don't know what is the best solution: either ignoring the return value of PyErr_WarnEx or swapping the lines from

                        if (PyErr_WarnEx(PyExc_DeprecationWarning,
                                    "PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) {
                            return NULL;
                        }
                        n = va_arg(*p_va, int);

    to

                        n = va_arg(*p_va, int);
                        if (PyErr_WarnEx(PyExc_DeprecationWarning,
                                    "PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) {
                            return NULL;
                        }

    The handling of the "y#" just below suffers from the same problem.

    @ambv
    Copy link
    Contributor

    ambv commented Dec 9, 2019

    Note: this is going to miss Python 3.8.1 as I'm releasing 3.8.1rc1 right now. Please address this before 3.8.2 (due in February).

    @ambv
    Copy link
    Contributor

    ambv commented Feb 25, 2020

    Sadly, this missed the train for 3.8.2 as well.

    @serhiy-storchaka
    Copy link
    Member

    New changeset 28d0bca by Serhiy Storchaka in branch 'master':
    bpo-38913: Fix segfault in Py_BuildValue("(s#O)", ...) if entered with exception raised. (GH-18656)
    28d0bca

    @serhiy-storchaka
    Copy link
    Member

    New changeset a7b8a96 by Serhiy Storchaka in branch '3.8':
    [3.8] bpo-38913: Fix segfault in Py_BuildValue("(sGH-O)", ...) if entered with exception raised. (GH-18656). (GH-18732)
    a7b8a96

    @serhiy-storchaka serhiy-storchaka added the 3.9 only security fixes label Mar 2, 2020
    @serhiy-storchaka serhiy-storchaka added the type-crash A hard crash of the interpreter, possibly with a core dump label Mar 2, 2020
    @stratakis
    Copy link
    Mannequin

    stratakis mannequin commented Mar 2, 2020

    After this change, the arm64 buildbots are reporting reference leaks:

    1:03:24 load avg: 0.95 Re-running failed tests in verbose mode
    1:03:24 load avg: 0.95 Re-running test_capi in verbose mode
    test_capi leaked [4, 4, 4] references, sum=12

    e.g. https://buildbot.python.org/all/#/builders/563/builds/25

    @serhiy-storchaka
    Copy link
    Member

    Actually there is a leak in PyErr_WarnEx().

    @serhiy-storchaka
    Copy link
    Member

    Opened bpo-39831.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.8 only security fixes 3.9 only security fixes extension-modules C modules in the Modules dir release-blocker type-crash A hard crash of the interpreter, possibly with a core dump
    Projects
    None yet
    Development

    No branches or pull requests

    4 participants