Skip to content

Commit cf09320

Browse files
Merge pull request #722 from TDacik/malloc_uniqueness
Malloc uniqueness
2 parents 749d92a + 309e5b3 commit cf09320

22 files changed

+424
-88
lines changed

src/analyses/base.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,9 +2680,11 @@ struct
26802680
if get_bool "sem.malloc.fail"
26812681
then AD.join addr AD.null_ptr (* calloc can fail and return NULL *)
26822682
else addr in
2683+
let ik = Cilfacade.ptrdiff_ikind () in
2684+
let blobsize = ID.mul (ID.cast_to ik @@ eval_int (Analyses.ask_of_ctx ctx) gs st size) (ID.cast_to ik @@ eval_int (Analyses.ask_of_ctx ctx) gs st n) in
26832685
(* the memory that was allocated by calloc is set to bottom, but we keep track that it originated from calloc, so when bottom is read from memory allocated by calloc it is turned to zero *)
2684-
set_many ~ctx (Analyses.ask_of_ctx ctx) gs st [(add_null (AD.from_var heap_var), TVoid [], `Array (CArrays.make (IdxDom.of_int (Cilfacade.ptrdiff_ikind ()) BI.one) (`Blob (VD.bot (), eval_int (Analyses.ask_of_ctx ctx) gs st size, false))));
2685-
(eval_lv (Analyses.ask_of_ctx ctx) gs st lv, (Cilfacade.typeOfLval lv), `Address (add_null (AD.from_var_offset (heap_var, `Index (IdxDom.of_int (Cilfacade.ptrdiff_ikind ()) BI.zero, `NoOffset)))))]
2686+
set_many ~ctx (Analyses.ask_of_ctx ctx) gs st [(add_null (AD.from_var heap_var), TVoid [], `Array (CArrays.make (IdxDom.of_int (Cilfacade.ptrdiff_ikind ()) BI.one) (`Blob (VD.bot (), blobsize, false))));
2687+
(eval_lv (Analyses.ask_of_ctx ctx) gs st lv, (Cilfacade.typeOfLval lv), `Address (add_null (AD.from_var_offset (heap_var, `Index (IdxDom.of_int (Cilfacade.ptrdiff_ikind ()) BI.zero, `NoOffset)))))]
26862688
| _ -> st
26872689
end
26882690
| Realloc { ptr = p; size }, _ ->

src/analyses/libraryFunctions.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ let gcc_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[
4141
(** Linux kernel functions. *)
4242
let linux_descs_list: (string * LibraryDesc.t) list = (* LibraryDsl. *) [
4343

44-
]
44+
]
4545

4646
(** Goblint functions. *)
4747
let goblint_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[

src/analyses/mallocWrapperAnalysis.ml

Lines changed: 80 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
open Prelude.Ana
44
open Analyses
55
open GobConfig
6+
open ThreadIdDomain
7+
module Q = Queries
68

7-
module Spec : Analyses.MCPSpec =
9+
module Spec: Analyses.MCPSpec =
810
struct
911
include Analyses.DefaultSpec
1012

@@ -13,24 +15,49 @@ struct
1315
let bot_name = "Unreachable node"
1416
end)
1517

16-
module Node = struct
17-
include Node
18+
module Chain = Lattice.Chain (struct
19+
let n () =
20+
let p = get_int "ana.malloc.unique_address_count" in
21+
if p < 0 then
22+
failwith "Option ana.malloc.unique_address_count has to be non-negative"
23+
else p + 1 (* Unique addresses + top address *)
24+
25+
let names x = if x = (n () - 1) then "top" else Format.asprintf "%d" x
26+
27+
end)
28+
29+
(* Map for counting malloc node visits up to n (of the current thread). *)
30+
module MallocCounter = struct
31+
include MapDomain.MapBot_LiftTop(PL)(Chain)
32+
33+
(* Increase counter for given node. If it does not exists yet, create it. *)
34+
let add_malloc counter node =
35+
let malloc = `Lifted node in
36+
let count = find malloc counter in
37+
if Chain.is_top count then
38+
counter
39+
else
40+
remove malloc counter |> add malloc (count + 1)
41+
end
42+
43+
module ThreadNode = struct
44+
include Printable.Prod3 (ThreadIdDomain.ThreadLifted) (Node) (Chain)
45+
1846
(* Description that gets appended to the varinfo-name in user output. *)
19-
let describe_varinfo (v: varinfo) node =
47+
let describe_varinfo (v: varinfo) (t, node, c) =
2048
let loc = UpdateCil.getLoc node in
2149
CilType.Location.show loc
2250

23-
let name_varinfo node = match node with
24-
| Node.Statement s -> "(alloc@sid:" ^ (string_of_int s.sid) ^ ")"
25-
| _ -> failwith "A function entry or return node can not be the node after a malloc"
51+
let name_varinfo (t, node, c) =
52+
Format.asprintf "(alloc@sid:%s@tid:%s(#%s))" (Node.show_id node) (ThreadLifted.show t) (Chain.show c)
53+
2654
end
2755

28-
module NodeVarinfoMap = RichVarinfo.BiVarinfoMap.Make(Node)
56+
module NodeVarinfoMap = RichVarinfo.BiVarinfoMap.Make(ThreadNode)
2957
let name () = "mallocWrapper"
30-
module D = PL
31-
module C = D
3258

33-
module Q = Queries
59+
module D = Lattice.Prod (MallocCounter) (PL)
60+
module C = D
3461

3562
let wrappers = Hashtbl.create 13
3663

@@ -48,42 +75,64 @@ struct
4875
ctx.local
4976

5077
let enter ctx (lval: lval option) (f:fundec) (args:exp list) : (D.t * D.t) list =
51-
let calleeofinterest = Hashtbl.mem wrappers f.svar.vname in
52-
let calleectx = if calleeofinterest then
53-
if ctx.local = `Top then
54-
`Lifted ctx.node (* if an interesting callee is called by an uninteresting caller, then we remember the callee context *)
55-
else ctx.local (* if an interesting callee is called by an interesting caller, then we remember the caller context *)
56-
else D.top () in (* if an uninteresting callee is called, then we forget what was called before *)
57-
[(ctx.local, calleectx)]
58-
59-
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) : D.t =
60-
ctx.local
61-
62-
let special ctx (lval: lval option) (f:varinfo) (arglist:exp list) : D.t =
63-
ctx.local
78+
let counter, wrapper_node = ctx.local in
79+
let new_wrapper_node =
80+
if Hashtbl.mem wrappers f.svar.vname then
81+
match wrapper_node with
82+
| `Lifted _ -> wrapper_node (* if an interesting callee is called by an interesting caller, then we remember the caller context *)
83+
| _ -> (`Lifted ctx.node) (* if an interesting callee is called by an uninteresting caller, then we remember the callee context *)
84+
else
85+
PL.top () (* if an uninteresting callee is called, then we forget what was called before *)
86+
in
87+
let callee = (counter, new_wrapper_node) in
88+
[(ctx.local, callee)]
89+
90+
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc ((counter, _):D.t) : D.t =
91+
(* Keep (potentially higher) counter from callee and keep wrapper node from caller *)
92+
let _, lnode = ctx.local in
93+
(counter, lnode)
94+
95+
let special (ctx: (D.t, G.t, C.t, V.t) ctx) (lval: lval option) (f:varinfo) (arglist:exp list) : D.t =
96+
let desc = LibraryFunctions.find f in
97+
match desc.special arglist with
98+
| Malloc _ | Calloc _ | Realloc _ ->
99+
let counter, wrapper_node = ctx.local in
100+
(MallocCounter.add_malloc counter ctx.node, wrapper_node)
101+
| _ -> ctx.local
64102

65103
let startstate v = D.bot ()
66-
let threadenter ctx lval f args = [D.top ()]
104+
105+
let threadenter ctx lval f args =
106+
(* The new thread receives a fresh counter *)
107+
[D.bot ()]
108+
67109
let threadspawn ctx lval f args fctx = ctx.local
68110
let exitstate v = D.top ()
69111

70112
type marshal = NodeVarinfoMap.marshal
71113

72114
let get_heap_var = NodeVarinfoMap.to_varinfo
73-
let query (ctx: (D.t, G.t, C.t, V.t) ctx) (type a) (q: a Q.t): a Queries.result =
115+
116+
117+
let query (ctx: (D.t, G.t, C.t, V.t) ctx) (type a) (q: a Q.t): a Q.result =
118+
let counter, wrapper_node = ctx.local in
74119
match q with
75120
| Q.HeapVar ->
76-
let node = match ctx.local with
77-
| `Lifted vinfo -> vinfo
121+
let node = match wrapper_node with
122+
| `Lifted wrapper_node -> wrapper_node
78123
| _ -> ctx.node
79124
in
80-
let var = get_heap_var node in
125+
let count = MallocCounter.find (`Lifted node) counter in
126+
let var = get_heap_var (ctx.ask Q.CurrentThreadId, node, count) in
81127
var.vdecl <- UpdateCil.getLoc node; (* TODO: does this do anything bad for incremental? *)
82128
`Lifted var
83129
| Q.IsHeapVar v ->
84130
NodeVarinfoMap.mem_varinfo v
85131
| Q.IsMultiple v ->
86-
NodeVarinfoMap.mem_varinfo v
132+
begin match NodeVarinfoMap.from_varinfo v with
133+
| Some (_, _, c) -> Chain.is_top c || not (ctx.ask Q.MustBeUniqueThread)
134+
| None -> false
135+
end
87136
| _ -> Queries.Result.top q
88137

89138
let init marshal =
@@ -95,4 +144,4 @@ struct
95144
end
96145

97146
let _ =
98-
MCP.register_analysis (module Spec : MCPSpec)
147+
MCP.register_analysis (module Spec)

src/cdomains/threadFlagDomain.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ module Simple: S =
3030
struct
3131
module SimpleNames =
3232
struct
33-
let n = 3
33+
let n () = 3
3434
let names = function
3535
| 0 -> "Singlethreaded"
3636
| 1 -> "Multithreaded (main)"

src/cdomains/valueDomain.ml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ struct
335335
let one_addr = let open Addr in function
336336
(* only allow conversion of float pointers if source and target type are the same *)
337337
| Addr ({ vtype = TFloat(fkind, _); _}, _) as x when (match t with TFloat (fkind', _) when fkind = fkind' -> true | _ -> false) -> x
338-
(* do not allow conversion from/to float pointers*)
338+
(* do not allow conversion from/to float pointers*)
339339
| Addr ({ vtype = TFloat(_); _}, _) -> UnknownPtr
340340
| _ when (match t with TFloat _ -> true | _ -> false) -> UnknownPtr
341341
| Addr ({ vtype = TVoid _; _} as v, offs) when not (Cilfacade.isCharType t) -> (* we had no information about the type (e.g. malloc), so we add it; ignore for casts to char* since they're special conversions (N1570 6.3.2.3.7) *)
@@ -914,7 +914,22 @@ struct
914914
begin
915915
let l', o' = shift_one_over l o in
916916
let x = zero_init_calloced_memory orig x t in
917-
mu (`Blob (join x (do_update_offset ask x offs value exp l' o' v t), s, orig))
917+
(* Strong update of scalar variable is possible if the variable is unique and size of written value matches size of blob being written to. *)
918+
let do_strong_update =
919+
begin match v with
920+
| (Var var, _) ->
921+
let blob_size_opt = ID.to_int s in
922+
not @@ ask.f (Q.IsMultiple var)
923+
&& not @@ Cil.isVoidType t (* Size of value is known *)
924+
&& Option.is_some blob_size_opt (* Size of blob is known *)
925+
&& BI.equal (Option.get blob_size_opt) (BI.of_int @@ Cil.alignOf_int t)
926+
| _ -> false
927+
end
928+
in
929+
if do_strong_update then
930+
`Blob ((do_update_offset ask x offs value exp l' o' v t), s, orig)
931+
else
932+
mu (`Blob (join x (do_update_offset ask x offs value exp l' o' v t), s, orig))
918933
end
919934
| `Thread _, _ ->
920935
(* hack for pthread_t variables *)

src/domains/lattice.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -580,8 +580,8 @@ struct
580580

581581
let bot () = 0
582582
let is_bot x = x = 0
583-
let top () = P.n - 1
584-
let is_top x = x = P.n - 1
583+
let top () = P.n () - 1
584+
let is_top x = x = P.n () - 1
585585

586586
let leq x y = x <= y
587587
let join x y = max x y

src/domains/printable.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ struct
463463
end
464464

465465
module type ChainParams = sig
466-
val n: int
466+
val n: unit -> int
467467
val names: int -> string
468468
end
469469

@@ -477,7 +477,7 @@ struct
477477
let printXml f x = BatPrintf.fprintf f "<value>\n<data>\n%s\n</data>\n</value>\n" (P.names x)
478478
let to_yojson x = `String (P.names x)
479479

480-
let arbitrary () = QCheck.int_range 0 (P.n - 1)
480+
let arbitrary () = QCheck.int_range 0 (P.n () - 1)
481481
let relift x = x
482482
end
483483

src/util/options.schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,12 @@
749749
"kmalloc", "__kmalloc", "usb_alloc_urb", "__builtin_alloca",
750750
"kzalloc"
751751
]
752+
},
753+
"unique_address_count": {
754+
"title": "ana.malloc.unique_address_count",
755+
"description": "Number of unique memory addresses allocated for each malloc node.",
756+
"type": "integer",
757+
"default": 0
752758
}
753759
},
754760
"additionalProperties": false

src/witness/observerAnalysis.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ struct
2424
module ChainParams =
2525
struct
2626
(* let n = List.length Arg.path *)
27-
let n = -1
27+
let n () = -1
2828
let names x = "state " ^ string_of_int x
2929
end
3030
module D = Lattice.Flat (Printable.Chain (ChainParams)) (Printable.DefaultNames)

src/witness/yamlWitness.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ struct
194194

195195
module ChainParams =
196196
struct
197-
let n = max_result - 1
197+
let n () = max_result - 1
198198
let names i = show_result (Option.get (result_of_enum i))
199199
end
200200
include Lattice.Chain (ChainParams)

0 commit comments

Comments
 (0)