Skip to content

Commit

Permalink
Merge pull request #33 from pqwy/bounds-everywhere
Browse files Browse the repository at this point in the history
Bounds everywhere
  • Loading branch information
avsm committed Aug 10, 2014
2 parents c9fc1f9 + 51904e5 commit 49bb74d
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 50 deletions.
61 changes: 32 additions & 29 deletions lib/cstruct.ml
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,21 @@ type t = {
} with sexp

let of_bigarray ?(off=0) ?len buffer =
let dim = Bigarray.Array1.dim buffer in
let len =
match len with
|None -> Bigarray.Array1.dim buffer
|Some len -> min len (Bigarray.Array1.dim buffer)
in { buffer; off; len }
| None -> dim - off
| Some len -> len in
if off < 0 || len < 0 || off + len > dim then
raise (Invalid_argument "Cstruct.of_bigarray");
{ buffer; off; len }

let to_bigarray buffer =
Bigarray.Array1.sub buffer.buffer buffer.off buffer.len

let create len =
let ba = Bigarray.Array1.create Bigarray.char Bigarray.c_layout len in
of_bigarray ba
let buffer = Bigarray.(Array1.create char c_layout len) in
{ buffer ; len ; off = 0 }

let check_bounds t len =
Bigarray.Array1.dim t.buffer >= len
Expand Down Expand Up @@ -74,20 +77,20 @@ let debug t =
);
str

let sub t off len =
let off = t.off + off in
if len < 0
|| off < 0
|| not (check_bounds t (off+len)) then
let sub t off0 len =
let off = t.off + off0 in
if off0 < 0 ||
len < 0 ||
not (check_bounds t (off+len)) then
raise (Invalid_argument "Cstruct.sub");
{ t with off; len }

let shift t amount =
let off = t.off + amount in
let len = t.len - amount in
if len < 0
|| off < 0
|| not (check_bounds t (off+len)) then
if amount < 0 ||
amount > t.len ||
not (check_bounds t (off+len)) then
raise (Invalid_argument "Cstruct.shift");
{ t with off; len }

Expand Down Expand Up @@ -138,74 +141,74 @@ let blit_to_string src srcoff dst dstoff len =
unsafe_blit_bigstring_to_string src.buffer (src.off+srcoff) dst dstoff len

let set_uint8 t i c =
if i >= t.len then raise (Invalid_argument (invalid_bounds i 1)) ;
if i >= t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 1)) ;
EndianBigstring.BigEndian.set_int8 t.buffer (t.off+i) c

let set_char t i c =
if i >= t.len then raise (Invalid_argument (invalid_bounds i 1)) ;
if i >= t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 1)) ;
EndianBigstring.BigEndian.set_char t.buffer (t.off+i) c

let get_uint8 t i =
if i >= t.len then raise (Invalid_argument (invalid_bounds i 1)) ;
if i >= t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 1)) ;
EndianBigstring.BigEndian.get_uint8 t.buffer (t.off+i)

let get_char t i =
if i >= t.len then raise (Invalid_argument (invalid_bounds i 1)) ;
if i >= t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 1)) ;
EndianBigstring.BigEndian.get_char t.buffer (t.off+i)

module BE = struct
include EndianBigstring.BigEndian

let set_uint16 t i c =
if (i+2) > t.len then raise (Invalid_argument (invalid_bounds i 2));
if (i+2) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 2));
set_int16 t.buffer (t.off+i) c

let set_uint32 t i c =
if (i+4) > t.len then raise (Invalid_argument (invalid_bounds i 4));
if (i+4) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 4));
set_int32 t.buffer (t.off+i) c

let set_uint64 t i c =
if (i+8) > t.len then raise (Invalid_argument (invalid_bounds i 8));
if (i+8) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 8));
set_int64 t.buffer (t.off+i) c

let get_uint16 t i =
if (i+2) > t.len then raise (Invalid_argument (invalid_bounds i 2));
if (i+2) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 2));
get_uint16 t.buffer (t.off+i)

