| // 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. |
| |
| // Adapted from sqlite's ossfuzz.c |
| |
| #include <cstdlib> |
| #include <iostream> // TODO(mpdenton) remove |
| #include <string> |
| #include <vector> |
| |
| #include "third_party/sqlite/sqlite3.h" |
| |
| namespace sql_fuzzer { |
| |
| namespace { |
| constexpr int kMaxNumRows = 10; |
| constexpr int kMaxNumColumns = 10; |
| |
| sqlite3_int64 killTime; |
| |
| /* Return the current real-world time in milliseconds since the |
| ** Julian epoch (-4714-11-24). |
| */ |
| static sqlite3_int64 timeOfDay(void) { |
| static sqlite3_vfs* clockVfs = 0; |
| sqlite3_int64 t; |
| if (clockVfs == 0) { |
| clockVfs = sqlite3_vfs_find(0); |
| if (clockVfs == 0) |
| return 0; |
| } |
| if (clockVfs->iVersion >= 2 && clockVfs->xCurrentTimeInt64 != 0) { |
| clockVfs->xCurrentTimeInt64(clockVfs, &t); |
| } else { |
| double r; |
| clockVfs->xCurrentTime(clockVfs, &r); |
| t = (sqlite3_int64)(r * 86400000.0); |
| } |
| return t; |
| } |
| |
| int progress_handler(void*) { |
| sqlite3_int64 iNow = timeOfDay(); |
| int rc = iNow >= killTime; |
| return rc; |
| } |
| } // namespace |
| |
| void RunSqlQueriesOnSameDB() { |
| // TODO(mpdenton) unimplemented |
| } |
| |
| sqlite3* InitConnectionForFuzzing() { |
| int rc; // Return code from various interfaces. |
| sqlite3* db; // Sqlite db. |
| |
| rc = sqlite3_initialize(); |
| if (rc) { |
| std::cerr << "Failed initialization. " << std::endl; |
| return nullptr; |
| } |
| |
| // Open the database connection. Only use an in-memory database. |
| rc = sqlite3_open_v2( |
| "fuzz.db", &db, |
| SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY, 0); |
| if (rc) { |
| std::cerr << "Failed to open DB. " << std::endl; |
| return nullptr; |
| } |
| |
| // Enables foreign key constraints |
| sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 1, &rc); |
| |
| // sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 0, &rc); // TODO(pwnall) |
| |
| return db; |
| } |
| |
| void EnableSqliteTracing(sqlite3* db) { |
| sqlite3_exec(db, "PRAGMA vdbe_debug=ON", 0, 0, 0); |
| } |
| |
| void CloseConnection(sqlite3* db) { |
| // Cleanup and return. |
| sqlite3_exec(db, "PRAGMA temp_store_directory=''", 0, 0, 0); |
| sqlite3_close(db); |
| } |
| |
| void RunSqlQueriesOnConnection(sqlite3* db, std::vector<std::string> queries) { |
| int rc; |
| for (size_t i = 0; i < queries.size(); i++) { |
| // Run each query one by one. |
| // First, compile the query. |
| sqlite3_stmt* stmt; |
| const char* pzTail; |
| rc = sqlite3_prepare_v2(db, queries[i].c_str(), -1, &stmt, &pzTail); |
| if (rc != SQLITE_OK) { |
| if (::getenv("PRINT_SQLITE_ERRORS")) { |
| std::cerr << "Could not compile: " << queries[i] << std::endl; |
| std::cerr << "Error message from db: " << sqlite3_errmsg(db) |
| << std::endl; |
| std::cerr << "-----------------------------" << std::endl; |
| } |
| continue; |
| } |
| |
| // No sqlite3_bind. |
| |
| // Reset progress callback for every query. Timeout after 1 second. |
| // ClusterFuzz timeouts are not useful, so we try to avoid them. |
| // This will hopefully make Clusterfuzz find better, smaller SELECT |
| // statements. |
| #ifndef SQLITE_OMIT_PROGRESS_CALLBACK |
| killTime = timeOfDay() + 1000; |
| sqlite3_progress_handler(db, 100, progress_handler, nullptr); |
| #endif |
| |
| // Now run the compiled query. |
| int col_cnt = sqlite3_column_count(stmt); |
| int count = 0; |
| rc = SQLITE_ROW; |
| while (rc == SQLITE_ROW && count++ <= kMaxNumRows) { |
| rc = sqlite3_step(stmt); |
| if (rc != SQLITE_DONE && rc != SQLITE_ROW) { |
| if (::getenv("PRINT_SQLITE_ERRORS")) { |
| std::cerr << "Step problem: " << queries[i] << std::endl; |
| std::cerr << "Error message from db: " << sqlite3_errmsg(db) |
| << std::endl; |
| std::cerr << "-----------------------------" << std::endl; |
| } |
| goto free_stmt; |
| } |
| // Loop through the columns to catch a little bit more coverage. |
| for (int i = 0; i < col_cnt && i < kMaxNumColumns; i++) { |
| switch (sqlite3_column_type(stmt, i)) { |
| case SQLITE_INTEGER: |
| sqlite3_column_int(stmt, i); |
| break; |
| case SQLITE_FLOAT: |
| sqlite3_column_double(stmt, i); |
| break; |
| case SQLITE_TEXT: |
| sqlite3_column_text(stmt, i); |
| break; |
| case SQLITE_BLOB: |
| sqlite3_column_blob(stmt, i); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| // Finalize the query |
| free_stmt: |
| sqlite3_finalize(stmt); |
| } |
| } |
| |
| void RunSqlQueries(std::vector<std::string> queries, bool enable_tracing) { |
| sqlite3* db = InitConnectionForFuzzing(); |
| if (enable_tracing) |
| EnableSqliteTracing(db); |
| |
| RunSqlQueriesOnConnection(db, queries); |
| |
| CloseConnection(db); |
| } |
| |
| } // namespace sql_fuzzer |