python 추적 분할 결함
Python에서 C 확장을 개발 중인데 몇 가지 세그먼트 폴트(seg faults)를 획득했습니다.
segfault가 발생하는 코드 행을 표시하는 방법을 찾고 있습니다(코드 한 줄 한 줄씩 추적하는 것과 같습니다). 어떻게 하면 될까요?
Linux의 경우 gdb에서 python을 실행합니다.
gdb python
(gdb) run /path/to/script.py
## wait for segfault ##
(gdb) backtrace
## stack trace of the c code
다음은 코드가 실행되는 Python의 모든 줄의 파일 이름과 줄 번호를 출력하는 방법입니다.
import sys
def trace(frame, event, arg):
print("%s, %s:%d" % (event, frame.f_code.co_filename, frame.f_lineno))
return trace
def test():
print("Line 8")
print("Line 9")
sys.settrace(trace)
test()
출력:
call, test.py:7
line, test.py:8
Line 8
line, test.py:9
Line 9
return, test.py:9
(물론 트레이스 출력을 파일에 쓰는 것이 좋습니다).
저는 같은 문제에 대한 해결책을 찾아 이곳에 왔지만, 다른 답변들은 전혀 도움이 되지 않았습니다.도움이 된 것은 이며, Python 2.7에 설치할 수 있습니다.pip install
.
faulthandler
Python은 2012년 9월에 출시된 버전 3.3에서만 소개되었으며, 이 버전에서는 대부분의 다른 답변이 작성된 후였습니다.
gdb에는 문서화되어 있지 않은 python 확장자가 있습니다.
Python 소스 grab(일반 설치에는 포함되지 않음)에서 가져옵니다.
이거 넣어주세요sys.path
그 후, 다음과 같이 입력합니다.
# gdb /gps/python2.7_x64/bin/python coredump
...
Core was generated by `/usr/bin/python script.py'.
Program terminated with signal 11, Segmentation fault.
#0 call_function (oparg=<optimized out>, pp_stack=0x7f9084d15dc0) at Python/ceval.c:4037
...
(gdb) python
>import libpython
>
>end
(gdb) bt
#0 call_function (oparg=<optimized out>, pp_stack=0x7f9084d15dc0) at Python/ceval.c:4037
#1 PyEval_EvalFrameEx (f=f@entry=
Frame 0x7f9084d20ad0,
for file /usr/lib/python2.7/site-packages/librabbitmq/__init__.py, line 220,
in drain_events (self=<Connection(channels={1: <Channel(channel_id=1, connection=<...>, is_open=True, connect_timeout=4, _default_channel=<....(truncated), throwflag=throwflag@entry=0) at Python/ceval.c:2681
...
(gdb) py-list
218 else:
219 timeout = float(timeout)
>220 self._basic_recv(timeout)
221
222 def channel(self, channel_id=None):
보시다시피 CPython 콜 체인에 대응하는 Python 스택을 확인할 수 있습니다.
몇 가지 주의사항:
- 사용하시는 gdb 버전은 7보다 커야 하며 컴파일은 다음과 같이 해야 합니다.
--with-python
gdb
python을 내장합니다(링크에 의해).libpython
)는 서브셸로 실행되지 않습니다.즉, 현재 설치되어 있는 python 버전과 반드시 일치하지는 않을 수 있습니다.$PATH
.- 다운로드가 필요합니다.
libpython.py
모든 버전의 Python 소스와 일치합니다.gdb
에 링크되어 있습니다. - gdb를 root으로 실행해야 할 수 있습니다.그럴 경우 셋업이 필요할 수 있습니다.
sys.path
디버깅하고 있는 코드의 코드에 일치합니다.
복사할 수 없는 경우libpython.py
안으로sys.path
위치를 추가할 수 있습니다.sys.path
다음과 같습니다.
(gdb) python
>import sys
>sys.path.append('/path/to/containing/dir/')
>import libpython
>
>end
이것은 python dev docs, fedora wiki 및 python wiki에 다소 문서화되어 있지 않습니다.
나이가 많으시면gdb
또는 이 기능을 사용할 수 없는 경우 Python 소스의 gdbinit도 복사 가능합니다.~/.gdbinit
비슷한 기능이 추가되어 있습니다.
C 확장의 세그먼트 장애는 개체에 대한 새 참조를 생성할 때 참조 카운트가 증가하지 않아 발생하는 경우가 매우 많습니다.따라서 segfault는 오브젝트에서 마지막 참조가 삭제된 후에만 발생하며 다른 오브젝트가 할당되어 있을 때만 발생하는 경우가 많기 때문에 추적하기가 매우 어렵습니다.
지금까지 C 확장 코드를 얼마나 썼는지는 말하지 않았지만, 이제 막 시작한 경우 ctype과 Cython 중 하나를 사용할 수 있는지 고려해 보십시오.Ctype은 요구에 따라 유연하지 않을 수 있지만 Cython을 사용하는 거의 모든 C 라이브러리에 링크하여 모든 참조 카운트를 자동으로 유지할 수 있어야 합니다.
Python 객체와 기본 C 객체의 수명이 다르더라도 문제가 발생할 수 있지만 상당히 단순해집니다.
다음 3가지 대안을 제시하겠습니다.
1: faulthandler를 이노블로 한 스크립트 실행:
python3 -X faulthandler your_script.py
2: 디버깅모드에서의 스크립트 실행(pdb)
python3 -m pdb your_script.py
continue 명령어를 사용하여 스크립트를 실행합니다.
gdb
툴은 가장 많은 정보를 제공하지만 스크립트에서 마지막으로 실행된 행 번호를 인쇄하지 않습니다.
3: pytest를 사용하게 되었습니다.이 기능이 작동하기 위해 코드를 다음 함수로 묶었습니다.test_
스크립트를 다음과 같이 실행합니다.
pytest your_script.py
언급URL : https://stackoverflow.com/questions/2663841/python-tracing-a-segmentation-fault
'programing' 카테고리의 다른 글
함수를 가변 길이 인수로 래핑하려면 어떻게 해야 합니까? (0) | 2022.11.18 |
---|---|
인코딩을 사용해야 합니까?URI 또는 인코딩URL 인코딩을 위한 URIC 구성 요소 (0) | 2022.11.18 |
Java에서는 상수 클래스를 어떻게 정의합니까? (0) | 2022.11.18 |
Python에는 왜 태플 이해가 없습니까? (0) | 2022.11.18 |
워치 핸들러 vuejs의 데이터 변수에 액세스할 수 없음 (0) | 2022.11.17 |