Skip to content

Commit 5fd5ef9

Browse files
committed
Improve file magic handling
Before this change, the magic string was read by reading the number of bytes we're expecting to read based on our magic string. If ours happens to be a prefix of the real one (e.g. ours is 'odoc-3.1.0' and the real one is 'odoc-3.1.0-2-g12345789') then the check was succeeding and then the subsequent unmarshalling was failing. This fixes that by writing the length too, so we always unmarshal the right length.
1 parent dbe1333 commit 5fd5ef9

File tree

1 file changed

+42
-9
lines changed

1 file changed

+42
-9
lines changed

src/odoc/odoc_file.ml

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,24 @@ type content =
2929
type t = { content : content; warnings : Odoc_model.Error.t list }
3030

3131
(** Written at the top of the files. Checked when loading. *)
32-
let magic = "odoc-%%VERSION%%"
32+
let magic = "ODOC"
33+
34+
let magic_version = "%%VERSION%%"
3335

3436
(** Exceptions while saving are allowed to leak. *)
3537
let save_ file f =
38+
let len = String.length magic_version in
39+
(* Sanity check, see similar check in load_ *)
40+
if len > 255 then
41+
failwith
42+
(Printf.sprintf
43+
"Magic version string %S is too long, must be <= 255 characters" magic);
44+
3645
Fs.Directory.mkdir_p (Fs.File.dirname file);
3746
Io_utils.with_open_out_bin (Fs.File.to_string file) (fun oc ->
3847
output_string oc magic;
48+
output_binary_int oc len;
49+
output_string oc magic_version;
3950
f oc)
4051

4152
let save_unit file (root : Root.t) (t : t) =
@@ -78,19 +89,41 @@ let save_unit file ~warnings m =
7889

7990
let load_ file f =
8091
let file = Fs.File.to_string file in
81-
(if Sys.file_exists file then Ok file
82-
else Error (`Msg (Printf.sprintf "File does not exist")))
83-
>>= fun file ->
84-
Io_utils.with_open_in_bin file @@ fun ic ->
85-
try
92+
93+
let check_exists () =
94+
if Sys.file_exists file then Ok ()
95+
else Error (`Msg (Printf.sprintf "File %s does not exist" file))
96+
in
97+
98+
let check_magic ic =
8699
let actual_magic = really_input_string ic (String.length magic) in
87-
if actual_magic = magic then f ic
100+
if actual_magic = magic then Ok ()
101+
else
102+
Error
103+
(`Msg
104+
(Printf.sprintf "%s has invalid magic %S, expected %S\n%!" file
105+
actual_magic magic))
106+
in
107+
let version_length ic () =
108+
let len = input_binary_int ic in
109+
if len > 0 && len <= 255 then Ok len
110+
else Error (`Msg (Printf.sprintf "%s has invalid version length" file))
111+
in
112+
let check_version ic len =
113+
let actual_magic = really_input_string ic len in
114+
if actual_magic = magic_version then Ok ()
88115
else
89116
let msg =
90-
Printf.sprintf "%s: invalid magic number %S, expected %S\n%!" file
91-
actual_magic magic
117+
Printf.sprintf "%s has invalid version %S, expected %S\n%!" file
118+
actual_magic magic_version
92119
in
93120
Error (`Msg msg)
121+
in
122+
123+
check_exists () >>= fun () ->
124+
Io_utils.with_open_in_bin file @@ fun ic ->
125+
try
126+
check_magic ic >>= version_length ic >>= check_version ic >>= fun () -> f ic
94127
with exn ->
95128
let msg =
96129
Printf.sprintf "Error while unmarshalling %S: %s\n%!" file

0 commit comments

Comments
 (0)