SQLite 数据库文件为何会损坏

概览

SQLite 数据库具有很强的抗损坏能力。如果事务进行到一半时,应用程序崩溃、操作系统崩溃,甚至发生断电,那么下一次访问数据库文件时,已经部分写入的事务应当自动回滚。恢复过程完全自动,不需要用户或应用程序采取任何行动。

尽管 SQLite 能抵抗数据库损坏,但它并非绝对免疫。本文介绍 SQLite 数据库可能损坏的各种方式。

1. 异常线程或进程覆盖文件

SQLite 数据库文件是普通的磁盘文件。这意味着任何进程都可以打开该文件,并用无效数据将它覆盖。SQLite 库无法防御这种情况。

1.1. 文件描述符关闭后仍继续使用

我们见过多起这样的情况:某个文件描述符最初对应一个文件,随后被关闭,之后又被重新分配给 SQLite 数据库。另一个线程稍后仍继续向旧文件描述符写入,未意识到原始文件已经关闭。但由于 SQLite 已经重新使用该描述符,原本应该写入原始文件的信息就覆盖了 SQLite 数据库的部分内容,造成数据库损坏。

一个案例发生在2013年8月30日前后,涉及 Fossil DVCS 的主代码仓库。当时,在调用 sqlite3_open_v2() 之前,文件描述符2(标准错误)被错误关闭了,我们怀疑是 stunnel 所为。因此,仓库数据库文件使用的描述符变成了2。随后,应用程序中的一个缺陷使 assert() 语句通过调用 write(2,...) 输出错误消息。

由于文件描述符2此时连接的是数据库文件,错误消息覆盖了数据库的一部分。为防范此类问题,SQLite 3.8.1版本(2013-10-17)及以后版本拒绝为数据库文件使用低编号的文件描述符。更多信息请参阅 SQLITE_MINIMUM_FILE_DESCRIPTOR。

2014年8月12日的一篇博客文章中,Facebook工程师报告 了另一例因使用已关闭文件描述符而造成的损坏。

2019年7月11日,Fossil 又收到一例此类错误报告。某个文件描述符先被打开用于调试输出,后来被关闭并由 SQLite 重新使用;调试逻辑却继续向原描述符写入。缺陷报告及修复链接见 论坛讨论。

1.2. 在事务进行期间备份或恢复

在后台运行自动备份的系统,可能会尝试在事务进行到一半时复制 SQLite 数据库文件。备份副本可能同时包含一部分旧内容和一部分新内容,因此可能已经损坏。

有多种安全方式可以备份 SQLite 数据库。这里的“安全”是指能够生成正确、未损坏的备份。以下方法不分先后:

  1. sqlite3_rsync 工具从 SQLite 3.47.0(2024-10-21)起提供,能够使用节省带宽的协议,通过 SSH 复制正在使用的 SQLite 数据库。
  1. VACUUM INTO filename 命令将 SQLite 数据库当前状态复制到一个独立文件中。
  1. backup API 是一个 C 语言接口,可以生成 SQLite 数据库的一致副本。

上述任何方法都适用于正在使用的数据库。只要复制期间没有正在进行的事务,直接复制 SQLite 数据库文件也是安全的。如果前一次写事务失败,则务必将回滚日志(*-journal 文件)或预写日志(*-wal 文件)与数据库文件一起复制。

1.3. 删除热日志

SQLite 通常将全部内容存储在单个磁盘文件中。不过,在执行事务期间,崩溃或断电后恢复数据库所需的信息会存储在辅助日志文件中。这类日志文件被称为 “热”日志。日志文件与原始数据库文件同名,并附加 -journal 或 -wal 后缀。

SQLite 必须能够看到日志文件,才能从崩溃或断电中恢复。如果在崩溃或断电后移动、删除或重命名 热日志文件,自动恢复便无法工作,数据库可能损坏。

这个问题的另一种表现,是 不一致地使用8+3文件名造成数据库损坏。

1.4. 数据库文件与热日志错配

前一个例子是一个更普遍问题的具体情况:SQLite 数据库的状态由数据库文件和日志文件共同控制。在静止状态下,日志文件不存在,只有数据库文件本身起作用。但如果日志文件存在,就必须将其与数据库保存在一起,避免损坏。以下操作均可能导致损坏:

  • 交换两个不同数据库的日志文件。
  • 用另一个日志文件覆盖原日志文件。
  • 将一个数据库的日志文件移动到另一个数据库。
  • 复制数据库文件时没有同时复制其日志。
  • 用另一个数据库文件覆盖原文件,却没有同时删除与原数据库关联的热日志。

