# Copyright 2013 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/dcheck_always_on.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
import("//third_party/protobuf/proto_library.gni")
import("//third_party/sqlite/sqlite_chromium_configuration_flags.gni")
import("//third_party/sqlite/sqlite_common_configuration_flags.gni")
import("//third_party/sqlite/sqlite_dev_configuration_flags.gni")
# Compile-time options passed to SQLite.
#
# These options are used when building our own SQLite library, which happens
# everywhere except on iOS. These compile-time options are exported via a
# public_config to all targets using SQLite, because they're needed by the
# sqlite.h header. To avoid name clashes (macro names are resolved using a
# global namespace), this block should only contain preprocessor macros that
# are unambiguously connected to SQLite.
#
# The vast majority of the macros here are documented at
# https://www.sqlite.org/compile.html
config("common_sqlite3_compile_options") {
# Start with the configuration flags which are also baked into the SQLite
# source when the amalgamation is generated. These are the same for all
# platforms.
defines = sqlite_common_configuration_flags
# The flags not baked in, but common for all platforms.
defines += [
# Skip writing transaction rollback journals on f2fs.
# f2fs tends to be used on Android, and may be used on ChromeOS.
"SQLITE_ENABLE_BATCH_ATOMIC_WRITE",
# Forces SQLite to only store temporary data in memory.
#
# This is the only supported setting on Android. Using it everywhere removes
# a source of cross-platform variation, and saves us from having to reason
# about SQLite storing data in the operating system's temporary directory.
"SQLITE_TEMP_STORE=3",
]
# On OSX, SQLite has extra logic for detecting the use of network
# filesystems (e.g., AFS, NFS) and for working around locking problems in
# these filesystems. This logic is gated by SQLITE_ENABLE_LOCKING_STYLE, which
# is 1 by default on OSX and iOS, and 0 everywhere else.
#
# When enabled, SQLITE_ENABLE_LOCKING_STYLE results in a compile-time warning
# on iOS. The recommended solution is to disable the flag on iOS, because
# iOS doesn't (yet?) have networked filesystems. Since we have to do this,
# might as well be explicit about the flag everywhere.
if (is_mac) {
defines += [ "SQLITE_ENABLE_LOCKING_STYLE=1" ]
} else {
defines += [ "SQLITE_ENABLE_LOCKING_STYLE=0" ]
}
if (using_sanitizer) {
defines += [
# Limit max length of data blobs and queries to 128 MB for fuzzing builds.
"SQLITE_MAX_LENGTH=128000000",
"SQLITE_MAX_SQL_LENGTH=128000000",
"SQLITE_PRINTF_PRECISION_LIMIT=1280000",
]
# During fuzz testing, valid SQL queries generated by fuzzing engine may
# lead to large memory allocations. If that happens, fuzzer reports an
# out-of-memory error. However, such errors are not valid bugs.
# To avoid hitting those irrelevant OOMs, we limit max number of memory
# pages, so fuzzer will not crash when reaching the limit.
# Apply this for fuzzing builds only, not for all builds with sanitizers.
if (use_fuzzing_engine) {
defines += [
"SQLITE_MAX_PAGE_COUNT=16384",
# Used to deserialize a database from a libfuzzer-provided data blob.
# This is to fuzz SQLite's resilience to database corruption.
"SQLITE_ENABLE_DESERIALIZE",
]
# The progress callback is used in fuzzing to cancel long-running queries
# so we don't spend too much time on them.
defines -= [ "SQLITE_OMIT_PROGRESS_CALLBACK" ]
}
}
if (is_debug || dcheck_always_on) {
if (use_fuzzing_engine && use_sanitizer_coverage) {
# Enable SQLite's assert() macros.
#
# TODO(pwnall): Fix all the bugs preventing us from enabling this flag for
# all DCHECK builds. See https://crbug.com/907371 and
# https://crrev.com/c/1343529.
defines += [ "SQLITE_DEBUG" ]
}
# Check preconditions when SQLite APIs are called. See
# https://sqlite.org/compile.html#enable_api_armor
#
# fuzzing builds have this disabled because the fuzzers are guaranteed to
# use the API correctly, and removing the checks opens up the possibility
# that the fuzzers will get more code coverage.
defines += [ "SQLITE_ENABLE_API_ARMOR" ]
}
}
# These options add SQLite features that we need in Chrome.
config("chromium_sqlite3_compile_options") {
configs = [ ":common_sqlite3_compile_options" ]
defines = sqlite_chromium_configuration_flags
}
# These options add SQLite features that we need in developer tools.
config("dev_sqlite3_compile_options") {
configs = [ ":common_sqlite3_compile_options" ]
defines = sqlite_dev_configuration_flags
}
config("sqlite_warnings") {
cflags = []
if (is_clang) {
cflags += [
"-Wno-shadow",
# sqlite contains a few functions that are unused, at least on
# Windows with Chrome's sqlite patches applied
# (interiorCursorEOF fts3EvalDeferredPhrase
# fts3EvalSelectDeferred sqlite3Fts3InitHashTable
# sqlite3Fts3InitTok).
"-Wno-unused-function",
]
if (is_debug || dcheck_always_on) {
cflags += [
# SQLite uses assert(!"description") to express
# NOT_REACHED() << "description". This is considered an implicit
# conversion from char[] to bool, and triggers a warning.
"-Wno-string-conversion",
]
}
}
if (is_linux || is_chromeos) {
cflags += [
# SQLite doesn't believe in compiler warnings, preferring testing.
# http://www.sqlite.org/faq.html#q17
"-Wno-int-to-pointer-cast",
"-Wno-pointer-to-int-cast",
]
}
if (is_ios) {
cflags += [
# SQLite issues a #pragma warning on iOS.
# http://sqlite.1065341.n5.nabble.com/Compiler-warning-quot-gethostuuid-is-disabled-quot-building-SQLite-for-iOS-td96881.html
#
# Contrary to what is said on the mailing list, setting
# SQLITE_ENABLE_LOCKING_STYLE to 0 does not make the warning go away.
"-Wno-#warnings",
]
}
if (is_win && !is_clang) {
cflags += [ "/wd4101" ] # 'zTrace' unreferenced variable in src/src/vdbe.c
}
}
# Naming the library "sqlite3" can cause conflicts with the system library.
component("chromium_sqlite3") {
visibility = [ ":*" ]
public = [ "sqlite3.h" ]
sources = [
"sqlite3_shim.c",
"sqlite3_shim_fixups.h",
"src/amalgamation/rename_exports.h",
"src/amalgamation/sqlite3.h",
]
inputs = [
# This file is #included into sqlite3_shim.c, which injects Chrome-specific
# definitions into the SQLite amalgamation code.
"src/amalgamation/sqlite3.c",
]
cflags = []
defines = []
if (is_component_build) {
if (is_win) {
defines += [ "SQLITE_API=__declspec(dllexport)" ]
} else {
defines += [ "SQLITE_API=__attribute__((visibility(\"default\")))" ]
}
}
if (is_linux || is_chromeos || is_android) {
defines += [
# Linux provides fdatasync(), a faster equivalent of fsync().
"fdatasync=fdatasync",
]
}
if (is_posix || is_fuchsia) {
defines += [
# Allow xSleep() call on Unix to use usleep() rather than sleep(), so it
# will have microsecond precision. Should only affect contended
# databases via the busy callback. Browser profile databases are mostly
# exclusive, but renderer databases may allow for contention.
"HAVE_USLEEP=1",
# Use pread/pwrite directly rather than emulating them.
"USE_PREAD=1",
]
}
include_dirs = [
".", # sqlite3.h here must override the one in src/amalgamation/.
"src/amalgamation",
]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
":chromium_sqlite3_compile_options",
"//build/config/compiler:no_chromium_code",
"//build/config/sanitizers:cfi_icall_generalize_pointers",
# Must be after no_chromium_code for warning flags to be ordered correctly.
":sqlite_warnings",
]
if (is_apple) {
frameworks = [ "CoreFoundation.framework" ]
if (!is_ios) {
frameworks += [ "CoreServices.framework" ]
}
} else if (is_android) {
defines += [
"SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576",
"SQLITE_DEFAULT_AUTOVACUUM=1",
]
}
deps = [ "//third_party/icu" ]
}
# Similar to component("chromium_sqlite") above, but uses the developer tools
# options at config("dev_sqlite3_compile_options").
#
# This target uses source_set instead of component intentionally because turning
# it into a shared library will result in symbol collisions with "chromium_sqlite".
# Given that this config is effectively test-only, we should link it statically
# and allow "chromium_sqlite" to be the only shared library.
# TODO(altimin): mark this component as testonly = true.
source_set("dev_sqlite3") {
visibility = [ ":*" ]
public = [ "dev/sqlite3.h" ]
sources = [
"dev/sqlite3_shim.c",
"sqlite3_shim_fixups.h",
"src/amalgamation_dev/rename_exports.h",
"src/amalgamation_dev/sqlite3.h",
]
inputs = [
# This file is #included into sqlite3_shim.c, which injects Chrome-specific
# definitions into the SQLite amalgamation code.
"src/amalgamation_dev/sqlite3.c",
]
cflags = []
defines = []
if (is_linux || is_chromeos || is_android) {
defines += [
# Linux provides fdatasync(), a faster equivalent of fsync().
"fdatasync=fdatasync",
]
}
if (is_posix || is_fuchsia) {
defines += [
# Allow xSleep() call on Unix to use usleep() rather than sleep(), so it
# will have microsecond precision. Should only affect contended
# databases via the busy callback. Browser profile databases are mostly
# exclusive, but renderer databases may allow for contention.
"HAVE_USLEEP=1",
# Use pread/pwrite directly rather than emulating them.
"USE_PREAD=1",
]
}
include_dirs = [
"dev", # sqlite3.h here must override the one in amalgamation_dev/.
"src/amalgamation_dev",
]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
":dev_sqlite3_compile_options",
"//build/config/compiler:no_chromium_code",
"//build/config/sanitizers:cfi_icall_generalize_pointers",
# Must be after no_chromium_code for warning flags to be ordered correctly.
":sqlite_warnings",
]
if (is_apple) {
frameworks = [ "CoreFoundation.framework" ]
if (!is_ios) {
frameworks += [ "CoreServices.framework" ]
}
} else if (is_android) {
defines += [
"SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576",
"SQLITE_DEFAULT_AUTOVACUUM=1",
]
}
deps = [ "//third_party/icu" ]
}
config("sqlite_export") {
if (is_component_build && is_win) {
defines = [ "SQLITE_API=__declspec(dllimport)" ]
}
}
# This is used to allow the SQLITE_API definition to be different when
# building sqlite3.c than it is when clients include sqlite3.h.
group("sqlite") {
public_deps = [ ":chromium_sqlite3" ]
public_configs = [
":chromium_sqlite3_compile_options",
":sqlite_export",
]
}
group("sqlite_dev") {
public_deps = [ ":dev_sqlite3" ]
public_configs = [ ":dev_sqlite3_compile_options" ]
}
if (is_win || is_mac || is_linux || is_chromeos) {
executable("sqlite_shell") {
include_dirs = [
# SQLite's shell.c contains an '#include "sqlite3.h", which we want to be
# resolved to //third_party/sqlite/sqlite3.h.
".",
]
sources = [
"sqlite_shell_icu_helper.cc",
"sqlite_shell_icu_helper.h",
"sqlite_shell_shim.c",
]
deps = [
":sqlite",
"//base",
"//base:i18n",
"//third_party/icu",
]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
":chromium_sqlite3_compile_options",
"//build/config/compiler:no_chromium_code",
# Must be after no_chromium_code for warning flags to be ordered
# correctly.
":sqlite_warnings",
]
}
# Similar to executable("sqlite_shell") above, but uses the developer tools
# options at config("dev_sqlite3_compile_options") and group("sqlite_dev").
executable("sqlite_dev_shell") {
include_dirs = [
# SQLite's shell.c contains an '#include "sqlite3.h", which we want to be
# resolved to //third_party/sqlite/sqlite3.h.
".",
]
sources = [
"sqlite_shell_icu_helper.cc",
"sqlite_shell_icu_helper.h",
"sqlite_shell_shim.c",
]
deps = [
":sqlite_dev",
"//base",
"//base:i18n",
"//third_party/icu",
]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
":dev_sqlite3_compile_options",
"//build/config/compiler:no_chromium_code",
# Must be after no_chromium_code for warning flags to be ordered
# correctly.
":sqlite_warnings",
]
}
}
# Libfuzzer-based fuzzer test from SQLite source tree.
fuzzer_test("sqlite3_ossfuzz_fuzzer") {
include_dirs = [ "." ]
sources = [ "src/test/ossfuzz.c" ]
deps = [ ":sqlite" ]
dict = "fuzz/sql.dict"
}
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",
]
deps = [ ":sqlite" ]
public_deps = [ ":sqlite3_lpm_fuzzer_input" ]
configs += [
":sqlite_warnings",
":chromium_sqlite3_compile_options",
]
all_dependent_configs = [
":lpm_fuzzer_omit_non_websql",
":chromium_sqlite3_compile_options",
]
}
source_set("sql_query_proto_to_string") {
sources = [
"fuzz/sql_query_proto_to_string.cc",
"fuzz/sql_query_proto_to_string.h",
]
deps = [ ":sqlite3_lpm_fuzzer_input" ]
}
# LPM-based fuzzer test.
fuzzer_test("sqlite3_lpm_fuzzer") {
sources = [
"fuzz/sql_fuzzer.cc",
"fuzz/sql_query_proto_to_string.cc",
"fuzz/sql_query_proto_to_string.h",
]
deps = [
":sqlite3_lpm_fuzzer_core",
"//third_party/libprotobuf-mutator",
]
additional_configs = [ ":sqlite_warnings" ]
libfuzzer_options = [
"max_len=2111000",
"len_control=0",
]
seed_corpus = "fuzz/lpm_fuzzer_seed_corpus/"
}
# FTS3-focused LPM-based fuzzer test.
fuzzer_test("sqlite3_fts3_lpm_fuzzer") {
sources = [
"fuzz/sql_fuzzer.cc",
"fuzz/sql_query_proto_to_string.cc",
"fuzz/sql_query_proto_to_string.h",
]
deps = [
":sqlite3_lpm_fuzzer_core",
"//third_party/libprotobuf-mutator",
]
additional_configs = [
":sqlite_warnings",
":sqlite3_fts3_lpm_fuzzer_config",
]
libfuzzer_options = [
"max_len=2111000",
"len_control=0",
]
}
fuzzer_test("sqlite3_shadow_table_fuzzer") {
sources = [ "fuzz/shadow_table_fuzzer.cc" ]
deps = [ ":sqlite" ]
additional_configs = [ ":sqlite_warnings" ]
}
fuzzer_test("sqlite3_select_printf_lpm_fuzzer") {
sources = [
"fuzz/sql_printf_fuzzer.cc",
"fuzz/sql_query_proto_to_string.cc",
"fuzz/sql_query_proto_to_string.h",
]
deps = [
":sqlite3_lpm_fuzzer_core",
"//third_party/libprotobuf-mutator",
]
libfuzzer_options = [ "max_len=111000" ]
}
fuzzer_test("sqlite3_select_strftime_lpm_fuzzer") {
sources = [
"fuzz/sql_query_proto_to_string.cc",
"fuzz/sql_query_proto_to_string.h",
"fuzz/sql_strftime_fuzzer.cc",
]
deps = [
":sqlite3_lpm_fuzzer_core",
"//third_party/libprotobuf-mutator",
]
libfuzzer_options = [ "max_len=111000" ]
}
fuzzer_test("sqlite3_select_expr_lpm_fuzzer") {
sources = [
"fuzz/sql_expr_fuzzer.cc",
"fuzz/sql_query_proto_to_string.cc",
"fuzz/sql_query_proto_to_string.h",
]
deps = [
":sqlite3_lpm_fuzzer_core",
"//third_party/libprotobuf-mutator",
]
libfuzzer_options = [
"max_len=111000",
"len_control=0",
]
}
config("sqlite3_fts3_lpm_fuzzer_config") {
defines = [ "FUZZ_FTS3" ]
}
config("lpm_fuzzer_omit_non_websql") {
defines = [
"FUZZ_OMIT_SAVEPOINT",
"FUZZ_OMIT_PRAGMA",
]
}
proto_library("sqlite3_lpm_fuzzer_input") {
sources = [
"fuzz/icu_codes.proto",
"fuzz/sql_queries.proto",
"fuzz/sql_query_grammar.proto",
]
}
# Generates a good corpus for the sqlite_lpm_fuzzer
# Don't build this tool on Windows since it uses a POSIX-only API and because it
# only needs to be used on devs' machines.
if (use_fuzzing_engine && !is_win) {
executable("sqlite3_lpm_corpus_gen") {
sources = [
"fuzz/sql_generate_corpus.cc",
"fuzz/sql_query_proto_to_string.cc",
"fuzz/sql_query_proto_to_string.h",
]
deps = [
":sqlite3_lpm_fuzzer_core",
"//base",
"//third_party/protobuf:protobuf_full",
]
}
}
config("sqlite3_dbfuzz2_config") {
cflags = [ "-Wno-sign-compare" ]
configs = [ ":sqlite_warnings" ]
}
# Upstream fuzzer that tests corrupted database files.
if (use_fuzzing_engine && !use_clang_coverage) {
fuzzer_test("sqlite3_dbfuzz2_fuzzer") {
include_dirs = [ "." ]
sources = [ "src/test/dbfuzz2.c" ]
deps = [ ":sqlite" ]
additional_configs = [ ":sqlite3_dbfuzz2_config" ]
seed_corpus = "fuzz/db_corpus"
}
}