From 2d8ca36f12279eac6c1a3c1325e472179ce8657f Mon Sep 17 00:00:00 2001 From: Benjamin Canou Date: Tue, 12 Jun 2018 21:27:45 +0200 Subject: [PATCH] Data_encoding: cosmetic fixes --- src/lib_data_encoding/binary_description.ml | 18 +++++++-------- src/lib_data_encoding/binary_error.ml | 18 ++++++++++----- src/lib_data_encoding/binary_error.mli | 6 +++-- src/lib_data_encoding/binary_length.ml | 4 ++-- src/lib_data_encoding/binary_reader.ml | 10 ++++---- src/lib_data_encoding/binary_schema.ml | 23 +++++++++++++------ src/lib_data_encoding/binary_schema.mli | 2 +- src/lib_data_encoding/binary_stream_reader.ml | 10 ++++---- src/lib_data_encoding/binary_writer.ml | 4 ++-- src/lib_data_encoding/data_encoding.mli | 12 ++++++++-- 10 files changed, 66 insertions(+), 41 deletions(-) diff --git a/src/lib_data_encoding/binary_description.ml b/src/lib_data_encoding/binary_description.ml index 62f776d8d..5783c7f70 100644 --- a/src/lib_data_encoding/binary_description.ml +++ b/src/lib_data_encoding/binary_description.ml @@ -58,7 +58,7 @@ let fixup_references uf = let rec fixup_layout = function | Ref s -> Ref (UF.find uf s).title | Enum (i, name) -> Enum (i, (UF.find uf name).title) - | Seq layout -> Seq (fixup_layout layout) + | Seq (layout, len) -> Seq (fixup_layout layout, len) | (Zero_width | Int _ | Bool @@ -295,15 +295,15 @@ let describe (type x) (encoding : x Encoding.t) = fields ref_name recursives references encoding.encoding | Delayed func -> fields ref_name recursives references (func ()).encoding - | List (_, { encoding }) -> + | List (len, { encoding }) -> let (layout, references) = layout None recursives references encoding in - ([ Anonymous_field (`Variable, Seq layout) ], + ([ Anonymous_field (`Variable, Seq (layout, len)) ], references) - | Array (_, { encoding }) -> + | Array (len, { encoding }) -> let (layout, references) = layout None recursives references encoding in - ([ Anonymous_field (`Variable, Seq layout) ], + ([ Anonymous_field (`Variable, Seq (layout, len)) ], references) | Bytes kind -> ([ Anonymous_field ((kind :> Kind.t), Bytes) ], references) @@ -436,14 +436,14 @@ let describe (type x) (encoding : x Encoding.t) = let size, cases = enum tbl encoding_array in let references = add_reference name (Int_enum { size ; cases }) references in (Enum (size, name), references) - | Array (_, data) -> + | Array (len, data) -> let (descr, references) = layout None recursives references data.encoding in - (Seq descr, references) - | List (_, data) -> + (Seq (descr, len), references) + | List (len, data) -> let layout, references = layout None recursives references data.encoding in - (Seq layout, references) + (Seq (layout, len), references) | Obj (Req { encoding = { encoding } }) | Obj (Dft { encoding = { encoding } }) -> layout ref_name recursives references encoding diff --git a/src/lib_data_encoding/binary_error.ml b/src/lib_data_encoding/binary_error.ml index c45fd148a..0f6fef62f 100644 --- a/src/lib_data_encoding/binary_error.ml +++ b/src/lib_data_encoding/binary_error.ml @@ -17,7 +17,8 @@ type read_error = | Invalid_float of { min : float ; v : float ; max : float } | Trailing_zero | Size_limit_exceeded - | Oversized_list + | List_too_long + | Array_too_long let pp_read_error ppf = function | Not_enough_data -> @@ -38,8 +39,10 @@ let pp_read_error ppf = function Format.fprintf ppf "Trailing zero in Z" | Size_limit_exceeded -> Format.fprintf ppf "Size limit exceeded" - | Oversized_list -> - Format.fprintf ppf "Size limit exceeded" + | List_too_long -> + Format.fprintf ppf "List length limit exceeded" + | Array_too_long -> + Format.fprintf ppf "Array length limit exceeded" exception Read_error of read_error @@ -51,7 +54,8 @@ type write_error = | Invalid_bytes_length of { expected : int ; found : int } | Invalid_string_length of { expected : int ; found : int } | Invalid_natural - | Oversized_list + | List_too_long + | Array_too_long let pp_write_error ppf = function | Size_limit_exceeded -> @@ -72,7 +76,9 @@ let pp_write_error ppf = function expected found | Invalid_natural -> Format.fprintf ppf "Negative natural" - | Oversized_list -> - Format.fprintf ppf "Size limit exceeded" + | List_too_long -> + Format.fprintf ppf "List length limit exceeded" + | Array_too_long -> + Format.fprintf ppf "Array length limit exceeded" exception Write_error of write_error diff --git a/src/lib_data_encoding/binary_error.mli b/src/lib_data_encoding/binary_error.mli index 565a29366..2ea1f68da 100644 --- a/src/lib_data_encoding/binary_error.mli +++ b/src/lib_data_encoding/binary_error.mli @@ -20,7 +20,8 @@ type read_error = | Invalid_float of { min : float ; v : float ; max : float } | Trailing_zero | Size_limit_exceeded - | Oversized_list + | List_too_long + | Array_too_long exception Read_error of read_error val pp_read_error: Format.formatter -> read_error -> unit @@ -32,7 +33,8 @@ type write_error = | Invalid_bytes_length of { expected : int ; found : int } | Invalid_string_length of { expected : int ; found : int } | Invalid_natural - | Oversized_list + | List_too_long + | Array_too_long val pp_write_error : Format.formatter -> write_error -> unit diff --git a/src/lib_data_encoding/binary_length.ml b/src/lib_data_encoding/binary_length.ml index 2cb1dbe90..c68383ebd 100644 --- a/src/lib_data_encoding/binary_length.ml +++ b/src/lib_data_encoding/binary_length.ml @@ -72,13 +72,13 @@ let rec length : type x. x Encoding.t -> x -> int = | Bytes `Variable -> MBytes.length value | String `Variable -> String.length value | Array (Some max_length, _e) when Array.length value > max_length -> - raise (Write_error Oversized_list) + raise (Write_error Array_too_long) | Array (_, e) -> Array.fold_left (fun acc v -> length e v + acc) 0 value | List (Some max_length, _e) when List.length value > max_length -> - raise (Write_error Oversized_list) + raise (Write_error List_too_long) | List (_, e) -> List.fold_left (fun acc v -> length e v + acc) diff --git a/src/lib_data_encoding/binary_reader.ml b/src/lib_data_encoding/binary_reader.ml index 1241bd46c..1013cef88 100644 --- a/src/lib_data_encoding/binary_reader.ml +++ b/src/lib_data_encoding/binary_reader.ml @@ -192,11 +192,11 @@ let rec read_rec : type ret. ret Encoding.t -> state -> ret Atom.string_enum arr state | Array (max_length, e) -> let max_length = Option.unopt ~default:max_int max_length in - let l = read_list max_length e state in + let l = read_list List_too_long max_length e state in Array.of_list l | List (max_length, e) -> let max_length = Option.unopt ~default:max_int max_length in - read_list max_length e state + read_list Array_too_long max_length e state | (Obj (Req { encoding = e })) -> read_rec e state | (Obj (Dft { encoding = e })) -> read_rec e state | (Obj (Opt { kind = `Dynamic ; encoding = e })) -> @@ -303,13 +303,13 @@ and read_variable_pair (left, right) | _ -> assert false (* Should be rejected by [Encoding.Kind.combine] *) -and read_list : type a. int -> a Encoding.t -> state -> a list - = fun max_length e state -> +and read_list : type a. read_error -> int -> a Encoding.t -> state -> a list + = fun error max_length e state -> let rec loop max_length acc = if state.remaining_bytes = 0 then List.rev acc else if max_length = 0 then - raise Oversized_list + raise error else let v = read_rec e state in loop (max_length - 1) (v :: acc) in diff --git a/src/lib_data_encoding/binary_schema.ml b/src/lib_data_encoding/binary_schema.ml index 374a84691..e34f2d39e 100644 --- a/src/lib_data_encoding/binary_schema.ml +++ b/src/lib_data_encoding/binary_schema.ml @@ -27,7 +27,7 @@ and layout = | Bytes | String | Enum of Binary_size.integer * string - | Seq of layout (* For arrays and lists *) + | Seq of layout * int option (* For arrays and lists *) | Ref of string | Padding @@ -115,8 +115,16 @@ module Printer_ast = struct Format.fprintf ppf "%a encoding an enumeration (see %s)" pp_int (size :> integer_extended) reference - | Seq (Ref reference) -> Format.fprintf ppf "sequence of $%s" reference - | Seq data -> Format.fprintf ppf "sequence of %a" pp_layout data + | Seq (data, len) -> + Format.fprintf ppf "sequence of " ; + begin match len with + | None -> () + | Some len -> Format.fprintf ppf "at most %d " len + end ; + begin match data with + | Ref reference -> Format.fprintf ppf "$%s" reference + | _ -> pp_layout ppf data + end let pp_tag_size ppf tag = @@ -387,13 +395,14 @@ module Encoding = struct (fun (size, cases, _) -> Enum (size, cases)) ; case ~title:"Seq" (Tag 9) - (obj2 + (obj3 (req "layout" layout) - (req "kind" (constant "Seq"))) + (req "kind" (constant "Seq")) + (opt "max_length" int31)) (function - | Seq layout -> Some (layout, ()) + | Seq (layout, len) -> Some (layout, (), len) | _ -> None) - (fun (layout, ()) -> Seq layout) ; + (fun (layout, (), len) -> Seq (layout, len)) ; case ~title:"Ref" (Tag 10) (obj2 diff --git a/src/lib_data_encoding/binary_schema.mli b/src/lib_data_encoding/binary_schema.mli index 9dd904c98..439735df0 100644 --- a/src/lib_data_encoding/binary_schema.mli +++ b/src/lib_data_encoding/binary_schema.mli @@ -27,7 +27,7 @@ and layout = | Bytes | String | Enum of Binary_size.integer * string - | Seq of layout (* For arrays and lists *) + | Seq of layout * int option (* For arrays and lists *) | Ref of string | Padding diff --git a/src/lib_data_encoding/binary_stream_reader.ml b/src/lib_data_encoding/binary_stream_reader.ml index e1d399ce6..c24792d7f 100644 --- a/src/lib_data_encoding/binary_stream_reader.ml +++ b/src/lib_data_encoding/binary_stream_reader.ml @@ -261,11 +261,11 @@ let rec read_rec Atom.string_enum arr resume state k | Array (max_length, e) -> let max_length = Option.unopt ~default:max_int max_length in - read_list max_length e state @@ fun (l, state) -> + read_list Array_too_long max_length e state @@ fun (l, state) -> k (Array.of_list l, state) | List (max_length, e) -> let max_length = Option.unopt ~default:max_int max_length in - read_list max_length e state k + read_list List_too_long max_length e state k | (Obj (Req { encoding = e })) -> read_rec whole e state k | (Obj (Dft { encoding = e })) -> read_rec whole e state k | (Obj (Opt { kind = `Dynamic ; encoding = e })) -> @@ -398,14 +398,14 @@ and read_variable_pair and read_list : type a ret. - int -> a Encoding.t -> state -> ((a list * state) -> ret status) -> ret status - = fun max_length e state k -> + read_error -> int -> a Encoding.t -> state -> ((a list * state) -> ret status) -> ret status + = fun error max_length e state k -> let rec loop state acc max_length = let size = remaining_bytes state in if size = 0 then k (List.rev acc, state) else if max_length = 0 then - raise Oversized_list + raise error else read_rec false e state @@ fun (v, state) -> loop state (v :: acc) (max_length - 1) in diff --git a/src/lib_data_encoding/binary_writer.ml b/src/lib_data_encoding/binary_writer.ml index bd2064af3..d3b53a049 100644 --- a/src/lib_data_encoding/binary_writer.ml +++ b/src/lib_data_encoding/binary_writer.ml @@ -226,11 +226,11 @@ let rec write_rec : type a. a Encoding.t -> state -> a -> unit = | String_enum (tbl, arr) -> Atom.string_enum tbl arr state value | Array (Some max_length, _e) when Array.length value > max_length -> - raise Oversized_list + raise Array_too_long | Array (_, e) -> Array.iter (write_rec e state) value | List (Some max_length, _e) when List.length value > max_length -> - raise Oversized_list + raise List_too_long | List (_, e) -> List.iter (write_rec e state) value | Obj (Req { encoding = e }) -> write_rec e state value diff --git a/src/lib_data_encoding/data_encoding.mli b/src/lib_data_encoding/data_encoding.mli index 3822fecb0..526017081 100644 --- a/src/lib_data_encoding/data_encoding.mli +++ b/src/lib_data_encoding/data_encoding.mli @@ -169,6 +169,9 @@ module Encoding: sig - encoded as the concatenation of all the element in binary prefixed its length in bytes + If [max_length] is passed and the encoding of elements has fixed + size, a {!check_size} is automatically added for earlier rejection. + @raise [Invalid_argument] if the inner encoding is variable. *) val array : ?max_length:int -> 'a encoding -> 'a array encoding @@ -177,6 +180,9 @@ module Encoding: sig - encoded as the concatenation of all the element in binary prefixed its length in bytes + If [max_length] is passed and the encoding of elements has fixed + size, a {!check_size} is automatically added for earlier rejection. + @raise [Invalid_argument] if the inner encoding is also variable. *) val list : ?max_length:int -> 'a encoding -> 'a list encoding @@ -633,7 +639,8 @@ module Binary: sig | Invalid_float of { min : float ; v : float ; max : float } | Trailing_zero | Size_limit_exceeded - | Oversized_list + | List_too_long + | Array_too_long exception Read_error of read_error val pp_read_error: Format.formatter -> read_error -> unit @@ -646,7 +653,8 @@ module Binary: sig | Invalid_bytes_length of { expected : int ; found : int } | Invalid_string_length of { expected : int ; found : int } | Invalid_natural - | Oversized_list + | List_too_long + | Array_too_long val pp_write_error : Format.formatter -> write_error -> unit exception Write_error of write_error