2. 文件锁问题

SQLite 使用数据库文件及 预写日志(WAL) 文件上的文件锁,协调并发进程之间的访问。没有这种协调,两个线程或进程就可能同时尝试对数据库文件作出彼此不兼容的修改,导致数据库损坏。

2.1. 文件系统的锁实现有缺陷或缺失

SQLite 依赖底层文件系统按文档规定执行加锁。但某些文件系统的加锁逻辑存在缺陷,锁并不总是按声明的方式工作。网络文件系统尤其如此,NFS尤为典型。如果在加锁原语存在缺陷的文件系统上使用 SQLite,两个或更多线程或进程又同时尝试访问同一个数据库,就可能导致数据库损坏。

2.2. 另一个线程调用 close() 取消 POSIX 建议锁

SQLite 在 Unix 平台上的默认加锁机制是 POSIX 建议锁。遗憾的是,POSIX 建议锁的设计有一些特殊行为,使其容易被误用或失效。尤其是,同一进程中的任意线程,即使通过另一个文件描述符,也能覆盖某个文件描述符所持有的 POSIX 建议锁。

一个尤其棘手的问题是:close() 系统调用会取消该进程内所有线程、所有文件描述符在同一个文件上持有的全部 POSIX 建议锁。

例如,假设一个多线程进程中,有两个或更多线程分别通过独立 SQLite 数据库连接访问同一个数据库文件。这时,第三个线程绕过 SQLite 库,想自行读取该数据库文件的内容。它可能想创建数据库备份,也可能只是识别文件类型,于是尝试读取前16个字节来判断是否确实为 SQLite 数据库。

无论原因是什么,第三个线程依次执行 open()、read() 和 close()。人们可能认为这无害,但 close() 系统调用使其他所有线程在该数据库上持有的锁都被解除。其他线程无法知道自己的锁刚刚被破坏了——POSIX 没有提供检测这种情况的机制——于是仍假定锁有效,继续运行。

这会导致两个或更多线程或进程同时尝试写入数据库,造成数据库损坏。

注意,两个或更多线程通过 SQLite 库访问同一个 SQLite 数据库文件,完全安全。SQLite 的 Unix 驱动了解 POSIX 建议锁的这些特殊行为,并采取措施规避。只有当某个线程试图绕过 SQLite 库直接读取数据库文件时,才会产生这个问题。

从 SQLite 3.51.0(2025-11-04)起,SQLite 增加了防御措施,尝试避免 close() 破坏锁所引发的问题。当数据库处于 WAL模式、又被多个进程访问时,这些措施有帮助,但它们并不能解决一切。为了避免损坏,开发者应注意:只要还有一个或多个数据库连接打开,即使这些连接位于其他线程中,也绝不要对 SQLite 数据库文件直接调用 close()。

2.3. 同一应用程序链接了多份 SQLite

如前一节所述,SQLite 会采取措施规避 POSIX 建议锁的特殊行为。其中一项措施是维护一个由互斥锁保护的全局列表,记录已经打开的 SQLite 数据库文件。但是,如果同一应用程序链接了多份 SQLite,这个全局列表也会有多个实例。

通过一份 SQLite 库打开的数据库连接,不知道通过另一份库打开的连接,因此无法规避 POSIX 建议锁的特殊行为。一个连接上的 close() 操作,可能不知不觉清除了另一个连接上的锁,导致数据库损坏。

上述场景听起来似乎难以发生,但 SQLite 开发者知道至少有一个已经发布的商业产品恰好包含这个缺陷。供应商向 SQLite 开发者寻求帮助,追查在 Linux 和 Mac 上偶尔发生的数据库损坏。最终发现,应用程序链接了两份独立 SQLite。

解决办法是修改应用程序构建流程,使其只链接一份 SQLite,而不是两份。

2.4. 两个进程使用不同的加锁协议

SQLite 在 Unix 平台上默认使用 POSIX 建议锁,但也有其他选项。通过 sqlite3_open_v2() 接口选择另一种 sqlite3_vfs,应用程序就可以使用可能更适合特定文件系统的其他加锁协议。例如,在必须运行于不支持 POSIX 建议锁的 NFS 文件系统上的应用中,可以选择点文件加锁。

