Skip to content

Set: BUILD_SET opcode can be failed with segfault#101952

@Eclips4

Description

@Eclips4

TARGET(BUILD_SET){
PyObject**values=&PEEK(oparg);
PyObject*set;
set=PySet_New(NULL);
interr=0;
for (inti=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);
interr=0;
for (inti=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?

#definePySet_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:

staticinlinePyTypeObject*Py_TYPE(PyObject*ob){returnob->ob_type}
(gdb) call (PyObject *) NULL $1 = (PyObject *) 0x0 (gdb) call $1->ob_type Cannot access memory at address0x8

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

Linked PRs

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