Easier minimization for SQLite LPM Fuzzer
Adds support for turning off specific queries with an environment
variable; makes it very easy to rule out a ton of irrelevant queries
in a very short amount of time when minimizing a test case.
R=metzman@chromium.org, pwnall@chromium.org
Bug: 909886
Change-Id: Ia785a8d89cad415f791fd28cd498244358437898
Reviewed-on: https://chromium-review.googlesource.com/c/1388035
Reviewed-by: Jonathan Metzman <metzman@chromium.org>
Reviewed-by: Victor Costan <pwnall@chromium.org>
Commit-Queue: Matthew Denton <mpdenton@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#620992}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 55a46db4d17608aca41a7016557d5cea064ae126
diff --git a/BUILD.gn b/BUILD.gn
index 2f89a7b..50dbf8e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -432,6 +432,8 @@
source_set("sqlite3_lpm_fuzzer_core") {
sources = [
+ "fuzz/disabled_queries_parser.cc",
+ "fuzz/disabled_queries_parser.h",
"fuzz/sql_run_queries.cc",
"fuzz/sql_run_queries.h",
]
diff --git a/fuzz/disabled_queries_parser.cc b/fuzz/disabled_queries_parser.cc
new file mode 100644
index 0000000..c2bd17b
--- /dev/null
+++ b/fuzz/disabled_queries_parser.cc
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/sqlite/fuzz/disabled_queries_parser.h"
+
+namespace sql_fuzzer {
+
+std::set<std::string> ParseDisabledQueries(std::string query_list) {
+ // Trimming
+ query_list.erase(query_list.find_last_not_of(" \t\n\r\f\v") + 1);
+ query_list.erase(0, query_list.find_first_not_of(" \t\n\r\f\v"));
+ std::set<std::string> ret;
+ std::string curr_query;
+ for (size_t i = 0; i < query_list.length(); i++) {
+ if (query_list[i] == ',') {
+ ret.insert(curr_query);
+ curr_query.clear();
+ continue;
+ }
+ curr_query += query_list[i];
+ }
+ if (curr_query.length() != 0) {
+ // Add last query, which doesn't have a trailing comma
+ ret.insert(curr_query);
+ }
+ return ret;
+}
+
+} // namespace sql_fuzzer
diff --git a/fuzz/disabled_queries_parser.h b/fuzz/disabled_queries_parser.h
new file mode 100644
index 0000000..665b871
--- /dev/null
+++ b/fuzz/disabled_queries_parser.h
@@ -0,0 +1,16 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_SQLITE_FUZZ_DISABLED_QUERIES_PARSER_H_
+#define THIRD_PARTY_SQLITE_FUZZ_DISABLED_QUERIES_PARSER_H_
+
+#include <set>
+#include <string>
+
+namespace sql_fuzzer {
+// |query_list| should be a list of disabled queries separated only by commas.
+std::set<std::string> ParseDisabledQueries(std::string query_list);
+} // namespace sql_fuzzer
+
+#endif // THIRD_PARTY_SQLITE_FUZZ_DISABLED_QUERIES_PARSER_H_
diff --git a/fuzz/sql_fuzzer.cc b/fuzz/sql_fuzzer.cc
index 7003a31..8ea762b 100644
--- a/fuzz/sql_fuzzer.cc
+++ b/fuzz/sql_fuzzer.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "testing/libfuzzer/proto/lpm_interface.h"
+#include "third_party/sqlite/fuzz/disabled_queries_parser.h"
#include "third_party/sqlite/fuzz/sql_query_grammar.pb.h"
#include "third_party/sqlite/fuzz/sql_query_proto_to_string.h"
#include "third_party/sqlite/fuzz/sql_run_queries.h"
@@ -34,6 +35,12 @@
// 5. Temp-file database, for better fuzzing of VACUUM and journalling.
DEFINE_BINARY_PROTO_FUZZER(const SQLQueries& sql_queries) {
+ char* skip_queries = getenv("SQL_SKIP_QUERIES");
+ if (skip_queries) {
+ sql_fuzzer::SetDisabledQueries(
+ sql_fuzzer::ParseDisabledQueries(skip_queries));
+ }
+
std::vector<std::string> queries = sql_fuzzer::SQLQueriesToVec(sql_queries);
if (getenv("LPM_DUMP_NATIVE_INPUT") && queries.size() != 0) {
diff --git a/fuzz/sql_multithreaded_fuzzer.cc b/fuzz/sql_multithreaded_fuzzer.cc
index 0f7ff82..e4162c6 100644
--- a/fuzz/sql_multithreaded_fuzzer.cc
+++ b/fuzz/sql_multithreaded_fuzzer.cc
@@ -13,6 +13,7 @@
#include <vector>
#include "testing/libfuzzer/proto/lpm_interface.h"
+#include "third_party/sqlite/fuzz/disabled_queries_parser.h"
#include "third_party/sqlite/fuzz/sql_query_grammar.pb.h"
#include "third_party/sqlite/fuzz/sql_query_proto_to_string.h"
#include "third_party/sqlite/fuzz/sql_run_queries.h"
@@ -25,6 +26,12 @@
}
DEFINE_BINARY_PROTO_FUZZER(const MultipleSQLQueries& multiple_sql_queries) {
+ char* skip_queries = getenv("SQL_SKIP_QUERIES");
+ if (skip_queries) {
+ sql_fuzzer::SetDisabledQueries(
+ sql_fuzzer::ParseDisabledQueries(skip_queries));
+ }
+
assert(multiple_sql_queries.GetDescriptor()->field_count() == kNumThreads);
sqlite3* db = sql_fuzzer::InitConnectionForFuzzing();
diff --git a/fuzz/sql_query_proto_to_string.cc b/fuzz/sql_query_proto_to_string.cc
index ef5d7e1..84a09fd 100644
--- a/fuzz/sql_query_proto_to_string.cc
+++ b/fuzz/sql_query_proto_to_string.cc
@@ -21,6 +21,10 @@
#define CONV_FN(TYPE, VAR_NAME) std::string TYPE##ToString(const TYPE& VAR_NAME)
+#define RETURN_IF_DISABLED_QUERY(TYPE) \
+ if (disabled_queries_.count(#TYPE) != 0) \
+ return "";
+
namespace sql_fuzzer {
namespace {
@@ -49,6 +53,8 @@
constexpr uint32_t kMaxViewNumber = 5;
constexpr uint32_t kMaxTriggerNumber = 10;
+
+std::set<std::string> disabled_queries_;
} // namespace
CONV_FN(Expr, expr);
@@ -1169,6 +1175,7 @@
}
CONV_FN(CreateTable, create_table) {
+ RETURN_IF_DISABLED_QUERY(CreateTable);
#if defined(FUZZ_FTS3)
return ""; // Don't create normal tables in FTS3 fuzzing mode.
#endif
@@ -1346,6 +1353,7 @@
}
CONV_FN(Insert, insert) {
+ RETURN_IF_DISABLED_QUERY(Insert);
std::string ret;
if (insert.has_with()) {
ret += WithStatementToString(insert.with());
@@ -1400,6 +1408,7 @@
}
CONV_FN(Delete, delete_) {
+ RETURN_IF_DISABLED_QUERY(Delete);
std::string ret;
if (delete_.has_with()) {
ret += WithStatementToString(delete_.with());
@@ -1417,6 +1426,7 @@
// ~~~~UPDATE~~~~
// WARNING no space at end
CONV_FN(Update, update) {
+ RETURN_IF_DISABLED_QUERY(Update);
std::string ret;
if (update.has_with()) {
ret += WithStatementToString(update.with());
@@ -1755,6 +1765,7 @@
}
CONV_FN(Select, select) {
+ RETURN_IF_DISABLED_QUERY(Select);
std::string ret;
if (select.has_with()) {
ret += WithStatementToString(select.with());
@@ -1873,6 +1884,7 @@
}
CONV_FN(FTS3SpecialCommand, fsc) {
+ RETURN_IF_DISABLED_QUERY(FTS3SpecialCommand);
std::string ret("INSERT INTO ");
ret += FTS3TableToString(fsc.table());
ret += "(";
@@ -1905,6 +1917,7 @@
// WARNING no space at end
CONV_FN(FTS3SelectMatch, fsm) {
+ RETURN_IF_DISABLED_QUERY(FTS3SelectMatch);
std::string ret("SELECT * FROM ");
ret += FTS3TableToString(fsm.table());
ret += " WHERE ";
@@ -1915,6 +1928,7 @@
}
CONV_FN(FTS3SpecificQuery, fsq) {
+ RETURN_IF_DISABLED_QUERY(FTS3SpecificQuery);
#if defined(FUZZ_FTS3)
// oneof
if (fsq.has_command()) {
@@ -1943,6 +1957,7 @@
}
CONV_FN(CreateFTS3Table, cft) {
+ RETURN_IF_DISABLED_QUERY(CreateFTS3Table);
std::string ret("CREATE VIRTUAL TABLE ");
if (cft.if_not_exists())
ret += "IF NOT EXISTS ";
@@ -2067,6 +2082,7 @@
}
CONV_FN(FTS3HiddenTableInsert, fi) {
+ RETURN_IF_DISABLED_QUERY(FTS3HiddenTableInsert);
std::string ret("INSERT INTO ");
ret += FTS3HiddenTableToString(fi.fht());
if (fi.col_vals_size() == 0) {
@@ -2090,6 +2106,7 @@
}
CONV_FN(FTS3HiddenTableUpdate, fu) {
+ RETURN_IF_DISABLED_QUERY(FTS3HiddenTableUpdate);
std::string ret("UPDATE ");
ret += FTS3HiddenTableToString(fu.fht());
ret += " ";
@@ -2117,6 +2134,7 @@
}
CONV_FN(FTS3HiddenTableDelete, fd) {
+ RETURN_IF_DISABLED_QUERY(FTS3HiddenTableDelete);
std::string ret("DELETE FROM ");
ret += FTS3HiddenTableToString(fd.fht());
if (fd.has_col_where()) {
@@ -2130,6 +2148,7 @@
// ~~~~TRANSACTIONS/SAVEPOINTS
CONV_FN(BeginTransaction, bt) {
+ RETURN_IF_DISABLED_QUERY(BeginTransaction);
std::string ret("BEGIN ");
if (bt.has_type()) {
ret += BeginTransaction_TransactionType_Name(bt.type());
@@ -2140,11 +2159,13 @@
}
CONV_FN(CommitTransaction, ct) {
+ RETURN_IF_DISABLED_QUERY(CommitTransaction);
return EnumStrReplaceUnderscores(
CommitTransaction_CommitText_Name(ct.text()));
}
CONV_FN(RollbackStatement, rt) {
+ RETURN_IF_DISABLED_QUERY(RollbackStatement);
#if !defined(FUZZ_OMIT_SAVEPOINT)
if (rt.has_save_point()) {
return "ROLLBACK TO SAVEPOINT " + SavePointToString(rt.save_point());
@@ -2155,15 +2176,18 @@
#if !defined(FUZZ_OMIT_SAVEPOINT)
CONV_FN(CreateSavePoint, csp) {
+ RETURN_IF_DISABLED_QUERY(CreateSavePoint);
return "SAVEPOINT " + SavePointToString(csp.save_point());
}
CONV_FN(ReleaseSavePoint, rsp) {
+ RETURN_IF_DISABLED_QUERY(ReleaseSavePoint);
return "RELEASE SAVEPOINT " + SavePointToString(rsp.save_point());
}
#endif
CONV_FN(Analyze, a) {
+ RETURN_IF_DISABLED_QUERY(Analyze);
std::string ret("ANALYZE");
if (a.has_schema_name()) {
ret += " ";
@@ -2188,6 +2212,7 @@
// ~~~~VACUUM~~~~
CONV_FN(Vacuum, v) {
+ RETURN_IF_DISABLED_QUERY(Vacuum);
std::string ret("VACUUM");
if (v.has_schema()) {
ret += " ";
@@ -2198,6 +2223,7 @@
// ~~~~PRAGMA~~~~
CONV_FN(Pragma, p) {
+ RETURN_IF_DISABLED_QUERY(Pragma);
#if defined(FUZZ_OMIT_PRAGMA)
return "";
#else
@@ -2255,6 +2281,7 @@
// ~~~~CREATE INDEX~~~~
CONV_FN(CreateIndex, ci) {
+ RETURN_IF_DISABLED_QUERY(CreateIndex);
std::string ret("CREATE ");
if (ci.unique())
ret += "UNIQUE ";
@@ -2280,6 +2307,7 @@
// ~~~~CREATE VIEW~~~~
CONV_FN(CreateView, cv) {
+ RETURN_IF_DISABLED_QUERY(CreateView);
std::string ret("CREATE ");
if (cv.has_temp_modifier()) {
ret += EnumStrReplaceUnderscores(TempModifier_Name(cv.temp_modifier()))
@@ -2321,6 +2349,7 @@
// WARNING no space at end
CONV_FN(CreateTrigger, ct) {
+ RETURN_IF_DISABLED_QUERY(CreateTrigger);
std::string ret("CREATE ");
if (ct.has_temp_modifier()) {
ret += EnumStrReplaceUnderscores(TempModifier_Name(ct.temp_modifier()))
@@ -2375,6 +2404,7 @@
// ~~~~REINDEX~~~~
CONV_FN(ReIndex, ri) {
+ RETURN_IF_DISABLED_QUERY(ReIndex);
// Chrome doesn't use REINDEX
#if !defined(SQLITE_OMIT_REINDEX)
if (ri.empty())
@@ -2400,6 +2430,7 @@
}
CONV_FN(Drop, d) {
+ RETURN_IF_DISABLED_QUERY(Drop);
std::string ret("DROP ");
std::string if_exists("");
std::string schema("");
@@ -2436,6 +2467,7 @@
// ~~~~ALTER TABLE~~~~
CONV_FN(AlterTable, at) {
+ RETURN_IF_DISABLED_QUERY(AlterTable);
std::string ret("ALTER TABLE ");
ret += ExprSchemaTableToString(at.schema_table());
ret += " ";
@@ -2460,6 +2492,7 @@
// ~~~~ATTACH DATABASE~~~~
CONV_FN(AttachDatabase, ad) {
+ RETURN_IF_DISABLED_QUERY(AttachDatabase);
std::string ret("ATTACH DATABASE \'");
if (ad.in_memory()) {
if (ad.file_uri()) {
@@ -2487,6 +2520,7 @@
// ~~~~DETACH DATABASE~~~~
CONV_FN(DetachDatabase, dd) {
+ RETURN_IF_DISABLED_QUERY(DetachDatabase);
std::string ret("DETACH DATABASE ");
ret += SchemaToString(dd.schema());
return ret;
@@ -2716,4 +2750,8 @@
return queries;
}
+void SetDisabledQueries(std::set<std::string> disabled_queries) {
+ disabled_queries_ = disabled_queries;
+}
+
} // namespace sql_fuzzer
diff --git a/fuzz/sql_query_proto_to_string.h b/fuzz/sql_query_proto_to_string.h
index 4664d74..b4b7fe9 100644
--- a/fuzz/sql_query_proto_to_string.h
+++ b/fuzz/sql_query_proto_to_string.h
@@ -23,6 +23,8 @@
std::string SQLQueryToString(const sql_query_grammar::SQLQuery&);
+void SetDisabledQueries(std::set<std::string> disabled_queries);
+
} // namespace sql_fuzzer
#endif // THIRD_PARTY_SQLITE_FUZZ_SQL_QUERY_PROTO_TO_STRING_H_