From a42a0c65d53ed98839e067c45cab9e27c82f0dbe Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Wed, 27 Nov 2024 08:28:22 -0800 Subject: [PATCH] [sqlite] symlink too-long db paths for db_open Summary: Add more defence for too long database paths: when creating a database and when opening an existing one. Also fix bug where `Filename.temp_file` creates empty file and symlink creation fails. Reviewed By: dulmarod Differential Revision: D66536892 Privacy Context Container: L1208441 fbshipit-source-id: 1d4031d7577299e175431018caa9beb3bfc36031 --- infer/src/base/Database.ml | 21 +++++++++++++++++++-- infer/src/base/SqliteUtils.ml | 7 ++++--- infer/src/base/SqliteUtils.mli | 3 +++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/infer/src/base/Database.ml b/infer/src/base/Database.ml index fe7479292c5..45718ff3e73 100644 --- a/infer/src/base/Database.ml +++ b/infer/src/base/Database.ml @@ -138,14 +138,31 @@ type location = Primary | Secondary of string [@@deriving show {with_path= false let results_dir_get_path entry = ResultsDirEntryName.get_path ~results_dir:Config.results_dir entry let get_db_path location id = - match location with Primary -> results_dir_get_path (get_db_entry id) | Secondary file -> file + match location with + | Secondary file -> + file + | Primary -> + let path_to_db = results_dir_get_path (get_db_entry id) in + if String.length path_to_db > SqliteUtils.sqlite_max_path_length then ( + let link_name = Filename.temp_file "infer-merge-sqlite-trampoline" ".db" in + Unix.unlink link_name ; + Unix.symlink ~target:(Filename.dirname path_to_db) ~link_name ; + Filename.concat link_name (Filename.basename path_to_db) ) + else path_to_db let create_db location id = let final_db_path = get_db_path location id in let pid = Unix.getpid () in + let in_dir = + (* if the length of the path to the results directory is greater than Sqlite's limit + then create the DB in [$TMPDIR] otherwise in [results_dir/tmp] *) + let results_temp_dir = results_dir_get_path Temporary in + if String.length results_temp_dir > SqliteUtils.sqlite_max_path_length - 50 then None + else Some results_temp_dir + in let temp_db_path = - Filename.temp_file ~in_dir:(results_dir_get_path Temporary) + Filename.temp_file ?in_dir ( match id with | CaptureDatabase -> "capture." ^ Pid.to_string pid ^ ".db" diff --git a/infer/src/base/SqliteUtils.ml b/infer/src/base/SqliteUtils.ml index 599304770ef..14b75edcbeb 100644 --- a/infer/src/base/SqliteUtils.ml +++ b/infer/src/base/SqliteUtils.ml @@ -103,9 +103,10 @@ let with_attached_db ~db_file ~db_name ?(immutable = false) ~f db = then (db_file, false) else let in_dir = ResultsDirEntryName.get_path ~results_dir:Config.results_dir Temporary in - let link_name = Filename.temp_file ~in_dir "infer-merge-sqlite-trampoline" "db" in - Unix.symlink ~target:db_file ~link_name ; - (link_name, true) + let link_name = Filename.temp_file ~in_dir "infer-merge-sqlite-trampoline-out" "" in + Unix.unlink link_name ; + Unix.symlink ~target:(Filename.dirname db_file) ~link_name ; + (Filename.concat link_name (Filename.basename db_file), true) in let attach_stmt = Printf.sprintf "ATTACH '%s%s%s' AS %s" diff --git a/infer/src/base/SqliteUtils.mli b/infer/src/base/SqliteUtils.mli index dd5cd64e4a0..6427d6e6a0a 100644 --- a/infer/src/base/SqliteUtils.mli +++ b/infer/src/base/SqliteUtils.mli @@ -14,6 +14,9 @@ exception Error of string (** Raised from serializers when final size exceeds Sqlite3 limits (normally 1000_000_000 bytes). *) exception DataTooBig +val sqlite_max_path_length : int +(** an underapproximation of the maximum path length allowed in sqlite *) + val check_result_code : Sqlite3.db -> log:string -> Sqlite3.Rc.t -> unit (** Assert that the result is either [Sqlite3.Rc.OK] or [Sqlite3.Rc.ROW]. If the result is not valid, raise {!Error}. *)