Skip to content

Commit 9917a29

Browse files
author
Ronald Judin
committed
Macros redefined in goblint_caml, SplitBranch checks type
1 parent 8f28a38 commit 9917a29

File tree

6 files changed

+50
-51
lines changed

6 files changed

+50
-51
lines changed

src/analyses/ocaml.ml

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ struct
118118
| Var v,_ ->
119119
(* If rval is a pointer, checks whether rval is accounted for, handles assignment to v accordingly *) (* state *)
120120
(* 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));
121+
122122
if Cil.isPointerType (Cil.typeOf rval) then
123123
if exp_accounted_for state rval then
124124
if exp_tracked state rval then D.add_a v (D.add_t v state)
@@ -137,7 +137,14 @@ struct
137137
let body ctx (f:fundec) : D.t =
138138
(* The (non-formals) locals are tracked and initially accounted for *)
139139
let state = ctx.local in
140-
List.fold_left (fun st v -> D.add_a v (D.add_t v st)) state f.sformals
140+
(* It is assumed that value-typed arguments are never nptrs. *)
141+
let is_value_type (t:typ): bool = match t with
142+
| TNamed (info, attr) -> info.tname = "value"
143+
| _ -> false in
144+
List.fold_left (fun st v -> if is_value_type v.vtype then
145+
(ctx.emit (Events.SplitBranch (Cil.Lval (Cil.var v), true)); D.add_a v (D.add_t v st))
146+
else D.add_a v (D.add_t v st))
147+
state f.sformals
141148

142149
(** Handles the [return] statement, i.e. "return exp" or "return", in function [f]. *)
143150
let return ctx (exp:exp option) (f:fundec) : D.t =
@@ -205,12 +212,10 @@ struct
205212
match desc.special arglist with
206213
| OCamlParam params ->
207214
(* Variables are registered with a Param macro. Such variables are also tracked. *)
208-
List.fold_left (fun state param -> M.debug "We reach here";
209-
match param with
210-
| AddrOf (Var v, _) -> M.debug "Address of";
211-
D.add_r v (D.add_t v state)
212-
| _ -> state
213-
) caller_state params
215+
List.fold_left (fun state param -> match param with
216+
| AddrOf (Var v, _) -> D.add_r v (D.add_t v state)
217+
| _ -> state
218+
) caller_state params
214219
| OCamlAlloc size_exp ->
215220
(* Garbage collection may trigger here and overwrite unregistered variables. *)
216221
M.debug "Garbage collection triggers";

