Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

debugpy triggers an infinite recursion in third party library (pivy) #735

Closed
sebjf opened this issue Sep 25, 2021 · 6 comments
Closed

debugpy triggers an infinite recursion in third party library (pivy) #735

sebjf opened this issue Sep 25, 2021 · 6 comments

Comments

@sebjf
Copy link

sebjf commented Sep 25, 2021

Environment data

  • debugpy version: 1.4.3
  • OS and version: Windows 19042
  • Python version (& distribution if applicable, e.g. Anaconda): 3.8.6
  • Using VS Code or Visual Studio: VS Code

Pivy is a library of Coin3D bindings for Python used in FreeCAD.

Actual behavior

Creating a pivy object with debugpy running will result in an RecursionError in pivy.

Traceback (most recent call last):
  File "D:\Program Files\FreeCAD\bin\lib\site-packages\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_trace_dispatch_regular.py", line 359, in __call__
    is_stepping = pydev_step_cmd != -1
RecursionError: maximum recursion depth exceeded in comparison
Fatal Python error: Cannot recover from stack overflow.
Python runtime state: initialized

Expected behavior

The pivy object is created normally.

Steps to reproduce:

  1. Get an installation of Python 3.8 with Pivy (e.g. by downloading and extracting the [FreeCAD libpack])(https://github.com/apeltauer/FreeCAD/releases)
  2. Install debugpy python -m pip install debugpy
  3. Import debugpy and begin listening import debugpy; debugpy.listen(5678); debugpy.trace_this_thread(True);
  4. Import pivy and create an object from the Interaction kit import pivy; pivy.coin.SoDragPointDragger()

Omitting debugpy.listen(5678) will create the object successfully, otherwise the instruction will fail with the complete output below.

Note that this issue does not occur with PTVSD.

D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin>python
Python 3.8.6+ (heads/3.8-dirty:a12f459ec2, Nov  5 2020, 12:01:10) [MSC v.1927 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import debugpy;  debugpy.listen(5678); debugpy.trace_this_thread(True);
('127.0.0.1', 5678)
>>> import pivy; pivy.coin.SoDragPointDragger()
Traceback (most recent call last):
  File "_pydevd_bundle/pydevd_cython.pyx", line 1664, in _pydevd_bundle.pydevd_cython.ThreadTracer.__call__
RecursionError: maximum recursion depth exceeded while calling a Python object
Fatal Python error: Cannot recover from stack overflow.
Python runtime state: initialized

Thread 0x00002d6c (most recent call first):
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 306 in wait
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 558 in wait
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\pydevd.py", line 246 in _on_run
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_daemon_thread.py", line 46 in run
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 932 in _bootstrap_inner
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 890 in _bootstrap

Thread 0x00006dcc (most recent call first):
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 302 in wait
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 558 in wait
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_timeout.py", line 43 in _on_run
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_daemon_thread.py", line 46 in run
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 932 in _bootstrap_inner
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 890 in _bootstrap

Thread 0x000045b4 (most recent call first):
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 306 in wait
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 558 in wait
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\pydevd.py", line 200 in _on_run
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_daemon_thread.py", line 46 in run
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 932 in _bootstrap_inner
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 890 in _bootstrap

Thread 0x000069a8 (most recent call first):
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_comm.py", line 219 in _read_line
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_comm.py", line 237 in _on_run
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_daemon_thread.py", line 46 in run
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 932 in _bootstrap_inner
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 890 in _bootstrap

Thread 0x000015f4 (most recent call first):
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 306 in wait
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\queue.py", line 179 in get
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_comm.py", line 382 in _on_run
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_daemon_thread.py", line 46 in run
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 932 in _bootstrap_inner
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\threading.py", line 890 in _bootstrap

Current thread 0x00006bc4 (most recent call first):
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15298 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  File "D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin\lib\site-packages\pivy\coin.py", line 15299 in __getattr__
  ...

D:\FreeCAD\FreeCADLibs_12.5.2_x64_VC17 - Copy\bin>
@int19h
Copy link
Collaborator

int19h commented Sep 27, 2021

These are SWIG-generated bindings (can be downloaded prebuilt from https://github.com/apeltauer/FreeCAD/releases/tag/LibPack_12.5.2). The code in question:

class SoBaseKit(SoNode):
    # ...
    def __getattr__(self,name):
       c = _coin.SoBaseKit_getNodekitCatalog(self) #line 15299
       if c.getPartNumber(name) >= 0:
           part = self.getPart(name,1)
           return part
       return SoNode.__getattr__(self, name)

So far as I can tell, the recursion itself is entirely within the library, which would be a bug in that library. It's most likely getting triggered by pydevd by querying for some attribute.

@sebjf, can you try setting a breakpoint on that line, and check the name that gets passed to __getattr__ that triggers this? It might give more clues.

@sebjf
Copy link
Author

sebjf commented Sep 28, 2021

So far as I can tell, the recursion itself is entirely within the library, which would be a bug in that library

That's what I observe too. I spent some time digging around Coin, to see if I could find how getNodekitCatalog decides to terminate, but the only definition I could find just returns a static member:

/*! \
  Returns the nodekit catalog which defines the layout of this \
  class' kit. \
*/ \
const SoNodekitCatalog * \
_class_::getNodekitCatalog(void) const \
{ \
  return _class_::classcatalog; \
} \

(_class_ is a macro argument)

It may be being overridden somewhere else, but I am not familiar enough with SWIG to determine if this is the case.

can you try setting a breakpoint on that line, and check the name that gets passed to getattr

The name argument is 'this'. However, if I put a print statement at the start of the function to see what's passed in in 'normal' use without the debugger, it is the same (this).

There are some more oddities to note though. One is that if I leave the print statement in and attach the debugger, then it seems to print to the console as if it were executing, starting with the argument __iter__.

Additionally, I've never seen control flow return to the function. It seems c = _coin.SoBaseKit_getNodekitCatalog(self) throws a TypeError exception, but this is handled somewhere silently.

@int19h
Copy link
Collaborator

int19h commented Sep 28, 2021

__iter__ is something that the debugger does query, to determine whether the object is a collection (and thus should be displayed as expandable in the Variables pane). This happens every time you break anywhere, basically, for all globals and locals visible at that point.

@int19h
Copy link
Collaborator

int19h commented Sep 28, 2021

So it's not actually infinite recursion. I'm still not clear as to why, but even without debugpy in the picture at all, this call recurses 497 times for me. With debugpy, it recurses 1134 times - probably due to attribute accesses that the debugger performs.

The problem is that the default recursion limit in Python is 1000. But, it can be changed with sys.setrecursionlimit(). Now, setting it to e.g. 2000 doesn't work, either - I think this is because there are multiple call chains like this when debugger inspects things, so it needs extra room for more than one of those. The minimum value that works is 2275.

What's even weirder is that the number of times it recurses changes if you change the recursion limit! E.g. if you set it to 2285, it recurses 1139 times.

I suspect that somewhere inside Pivy, it triggers and catches RecursionError, so during normal operation you don't see that at all; but when debugger is added on top, and its tracing gets invoked when already at the recursion limit, that's what breaks it.

I don't think we can do much about this. The recursion here is really weird, and probably a perf issue at the very least, so I would recommend filing it as a bug on Pivy (and linking to this one so that they can start with this analysis). But in any case, we can't really gracefully handle Python recursion limits in a debugger that is itself largely written in Python. So the only remedy is to increase the limit.

@int19h int19h closed this as completed Sep 28, 2021
@int19h
Copy link
Collaborator

int19h commented Sep 29, 2021

One more thing. The recursion is actually triggered by _coin.SoDragPointDragger_swiginit when the object is created. The only thing that one does is call SWIG_Python_InitShadowInstance on itself:

https://github.com/swig/swig/blob/v4.0.2/Lib/python/pyrun.swg#L1266-L1281

Note the call to SWIG_Python_GetSwigThis. This is where the __getattr__("this") call is coming from. Now the implementation of __getattr__ unconditionally calls SoBaseKit_getNodekitCatalog, which at some point does:

res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_SoBaseKit, 0 |  0 );

and SWIG_ConvertPtr is a macro that expands to SWIG_Python_ConvertPtrAndOwn, which again calls SWIG_Python_GetSwigThis:

https://github.com/swig/swig/blob/v4.0.2/Lib/python/pyrun.swg#L1051

And so it recurses. Of note, the call to 'SoBaseKit_getNodekitCatalog' actually comes from Pivy customizations of SWIG:

https://github.com/coin3d/pivy/blob/b6f6f166ff63065fbad8b034cb99011c9eab7596/Inventor/nodekits/SoBaseKit.i

Note that __setattr__ already checks for "this". It probably needs the same check for __getattr__.

@sebjf
Copy link
Author

sebjf commented Sep 29, 2021

Thanks for the additional comments!

The problem is that the default recursion limit in Python is 1000. But, it can be changed with sys.setrecursionlimit(). Now, setting it to e.g. 2000 doesn't work, either

I needed to increase the stack size of the debug build of FreeCAD to prevent a crash originally. Though with the debugger attached I went up to something like a 1,000,000 recursion limit/stack size of 1.5Gb and it still crashed, so I really don't know whats going on.

Note that setattr already checks for "this". It probably needs the same check for getattr.

I experimented and think this is correct. I tried handing that case prior but not properly understanding what SWIG was doing, returning the SoNode implementation seems to resolve the issue without breaking anything else in the component however.

I will raise an issue on pivy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants