fix(local-tool): suppress KneronPLUS DeviceGroup.__del__ access violation

Windows 上 bridge script 結束時 Python GC 呼叫 DeviceGroup.__del__ →
kp_disconnect_devices 對已釋放的 native handle 操作 → OSError: access
violation reading 0x00...0C。這是 KneronPLUS SDK 的 destructor 沒做
null check 的已知問題,不影響功能但會印嚇人的 stack trace 到 stderr。

修法:
- 新增 _cleanup() 函式:明確 kp.core.disconnect_devices + 把
  _device_group 設 None(讓 __del__ 成 no-op)
- atexit.register(_cleanup) 確保 interpreter 關閉前 cleanup
- main() return 後也同步呼叫一次(belt-and-suspenders)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jim800121chen 2026-04-16 15:40:30 +08:00
parent 14d5a0ed2f
commit a6a121ae86

View File

@ -1112,5 +1112,26 @@ def main():
_respond({"error": str(e)}) _respond({"error": str(e)})
def _cleanup():
"""Explicitly disconnect and clear _device_group before Python GC runs.
KneronPLUS SDK's DeviceGroup.__del__ calls kp_disconnect_devices on a
native handle that may already be freed when the interpreter is shutting
down, causing 'OSError: access violation reading 0x00...'. By doing a
clean disconnect + setting the global to None here, __del__ becomes a
no-op (None has no __del__).
"""
global _device_group
if _device_group is not None:
try:
kp.core.disconnect_devices(_device_group)
except Exception:
pass
_device_group = None
if __name__ == "__main__": if __name__ == "__main__":
import atexit
atexit.register(_cleanup)
main() main()
_cleanup() # also call synchronously in case atexit doesn't fire