访问同一个数据库文件的所有连接,必须使用相同加锁协议。如果一个应用使用 POSIX 建议锁,而另一个使用点文件加锁,它们就无法看到彼此的锁,也无法协调数据库访问,可能导致数据库损坏。

2.5. 数据库使用期间取消文件链接或重命名

如果两个进程已经连接同一个数据库文件,其中一个进程关闭自己的连接、取消该文件的链接,然后在原位置创建同名的新数据库文件并重新打开,那么两个进程实际上是在访问名称相同、内容不同的数据库文件。注意,只有允许在文件仍被打开读写时取消链接的 POSIX 及类 POSIX 系统才会出现这种情况。

Windows 不允许这样做。由于回滚日志和 WAL 文件名由数据库文件名决定,这两个不同的数据库会共用同一个回滚日志或 WAL 文件。某个数据库的回滚或恢复操作可能使用另一个数据库的内容,导致损坏。如果在数据库文件打开期间将其重命名,并以旧名称创建新文件,也会发生类似问题。

换言之,对仍然打开的数据库文件取消链接或重命名,会产生未定义且很可能不符合预期的行为。

从 SQLite 3.7.17版本(2013-05-20)起,如果数据库文件在使用期间被取消链接,Unix OS 接口会向 错误日志 发送 SQLITE_WARNING 消息。

2.6. 同一个文件有多个链接

如果单个数据库文件有多个链接——硬链接或软链接——也就意味着这个文件有多个名称。如果两个或更多进程通过不同名称打开数据库,它们会使用不同的回滚日志和 WAL 文件。这样,如果某个进程崩溃,另一个进程便无法恢复正在进行的事务,因为它会去错误的位置查找相应日志。

换言之,打开和使用一个具有两个或更多名称的数据库文件,会产生未定义且很可能不符合预期的行为。

从 SQLite 3.7.17版本(2013-05-20)起,如果数据库文件有多个硬链接,Unix OS 接口会向 错误日志 发送 SQLITE_WARNING 消息。

从 SQLite 3.10.0版本(2016-01-06)起,Unix OS 接口会尝试解析符号链接,并使用数据库文件的规范名称打开它。在3.10.0之前,通过符号链接打开数据库文件,类似于打开一个具有多个硬链接的文件,会产生未定义行为。

2.7. 将打开的数据库连接跨 fork() 传给子进程

不要先打开 SQLite 数据库连接,再调用 fork(),然后尝试在子进程中使用该连接。这会产生各种加锁问题,很容易造成数据库损坏。SQLite 不支持这种行为。子进程使用的任何数据库连接,都必须由子进程自己打开,不能从父进程继承。

如果连接是在父进程中打开的,甚至不要在子进程中对它调用 sqlite3_close()。关闭底层文件描述符是安全的,但 sqlite3_close() 接口可能触发清理活动,删除父进程仍在使用的内容,导致错误,甚至数据库损坏。

3. 同步失败

为保证数据库文件始终一致,SQLite 会不时要求操作系统将所有待写入的数据刷新到持久存储,并等待刷新完成。在 Unix 上通过 fsync() 系统调用实现,在 Windows 上则通过 FlushFileBuffers()。我们将这种刷新待写入数据的操作称为“同步”(sync)。

实际上,如果只关心写入的原子性和一致性,并愿意放弃写入的持久性,同步操作就不必等待内容完全写入持久介质。可以把同步操作视为一道 I/O 屏障:只要同步之前的所有写入,都在同步之后的任何写入之前完成,数据库就不会损坏。

如果同步只起 I/O 屏障作用,并非真正同步,那么断电或系统崩溃可能导致一个或多个此前已提交的事务回滚,违反 ACID 中的持久性属性;但数据库至少仍保持一致,而这正是大多数人关心的事情。

3.1. 磁盘驱动器不遵守同步请求

遗憾的是,大多数消费级大容量存储设备会在同步问题上说谎。磁盘驱动器一旦把内容放入磁道缓冲区,就宣称内容已经安全保存到持久介质,实际上还没有写入磁性介质。这会让驱动器看起来更快,对制造商十分重要,因为他们希望在行业媒体中展示漂亮的基准测试数字。

