Skip to content

Commit 8f28a38

Browse files
author
Ronald Judin
committed
Deleted is_sink and is_source, added checking for pointers, added tracking and warning to special, experimented with SplitBranch
1 parent ac87d38 commit 8f28a38

File tree

3 files changed

+42
-45
lines changed

3 files changed

+42
-45
lines changed

src/analyses/ocaml.ml

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,6 @@ open Analyses
1010

1111
module VarinfoSet = SetDomain.Make(CilType.Varinfo)
1212

13-
(* Use to check if a specific function is a sink / source *)
14-
(* Sources take value-typed arguments *)
15-
(* Sinks may trigger garbage collection *)
16-
let is_sink varinfo = Cil.hasAttribute "ocaml_sink" varinfo.vattr
17-
let is_source varinfo = Cil.hasAttribute "ocaml_source" varinfo.vattr
18-
19-
2013
(** "Fake" variable to handle returning from a function *)
2114
let return_varinfo = dummyFunDec.svar
2215

@@ -84,12 +77,12 @@ struct
8477
| AlignOfE e
8578
| CastE (_,e)
8679
| UnOp (_,e,_) -> exp_accounted_for state e
87-
| SizeOf _ | SizeOfStr _ | Const _ | AlignOf _ | AddrOfLabel _ -> false
80+
| SizeOf _ | SizeOfStr _ | Const _ | AlignOf _ | AddrOfLabel _ -> true
8881
| Question (b, t, f, _) -> exp_accounted_for state b && exp_accounted_for state t && exp_accounted_for state f
8982
and lval_accounted_for state = function
9083
| (Var v, _) ->
9184
(* Checks whether variable v is accounted for *) (*false*)
92-
if D.mem_a v state || not (D.mem_t v state) then true else let _ = M.warn "Value %a might be garbage collected" CilType.Varinfo.pretty v in false
85+
if D.mem_a v state || not (D.mem_t v state) then true else (M.warn "Value %a might be garbage collected" CilType.Varinfo.pretty v; false)
9386
| _ ->
9487
(* The Gemara asks: is using an offset safe for the expression? The Gemara answers: by default, no. We assume our language has no pointers *)
9588
false
@@ -123,11 +116,15 @@ struct
123116
let state = ctx.local in
124117
match lval with
125118
| Var v,_ ->
126-
(* If lval is of type value, checks whether rval is accounted for, handles assignment to v accordingly *) (* state *)
127-
if exp_accounted_for state rval then
128-
if exp_tracked state rval then D.add_a v (D.add_t v state)
129-
else D.add_a v (D.remove_t v state)
130-
else let _ = M.info "The above is being assigned" in D.remove_a v (D.add_t v state)
119+
(* If rval is a pointer, checks whether rval is accounted for, handles assignment to v accordingly *) (* state *)
120+
(* Emits an event for the variable v not being zero. *)
121+
ctx.emit (Events.SplitBranch (Cil.BinOp (Cil.Eq, Cil.Lval lval, Cil.zero, Cil.intType), false));
122+
if Cil.isPointerType (Cil.typeOf rval) then
123+
if exp_accounted_for state rval then
124+
if exp_tracked state rval then D.add_a v (D.add_t v state)
125+
else D.add_a v (D.remove_t v state) (* TODO: Is add_a necessary for untracked variables? *)
126+
else (M.info "The above is being assigned"; D.remove_a v (D.add_t v state))
127+
else D.remove_t v state
131128
| _ -> state
132129

133130
(** Handles conditional branching yielding truth value [tv]. *)
@@ -152,7 +149,7 @@ struct
152149
(* TODO: Consider how the return_varinfo needs to be tracked. *)
153150
(* state *)
154151
if exp_accounted_for state e then D.add_a return_varinfo state
155-
else let _ = M.warn "Value returned might be garbage collected" in D.remove_a return_varinfo state
152+
else (M.warn "Value returned might be garbage collected"; D.remove_a return_varinfo state)
156153
| None -> state
157154

158155
(** For a function call "lval = f(args)" or "f(args)",
@@ -193,7 +190,7 @@ struct
193190
(* TODO: Consider how the return_varinfo needs to be tracked. *)
194191
match lval with (* The variable returned is played by return_varinfo *)
195192
| Some (Var v, _) -> if D.mem_a return_varinfo callee_local then D.add_a v caller_state
196-
else let _ = M.warn "Returned value may be garbage-collected" in D.remove_a v caller_state
193+
else (M.warn "Returned value may be garbage-collected"; D.remove_a v caller_state)
197194
| _ -> caller_state
198195

199196
(** For a call to a _special_ function f "lval = f(args)" or "f(args)",
@@ -206,34 +203,25 @@ struct
206203
(* caller_state *)
207204
let desc = LibraryFunctions.find f in
208205
match desc.special arglist with
209-
(* Variables are registered with a Param macro. *)
210206
| OCamlParam params ->
211-
List.fold_left (fun state param -> let _ = M.info "We reach here" in
207+
(* Variables are registered with a Param macro. Such variables are also tracked. *)
208+
List.fold_left (fun state param -> M.debug "We reach here";
212209
match param with
213-
| AddrOf (Var v, _) -> let _ = M.info "Address of" in
214-
D.add_r v state
210+
| AddrOf (Var v, _) -> M.debug "Address of";
211+
D.add_r v (D.add_t v state)
215212
| _ -> state
216213
) caller_state params
217214
| OCamlAlloc size_exp ->
218-
(* Garbage collection may trigger here and overwrite unregistered variables *)
219-
let _ = M.debug "Garbage collection triggers" in (match lval with
220-
| Some (Var v, _) -> D.add_a v (D.after_gc caller_state)
221-
| _ ->
222-
(* if not (List.for_all (exp_accounted_for caller_state) arglist) then let _ = M.warn "GC might delete value" in D.empty () else *) D.empty ()
223-
)
215+
(* Garbage collection may trigger here and overwrite unregistered variables. *)
216+
M.debug "Garbage collection triggers";
217+
List.iter (fun e -> ignore (exp_accounted_for caller_state e)) arglist; (* Just to trigger warnings *)
218+
(match lval with
219+
| Some (Var v, _) -> D.add_a v (D.add_t v (D.after_gc caller_state))
220+
| _ -> D.after_gc caller_state
221+
)
224222
| _ ->
225-
List.iter (fun e -> ignore (exp_accounted_for caller_state e)) arglist; (* Just to trigger warnings for arguments passed to sinks/sources *)
226-
if is_source f then match lval with (* Assigning the source's result makes the variable accounted for. *)
227-
| Some (Var v, _) -> D.add_a v caller_state
228-
| _ -> caller_state
229-
else
230-
if is_sink f then (* Warns if unaccounted variables reach the function. Empties the state of unregistered variables. *)
231-
let _ = M.debug "Garbage collection triggers" in match lval with
232-
| Some (Var v, _) -> D.add_a v (D.after_gc caller_state)
233-
| _ ->
234-
(* if not (List.for_all (exp_accounted_for caller_state) arglist) then let _ = M.warn "GC might delete value" in D.empty () else *)
235-
D.after_gc caller_state
236-
else caller_state
223+
List.iter (fun e -> ignore (exp_accounted_for caller_state e)) arglist; (* Just to trigger warnings for arguments passed to special functions *)
224+
caller_state
237225

238226
(* You may leave these alone *)
239227
let startstate v = D.bot ()

src/util/library/libraryFunctions.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,8 @@ let ocaml_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[
12471247
("caml_copy_double", special [drop "nptr" []] (OCamlAlloc (GoblintCil.integer 1)));
12481248
(* Eeskuju: ("malloc", special [__ "size" []] @@ fun size -> Malloc size); *)
12491249
("caml_alloc_small", special [__ "wosize" []; __ "tag" []] @@ fun wosize tag -> OCamlAlloc wosize);
1250+
(* TODO: This specification is not correct because it doesn't warn where it should. Also rethink the argument names. *)
1251+
("caml_alloc_3", special [__ "tag" []; __ "arg1" [r]; __ "arg2" [r]; __ "arg3" [r]] @@ fun tag _arg1 _arg2 _arg3 -> OCamlAlloc (GoblintCil.integer 3));
12501252
("__goblint_caml_param0", special [] @@ OCamlParam []);
12511253
("__goblint_caml_param1", special [__ "param" []] @@ fun param -> OCamlParam [param]);
12521254
("__goblint_caml_param2", special [__ "param1" []; __ "param2" []] @@ fun param1 param2 -> OCamlParam [param1; param2]);
Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// PARAM: --set "ana.activated[+]" ocaml --set "mainfun[+]" "caml_gc_counters" --set "mainfun[+]" "caml_gc_counters_correct" --disable warn.imprecise --set "exp.extraspecials[+]" printInt
22

3-
// OCaml code fixed by Demi Marie Obenour in https://github.com/ocaml/ocaml/pull/13370, before and after the fix.
3+
// Buggy code from https://github.com/ocaml/ocaml/pull/13370 where some local variables are not registered.
44

55
#include <caml/mlvalues.h>
66
#include <caml/alloc.h>
@@ -11,10 +11,12 @@
1111

1212
#define CAMLparam0() __goblint_caml_param0()
1313
#define CAMLparam1(x) __goblint_caml_param1(&x)
14-
#define CAMLlocal1(x) __goblint_caml_param1(&x) // The local and param functions behave the same for our purposes, registering variables.
15-
#define CAMLlocal3(x, y, z) __goblint_caml_param3(&x, &y, &z)
14+
#define CAMLlocal1(x) value x = Val_unit; __goblint_caml_param1(&x) // The local and param functions behave the same for our purposes, registering variables.
15+
#define CAMLlocal3(x, y, z) value x = Val_unit; value y = Val_unit; value z = Val_unit; __goblint_caml_param3(&x, &y, &z)
1616
#define CAMLreturn(x) return (x) // From AI - CAMLreturn needs some variable named caml__frame, which is not available in our mock CAMLparam1, so we mock the return as well.
1717

18+
// A reference to caml_gc_minor_words_unboxed can be found in _opam/lib/ocaml/ml/gc.ml.
19+
#define caml_gc_minor_words_unboxed() (0.0) // TODO: Put a value here that's in the OCaml heap.
1820

1921
CAMLprim value caml_gc_counters(value v)
2022
{
@@ -23,10 +25,13 @@ CAMLprim value caml_gc_counters(value v)
2325

2426
/* get a copy of these before allocating anything... */
2527
double minwords = caml_gc_minor_words_unboxed();
26-
double prowords = (double)Caml_state->stat_promoted_words;
28+
/*double prowords = (double)Caml_state->stat_promoted_words;
2729
double majwords = Caml_state->stat_major_words +
28-
(double) Caml_state->allocated_words;
30+
(double) Caml_state->allocated_words;*/
31+
double prowords = v; // It does not find the Caml_state so dummy values are used for the test. The argument v, which is otherwise unused, is used as the dummy value because it allows for simulating the variables' registration.
32+
double majwords = v;
2933

34+
// Evaluating one argument could erase the next variables.
3035
res = caml_alloc_3(0,
3136
caml_copy_double(minwords),
3237
caml_copy_double(prowords),
@@ -41,9 +46,11 @@ CAMLprim value caml_gc_counters_correct(value v)
4146

4247
/* get a copy of these before allocating anything... */
4348
double minwords = caml_gc_minor_words_unboxed();
44-
double prowords = (double)Caml_state->stat_promoted_words;
49+
/*double prowords = (double)Caml_state->stat_promoted_words;
4550
double majwords = Caml_state->stat_major_words +
46-
(double) Caml_state->allocated_words;
51+
(double) Caml_state->allocated_words;*/
52+
double prowords = 0;
53+
double majwords = 0;
4754

4855
minwords_ = caml_copy_double(minwords);
4956
prowords_ = caml_copy_double(prowords);

0 commit comments

Comments
 (0)