@@ -13,7 +13,9 @@ module VarinfoSet = SetDomain.Make(CilType.Varinfo)
1313(* * "Fake" variable to handle returning from a function *)
1414let return_varinfo = dummyFunDec.svar
1515(* * Flag for first function entered *)
16- let first_function = true
16+ let first_function = (emptyFunction " @first" ).svar
17+ (* * Flag for deregistering at return *)
18+ let to_deregister = (emptyFunction " @dereg" ).svar
1719
1820module Spec : Analyses .MCPSpec =
1921struct
@@ -106,22 +108,22 @@ struct
106108 | TNamed (info , attr ) -> info.tname = " value"
107109 | _ -> false
108110
111+ let assignment (v :varinfo ) (rval :exp ) (state :D.t ) (warning :string ): D.t =
112+ (* If rval is a pointer, checks whether rval is accounted for, handles assignment to v accordingly *)
113+ if Cil. isPointerType (Cil. typeOf rval) || is_value_type (Cil. typeOf rval) then
114+ if exp_accounted_for state rval then
115+ if exp_registered state rval then D. add_a v (D. add_r v state)
116+ else D. add_a v (D. remove_r v state)
117+ else (M. info " %s" warning; D. remove_a v state)
118+ else D. add_a v (D. add_r v state)
119+
109120 (* transfer functions *)
110121
111122 (* * Handles assignment of [rval] to [lval]. *)
112123 let assign ctx (lval :lval ) (rval :exp ) : D.t =
113124 let state = ctx.local in
114125 match lval with
115- | Var v ,_ ->
116- (* If rval is a pointer, checks whether rval is accounted for, handles assignment to v accordingly *) (* state *)
117- (* Emits an event for the variable v not being zero. *)
118-
119- if Cil. isPointerType (Cil. typeOf rval) || is_value_type (Cil. typeOf rval) then
120- if exp_accounted_for state rval then
121- if exp_registered state rval then D. add_a v (D. add_r v state)
122- else D. add_a v (D. remove_r v state)
123- else (M. info " The above is being assigned" ; D. remove_a v state)
124- else D. add_a v (D. add_r v state)
126+ | Var v ,_ -> assignment v rval state " The above is being assigned"
125127 | _ -> state
126128
127129 (* * Handles conditional branching yielding truth value [tv]. *)
@@ -133,16 +135,14 @@ struct
133135 (* * Handles going from start node of function [f] into the function body of [f].
134136 Meant to handle e.g. initializiation of local variables. *)
135137 let body ctx (f :fundec ) : D.t =
136- (* The (non-formals) locals are initially accounted for *)
137138 let state = ctx.local in
138- (* It is assumed that the startstate's values are not nptrs. *)
139- let state = List. fold_left ( fun st v -> if first_function && is_value_type v.vtype then
140- (ctx.emit ( Events. SplitBranch ( Cil. Lval ( Cil. var v), true )); D. add_a v st)
141- else D. add_a v ( D. add_r v st ))
142- state f.sformals in
139+ (* It is assumed that the startstate's values are not nptrs. This avoids warnings from other analyses. *)
140+ if D. mem_r first_function state then
141+ List. iter ( fun v -> ( if is_value_type v.vtype then
142+ (ctx.emit ( Events. SplitBranch ( Cil. Lval ( Cil. var v), true ))) ))
143+ f.sformals;
143144 (* TODO: Is there a way without a flag to only emit at the start? *)
144- let first_function = false in
145- state
145+ D. remove_r first_function state
146146
147147 (* * Handles the [return] statement, i.e. "return exp" or "return", in function [f]. *)
148148 let return ctx (exp :exp option ) (f :fundec ) : D.t =
@@ -151,17 +151,11 @@ struct
151151 | Some e ->
152152 (* Checks that value returned is accounted for. *)
153153 (* Return_varinfo is used in place of a "real" variable. *)
154- (* TODO: Consider how the return_varinfo needs to be tracked. *)
155- let return_state =
156- if Cil. isPointerType (Cil. typeOf e) || is_value_type (Cil. typeOf e) then
157- if exp_accounted_for state e then
158- if exp_registered state e then D. add_a return_varinfo (D. add_r return_varinfo state)
159- else D. add_a return_varinfo (D. remove_r return_varinfo state)
160- else (M. warn " Value returned might be garbage collected" ; D. remove_a return_varinfo state)
161- else D. add_a return_varinfo (D. add_r return_varinfo state)
162- in
163- (* Remove this function's formals and locals *)
164- List. fold_left (fun st v -> D. remove_a v (D. remove_r v st)) return_state (f.sformals @ f.slocals)
154+ let return_state = assignment return_varinfo e state " The above is being returned" in
155+ (* Remove this function's formals and locals if correctly returned *)
156+ D. remove_r to_deregister (if D. mem_r to_deregister return_state then
157+ List. fold_left (fun st v -> D. remove_a v (D. remove_r v st)) return_state (f.sformals @ f.slocals)
158+ else return_state)
165159 | None -> state
166160
167161 (* * For a function call "lval = f(args)" or "f(args)",
@@ -173,16 +167,13 @@ struct
173167 List. iter (fun e -> ignore (exp_accounted_for caller_state e)) args;
174168 (* Entering a function doesn't change the caller state *)
175169 let callee_state = List. fold_left2 (fun st v rval ->
176- (* At the start, arguments are accounted for and not registered. *)
177- if rval == MyCFG. unknown_exp then D. add_a v (D. remove_r v st) else
178- (* Arguments of inner functions inherit the caller's state. *)
179- if Cil. isPointerType (Cil. typeOf rval) || is_value_type (Cil. typeOf rval) then
180- if exp_accounted_for st rval then
181- if exp_registered st rval then D. add_a v (D. add_r v st)
182- else D. add_a v (D. remove_r v st)
183- else (M. info " The above is being assigned" ; D. remove_a v st)
184- else D. add_a v (D. add_r v st))
185- caller_state f.sformals args in
170+ (* At the start, arguments are accounted for and not registered. The first_function flag is added.*)
171+ if rval == MyCFG. unknown_exp then
172+ if is_value_type v.vtype then D. add_r first_function (D. add_a v (D. remove_r v st))
173+ else D. add_a v (D. add_r v st)
174+ (* Arguments of inner functions inherit the caller's state. *)
175+ else assignment v rval st " Entering function with possibly deleted argument" )
176+ caller_state f.sformals args in
186177 (* first component is state of caller, second component is state of callee *)
187178 [caller_state, callee_state]
188179
@@ -201,15 +192,15 @@ struct
201192 let caller_state = ctx.local in
202193 (* Records whether lval was accounted for. Registration for v must already be handled. *)
203194 (* TODO: What happens if a pointer to a value is returned? *)
204- (* TODO: Rethink type checking with return_varinfo. *)
205195 match lval with (* The variable returned is played by return_varinfo *)
206196 | Some (Var v , _ ) ->
207197 let state =
208- if Cil. isPointerType return_varinfo.vtype || is_value_type return_varinfo.vtype then
209- if D. mem_a return_varinfo callee_local then
210- if D. mem_r return_varinfo callee_local then D. add_a v (D. add_r v caller_state)
198+ (* TODO: It never warns about being combined. Is there a problem with the svar type? *)
199+ if Cil. isPointerType f.svar.vtype || is_value_type f.svar.vtype then
200+ if D. mem_a return_varinfo caller_state then
201+ if D. mem_r return_varinfo caller_state then D. add_a v (D. add_r v caller_state)
211202 else D. add_a v (D. remove_r v caller_state)
212- else (M. warn " Returned value may be garbage-collected " ; D. remove_a v caller_state)
203+ else (M. info " The above is being combined " ; D. remove_a v caller_state)
213204 else D. add_a v (D. add_r v caller_state) in
214205 D. remove_a return_varinfo (D. remove_r return_varinfo state)
215206 | _ -> caller_state
@@ -219,7 +210,6 @@ struct
219210 For this analysis, source and sink functions will be considered _special_ and have to be treated here. *)
220211 let special ctx (lval : lval option ) (f :varinfo ) (arglist :exp list ) : D.t =
221212 let caller_state = ctx.local in
222- (* TODO: Check if f is a sink / source and handle it appropriately *)
223213 (* To warn about a potential issue in the code, use M.warn. *)
224214 (* caller_state *)
225215 let desc = LibraryFunctions. find f in
@@ -238,6 +228,10 @@ struct
238228 | Some (Var v , _ ) -> D. add_a v (D. after_gc caller_state)
239229 | _ -> D. after_gc caller_state
240230 )
231+ (* TODO: Does not deregister, but queues it. This is unsound if deregistration is done before returning instead of at the same time. *)
232+ | OCamlReturn ->
233+ (* Marks a function as deregistering at return *)
234+ D. add_r to_deregister caller_state
241235 | _ -> caller_state
242236
243237 (* You may leave these alone *)
0 commit comments