Python 对不需要的系统调用引发异常
我被告知修复遗留应用程序中的错误 我可以重现一个bug,但我不知道在哪个python源代码行执行错误 我可以看到Python 对不需要的系统调用引发异常,python,debugging,system-calls,Python,Debugging,System Calls,我被告知修复遗留应用程序中的错误 我可以重现一个bug,但我不知道在哪个python源代码行执行错误 我可以看到strace的相关故障:打开了一个文件,但不应该打开 我想让相关的open()linux系统调用在python解释器中引发一个异常。我的目标:我希望看到stacktrace能够修复bug 通过这种方式,我可以避免使用调试器在许多行中单步执行所需的时间 其他词也一样:如果执行syscall,这将导致strace输出open(“/somefile”,O_RDONLY)=4,python解释
strace
的相关故障:打开了一个文件,但不应该打开
我想让相关的open()linux系统调用在python解释器中引发一个异常。我的目标:我希望看到stacktrace能够修复bug
通过这种方式,我可以避免使用调试器在许多行中单步执行所需的时间
其他词也一样:如果执行syscall,这将导致strace输出open(“/somefile”,O_RDONLY)=4
,python解释器将返回退出
有人有办法吗
如果您不明白我在寻找什么,请留下评论。在导入模块之前,我们可以在
打开
上进行修补,下面是一个示例:
在test.py
中:
def func():
with open('test', 'w') as f:
pass
try:
import __builtin__ # for python2
except ImportError:
import builtins as __builtin__ #for python3
import copy
import traceback
orig_open = copy.copy(__builtin__.open)
def myopen(*args):
traceback.print_stack()
return orig_open(*args)
__builtin__.open = myopen
from test import func # Note that we import the module after patching on open()
func()
在test2.py
中:
def func():
with open('test', 'w') as f:
pass
try:
import __builtin__ # for python2
except ImportError:
import builtins as __builtin__ #for python3
import copy
import traceback
orig_open = copy.copy(__builtin__.open)
def myopen(*args):
traceback.print_stack()
return orig_open(*args)
__builtin__.open = myopen
from test import func # Note that we import the module after patching on open()
func()
当在test2.py
中调用func()
时,将打印调用堆栈:
$ python test2.py
File "test2.py", line 19, in <module>
func()
File "/tmp/test.py", line 4, in func
with open('test', 'w') as f:
File "test2.py", line 12, in myopen
traceback.print_stack()
$python test2.py
文件“test2.py”,第19行,在
func()
文件“/tmp/test.py”,第4行,在func中
打开('test','w')作为f:
myopen中第12行的文件“test2.py”
traceback.print_stack()
您可以在gdb下运行python,在open()
syscall上设置一个(有条件的)断点(或者更确切地说,是libc中调用它的存根函数),当遇到断点时,向python进程发送一个SIGINT
信号并让它继续,因此,python脚本的执行应该以所需的堆栈跟踪中断
下面的shell脚本自动执行该过程
用法:
在打开时堆栈跟踪
文件名
脚本.py
]
堆栈跟踪打开时:
#!/usr/bin/env bash
myname="$(basename "$0")"
if [[ $# -lt 4 || "$2" != '--' ]]
then
echo >&2 "Usage: $myname <filename> -- python <script.py> [script args ...]"
exit 1
fi
fname=$1
python_exe="$3"
shift 3
gdb -q "$python_exe" <<END
set breakpoint pending on
break open
condition 1 strcmp(\$rdi,"$fname") == 0
run "$@"
signal 2
cont
quit
END
#/usr/bin/env bash
myname=“$(basename“$0”)”
如果[$#-lt 4 | |“$2”!='--']]
然后
echo>&2“用法:$myname--python[script args…””
出口1
fi
fname=$1
python_exe=“$3”
班次3
gdb-q“$python_exe”是否可以临时重命名/somefile
,以便尝试打开它的任何调用都会失败?(假设代码本身没有处理丢失文件的情况。)不,重命名文件没有帮助。我尝试了这个方法,但没有帮助。我猜open sys调用发生在一个遗留的c扩展名中。@guettli如果我是你,我会下载源代码并使用grep-R
或ag
在所有源代码中搜索打开的文件名。由于打开操作可能发生在二进制库中,如果库不符合调试信息,则即使我们可以打印调用堆栈,也很难找到调用open()
的特定位置。因为我有“在syscall上Stacktrace”的想法,我已经找到了一些使用这种基本调试工具的用例。是的,对于这个问题的用例,我可以找到解决方法。@guettli,祝贺你!哇,太棒了。到目前为止,我还不是gdb专家。我认为它可能有一些神奇的东西。你得到了赏金。