python / python/cpython

logging: `SMTPHandler.emit()` leaks the SMTP connection when sending fails

未关闭
#155,946 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

stdlib type-bug
主要语言
Python
星标
77.2k
派生
36k
PR 合并指标
PR 指标待抓取

描述

Bug report

Bug description:

SMTPHandler.emit() only closes its SMTP connection on the success path: smtp.quit() is the last statement of the try block (Lib/logging/handlers.py#L1109-L1154).

If starttls(), login() or send_message() raises, control jumps to except Exception: self.handleError(record) and the connection is never closed — cleanup is left to the garbage collector.

Reproducer
import gc, logging, logging.handlers, socket, threading, time

logging.raiseExceptions = False
open_conns = []

def handle(conn):
    conn.sendall(b"220 fake ESMTP\r\n")
    for line in conn.makefile("rb"):
        cmd = line.strip().upper()
        if cmd.startswith(b"EHLO"):
            conn.sendall(b"250-fake\r\n250 AUTH PLAIN LOGIN\r\n")
        elif cmd.startswith(b"AUTH"):
            conn.sendall(b"535 authentication failed\r\n")
        else:
            conn.sendall(b"250 ok\r\n")
    open_conns.remove(conn)  # reached when the client closes the connection
    conn.close()

def serve(listener):
    while True:
        conn, _ = listener.accept()
        open_conns.append(conn)
        threading.Thread(target=handle, args=(conn,), daemon=True).start()

listener = socket.create_server(("127.0.0.1", 0))
threading.Thread(target=serve, args=(listener,), daemon=True).start()

h = logging.handlers.SMTPHandler(("127.0.0.1", listener.getsockname()[1]),
                                 "me@example.com", "you@example.com", "subject",
                                 credentials=("user", "wrong-password"))
for i in range(5):
    h.emit(logging.makeLogRecord({"msg": "hello"}))  # SMTPAuthenticationError
time.sleep(0.5)
print("open connections after 5 failed emits:", len(open_conns))
gc.collect(); time.sleep(0.5)
print("after gc.collect():", len(open_conns))

Output on main:

open connections after 5 failed emits: 5
after gc.collect(): 0
CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

Linked PRs
  • gh-155950

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 Lib/logging/handlers.py 中的 SMTPHandler.emit() 开始,并运行提供的身份验证失败复现程序。完成的标准是,starttls()、login() 或 send_message() 失败的路径不再让 SMTP 连接保持打开状态,并根据复现程序检查行为;关联的 PR gh-155950 表明相关工作已经在进行中。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
backend
Issue 类型
缺陷
难度
2/5
预计耗时
1-3 小时
活跃度
停滞
描述清晰度
描述清楚
新手友好度
25/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。