fix(frame): 工具执行加异常保护,畸形参数不再崩溃 CAD / 泄漏写锁 #10

Merged
gjm merged 2 commits from home-lenovo-legion-r9000/home-ai-dev AGit into main 2026-10-14 15:45:19 +08:00
Collaborator

cad_mcp_frame 的工具执行发生在 AutoCAD 主线程的窗口消息处理链上
(TcpServerLoop -> PostMessage -> WndProc -> ExecuteTaskInMainThread -> mcp_Tools::Call)。
插件 Execute 在参数类型不符时会抛 nlohmann::type_error(如 args.value("bulge", 0.5)
收到字符串、parsePoint 对 ["a","b"] 取 get())。原实现全程无 try/catch,
异常逃逸出 WndProc 属未定义行为(实测表现为 CAD 崩溃),且会让 DLL 代理的文档写锁
无法释放。LLM 驱动的审图流程会生成这类错误参数,属日常会踩到的路径。

  • mcp_ConfigParser.cpp: mcp_Tools::Call 用 try/catch 包住 Execute,
    std::exception -> make_error(-32603)(上层映射为 result.isError=true),catch(...) 兜底。
  • mcp_server.cpp: HandleToolsCall 入口校验 params/arguments 必须是对象、name 必须是
    字符串,否则回 -32602(协议错误),从源头避免 value()/get<>() 抛异常;
    ExecuteTaskInMainThread 增加兜底 try/catch,并补 !req.is_object() -> -32600。
  • mcp_tool.cpp: mcp_Tool_DllProxy::Execute 的文档写锁改为 RAII 守卫
    (ScopedDocumentWriteLock),异常展开时同样解锁,避免写锁泄漏。

验证(关 CAD -> 重建 -> 重启后实测):

  • 新增 verify_mcp_fault_injection.py 22/22 PASS:
    A 结构性错误(params/arguments/name 类型错、非对象请求、非法 JSON)分别回
    -32602/-32600/-32700;B 工具内部类型异常被兜为 result.isError=true;
    C 反复注入 10 次后 CAD 存活、写锁未泄漏(有效写操作仍成功)。
  • 回归:verify_mcp_frame 4/4、verify_stdio_bridge 24/24、verify_annotate 9/9、
    dwg_review --check 正常。
cad_mcp_frame 的工具执行发生在 AutoCAD 主线程的窗口消息处理链上 (TcpServerLoop -> PostMessage -> WndProc -> ExecuteTaskInMainThread -> mcp_Tools::Call)。 插件 Execute 在参数类型不符时会抛 nlohmann::type_error(如 args.value("bulge", 0.5) 收到字符串、parsePoint 对 ["a","b"] 取 get<double>())。原实现全程无 try/catch, 异常逃逸出 WndProc 属未定义行为(实测表现为 CAD 崩溃),且会让 DLL 代理的文档写锁 无法释放。LLM 驱动的审图流程会生成这类错误参数,属日常会踩到的路径。 - mcp_ConfigParser.cpp: mcp_Tools::Call 用 try/catch 包住 Execute, std::exception -> make_error(-32603)(上层映射为 result.isError=true),catch(...) 兜底。 - mcp_server.cpp: HandleToolsCall 入口校验 params/arguments 必须是对象、name 必须是 字符串,否则回 -32602(协议错误),从源头避免 value()/get<>() 抛异常; ExecuteTaskInMainThread 增加兜底 try/catch,并补 !req.is_object() -> -32600。 - mcp_tool.cpp: mcp_Tool_DllProxy::Execute 的文档写锁改为 RAII 守卫 (ScopedDocumentWriteLock),异常展开时同样解锁,避免写锁泄漏。 验证(关 CAD -> 重建 -> 重启后实测): - 新增 verify_mcp_fault_injection.py 22/22 PASS: A 结构性错误(params/arguments/name 类型错、非对象请求、非法 JSON)分别回 -32602/-32600/-32700;B 工具内部类型异常被兜为 result.isError=true; C 反复注入 10 次后 CAD 存活、写锁未泄漏(有效写操作仍成功)。 - 回归:verify_mcp_frame 4/4、verify_stdio_bridge 24/24、verify_annotate 9/9、 dwg_review --check 正常。
home-Lenovo-Legion-r9000 added 1 commit 2026-10-14 15:40:29 +08:00
cad_mcp_frame 的工具执行发生在 AutoCAD 主线程的窗口消息处理链上
(TcpServerLoop -> PostMessage -> WndProc -> ExecuteTaskInMainThread -> mcp_Tools::Call)。
插件 Execute 在参数类型不符时会抛 nlohmann::type_error(如 args.value("bulge", 0.5)
收到字符串、parsePoint 对 ["a","b"] 取 get<double>())。原实现全程无 try/catch,
异常逃逸出 WndProc 属未定义行为(实测表现为 CAD 崩溃),且会让 DLL 代理的文档写锁
无法释放。LLM 驱动的审图流程会生成这类错误参数,属日常会踩到的路径。

- mcp_ConfigParser.cpp: mcp_Tools::Call 用 try/catch 包住 Execute,
  std::exception -> make_error(-32603)(上层映射为 result.isError=true),catch(...) 兜底。
- mcp_server.cpp: HandleToolsCall 入口校验 params/arguments 必须是对象、name 必须是
  字符串,否则回 -32602(协议错误),从源头避免 value()/get<>() 抛异常;
  ExecuteTaskInMainThread 增加兜底 try/catch,并补 !req.is_object() -> -32600。
- mcp_tool.cpp: mcp_Tool_DllProxy::Execute 的文档写锁改为 RAII 守卫
  (ScopedDocumentWriteLock),异常展开时同样解锁,避免写锁泄漏。

验证(关 CAD -> 重建 -> 重启后实测):
- 新增 verify_mcp_fault_injection.py 22/22 PASS:
  A 结构性错误(params/arguments/name 类型错、非对象请求、非法 JSON)分别回
  -32602/-32600/-32700;B 工具内部类型异常被兜为 result.isError=true;
  C 反复注入 10 次后 CAD 存活、写锁未泄漏(有效写操作仍成功)。
- 回归:verify_mcp_frame 4/4、verify_stdio_bridge 24/24、verify_annotate 9/9、
  dwg_review --check 正常。
home-Lenovo-Legion-r9000 added 1 commit 2026-10-14 15:40:56 +08:00
gjm merged commit 446a5b3cb9 into main 2026-10-14 15:45:19 +08:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: gjm/cad-agent#10