python / python/cpython

tarfile silently stops/skips on bad member header (e.g. checksum mismatch)

未关闭
#120,740 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

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

描述

Bug report

Bug description:

When reading a tar archive that includes a file with a bad header (such as a checksum mismatch), getmembers simply stops listing the members at that file, without reporting an error, and ignoring the files that come after it (Edit: unless ignore_zeros=True is set).

I would expect instead that getmembers lists all members, and extractfile raises a TarError when trying to extract a file with an invalid header (such as a bad chksum or typeflag).

import os
import contextlib
import subprocess
from io import BytesIO
from tarfile import TarFile, TarInfo
from tempfile import TemporaryDirectory

# generate a tar file in memory
bio = BytesIO()
with TarFile(mode="w", fileobj=bio, errorlevel=2) as tf:
    ti = TarInfo()
    ti.size = 3
    for name, data in (("foo", b"123"), ("bar", b"456"), ("quz", b"789")):
        ti.name = name
        tf.addfile(ti, BytesIO(data))

# break the checksum of the second file 'bar'
assert b"\x00006425\x00" in bio.getvalue()
broken = bio.getvalue().replace(b"\x00006425\x00", b"\x00106425\x00")

# try to read the tar file
with TarFile(fileobj=BytesIO(broken), errorlevel=2) as tf:
    for ti in tf.getmembers():
        print(repr(ti.name))
        with tf.extractfile(ti) as fh:
            print(repr(fh.read()))
# => only "foo" is extracted

with TemporaryDirectory() as td:
    with contextlib.chdir(td):
        with TarFile(fileobj=BytesIO(broken), errorlevel=2) as tf:
            tf.extractall()
        print(os.listdir())
        # => again only "foo" is extracted
        os.unlink("foo")
        with TarFile(fileobj=BytesIO(broken), errorlevel=2) as tf:
            tf.extractall(filter="data")
        print(os.listdir())
        # => filter doesn't change anything
        with open("test.tar", "wb") as fh:
            fh.write(broken)
        subprocess.run(["tar", "tvf", "test.tar"], check=False)
        # => GNU tar 1.34 correctly identifies error and continues processing

Output:

'foo'
b'123'
['foo']
['foo']
-rw-r--r-- 0/0               3 1970-01-01 00:00 foo
tar: Skipping to next header
-rw-r--r-- 0/0               3 1970-01-01 00:00 quz
tar: Exiting with failure status due to previous errors
CPython versions tested on:

3.12, 3.13

Operating systems tested on:

Linux, Windows

贡献指南

打开贡献指南

从这里开始

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

调研方向

使用提供的 BytesIO 示例复现该行为,然后从报告中列出的入口点 TarFile.getmembers()、extractfile() 和 extractall() 开始。跟踪无效成员头部的处理方式,以及后续头部是如何被访问到的。完成的标准是:按要求报告错误的头部,同时后续有效成员仍可继续处理,并且受影响的行为有测试覆盖。

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

评估

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

把新 issue 发到你的邮箱

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