src/util/library/libraryFunctions.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,10 +1245,12 @@ let legacy_libs_misc_list: (string * LibraryDesc.t) list = LibraryDsl.[
12451245

12461246
let ocaml_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[
12471247
("caml_copy_double", special [drop "nptr" []] (OCamlAlloc (GoblintCil.integer 1)));
1248-
(* Eeskuju: ("malloc", special [__ "size" []] @@ fun size -> Malloc size); *)
1248+
(* Example: ("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. *)
1250+
("caml_alloc_2", special [__ "tag" []; __ "arg1" [r]; __ "arg2" [r]] @@ fun tag _arg1 _arg2 -> OCamlAlloc (GoblintCil.integer 2));
12511251
("caml_alloc_3", special [__ "tag" []; __ "arg1" [r]; __ "arg2" [r]; __ "arg3" [r]] @@ fun tag _arg1 _arg2 _arg3 -> OCamlAlloc (GoblintCil.integer 3));
1252+
("caml_alloc_4", special [__ "tag" []; __ "arg1" [r]; __ "arg2" [r]; __ "arg3" [r]; __ "arg4" [r]] @@ fun tag _arg1 _arg2 _arg3 _arg4 -> OCamlAlloc (GoblintCil.integer 4));
1253+
("caml_alloc_5", special [__ "tag" []; __ "arg1" [r]; __ "arg2" [r]; __ "arg3" [r]; __ "arg4" [r]; __ "arg5" [r]] @@ fun tag _arg1 _arg2 _arg3 _arg4 _arg5 -> OCamlAlloc (GoblintCil.integer 5));
12521254
("__goblint_caml_param0", special [] @@ OCamlParam []);
12531255
("__goblint_caml_param1", special [__ "param" []] @@ fun param -> OCamlParam [param]);
12541256
("__goblint_caml_param2", special [__ "param1" []; __ "param2" []] @@ fun param1 param2 -> OCamlParam [param1; param2]);

tests/regression/90-ocaml/01-bagnall.c

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,7 @@
66
#include <string.h>
77
#include <caml/mlvalues.h>
88
#include <caml/alloc.h>
9-
#include <caml/memory.h>
10-
11-
/* A small definition of the LXM state so sizeof works - from AI */
12-
struct LXM_state { uint64_t a; uint64_t x[2]; uint64_t s; };
13-
14-
/* Minimal macros to mimic expected behaviour */
15-
#define Wsizeof(ty) ((sizeof(ty) + sizeof(value) - 1) / sizeof(value))
16-
#define LXM_val(v) ((struct LXM_state *) Data_abstract_val(v))
17-
18-
#define CAMLparam1(x) __goblint_caml_param1(&x)
19-
#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.
20-
21-
/*CAMLextern value caml_alloc_small (mlsize_t wosize, tag_t) __attribute__((__ocaml_sink__));*/
9+
#include "goblint_caml.h"
2210

2311
CAMLprim value pringo_LXM_copy(value v)
2412
{

tests/regression/90-ocaml/02-floatops.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,6 @@
22

33
// Code from stubs.c in src/common/cdomains/floatOps that should be correct despite missing CAMLparam, as discussed in https://github.com/goblint/analyzer/issues/1371.
44

5-
/* A small definition of the LXM state so sizeof works - from AI */
6-
//struct LXM_state { uint64_t a; uint64_t x[2]; uint64_t s; };
7-
8-
/* Minimal macros to mimic expected behaviour */
9-
#define Wsizeof(ty) ((sizeof(ty) + sizeof(value) - 1) / sizeof(value))
10-
#define LXM_val(v) ((struct LXM_state *) Data_abstract_val(v))
11-
12-
#define CAMLparam1(x) __goblint_caml_param1(&x)
13-
#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.
14-
15-
165
#define _GNU_SOURCE // necessary for M_PI to be defined
176
#include <stdio.h>
187
#include <math.h>
@@ -21,6 +10,7 @@
2110
#include <assert.h>
2211
#include <caml/mlvalues.h>
2312
#include <caml/alloc.h>
13+
#include "goblint_caml.h"
2414

2515
// Order must match with round_mode in floatOps.ml
2616
enum round_mode

tests/regression/90-ocaml/03-obenour.c

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,10 @@
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-
// Buggy code from https://github.com/ocaml/ocaml/pull/13370 where some local variables are not registered.
3+
// Buggy code from https://github.com/ocaml/ocaml/pull/13370 where unregistered temporary variables may be garbage-collected.
44

55
#include <caml/mlvalues.h>
66
#include <caml/alloc.h>
7-
8-
/* Minimal macros to mimic expected behaviour */
9-
#define Wsizeof(ty) ((sizeof(ty) + sizeof(value) - 1) / sizeof(value))
10-
#define LXM_val(v) ((struct LXM_state *) Data_abstract_val(v))
11-
12-
#define CAMLparam0() __goblint_caml_param0()
13-
#define CAMLparam1(x) __goblint_caml_param1(&x)
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)
16-
#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.
17-
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.
7+
#include "goblint_caml.h"
208

219
CAMLprim value caml_gc_counters(value v)
2210
{
@@ -28,10 +16,9 @@ CAMLprim value caml_gc_counters(value v)
2816
/*double prowords = (double)Caml_state->stat_promoted_words;
2917
double majwords = Caml_state->stat_major_words +
3018
(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;
19+
double prowords = 0; // It does not find the Caml_state so dummy values are used for the test.
20+
double majwords = 0;
3321

34-
// Evaluating one argument could erase the next variables.
3522
res = caml_alloc_3(0,
3623
caml_copy_double(minwords),
3724
caml_copy_double(prowords),
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* Redefinitions of caml macros for the C-stub analysis. This file replaces caml/memory.h in tests' imports. */
2+
3+
/* A small definition of the LXM state so sizeof works - from AI */
4+
struct LXM_state { uint64_t a; uint64_t x[2]; uint64_t s; };
5+
6+
/* Minimal macros to mimic expected behaviour */
7+
#define Wsizeof(ty) ((sizeof(ty) + sizeof(value) - 1) / sizeof(value))
8+
#define LXM_val(v) ((struct LXM_state *) Data_abstract_val(v))
9+
10+
// Param and local macros redefined to register variables as GC roots, and CAMLreturn mocked to work with them.
11+
#define CAMLparam0() __goblint_caml_param0()
12+
#define CAMLparam1(x) __goblint_caml_param1(&x)
13+
#define CAMLparam2(x, y) __goblint_caml_param2(&x, &y)
14+
#define CAMLparam3(x, y, z) __goblint_caml_param3(&x, &y, &z)
15+
#define CAMLparam4(x, y, z, w) __goblint_caml_param4(&x, &y, &z, &w)
16+
#define CAMLparam5(x, y, z, w, v) __goblint_caml_param5(&x, &y, &z, &w, &v)
17+
18+
#define CAMLlocal1(x) value x = Val_unit; __goblint_caml_param1(&x) // The local and param functions behave the same for our purposes, registering variables.
19+
#define CAMLlocal2(x, y) value x = Val_unit; value y = Val_unit; __goblint_caml_param2(&x, &y)
20+
#define CAMLlocal3(x, y, z) value x = Val_unit; value y = Val_unit; value z = Val_unit; __goblint_caml_param3(&x, &y, &z)
21+
#define CAMLlocal4(x, y, z, w) value x = Val_unit; value y = Val_unit; value z = Val_unit; value w = Val_unit; __goblint_caml_param4(&x, &y, &z, &w)
22+
#define CAMLlocal5(x, y, z, w, v) value x = Val_unit; value y = Val_unit; value z = Val_unit; value w = Val_unit; value v = Val_unit; __goblint_caml_param5(&x, &y, &z, &w, &v)
23+
24+
#define CAMLreturn(x) return (x) // The real CAMLreturn needs some variable named caml__frame, which is not available in our redefinitions above.
25+
26+
// A reference to caml_gc_minor_words_unboxed can be found in _opam/lib/ocaml/ml/gc.ml.
27+
#define caml_gc_minor_words_unboxed() (0.0)

0 commit comments

Comments
 (0)