# Copyright (c) 2013 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. 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"). component("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_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 = [ "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", ":sqlite_export", ] } 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", ] } # 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) { fuzzer_test("sqlite3_dbfuzz2_fuzzer") { include_dirs = [ "." ] sources = [ "src/test/dbfuzz2.c" ] deps = [ ":sqlite" ] additional_configs = [ ":sqlite3_dbfuzz2_config" ] seed_corpus = "fuzz/db_corpus" } }