fix(host): _read_loop 跳过非 dict params 等脏消息,不杀死读循环

顶层为 dict 但 params 为真值非 dict 时,旧代码在 params.get 处抛
AttributeError,被外层 except 吞掉、读线程退出,后续正常消息
再也送达不了。改后校验跳过并记 stderr 日志、脏消息不进 events、
读循环继续;None/缺失/假值沿用旧 or {} 语义。审计同函数其它
get 路径:一并守住不可哈希的响应 id(pending.get)与 threadId /
thread.id(turn_queues.get)的 TypeError 致死路径;params.thread
已有 isinstance 守卫、_append_trace 已有 try 包裹,均不动。
This commit is contained in:
host committed 2026-11-03 02:49:26 +00:00
1 parent fddd08546d
commit 24adb568da
2 files changed
+186 -1

No files matched your search

+42 -1
View File
@@ -504,16 +504,57 @@ class Server:
self._answer_server_request(msg)
continue
if "id" in msg:
mid = msg["id"]
if isinstance(mid, (list, dict)):
# id 在此被当 pending 字典的 key:不可哈希时
# 旧代码在 pending.get 处抛 TypeError,被外层
# except 吞掉、读线程退出。这类 id 本就不可能
# 命中 pending(key 全是 request 发出的 int),
# 跳过本条、读循环继续。
sys.stderr.write(
"host _read_loop: skip response with "
"unhashable id type=%s value=%.200s\n"
% (type(mid).__name__, repr(mid)))
sys.stderr.flush()
continue
with self.pending_lock:
q = self.pending.get(msg["id"])
q = self.pending.get(mid)
if q is not None:
q.put(msg)
continue
# 通知
params = msg.get("params") or {}
if not isinstance(params, dict):
# 残留项:params 为真值非 dict(如 "foo"/123/
# [1,2]/True)时旧代码在下一行 params.get 抛
# AttributeError,被外层 except 吞掉、读线程退出,
# 后续正常消息再也送达不了。脏消息跳过、不进
# events、不当正常请求处理,读循环继续。
# None/缺失/假值沿用旧的 `or {}` 语义(已是
# dict,不走此分支),正常消息语义不动。
sys.stderr.write(
"host _read_loop: skip notification with "
"non-dict params type=%s value=%.200s\n"
% (type(params).__name__, repr(params)))
sys.stderr.flush()
continue
thread_id = params.get("threadId")
if not thread_id and isinstance(params.get("thread"), dict):
thread_id = params["thread"].get("id")
if not isinstance(thread_id, str) and thread_id is not None:
# thread_id 只用于 turn_queues 路由:不可哈希的
# 值(如 list/dict)旧代码在 turn_queues.get 处
# 抛 TypeError 杀死读线程;非 str 的 key 本就不
# 可能命中 turn_queues(key 全是 str),一律视为
# 不可路由,事件本身仍保留、只跳过路由。
if isinstance(thread_id, (list, dict)):
sys.stderr.write(
"host _read_loop: skip turn routing with "
"unhashable thread_id type=%s value=%.200s\n"
% (type(thread_id).__name__,
repr(thread_id)))
sys.stderr.flush()
thread_id = None
with self.events_lock:
self.events.append(msg)
if self.trace_path is not None: