package monolith

  1. Overview
  2. Docs

Source file Gen.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
(******************************************************************************)
(*                                                                            *)
(*                                  Monolith                                  *)
(*                                                                            *)
(*                              François Pottier                              *)
(*                                                                            *)
(*  Copyright Inria. All rights reserved. This file is distributed under the  *)
(*  terms of the GNU Lesser General Public License as published by the Free   *)
(*  Software Foundation, either version 3 of the License, or (at your         *)
(*  option) any later version, as described in the file LICENSE.              *)
(*                                                                            *)
(******************************************************************************)

(* This module offers facilities for generating values of various types,
   based on data that is read from our standard input channel (which is
   controlled by afl-fuzz). *)

open Misc
open Error

(* -------------------------------------------------------------------------- *)

(* The exception [Reject] is raised to indicate that a wrong choice was made
   during data generation, so this test should be silently stopped. E.g.,
   attempting to choose an object from an empty list raises [Reject]. *)

exception Reject

let reject () =
  raise Reject

let guard b =
  if not b then reject()

(* -------------------------------------------------------------------------- *)

(* The data generation functions require a source of bits, which is internally
   represented as an input channel. *)

(* The function [with_source s f] makes the source [s] available during the
   execution of the function call [f()]. If [s] is [None], random data is
   used; if [s] is [Some filename], then input data is read from the file
   [filename]. In the latter case, any of the data generation functions can
   raise [Reject] at any time, as the input data file can be exhausted. *)

(* The channel through which input bits are read. *)

let source =
  ref stdin

let set_source s =
  match s with
  | None ->
      source := open_in "/dev/urandom"
  | Some filename ->
      source := open_in filename

let close_source () =
  close_in_noerr !source

let with_source s f =
  set_source s;
  Fun.protect ~finally:close_source f

(* -------------------------------------------------------------------------- *)

(* Generators. *)

type 'a gen =
  unit -> 'a

exception OutOfInputData

(* [wrap f x] invokes [f x], which is expected to read some data from
   the input channel, and handles the exceptions that might result. *)

let wrap f x =
  try
    f x
  with
  | End_of_file ->
      (* The input stream has been exhausted. We remap to a different
         exception so as to avoid any confusion. *)
      raise OutOfInputData
  | Sys_error _ ->
      (* The source channel seems to have been closed. It is likely that
         a data generation function has been invoked outside of the data
         generation phase. *)
      error "Monolith.Gen.* cannot be used outside of Monolith.main."

(* [byte()] produces an unsigned 8-bit integer. *)

let byte () =
  wrap input_byte !source

(* [short()] produces an unsigned 16-bit integer. *)

let short () =
  byte() lsl 8 lor byte()

(* [long()] produces an unsigned 32-bit integer. *)

let long () =
  assert (Sys.word_size > 32);
  short() lsl 16 lor short()

(* [signed_long()] produces a signed 32-bit integer. *)

(* On a 32-bit machine, I expect that we get only 31 bits. *)

let signed_long () =
  wrap input_binary_int !source

(* [bits()] produces a signed integer. All values of type [int] can in
   principle be produced. *)

let bits63 () =
  (signed_long() lsl 31) lor (signed_long() land (1 lsl 32 - 1))

let bits () =
  match Sys.word_size with
  | 32 ->
      signed_long()
  | 64 ->
      bits63()
  | _ ->
      assert false

(* [bool()] produces a Boolean. *)

let bool () =
  let b = byte() in
  b land 1 = 1

(* [char()] produces a character. *)

let char () =
  let b = byte() in
  Char.chr b

(* [log2 n] is the base two logarithm of [n]. *)

let rec log2 accu n =
  if n = 1 then
    accu
  else
    log2 (accu + 1) (n lsr 1)

let log2 n =
  assert (0 < n);
  log2 0 n

(* [next_power_of_two n] is the smallest power of two that is strictly
   greater than [n]. *)

let next_power_of_two n =
  1 lsl (log2 n + 1)

(* [mask n] is a mask (a sequence of "1" bits), and it is the smallest
   mask such that [n land (mask n)] is [n]. *)

let mask n =
  next_power_of_two n - 1

(* [truncate n i] truncates the integer [i], which may be larger than [n],
   so that it fits in the semi-open interval [0, n). *)

(* This could be done just by computing [i mod n]. However, it is perhaps
   preferable to avoid depending on the most significant bits of [i]; this may
   help afl-fuzz detect that these bits are irrelevant. For this reason, we
   first perform a logical AND against [mask n]. *)

let truncate n i =
  assert (0 < n);
  assert (0 <= i);
  (i land (mask n)) mod n

let int n () =
  guard (0 < n);
  if n = 1 then
    (* Read 0 bits of input data. *)
    0
  else if n <= 1 lsl 8 then
    (* Read 8 bits of input data. *)
    byte() |> truncate n
  else if n <= 1 lsl 16 then
    (* Read 16 bits of input data. *)
    short() |> truncate n
  else if n <= 1 lsl 32 then
    long() |> truncate n
  else begin
    assert (Sys.word_size = 64);
    (bits63() land max_int) |> truncate n
  end

let choose xs =
  let xs = Array.of_list xs in
  fun () ->
    let n = Array.length xs in
    let i = int n () in
    xs.(i)

let lt j =
  int j

let le j =
  int (j + 1)

let semi_open_interval i j () =
  if i < j then begin
    assert (0 < j - i); (* protect against overflow *)
    i + int (j - i) ()
  end
  else
    reject()

(* We do not define [closed_interval i j] as [semi_open_interval i (j + 1)]
   because this definition does not work when [j] is [max_int]. *)

let closed_interval i j () =
  if i <= j then begin
    assert (0 <= j - i && j - i < max_int); (* protect against overflow *)
    i + int (j - i + 1) ()
  end
  else
    reject()

let sequential () =
  (* The reference that is allocated here is a piece of state that may need to
     be reset at the beginning of every run, so that all runs begin with the
     same initial state. Thus, it must be declared. We do not know whether
     [GlobalState.save] has been called already, or has not been called yet.
     We exploit the fact that it is permitted to call [GlobalState.register]
     at any time. *)
  let r = ref 0 in
  GlobalState.register_ref r;
  fun () ->
    postincrement r

let option element () =
  if bool() then
    None
  else
    Some (element())

let result left right () =
  if bool() then
    Ok (left())
  else
    Error (right())

(* A simplified version of [List.init]. *)
let rec init f accu k =
  if k = 0 then accu else init f (f() :: accu) (k - 1)

let list n element () =
  init element [] (n())

let array n element () =
  Array.init (n ()) (fun _i -> element())

let string n char () =
  String.init (n ()) (fun _i -> char())
OCaml

Innovation. Community. Security.