From b4aebc839a1a4dc87275739d0d2c85504074e036 Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Fri, 13 Dec 2024 08:31:37 -0800 Subject: [PATCH] [multicore] avoid racing on chdir Summary: In multicore we can't allow the workers to change the working directory concurrently in `Utils.do_in_dir` as they will eventually execute their functions in the wrong directory. This diff introduces a mutex for exclusion, and removes redundant uses of the function which can crash due to recursively locking the mutex. Reviewed By: jvillard Differential Revision: D67195918 Privacy Context Container: L1208441 fbshipit-source-id: 6f7c3518fbc9b638e8a5e71fa15bf4ce621ffe22 --- infer/src/base/DBWriter.ml | 10 +++++----- infer/src/base/Utils.ml | 9 ++++++--- infer/src/base/Utils.mli | 3 ++- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/infer/src/base/DBWriter.ml b/infer/src/base/DBWriter.ml index b538a58f62..0ba47fb9ef 100644 --- a/infer/src/base/DBWriter.ml +++ b/infer/src/base/DBWriter.ml @@ -12,6 +12,8 @@ module F = Format module ServerSocket = struct let socket_name = ResultsDirEntryName.db_writer_socket_name + let socket_path = Config.toplevel_results_dir ^/ socket_name + let socket_addr = Unix.ADDR_UNIX socket_name let socket_domain = Unix.domain_of_sockaddr socket_addr @@ -22,7 +24,7 @@ module ServerSocket = struct function. *) let in_results_dir ~f = Utils.do_in_dir ~dir:Config.toplevel_results_dir ~f - let socket_exists () = in_results_dir ~f:(fun () -> Sys.file_exists_exn socket_name) + let socket_exists () = Sys.file_exists_exn socket_path (* Error recuperation is done by attempting this function at module initialization time, and not using DbWriter at all in case it fails. See {!can_use_socket} below. *) @@ -37,12 +39,10 @@ module ServerSocket = struct socket - let remove_socket_file () = - in_results_dir ~f:(fun () -> if socket_exists () then Unix.unlink socket_name) - + let remove_socket_file () = if socket_exists () then Unix.unlink socket_path let remove_socket socket = - in_results_dir ~f:(fun () -> Unix.close socket) ; + Unix.close socket ; remove_socket_file () diff --git a/infer/src/base/Utils.ml b/infer/src/base/Utils.ml index f35b0d8f55..a8e7bf42ae 100644 --- a/infer/src/base/Utils.ml +++ b/infer/src/base/Utils.ml @@ -435,10 +435,13 @@ let timeit ~f = (ret_val, duration) +let mutex = Error_checking_mutex.create () + let do_in_dir ~dir ~f = - let cwd = Unix.getcwd () in - Unix.chdir dir ; - Exception.try_finally ~f ~finally:(fun () -> Unix.chdir cwd) + Error_checking_mutex.critical_section mutex ~f:(fun () -> + let cwd = Unix.getcwd () in + Unix.chdir dir ; + Exception.try_finally ~f ~finally:(fun () -> Unix.chdir cwd) ) let get_available_memory_MB () = diff --git a/infer/src/base/Utils.mli b/infer/src/base/Utils.mli index c36392e5d1..b2e27397f4 100644 --- a/infer/src/base/Utils.mli +++ b/infer/src/base/Utils.mli @@ -127,7 +127,8 @@ val timeit : f:(unit -> 'a) -> 'a * Mtime.Span.t (** Returns the execution time of [f] together with its result *) val do_in_dir : dir:string -> f:(unit -> 'a) -> 'a -(** executes [f] after cding into [dir] and then restores original cwd *) +(** executes [f] after cding into [dir] and then restores original cwd. Uses a mutex to prevent + races on [chdir] in multicore mode. *) val get_available_memory_MB : unit -> int option (** On Linux systems, return [Some x] where [MemAvailable x] is in [/proc/meminfo]. Returns [None]