let get_uint32 t i =
if (i+4) > t.len then raise (Invalid_argument (invalid_bounds i 4));
if (i+4) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 4));
get_int32 t.buffer (t.off+i)

let get_uint64 t i =
if (i+8) > t.len then raise (Invalid_argument (invalid_bounds i 8));
if (i+8) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 8));
get_int64 t.buffer (t.off+i)
end

module LE = struct
include EndianBigstring.LittleEndian

let set_uint16 t i c =
if (i+2) > t.len then raise (Invalid_argument (invalid_bounds i 2));
if (i+2) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 2));
set_int16 t.buffer (t.off+i) c

let set_uint32 t i c =
if (i+4) > t.len then raise (Invalid_argument (invalid_bounds i 4));
if (i+4) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 4));
set_int32 t.buffer (t.off+i) c

let set_uint64 t i c =
if (i+8) > t.len then raise (Invalid_argument (invalid_bounds i 8));
if (i+8) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 8));
set_int64 t.buffer (t.off+i) c

let get_uint16 t i =
if (i+2) > t.len then raise (Invalid_argument (invalid_bounds i 2));
if (i+2) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 2));
get_uint16 t.buffer (t.off+i)

let get_uint32 t i =
if (i+4) > t.len then raise (Invalid_argument (invalid_bounds i 4));
if (i+4) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 4));
get_int32 t.buffer (t.off+i)

let get_uint64 t i =
if (i+8) > t.len then raise (Invalid_argument (invalid_bounds i 8));
if (i+8) > t.len || i < 0 then raise (Invalid_argument (invalid_bounds i 8));
get_int64 t.buffer (t.off+i)
end

Expand Down
179 changes: 158 additions & 21 deletions lib_test/bounds.ml
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,19 @@ let test_positive_shift () =
let y = Cstruct.shift x 1 in
assert_equal ~printer:string_of_int 0 (Cstruct.len y)

(* Check we can shift in the -ve direction *)
(* Check that negative shifts are forbidden. *)
let test_negative_shift () =
let x = Cstruct.create 10 in
let y = Cstruct.sub x 5 5 in
let z = Cstruct.shift y (-5) in
assert_equal ~printer:string_of_int 0 z.Cstruct.off;
assert_equal ~printer:string_of_int 10 z.Cstruct.len
let x = Cstruct.create 2 in
let y = Cstruct.sub x 1 1 in
try
let z = Cstruct.shift x (-1) in
failwith (Printf.sprintf "test_negative_shift/outer: %s" (to_string z))
with Invalid_argument _ ->
try
let z = Cstruct.shift y (-1) in
failwith (Printf.sprintf "test_negative_shift/inner: %s" (to_string z))
with Invalid_argument _ ->
()

(* Check that an attempt to shift beyond the end of the buffer fails *)
let test_bad_positive_shift () =
Expand All @@ -56,14 +62,6 @@ let test_bad_positive_shift () =
failwith (Printf.sprintf "test_bad_positive_shift: %s" (to_string y))
with Invalid_argument _ -> ()

(* Check that an attempt to shift before the start of the buffer fails *)
let test_bad_negative_shift () =
let x = Cstruct.create 10 in
try
let y = Cstruct.shift x (-1) in
failwith (Printf.sprintf "test_bad_negative_shift: %s" (to_string y))
with Invalid_argument _ -> ()

(* Check that 'sub' works *)
let test_sub () =
let x = Cstruct.create 100 in
Expand All @@ -74,6 +72,19 @@ let test_sub () =
assert_equal ~printer:string_of_int 20 z.Cstruct.off;
assert_equal ~printer:string_of_int 60 z.Cstruct.len

let test_negative_sub () =
let x = Cstruct.create 2 in
let y = Cstruct.sub x 1 1 in
try
let z = Cstruct.sub x (-1) 0 in
failwith (Printf.sprintf "test_negative_sub/outer: %s" (to_string z))
with Invalid_argument _ ->
try
let z = Cstruct.sub y (-1) 0 in
failwith (Printf.sprintf "test_negative_sub/inner: %s" (to_string z))
with Invalid_argument _ ->
()

