为什么这个 Py_DECREF 会导致段错误?
Why does this Py_DECREF cause a segfault?
我正在处理 Python 扩展中的一个烦人的段错误。深入到核心,我首先创建了一个独立的 C 版本的扩展,在尝试进一步减少问题的同时,我最终得到了这个。这是完整的程序:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int main(void) {
PyObject *num;
PyObject *args;
num = PyLong_FromLong(0);
if (!num) return -1;
args = PyTuple_Pack(1, num);
if (!args) return -1;
Py_DECREF(args); /* <-- segfault */
return 0;
}
如果我省略 Py_DECREF,我不会收到错误。根据文档,PyTuple_Pack returns 一个新参考,我现在 "own"。难道我不应该被允许对其进行 DECREF 吗?
运行在valgrind中,相关报错信息是这样的:
==7160== Memcheck, a memory error detector
==7160== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==7160== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==7160== Command: ./pyctest
==7160==
==7160== Invalid read of size 4
==7160== at 0x4F2B13E: ??? (in /usr/lib64/libpython3.6m.so.1.0)
==7160== by 0x40078B: main (pyctest.c:11)
==7160== Address 0xa0 is not stack'd, malloc'd or (recently) free'd
==7160==
==7160==
==7160== Process terminating with default action of signal 11 (SIGSEGV)
==7160== Access not within mapped region at address 0xA0
==7160== at 0x4F2B13E: ??? (in /usr/lib64/libpython3.6m.so.1.0)
==7160== by 0x40078B: main (pyctest.c:11)
编辑
一些构建细节。这是在 RHEL7 Linux 系统上。
$ python3-config --cflags
-I/usr/include/python3.6m -I/usr/include/python3.6m -Wno-unused-result -Wsign-compare -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv
$ python3-config --ldflags
-L/usr/lib64 -lpython3.6m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic
$ cat Makefile
LDFLAGS=-L/usr/lib64 -lpython3.6m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic
CFLAGS=-I/usr/include/python3.6m -I/usr/include/python3.6m -Wno-unused-result -Wsign-compare -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv
pyctest: pyctest.c
gcc $(CFLAGS) pyctest.c -o pyctest $(LDFLAGS)
$
段错误的发生可能是由于 Python 调试和生产环境之间的混淆导致的未定义行为。
我正在处理 Python 扩展中的一个烦人的段错误。深入到核心,我首先创建了一个独立的 C 版本的扩展,在尝试进一步减少问题的同时,我最终得到了这个。这是完整的程序:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int main(void) {
PyObject *num;
PyObject *args;
num = PyLong_FromLong(0);
if (!num) return -1;
args = PyTuple_Pack(1, num);
if (!args) return -1;
Py_DECREF(args); /* <-- segfault */
return 0;
}
如果我省略 Py_DECREF,我不会收到错误。根据文档,PyTuple_Pack returns 一个新参考,我现在 "own"。难道我不应该被允许对其进行 DECREF 吗?
运行在valgrind中,相关报错信息是这样的:
==7160== Memcheck, a memory error detector
==7160== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==7160== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==7160== Command: ./pyctest
==7160==
==7160== Invalid read of size 4
==7160== at 0x4F2B13E: ??? (in /usr/lib64/libpython3.6m.so.1.0)
==7160== by 0x40078B: main (pyctest.c:11)
==7160== Address 0xa0 is not stack'd, malloc'd or (recently) free'd
==7160==
==7160==
==7160== Process terminating with default action of signal 11 (SIGSEGV)
==7160== Access not within mapped region at address 0xA0
==7160== at 0x4F2B13E: ??? (in /usr/lib64/libpython3.6m.so.1.0)
==7160== by 0x40078B: main (pyctest.c:11)
编辑
一些构建细节。这是在 RHEL7 Linux 系统上。
$ python3-config --cflags
-I/usr/include/python3.6m -I/usr/include/python3.6m -Wno-unused-result -Wsign-compare -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv
$ python3-config --ldflags
-L/usr/lib64 -lpython3.6m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic
$ cat Makefile
LDFLAGS=-L/usr/lib64 -lpython3.6m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic
CFLAGS=-I/usr/include/python3.6m -I/usr/include/python3.6m -Wno-unused-result -Wsign-compare -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv
pyctest: pyctest.c
gcc $(CFLAGS) pyctest.c -o pyctest $(LDFLAGS)
$
段错误的发生可能是由于 Python 调试和生产环境之间的混淆导致的未定义行为。