-
Notifications
You must be signed in to change notification settings - Fork 273
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
provides versioned backends for program units symbol tables
TL;DR; follow mainstream OCaml and make dynamic loading sound and safe (not again, as it never was before). The Problem =========== The long story. Before OCaml 4.08 the dynlink module was unsound. Linking the same module resulted in GC roots table corruption and segmentation faults. To prevent this behavior, we were tracking loaded units. However, we weren't able to reliably track units that were linked into the program directly with the OCaml linker. We were using `findlib.dynload` and a corresponding functionality in dune that provide us the information about the units that were used to link the host program. Unfortunately, `findlib.dynload` was recording this information in terms of the findlib packages, not in compilation units. Therefore, in order to resolve a package name to corresponding compilation unit names we needed a working findlib system, i.e., the META files for all packages that are statically linked in the binary should be present in the hard-coded locations. In normal mode of operation, when packages that were used to build bap are present in the file system it didn't pose any problems. However, when bap together with its plugins was packed into a debian package and distributed to other machines no meta files were available. To enable binary distributions we developed an ocamlbuild plugin that was resolving package names to compilation unit names during the compilation time, so that bap (and other tools built from our main source repository) wasn't dependent on the runtime presence of META files. However, when a host program is compiled with dune, or any other build system that doesn't reflect package names to unit names and store them in the host file predicates (read it anywhere outside of bap), then when packaged and distributed to other hosts the program will fail in runtime. The Solution ============ Sine the bug is fixed in 4.08 there is no a big problem. There is still some impendance mismatch between the names of the libraries (cmxs or cma) that we load and the names of the units that comprise the library, therefore, we can't know beforehand whether a library that we load is already linked into the main program, because we can only query dynlink for the names of the compilation units, not for the names of the libraries, that used during the linking procedure. We address this problem by looking into the error code, if the code is `Dynlink.Module_already_loaded _` then instead of failing, we record the library that loads this module in our repository. The only problem with this solution is that it is probably to early for us to drop the support for OCaml 4.07. Therefore, we decided to provide two backends. The fallback solution still uses the old findlib approach, but we decided to make it a little bit more robust, to minimize the debugging time in case it will fail. We now check if we have the static information about the compilation units that comprise the host program, and if we don't then we ensure that we have working ocamlfind and META files. If not than we terminate the program with more or less comprehensible message. If we have a modern compiler, then we just use the Dynlink module (which is guarded with ppx_optcomp).
- Loading branch information
Showing
11 changed files
with
132 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1 @@ | ||
let plugindir = "$plugindir" | ||
|
||
module Units = Bap_plugins_units_$plugins_backend |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
open Core_kernel | ||
|
||
open Bap_plugins_units_intf | ||
|
||
[%%if ocaml_version < (4,08,0)] | ||
include Bap_plugins_units_fallback | ||
[%%else] | ||
let name = "dynlink" | ||
|
||
let units : reason String.Table.t = String.Table.create () | ||
|
||
let copy_units_from_dynlink () = | ||
Dynlink.all_units () |> | ||
List.iter ~f:(fun unit -> Hashtbl.add_exn units unit `In_core) | ||
|
||
let init () = copy_units_from_dynlink () | ||
let list () = Hashtbl.keys units | ||
let record name reason = Hashtbl.add_exn units name reason | ||
let lookup = Hashtbl.find units | ||
let handle_error name reason = function | ||
| Dynlink.Module_already_loaded _ -> | ||
Hashtbl.set units name reason; | ||
Ok () | ||
| other -> | ||
Or_error.error_string (Dynlink.error_message other) | ||
[%%endif] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1 @@ | ||
type reason = [ | ||
| `In_core | ||
| `Provided_by of string | ||
| `Requested_by of string | ||
] | ||
|
||
|
||
module type S = sig | ||
val init : unit Lazy.t | ||
|
||
val record : string -> reason -> unit | ||
val lookup : string -> reason option | ||
end | ||
include Bap_plugins_units_intf.S |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.