1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
// Copyright 2018 The Chromium Authors
// 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
|