公平地说,只要在磁道缓冲区内容真正写入介质之前没有断电或硬复位,这种说谎通常无害。但如果断电或硬复位真的发生,导致同步之后写入的内容先到达介质,而同步之前的内容仍留在磁道缓冲区,就可能造成数据库损坏。

USB 闪存盘在同步请求方面似乎尤其擅长说谎。向 USB 闪存盘上的 SQLite 数据库提交一个大事务,很容易观察到这一点:COMMIT 命令会较快返回,说明闪存盘告诉操作系统、操作系统又告诉 SQLite,全部内容已安全写入持久存储;但闪存盘上的 LED 指示灯仍会继续闪烁数秒。

在 LED 仍然闪烁时拔掉闪存盘,常常会导致数据库损坏。

注意,SQLite 必须相信操作系统和硬件对同步请求状态的报告。SQLite 无法判断其中哪一方是否说谎,也无法检测写入是否可能乱序。不过,相比默认回滚日志模式,SQLite 的 WAL模式 对乱序写入更宽容。在 WAL 模式下,同步操作失败只有在 检查点 操作期间才会造成数据库损坏。

COMMIT 期间同步失败,可能导致持久性丢失,却不会导致数据库文件损坏。因此,应对同步失败引发数据库损坏的一种防线,是使用 WAL 模式并尽可能降低检查点执行频率。

3.2. 使用 PRAGMA 禁用同步

SQLite 为保障完整性而执行的同步操作,可以通过 synchronous pragma 在运行时禁用。设置 PRAGMA synchronous=OFF 后,所有同步操作都会省略。这会让 SQLite 看起来运行得更快,但也允许操作系统自由重排写入。如果全部内容到达持久存储之前发生断电或硬复位,就可能造成数据库损坏。

为了获得最高可靠性并增强抵御数据库损坏的能力,SQLite 应始终使用默认的 FULL synchronous 设置。

4. 磁盘驱动器和闪存故障

如果磁盘驱动器或闪存故障改变了文件内容,SQLite 数据库就可能损坏。这种情况很少见,但磁盘偶尔确实会翻转某个扇区中的一个位。

4.1. 不具备掉电安全性的闪存控制器

据我们了解,某些闪存控制器的磨损均衡逻辑,会在写入期间断电时造成随机的文件系统损坏。例如,一个在断电时根本没有打开的文件,其中间部分也可能随机发生改变。

因此,设备可能正在向闪存中的 MP3 文件写入内容时断电,结果却造成 SQLite 数据库损坏,即使断电时该数据库根本没有被使用。

4.2. 虚假容量的 USB 闪存盘

市面上流通着许多欺诈性 USB 闪存盘。它们声称容量很大,例如8GB,实际却只能存储小得多的内容,例如1GB。尝试向这些设备写入数据,常常会覆盖其他无关文件。因此,使用虚假容量的闪存设备很容易导致数据库损坏。搜索“fake capacity usb”等关键词,就会找到大量令人担忧的信息。

5. 内存损坏

SQLite 是一个 C 语言库,与使用它的应用程序运行在同一地址空间中。这意味着应用中的野指针、缓冲区溢出、堆损坏或其他故障,都可能破坏 SQLite 内部数据结构,最终造成数据库文件损坏。

通常,这些问题会在数据库损坏之前表现为段错误。但也有案例中,应用程序代码错误使 SQLite 以微妙方式失常,没有立即崩溃,而是破坏了数据库文件。

使用 内存映射I/O 时,内存损坏问题更加严重。如果数据库文件全部或部分映射到应用地址空间,野指针只要覆盖该映射空间的任何部分,就会立即破坏数据库文件,不需要应用随后调用 write() 系统调用。

6. 操作系统的其他问题

操作系统有时会表现出非标准行为,从而引发问题。这些行为可能是有意设计,也可能是实现错误。但无论原因如何,只要操作系统的实际行为与 SQLite 的预期不同,就有可能造成数据库损坏。

6.1. Linux Threads

一些旧版 Linux 使用 LinuxThreads 库支持线程。LinuxThreads 类似于 Pthreads,但在 POSIX 建议锁处理方面存在细微差异。SQLite 2.2.3至3.6.23版本会在运行时识别 LinuxThreads,并采取相应措施规避其非标准行为。大多数现代 Linux 实现则使用更新且正确的 NPTL Pthreads 实现。

