linux下python core分析:查看core的python函数代码栈的方法以及常见的core的原因
python出的core,栈都是c语言的栈,没办法从core中知道core在了python代码的哪一行,导致无从下手分析定位问题,搜索了一下相关资料,没有特别系统的分析方法,所以整理一下分析python core的方法以及一些可能的原因总结
core是什么?
linux下进程异常崩溃退出时,可以生成一份当时的内存、寄存器等的文件镜像,也就是一个core文件,我们可以用gdb命令分析core文件,查看当时的代码栈、内存等信息
检查是否开启core
- 使用 ulimit -a 查看第一行 core file size,如果是0就代表没有开,需要在/etc/profile中加一行ulimit -c unlimited,然后source /etc/profile,当前及后续登录的shell都会开启core
- 修改/etc/sysctl.conf中kernel.core_pattern = /home/core.%e.%p.%t,修改core的生成路径,sysctl -p使配置生效
环境准备
实测yum install安装的python不可用,需要编译一个新的python,编译时指定--with-pydebug参数。
加--with-pydebug参数后,编译的时候gcc会带-g参数,有调试信息,该参数同样会启用python的一些检查机制,方便我们编码时提前发现问题。具体的参数内容可见官方文档: docs.python.org/zh-cn/3.12/…
- 操作系统: linux centos8
- python版本: python3.8
下载python解释器源码
下载地址:www.python.org/ftp/python/…
编译python
编译前需要下载一些依赖的工具
yum install zlib-devel bzip2-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make libffi-devel
然后开始编译
tar -xvf Python-3.8.8.tar.xz
cd Python-3.8.8
./configure --with-pydebug
make
编译完成后,会在当前目录生成一个python二进制文件,就是我们想要的python解释器了。
查看core的python栈
生成一个core
首先写一个python脚本来生成一个core。脚本通过访问0地址来生成core
from ctypes import c_int
print(c_int.from_address(0).value)
执行./python generate_core.py来执行脚本,会生成一个core。(生成core的路径可以通过查看操作系统的/proc/sys/kernel/core_pattern查看)
分析core
使用gdb工具来打开一个core文件,然后使用bt命令打印栈信息
gdb python_path(编译的python二进制的绝对路径) core_path(core文件的绝对路径)
可以看到栈信息全是c的栈,然后载入使用Python源码中自带的gdb工具,键入
python import sys; sys.path.append("/root/python3.8/Python-3.8.8/Tools/gdb"); import libpython
使用py-bt命令打印python栈信息
py-bt
可以看到对应的core的python栈了,接下来就可以根据业务逻辑代码,去分析为什么会产生core。
常见的产生core的原因
常见的产生core的情况是有以下几种
Segmentation faule(段错误),这时进程的退出码是-11
1、访问非法指针
上面的生成core的示例脚本就是一个访问非法指针的例子,在64位操作系统中,指针的大小是8个字节,常见的指针地址一般前两个字节是0x00, 第三个字节是0x7f, 后面的是随机的。如果访问非法指针,那么就会取不到值引发信号11段错误,导致出core。
可以看到这个core的原因是memcpy函数访问了空指针导致的core。
2、调用非法函数(也等同于访问非法指针,只是现象不同)
示例代码,该代码定义了一个函数指针,然后创建了一个指向空的函数指针,调用该函数
#include<stdio.h>
typedef int(*func)(int, int);
int main()
{
func add_func = NULL;
add_func(1, 2);
return 0;
}
编译运行该文件
gcc test.c
./a.out
会生成一个core,可以看到core原因是段错误
然后gdb解析core
这种的core,栈后面的函数是??,找不到地址对应的函数符号名,前面的栈地址指针也是非法的,这个是一个空指针
abort,系统主动abort,这时进程的退出码是-6
一般是os的检测,多次free同一块内存可以触发
示例代码
#include<stdio.h>
#include <stdlib.h>
int main()
{
char *name = (char *)malloc(8);
free(name);
free(name);
return 0;
}
编译运行(编译时在使用gcc -g test.c 添加调试信息)
可以看到core的原因是Aborted,同时前面提示了double free。
由于添加了调试信息,gdb的时候可以看到哪一行代码调用的free函数引发的abort
主动产生core的方法
示例代码很简单
import time
while True:
print('hello world!!!')
time.sleep(1)
不想影响当前进程的执行,又想保留一个core现场
使用gcore 进程pid 的命令,会生成一个core
gcore $pid
到系统的对应目录下找这个core文件使用gdb解析即可分析
主动core并且停止当前进程的运行
使用kill命令向进程发信号6(abort)或者11(segmentation fault)即可
kill -6 $pid
例如 kill -6 1742424
转载自:https://juejin.cn/post/7362196417279033359