blob: 6485c69459a1a1f522ed451a20be5bf6de6b2508 [file] [log] [blame]
// 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 <iostream> // TODO(mpdenton) remove
#include <string>
#include <vector>
#include "third_party/sqlite/sqlite3.h"
namespace sql_fuzzer {
namespace {
int progress_handler(void*) {
return 1;
}
} // 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;
}
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
// Invoke the progress handler frequently to check to see if we
// are taking too long. The progress handler will return true
// (which will block further processing) if more than 10 seconds have
// elapsed since the start of the test.
sqlite3_progress_handler(db, 23, progress_handler, nullptr);
#endif
// 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 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.
// Now run the compiled query.
int col_cnt = sqlite3_column_count(stmt);
rc = SQLITE_ROW;
while (rc == SQLITE_ROW) {
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++) {
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) {
sqlite3* db = InitConnectionForFuzzing();
RunSqlQueriesOnConnection(db, queries);
CloseConnection(db);
}
} // namespace sql_fuzzer