从 SQLite 3.7.0版本(2010-07-21)起,SQLite 假定系统使用 NPTL,不再检查。因此,如果较新的 SQLite 在仍使用 LinuxThreads 的旧 Linux 系统上的多线程应用中运行,就可能出现微妙故障并破坏数据库文件。

6.2. QNX 上 mmap() 的故障

QNX 的 mmap() 存在一个微妙问题:对同一个文件描述符第二次调用 mmap(),可能使第一次调用获得的内存被清零。在 Unix 上,SQLite 使用 mmap() 创建用于 WAL模式 事务协调的共享内存区域;对于大事务,它会多次调用 mmap()。已有实验证明,在这种场景下,QNX 的 mmap() 会破坏数据库文件。

QNX 工程师已知晓该问题并在着手解决。你读到本文时,它可能已经修复。

在 QNX 上运行时,建议始终不要使用 内存映射I/O。此外,若要使用 WAL模式,建议应用采用 排他锁模式,从而 在不使用共享内存的情况下使用WAL。

6.3. 文件系统损坏

由于 SQLite 数据库是普通磁盘文件,文件系统的任何故障都可能破坏数据库。现代操作系统的文件系统十分可靠,但错误仍然会发生。例如,2013年10月1日,存储 Tcl/Tk Wiki 的 SQLite 数据库损坏了;几天前,其主机刚切换到一个不可靠的 Linux 内核构建,其中的文件系统层存在问题。

在那个案例中,文件系统最终损坏得如此严重,以至于机器无法使用,但最早的故障迹象却是 SQLite 数据库损坏。

7. SQLite 配置错误

SQLite 内置许多防止数据库损坏的保护措施,但配置选项可以禁用其中不少保护。如果禁用了保护,数据库就可能损坏。

以下是禁用 SQLite 内置保护机制的例子:

  • 设置 PRAGMA synchronous=OFF,可能在操作系统崩溃或断电时导致数据库损坏,不过在应用程序崩溃时,这个设置不会因此造成损坏。

8. SQLite 中的缺陷

SQLite 经过 非常细致的测试,尽可能确保没有缺陷。每个 SQLite 版本的众多测试中,包含模拟断电、I/O 错误和内存不足(OOM)的测试,以验证这些事件不会造成数据库损坏。SQLite 也经过实际应用检验,约有20亿个活跃部署,没有严重问题。

不过,软件不可能百分之百完美。SQLite 历史上曾有少量可能造成数据库损坏的缺陷,目前均已修复;也可能还有未被发现的缺陷。由于测试广泛、使用范围巨大,导致数据库损坏的缺陷往往十分隐蔽。应用遇到 SQLite 缺陷的概率很小。

为说明这一点,下面记录了2009年4月1日至2013年4月15日这四年期间发现的全部数据库损坏缺陷。这份记录应能让读者直观了解,什么样的 SQLite 缺陷可能绕过测试流程并进入正式版本。

8.1. 写入 WAL 模式数据库时的竞态条件

当两个或更多数据库连接位于不同线程或进程中,并且都打开了同一个 WAL模式 数据库,如果两个连接同时尝试写入或执行检查点,就存在可能破坏数据库文件的竞态条件。这就是 WAL-reset缺陷。它存在于 SQLite 3.7.0至3.51.2的所有版本中。详情请参阅 WAL-reset缺陷 文档。

8.2. 过时的表达式索引

“表达式索引”指引用表达式或 VIRTUAL生成列 的索引。表达式索引按要求应只使用 确定性函数。但当数据库在不同平台之间迁移,或更换 SQLite 版本时,某些本应确定的函数有时会略微改变输出。这可能使索引看起来像是损坏了。更多详情请参阅 过时的表达式索引 文档。

8.3. 数据库收缩导致的误报损坏

如果数据库先由 SQLite 3.7.0或更高版本写入,随后又由3.6.23或更早版本写入,而且这次写入使数据库文件缩小,那么 SQLite 3.7.0下次访问文件时,可能报告数据库损坏。但文件实际上并未损坏,只是3.7.0的损坏检测过于严格。

该问题于2011年2月20日修复。修复首次出现在 SQLite 3.7.6版本(2011-04-12)。

8.4. 回滚模式与 WAL 模式切换后发生损坏

如果某个进程或线程反复将 SQLite 数据库切入、切出 WAL模式,并在切换之间运行 VACUUM 命令,另一个仍打开该数据库文件的进程或线程可能未察觉数据库已经改变。第二个进程或线程随后可能使用过时缓存修改数据库,造成数据库损坏。

该问题是在内部测试中发现的,从未在实际应用中观察到。它于2011年1月27日修复,包含在3.7.5版本中。

8.5. 获取锁时的 I/O 错误导致损坏

如果操作系统在尝试获取 WAL模式 共享内存上的某种锁时返回 I/O 错误,SQLite 可能未能重置缓存。如果之后尝试写入,就可能造成数据库损坏。

注意,只有获取锁的尝试产生 I/O 错误时才会出现该问题。如果仅仅没有获得锁,例如另一个线程或进程已持有冲突锁,就绝不会因此损坏。我们不知道有哪个操作系统会在尝试获取共享内存上的文件锁时,以 I/O 错误失败。因此,这属于理论问题而非现实问题。不用说,它从未在实际应用中被观察到。

该问题是在使用模拟 I/O 错误的测试框架对 SQLite 进行压力测试时发现的。

该问题于2010年9月20日为 SQLite 3.7.3版本修复。

8.6. 数据库页从空闲页列表中丢失

从 SQLite 数据库删除内容时,不再使用的页会加入空闲页列表,并用于存储后续插入的新内容。SQLite 3.6.16至3.7.2存在一个缺陷,可能在使用 incremental_vacuum 时,使部分页从空闲页列表中丢失。这不会丢失数据,但会使数据库文件比实际需要的更大。

它还会导致 integrity_check pragma 报告空闲页列表中缺少页。

该问题于2010年8月23日为 SQLite 3.7.2版本修复。

8.7. 交替使用3.6和3.7写入后发生损坏

SQLite 3.7.0对数据库文件格式引入了多项新改进,包括但不限于 WAL。3.7.0是对这些新特性进行检验的版本。我们预计会发现问题,事实也确实如此。

如果数据库最初由 SQLite 3.7.0创建,随后由 SQLite 3.6.23.1写入并使文件增大,之后再由 SQLite 3.7.0写入,数据库就可能损坏。

该问题于2010年8月4日为 SQLite 3.7.1版本修复。

8.8. Windows 系统恢复过程中的竞态条件

SQLite 3.7.16.2修复了 Windows 加锁逻辑中的一个微妙竞态条件。如果前一个写入进程在事务中途崩溃,数据库就需要恢复;当两个或更多进程同时尝试打开该数据库时,竞态条件可能让其中一个进程错误地认为恢复已经完成,使其未执行恢复就继续访问数据库文件。

如果该进程写入文件,数据库就可能损坏。这个竞态条件显然存在于自2004年以来此前所有 Windows 版 SQLite 中,但竞态窗口很窄。实际要触发它,需要一台较快的多核机器,让两个进程在不同核心上同一时刻启动恢复。该缺陷仅涉及 Windows,不影响 POSIX OS 接口。

8.9. 嵌套事务辅助日志中的边界值错误

使用 SAVEPOINT 启动嵌套事务时,SQLite 使用辅助回滚日志记录嵌套事务中的修改,以便必要时回滚内部事务。辅助日志不负责防止程序崩溃或断电引起的数据库损坏;只有回滚嵌套事务中的内部事务时,才会用到它。

这些辅助日志可以保存在内存中,也可以保存在磁盘临时文件中。默认存储在磁盘上,但可通过编译时选项 -DSQLITE_TEMP_STORE 或运行时 PRAGMA temp_store 语句修改。只有辅助日志保存在内存中时,才会发生该缺陷。

SQLite 3.35.0版本(2021-03-12)加入一项优化,减少内存中辅助日志的内存用量。遗憾的是,新逻辑中的一个边界检查写错了:本应使用 < 运算符,却写成了 <=。一旦发生回滚,这个错误可能使辅助日志进入不一致状态。

如果之后继续修改,并最终提交外层事务,数据库就可能处于不一致状态。

一位使用模糊测试器寻找 SQLite 缺陷的 独立研究者 发现了这个问题。模糊测试器触发了用于验证辅助日志内部状态的某条 assert()语句 的断言失败。

这是一个足够隐蔽的边界案例。如果不是 SQLite 大量使用断言、研究者持续而顽强地追查,并使用定制的先进模糊测试器,这个缺陷可能多年都不会被注意到。

该问题已经 修复,修复包含在 3.37.2版本(2022-01-06)中。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容