sqlancer/sqlancer

GitHub: sqlancer/sqlancer

SQLancer 是一个自动测试数据库管理系统实现错误的安全研究工具。

Stars: 1723 | Forks: 398

[![Build Status](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/1c4aee7e5c005430.svg)](https://github.com/sqlancer/sqlancer/actions) ![SQLancer](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/4d6b71bc1e005431.png) SQLancer 是一个用于自动测试数据库管理系统(DBMS)的工具,旨在发现其实现中的错误。也就是说,它发现的是 DBMS 实现代码中的错误,而不是用户编写的查询中的错误。SQLancer 已经在成熟且广泛使用的 DBMS 中发现了数百个错误。 SQLancer 在自动测试 DBMS 时面临两个核心挑战: 1. **测试输入生成**:SQLancer 实现了用于自动生成 SQL 语句的方法。它包含多种手工编写的 SQL 生成器,按多个阶段运行。首先,会创建一个数据库模式,这指的是若干表及其列。然后,向这些表中插入数据,并创建其他类型的数据库状态,如索引、视图或数据库特定选项。最后,生成查询,这些查询可以使用 SQLancer 提供的多种结果验证器(也称为 *测试预言机*)进行验证。除了以无指导方式创建语句的标准方法外,SQLancer 还支持一种反馈引导的测试输入生成方法,旨在根据直觉尽可能多地测试唯一查询计划,从而在数据库系统中触发许多有趣的行为[[ICSE '23]](https://arxiv.org/pdf/2312.17510)。 2. **测试预言机**:SQLancer 的一项关键创新在于它提供了发现 DBMS 中深层类型错误的方法。作为主要关注点,它可以发现逻辑错误,即导致 DBMS 返回错误结果集(例如遗漏记录)的错误。我们提出了多种互补的测试预言机,例如 *三值逻辑分区(TLP)* [[OOPSLA '20]](https://dl.acm.org/doi/pdf/10.1145/3428279)、*非优化参考引擎构建(NoREC)* [[ESEC/FSE 2020]](https://arxiv.org/abs/2007.08292)、*枢轴查询合成(PQS)* [[OSDI '20]](https://www.usenix.org/system/files/osdi20-rigger.pdf)、*差异查询执行(DQP)* [[SIGMOD '24]](https://dl.acm.org/doi/pdf/10.1145/3654991) 以及 *基于常量优化驱动的数据库系统测试(CODDTest)* [SIGMOD '25]。它还可以发现特定类别的性能问题,这指的是 DBMS 可以通过一种称为 *基数估计限制测试(CERT)* [ICSE '24] 的方法更高效地生成结果。SQLancer 能够通过声明 DBMS 可能返回的所有潜在错误来检测意外的内部错误(例如数据库损坏)。最后,SQLancer 可以发现崩溃错误,这类错误会导致 DBMS 进程终止。为此,它使用了一个隐式测试预言机。 # 快速入门 [[视频指南]](https://www.youtube.com/watch?v=lcZ6LixPH1Y) 最低要求: * Java 11 或更高版本 * [Maven](https://maven.apache.org/) 以下命令克隆 SQLancer,创建 JAR 包,并启动 SQLancer 以使用 [非优化参考引擎构建(NoREC)](https://arxiv.org/abs/2007.08292) 测试 SQLite: ``` git clone https://github.com/sqlancer/sqlancer cd sqlancer mvn package -DskipTests cd target java -jar sqlancer-*.jar --num-threads 4 sqlite3 --oracle NoREC ``` **运行与终止。** 如果执行时每五秒打印一次进度信息,则说明工具工作正常。快捷键 CTRL+C 可用于手动终止 SQLancer。如果 SQLancer 未发现任何错误,它会无限期执行。可使用 `--num-tries` 选项控制在发现多少个错误后终止 SQLancer。或者,也可使用 `--timeout-seconds` 选项指定允许 SQLancer 运行的最大时长。 **参数。** 如果不带参数启动 SQLancer,将显示可用选项和命令。请注意,所有 DBMS 测试实现都支持的一般选项(例如 `--num-threads`)需要放在要测试的 DBMS 名称之前(例如 `sqlite3`)。仅特定 DBMS 支持的选项(例如 SQLite3 的 `--test-rtree`)或每个测试实现提供不同值的选项(例如 `--oracle NoREC`)需要放在 DBMS 名称之后。 **DBMS。** 在 SQLite 上运行 SQLancer 无需安装和设置 DBMS。原因是嵌入式 DBMS 在与应用程序相同的进程中运行,因此无需单独安装或设置。SQLancer 支持的嵌入式 DBMS 包括 DuckDB、H2 和 SQLite。它们的可执行文件作为 [JAR 依赖项](https://github.com/sqlancer/sqlancer/blob/main/pom.xml) 包含在内。请注意,这些系统中的任何崩溃也会导致运行 SQLancer 的 JVM 崩溃。 # 使用 SQLancer **日志。** SQLancer 将日志存储在 `target/logs` 子目录中。默认启用 `--log-each-select` 选项,这会将发送到 DBMS 的每条 SQL 语句记录到日志中。对应的文件名以 `-cur.log` 为后缀。此外,如果 SQLancer 检测到逻辑错误,它会创建一个扩展名为 `.log` 的文件,其中记录了用于重现错误的 SQL 语句,包括导致错误执行的最后一条查询以及用于设置数据库状态的其他语句。 **减少错误。** 在找到导致错误的测试输入后,通常需要将其缩减以便进一步分析,因为其中可能包含许多冗余的 SQL 语句。 一种方法是手动操作:逐条移除语句或特性,重新播放导致错误的语句,并应用测试预言机(例如对于 TLP 或 NoREC 这类预言机,需要验证两条查询是否仍产生不同的结果)。这个过程可以通过所谓的 [delta-debugging 方法](https://www.debuggingbook.org/html/DeltaDebugger.html) 自动化。SQLancer 包含一个 delta debugging 方法的实验性实现,可通过 `--use-reducer` 启用。过去,我们曾成功使用 [C-Reduce](https://embed.cs.utah.edu/creduce/),这需要在一个脚本中指定测试预言机,并由 C-Reduce 执行。 **测试最新版本的 DBMS。** 对于大多数 DBMS,SQLancer 仅支持之前的 *发布版本*。因此,SQLancer 发现的问题可能已在 DBMS 的最新 *开发版本* 中修复。如果您不是正在测试的 DBMS 的开发者,我们鼓励您在报告错误之前验证该错误是否仍然可复现。我们很乐意在报告由 SQLancer 发现的错误时提及它。我们也非常期待听到您使用 SQLancer 的体验或相关用例与扩展。 **选项。** SQLancer 提供了许多可用于自定义其行为的选项。执行 `java -jar sqlancer-*.jar --help` 将列出这些选项,并输出类似以下内容: ``` Usage: SQLancer [options] [command] [command options] Options: --ast-reducer-max-steps EXPERIMENTAL Maximum steps the AST-based reducer will do Default: -1 --ast-reducer-max-time EXPERIMENTAL Maximum time duration (secs) the statement reducer will do Default: -1 --canonicalize-sql-strings Should canonicalize query string (add ';' at the end Default: true --constant-cache-size Specifies the size of the constant cache. This option only takes effect when constant caching is enabled Default: 100 ... ``` **使用哪个 SQLancer 版本。** 推荐使用 GitHub 上的最新源代码版本。不定期发布的官方版本也可在以下平台获取: * [GitHub](https://github.com/sqlancer/sqlancer/releases) * [Maven Central](https://search.maven.org/artifact/com.sqlancer/sqlancer) * [DockerHub](https://hub.docker.com/r/mrigger/sqlancer) **理解 SQL 生成。** 要分析导致错误的 SQL 语句,了解 SQLancer 的特性很有帮助。首先,SQLancer 总是会生成语法上对目标 DBMS 有效的 SQL 语句。因此,不应观察到任何语法错误。其次,SQLancer 可能会生成语义上无效的语句。例如,SQLancer 可能尝试向具有 `UNIQUE` 约束的列中插入重复值,因为完全避免此类语义错误具有挑战性。第三,任何由 SQLancer 报告的错误都应是真实错误,除了 CERT(因为性能问题不像其他类型的错误那样明确)。如果观察到 SQLancer 报告但您认为不是错误的错误,可能是您的设置存在问题。最后,值得一提的是,SQLancer 与特定版本的 DBMS 相关联,您可以在 [GitHub Actions 工作流](https://github.com/sqlancer/sqlancer/blob/documentation/.github/workflows/main.yml) 中找到与之测试的版本。如果您测试的是其他版本,可能会观察到各种误报(例如由语法错误引起)。虽然我们总是希望 SQLancer 与每个 DBMS 的最新开发版本保持同步,但我们缺乏实现这一目标所需的资源。 **支持的数据库。** SQLancer 需要为每个支持的数据库编写特定代码。截至 2025 年 1 月,它支持 Citus、ClickHouse、CnosDB、CockroachDB、Databend、(Apache) DataFusion、(Apache) Doris、DuckDB、H2、HSQLDB、MariaDB、Materialize、MySQL、OceanBase、PostgreSQL、Presto、QuestDB、SQLite3、TiDB 和 YugabyteDB。各个 DBMS 的支持程度 [有所不同](https://github.com/sqlancer/sqlancer/blob/documentation-approaches/CONTRIBUTING.md)。 # 方法与论文 SQLancer 开创并包含了多种用于数据库测试的方法,按时间顺序列出如下: | 技术 | 发表 venue | 链接 | 描述 | |------|------------|------|------| | Pivoted Query Synthesis (PQS) | OSDI 2020 | [论文](https://www.usenix.org/system/files/osdi20-rigger.pdf) [视频](https://www.youtube.com/watch?v=0aeDyXgzo04 ) | PQS 是我们设计并实现的第一种方法。它随机选择一行(称为枢轴行),生成一个查询以确保获取该行。如果该行未包含在结果集中,则检测到错误。该方法详细描述于此。PQS 能有效检测错误,但需要比其他基于变异测试或差异测试的方法更多的实现工作。因此,目前尚未维护。 | | Non-optimizing Reference Engine Construction (NoREC) | E/FSE 2020 | [论文](https://arxiv.org/abs/2007.08292) [视频](https://www.youtube.com/watch?v=4mbzytrWJhQ) | NoREC 旨在发现优化错误。它将一个可能被 DBMS 优化的查询转换为一个几乎不适用优化的查询,并比较两个结果集。结果集不匹配表示 DBMS 中存在错误。该方法主要适用于带有过滤谓词的简单查询。 | | Ternary Logic Partitioning (TLP) | OOPSLA 2020 | [论文](https://dl.acm.org/doi/pdf/10.1145/3428279) [视频](https://www.youtube.com/watch?v=FN9OLbGh0VI) | TLP 将查询划分为三个分区查询,将结果组合并与原始查询的结果集进行比较。结果集不匹配表示 DBMS 中存在错误。相比 NoREC 和 PQS,它能检测更高级特性(如聚合函数)中的错误,是目前最广泛采用的测试技术之一。 | | Differential Query Execution (DQE) | ICSE 2023 | [论文](https://ieeexplore.ieee.org/document/10172736) [代码](https://github.com/sqlancer/sqlancer/pull/1251) | DQE 是一种用于检测 SELECT、UPDATE 和 DELETE 查询逻辑错误的新颖通用方法。DQE 通过使用相同的谓词 φ 执行 SELECT、UPDATE 和 DELETE 查询并观察其执行结果之间的不一致来解决问题。例如,如果被 UPDATE 查询更新的行未出现在具有相同谓词 φ 的 SELECT 查询结果中,则检测到目标 DBMS 中的逻辑错误。我们为每张表添加两列以唯一标识每行并跟踪是否被修改。我们还重写 SELECT 和 UPDATE 查询以识别其访问的行。DQE 支持 MySQL。 | | Query Plan Guidance (QPG) | ICSE 2023 | [论文](https://arxiv.org/pdf/2312.17510) [视频](https://youtu.be/6EjQ1cKiZJU?si=gh7uoykRqNjl3GXR&t=1820) [代码](https://github.com/sqlancer/sqlancer/issues/641) | QPG 是一种反馈引导的测试用例生成方法。其核心思想是:查询计划可以反映 DBMS 内部是否执行了有趣的行为。通过变异数据库状态并在未观察到新查询计划时期望触发新查询计划来实现。该方法通过 `--qpg-enable` 选项启用,支持 SQLite、CockroachDB、TiDB 和 Materialize 的 TLP 和 NoREC 预言机。这是唯一专门针对测试输入生成问题的方法。 | | Cardinality Estimation Restriction Testing (CERT) | ICSE 2024 | [论文](https://arxiv.org/pdf/2306.00355) [代码](https://github.com/sqlancer/sqlancer/issues/822) | CERT 旨在通过意外的估计基数发现性能问题,即返回行的估计数量。从给定输入查询出发,导出一个更严格的查询,其估计基数应不超过原始查询。违反此条件表明可能存在性能问题。CERT 支持 TiDB、CockroachDB 和 MySQL。它是 SQLancer 中唯一专门用于发现性能问题的测试预言机。 | | Differential Query Plans (DQP) | SIGMOD 2024 | [论文](https://dl.acm.org/doi/pdf/10.1145/3654991) [视频](https://www.youtube.com/watch?v=9Qp7quJfGEk) [代码](https://github.com/sqlancer/sqlancer/issues/918) | DQP 通过控制给定查询的不同查询计划执行并验证它们是否产生一致结果来发现逻辑错误。DQP 支持 MySQL、MariaDB 和 TiDB。 | | Constant Optimization Driven Database System Testing (CODDTest) | SIGMOD 2025 | [代码](https://github.com/sqlancer/sqlancer/pull/1054) | CODDTest 发现 DBMS 中的逻辑错误,包括子查询等高级特性。其核心思想是假设数据库会话中的状态是常量,从而可以将查询的部分替换为其结果,本质上对应于常量折叠和常量传播这两种传统编译器优化。 | 请在此处查找 `.bib` 条目 [这里](docs/PAPERS.md)。 | # 常见问题 **我在最新版本的受支持 DBMS 上运行 SQLancer。SQLancer 打印出许多 AssertionError 是正常的吗?** 在许多情况下,SQLancer 并不支持 DBMS 的最新版本。您可以查看 [`.github/workflows/main.yml`](https://github.com/sqlancer/sqlancer/blob/master/.github/workflows/main.yml) 文件,以确定我们在 CI 测试中使用的版本,这对应于当前受支持的数据库版本。如果 SQLancer 识别到错误,它应只打印一个 `AssertionError` 并生成相应的日志文件。要升级 SQLancer 以支持新的 DBMS 版本,有两种建议方案:(1) 更新生成器,使其不再生成可能导致错误的特定模式(例如,如果某个关键字或选项不再受支持);(2) 将新出现的错误添加为 [预期错误](https://github.com/sqlancer/sqlancer/blob/354d591cfcd37fa1de85ec77ec933d5d975e947a/src/sqlancer/common/query/ExpectedErrors.java),以便 SQLancer 在出现这些错误时忽略它们(例如,这在无法轻易避免某些导致错误的模式时非常有用)。 另一个可能导致受支持版本上出现大量失败的原因是错误信息以非英语区域设置打印(这将在堆栈跟踪中可见)。在这种情况下,请尝试将 DBMS 的区域设置设置为英语(例如,请参阅 [PostgreSQL 主页](https://www.postgresql.org/docs/current/locale.html))。 **启动 SQLancer 时,出现类似“数据库 'test' 不存在”的错误。如何在不出现此错误的情况下运行 SQLancer?** 对于某些 DBMS,SQLancer 期望存在一个名为 “test” 的数据库,它将其用作连接时的初始数据库。如果您尚未创建此类数据库,可以使用类似 `CREATE DATABASE test` 的命令来创建它(例如,请参阅 [PostgreSQL 文档](https://www.postgresql.org/docs/current/sql-createdatabase.html))。 # 链接 文档和资源: * [为 SQLancer 贡献](CONTRIBUTING.md) * [论文与 .bib 条目](docs/PAPERS.md) * 更多关于我们的数据库测试工作和我们发现的错误的信息[此处](https://www.manuelrigger.at/dbms-bugs/)。 视频: * [SQLancer 教程播放列表](https://www.youtube.com/playlist?list=PLm7ofmclym1E2LwBeSer_AAhzBSxBYDci) * [SQLancer 讲座](https://youtube.com/playlist?list=PLm7ofmclym1E9-AbYy-PkrMfHpB9VdlZJ) 密切相关的工具: * [go-sqlancer](https://github.com/chaos-mesh/go-sqlancer):PingCAP 重新实现的 SQLancer 部分方法(Go 语言) * [Jepsen](https://github.com/jepsen-io):分布式(数据库)系统测试 * [SQLRight](https://github.com/PSU-Security-Universe/sqlright):支持 NoREC 和 TLP 的覆盖率引导的数据库模糊测试器 * [SQLsmith](https://github.com/anse1/sqlsmith):用于模糊测试的随机 SQL 查询生成器 * [Squirrel](https://github.com/s3team/Squirrel):覆盖率引导的数据库模糊测试器
标签:CI, DBMS, ICSE, JS文件枚举, NoREC, SQL, SQLancer, SQL生成, Ternary Logic Partitioning, 反馈引导测试, 域名枚举, 开源, 性能测试, 数据库测试, 数据库漏洞发现, 查询计划, 测试生成, 测试用例, 测试预言机, 系统审计, 逻辑错误