(* Check that 'sub' can't set 'len' too big *)
let test_sub_len_too_big () =
let x = Cstruct.create 0 in
Expand Down Expand Up @@ -105,12 +116,51 @@ let test_sub_offset_too_big () =
with Invalid_argument _ -> ()
end

let test_sub_offset_too_small () =
let x = Cstruct.create 0 in
let test_of_bigarray_negative_params () =
let ba = Bigarray.(Array1.create char c_layout 1) in
try
let y = Cstruct.sub x (-1) 0 in
failwith (Printf.sprintf "test_sub_offset_too_small: %s" (to_string y))
with Invalid_argument _ -> ()
let x = Cstruct.of_bigarray ~off:(-1) ba in
failwith (Printf.sprintf "test_of_bigarray_negative_params: negative ~off: %s" (to_string x))
with Invalid_argument _ ->
try
let x = Cstruct.of_bigarray ~len:(-1) ba in
failwith (Printf.sprintf "test_of_bigarray_negative_params: negative ~len: %s" (to_string x))
with Invalid_argument _ ->
()

let test_of_bigarray_large_offset () =
let ba = Bigarray.(Array1.create char c_layout 1) in
let _ = Cstruct.of_bigarray ~off:1 ~len:0 ba
and _ = Cstruct.of_bigarray ~off:1 ba in
try
let x = Cstruct.of_bigarray ~off:2 ~len:0 ba in
failwith (Printf.sprintf "test_of_bigarray_large_offset: %s" (to_string x))
with Invalid_argument _ ->
try
let x = Cstruct.of_bigarray ~off:2 ba in
failwith (Printf.sprintf "test_of_bigarray_large_offset: large ~off: %s" (to_string x))
with Invalid_argument _ ->
()

let test_of_bigarray_large_length () =
let ba = Bigarray.(Array1.create char c_layout 1) in
try
let x = Cstruct.of_bigarray ~off:0 ~len:2 ba in
failwith (Printf.sprintf "test_of_bigarray_large_length: %s" (to_string x))
with Invalid_argument _ ->
try
let x = Cstruct.of_bigarray ~off:1 ~len:1 ba in
failwith (Printf.sprintf "test_of_bigarray_large_length: %s" (to_string x))
with Invalid_argument _ ->
try
let x = Cstruct.of_bigarray ~off:2 ~len:0 ba in
failwith (Printf.sprintf "test_of_bigarray_large_length: %s" (to_string x))
with Invalid_argument _ ->
try
let x = Cstruct.of_bigarray ~off:2 ba in
failwith (Printf.sprintf "test_of_bigarray_large_length: %s" (to_string x))
with Invalid_argument _ ->
()

let test_set_len_too_big () =
let x = Cstruct.create 0 in
Expand Down Expand Up @@ -278,6 +328,75 @@ let test_view_bounds_too_small_get_le64 () =
with
Invalid_argument _ -> ()

(* Steamroll over a buffer and a contained subview, checking that only the
* contents of the subview is visible. *)
let test_subview_containment_get_char,
test_subview_containment_get_8,
test_subview_containment_get_be16,
test_subview_containment_get_be32,
test_subview_containment_get_be64,
test_subview_containment_get_le16,
test_subview_containment_get_le32,
test_subview_containment_get_le64
=
let open Cstruct in
let test get zero () =
let x = create 24 in
let x' = sub x 8 8 in
for i = 0 to len x - 1 do set_uint8 x i 0xff done ;
for i = 0 to len x' - 1 do set_uint8 x' i 0x00 done ;
for i = -8 to 8 do
try
let v = get x' i in
if v <> zero then
failwith "test_subview_containment_get"
with Invalid_argument _ -> ()
done
in
test get_char '\000',
test get_uint8 0,
test BE.get_uint16 0,
test BE.get_uint32 0l,
test BE.get_uint64 0L,
test LE.get_uint16 0,
test LE.get_uint32 0l,
test LE.get_uint64 0L

(* Steamroll over a buffer and a contained subview, checking that only the
* contents of the subview is writable. *)
let test_subview_containment_set_char,
test_subview_containment_set_8,
test_subview_containment_set_be16,
test_subview_containment_set_be32,
test_subview_containment_set_be64,
test_subview_containment_set_le16,
test_subview_containment_set_le32,
test_subview_containment_set_le64
=
let open Cstruct in
let test set ff () =
let x = create 24 in
let x' = sub x 8 8 in
for i = 0 to len x - 1 do set_uint8 x i 0x00 done ;
for i = -8 to 8 do
try set x' i ff with Invalid_argument _ -> ()
done;
let acc = ref 0 in
for i = 0 to len x - 1 do
acc := !acc + get_uint8 x i
done ;
if !acc <> (len x' * 0xff) then
failwith "test_subview_containment_set"
in
test set_char '\255',
test set_uint8 0xff,
test BE.set_uint16 0xffff,
test BE.set_uint32 0xffffffffl,
test BE.set_uint64 0xffffffffffffffffL,
test LE.set_uint16 0xffff,
test LE.set_uint32 0xffffffffl,
test LE.set_uint64 0xffffffffffffffffL

let _ =
let verbose = ref false in
Arg.parse [
Expand All @@ -291,12 +410,14 @@ let _ =
"test positive shift" >:: test_positive_shift;
"test negative shift" >:: test_negative_shift;
"test bad positive shift" >:: test_bad_positive_shift;
"test bad negative shift" >:: test_bad_negative_shift;
"test sub" >:: test_sub;
"test negative sub" >:: test_negative_sub;
"test sub len too big" >:: test_sub_len_too_big;
"test sub len too small" >:: test_sub_len_too_small;
"test sub offset too big" >:: test_sub_offset_too_big;
"test sub offset too small" >:: test_sub_offset_too_small;
"test of_bigarray negative params" >:: test_of_bigarray_negative_params;
"test of_bigarray large offset" >:: test_of_bigarray_large_offset;
"test of_bigarray large length" >:: test_of_bigarray_large_length;
"test set len too big" >:: test_set_len_too_big;
"test set len too small" >:: test_set_len_too_small;
"test add len too big" >:: test_add_len_too_big;
Expand All @@ -317,6 +438,22 @@ let _ =
"test_view_bounds_too_small_get_le16" >:: test_view_bounds_too_small_get_le16;
"test_view_bounds_too_small_get_le32" >:: test_view_bounds_too_small_get_le32;
"test_view_bounds_too_small_get_le64" >:: test_view_bounds_too_small_get_le64;
"test_subview_containment_get_char" >:: test_subview_containment_get_char;
"test_subview_containment_get_8" >:: test_subview_containment_get_8;
"test_subview_containment_get_be16" >:: test_subview_containment_get_be16;
"test_subview_containment_get_be32" >:: test_subview_containment_get_be32;
"test_subview_containment_get_be64" >:: test_subview_containment_get_be64;
"test_subview_containment_get_le16" >:: test_subview_containment_get_le16;
"test_subview_containment_get_le32" >:: test_subview_containment_get_le32;
"test_subview_containment_get_le64" >:: test_subview_containment_get_le64;
"test_subview_containment_set_char" >:: test_subview_containment_set_char;
"test_subview_containment_set_8" >:: test_subview_containment_set_8;
"test_subview_containment_set_be16" >:: test_subview_containment_set_be16;
"test_subview_containment_set_be32" >:: test_subview_containment_set_be32;
"test_subview_containment_set_be64" >:: test_subview_containment_set_be64;
"test_subview_containment_set_le16" >:: test_subview_containment_set_le16;
"test_subview_containment_set_le32" >:: test_subview_containment_set_le32;
"test_subview_containment_set_le64" >:: test_subview_containment_set_le64;
] in
run_test_tt ~verbose:!verbose suite

0 comments on commit 49bb74d

Please sign in to comment.