Skip to content

Set: BUILD_SET opcode can be failed with segfault #101952

Description

@Eclips4

TARGET(BUILD_SET) {
PyObject **values = &PEEK(oparg);
PyObject *set;
set = PySet_New(NULL);
int err = 0;
for (int i = 0; i < oparg; i++) {
PyObject *item = values[i];
if (err == 0)
err = PySet_Add(set, item);
Py_DECREF(item);
}
if (err != 0) {
Py_DECREF(set);
if (true) { STACK_SHRINK(oparg); goto error; }
}
STACK_SHRINK(oparg);
STACK_GROW(1);
POKE(1, set);
DISPATCH();
}

&

cpython/Python/bytecodes.c

Lines 1303 to 1316 in 36b139a

inst(BUILD_SET, (values[oparg] -- set)) {
set = PySet_New(NULL);
int err = 0;
for (int i = 0; i < oparg; i++) {
PyObject *item = values[i];
if (err == 0)
err = PySet_Add(set, item);
Py_DECREF(item);
}
if (err != 0) {
Py_DECREF(set);
ERROR_IF(true, error);
}
}

Doesn't take in account case, when PySet_New(NULL) returns NULL.
We are checking that PySet_Add doesn't return a non-zero(-1) value.
But, PySet_Add has a check, that first argument is a subclass of set. Which fails, if we will pass (PyObject *) NULL as first argument. Why?

#define PySet_Check(ob) \
    (Py_IS_TYPE((ob), &PySet_Type) || \
    PyType_IsSubtype(Py_TYPE(ob), &PySet_Type))

PySet_Add uses this macross. But, Py_TYPE will be failed with segfault when try to access ob_type of (PyObject *) NULL.

Implementation of Py_TYPE:

static inline PyTypeObject* Py_TYPE(PyObject *ob) {
    return ob->ob_type;
}
(gdb) call (PyObject *) NULL
$1 = (PyObject *) 0x0
(gdb) call $1->ob_type
Cannot access memory at address 0x8

So, we should add check, that value of PySet_New is not-null.

Linked PRs

Activity

added
type-crashA hard crash of the interpreter, possibly with a core dump
on Feb 16, 2023

kumaraditya303 commented on Feb 16, 2023

@kumaraditya303
Contributor

cc @gvanrossum Appears to be introduced in #100912

gvanrossum commented on Feb 16, 2023

@gvanrossum
Member

Yeah, the original code had

if (set == NULL)
                goto error;

which somehow got lost.

How can I repro this?

gvanrossum commented on Feb 16, 2023

@gvanrossum
Member

If someone could come up with a fix I'll review it, that's the quickest way.

Eclips4 commented on Feb 16, 2023

@Eclips4
MemberAuthor

I can fix it, but i don't know yet how to reproduce it. I was just looking through the bytecodes.c file =)

gvanrossum commented on Feb 16, 2023

@gvanrossum
Member

It's probably hard to repro, because the only way PySet_New() can error is if it runs out of memory. I think restoring those two lines will do it (nothing has been popped off the stack at that point yet).

Eclips4 commented on Feb 16, 2023

@Eclips4
MemberAuthor

Okay, i'll soon send a PR

added a commit that references this issue on Feb 16, 2023
added a commit that references this issue on Feb 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions