Skip to content

Commit

Permalink
[sqlite] symlink too-long db paths for db_open
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ngorogiannis authored and facebook-github-bot committed Nov 27, 2024
1 parent 9346105 commit a42a0c6
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 5 deletions.
21 changes: 19 additions & 2 deletions infer/src/base/Database.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
7 changes: 4 additions & 3 deletions infer/src/base/SqliteUtils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 3 additions & 0 deletions infer/src/base/SqliteUtils.mli
Original file line number Diff line number Diff line change
Expand Up @@ -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}. *)
Expand Down

0 comments on commit a42a0c6

Please sign in to comment.