Skip to content

Commit 9cea9fb

Browse files
committed
Add first version of a simple memory leak analysis
1 parent c72fded commit 9cea9fb

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

src/analyses/memLeak.ml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
(** An analysis for the detection of memory leaks ([memLeak]). *)
2+
3+
open GoblintCil
4+
open Analyses
5+
open MessageCategory
6+
7+
module ToppedVarInfoSet = SetDomain.ToppedSet(CilType.Varinfo)(struct let topname = "All Heap Variables" end)
8+
9+
module Spec : Analyses.MCPSpec =
10+
struct
11+
include Analyses.DefaultSpec
12+
13+
let name () = "memLeak"
14+
15+
module D = ToppedVarInfoSet
16+
module C = Lattice.Unit
17+
18+
let context _ _ = ()
19+
20+
(* HELPER FUNCTIONS *)
21+
let warn_for_multi_threaded ctx =
22+
if not (ctx.ask (Queries.MustBeSingleThreaded { since_start = true })) then
23+
M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Program isn't running in single-threaded mode. A memory leak might occur due to multi-threading"
24+
25+
(* TRANSFER FUNCTIONS *)
26+
let assign ctx (lval:lval) (rval:exp) : D.t =
27+
ctx.local
28+
29+
let branch ctx (exp:exp) (tv:bool) : D.t =
30+
ctx.local
31+
32+
let body ctx (f:fundec) : D.t =
33+
ctx.local
34+
35+
let return ctx (exp:exp option) (f:fundec) : D.t =
36+
let state = ctx.local in
37+
(* TODO: Is this too hacky of a solution? *)
38+
if f.svar.vname = "main" && not @@ D.is_empty state then
39+
M.warn ~category:(Behavior (Undefined MemoryLeak)) ~tags:[CWE 401] "Memory leak from function \"%s\": %a\n" f.svar.vname D.pretty state;
40+
state
41+
42+
let enter ctx (lval:lval option) (f:fundec) (args:exp list) : (D.t * D.t) list =
43+
[ctx.local, ctx.local]
44+
45+
let combine_env ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (callee_local:D.t) (f_ask:Queries.ask) : D.t =
46+
callee_local
47+
48+
let combine_assign ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (callee_local:D.t) (f_ask: Queries.ask): D.t =
49+
ctx.local
50+
51+
let special ctx (lval:lval option) (f:varinfo) (arglist:exp list) : D.t =
52+
let state = ctx.local in
53+
let desc = LibraryFunctions.find f in
54+
match desc.special arglist with
55+
| Malloc _
56+
| Calloc _
57+
| Realloc _ ->
58+
(* Warn about multi-threaded programs as soon as we encounter a dynamic memory allocation function *)
59+
warn_for_multi_threaded ctx;
60+
begin match ctx.ask Queries.HeapVar with
61+
| `Lifted var -> D.add var state
62+
| _ -> state
63+
end
64+
| Free ptr ->
65+
begin match ctx.ask (Queries.MayPointTo ptr) with
66+
| a when not (Queries.LS.is_top a) && not (Queries.LS.mem (dummyFunDec.svar, `NoOffset) a) ->
67+
(* TODO: Need to always set "ana.malloc.unique_address_count" to smth > 0 *)
68+
let unique_pointed_to_heap_vars =
69+
Queries.LS.filter (fun (v, _) -> ctx.ask (Queries.IsHeapVar v) && not @@ ctx.ask (Queries.IsMultiple v)) a
70+
|> Queries.LS.elements
71+
|> List.map fst
72+
|> D.of_list
73+
in
74+
D.diff state unique_pointed_to_heap_vars
75+
| _ -> state
76+
end
77+
| _ -> state
78+
79+
let threadenter ctx lval f args = [ctx.local]
80+
let threadspawn ctx lval f args fctx = ctx.local
81+
82+
let startstate v = D.bot ()
83+
let exitstate v = D.top ()
84+
end
85+
86+
let _ =
87+
MCP.register_analysis (module Spec : MCPSpec)

0 commit comments

Comments
 (0)