Skip to content

Commit 499cc76

Browse files
committed
CHC: add primary proofobligation creation for output parameters
1 parent e603b94 commit 499cc76

File tree

2 files changed

+415
-0
lines changed

2 files changed

+415
-0
lines changed
Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
(* =============================================================================
2+
CodeHawk C Analyzer
3+
Author: Henny Sipma
4+
------------------------------------------------------------------------------
5+
The MIT License (MIT)
6+
7+
Copyright (c) 2025 Aarno Labs LLC
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a copy
10+
of this software and associated documentation files (the "Software"), to deal
11+
in the Software without restriction, including without limitation the rights
12+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
copies of the Software, and to permit persons to whom the Software is
14+
furnished to do so, subject to the following conditions:
15+
16+
The above copyright notice and this permission notice shall be included in all
17+
copies or substantial portions of the Software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25+
SOFTWARE.
26+
============================================================================= *)
27+
28+
(* chlib *)
29+
open CHPretty
30+
31+
(* chutil *)
32+
open CHLogger
33+
open CHTimingLog
34+
35+
(* cchlib *)
36+
open CCHBasicTypes
37+
open CCHBasicUtil
38+
open CCHContext
39+
open CCHDeclarations
40+
open CCHFileContract
41+
open CCHLibTypes
42+
open CCHSettings
43+
open CCHTypesUtil
44+
open CCHUtilities
45+
46+
(* cchpre *)
47+
open CCHPreFileIO
48+
open CCHPreTypes
49+
open CCHProofScaffolding
50+
51+
52+
let fenv = CCHFileEnvironment.file_environment
53+
54+
55+
class po_creator_t (f:fundec) (pointer_parameters: varinfo list) =
56+
object (self)
57+
58+
method private f = f
59+
60+
method private ftype = self#f.svar.vtype
61+
62+
method private fname = self#f.svar.vname
63+
64+
method private pointer_parameters = pointer_parameters
65+
66+
method private env = self#f.sdecls
67+
68+
method private spomanager = proof_scaffolding#get_spo_manager self#fname
69+
70+
method private add_ppo
71+
(pred: po_predicate_t)
72+
(loc: location)
73+
(ctxt: program_context_int) =
74+
(proof_scaffolding#get_ppo_manager self#fname)#add_ppo loc ctxt pred
75+
76+
method create_proof_obligations =
77+
self#create_po_block (mk_program_context ()) self#f.sbody
78+
79+
method private create_po_block (context: program_context_int) (b: block) =
80+
List.iter (fun s -> self#create_po_stmt (context#add_stmt s.sid) s) b.bstmts
81+
82+
method private create_po_stmt (context: program_context_int) (s: stmt) =
83+
self#create_po_stmtkind context s.skind
84+
85+
method private create_po_stmtkind (context: program_context_int) (k: stmtkind) =
86+
match k with
87+
| Instr l ->
88+
List.iteri
89+
(fun i instr -> self#create_po_instr (context#add_instr i) instr) l
90+
91+
| Return (e, loc) -> self#create_po_return context e loc
92+
93+
| ComputedGoto (e, loc) -> self#create_po_computed_goto context e loc
94+
95+
| If (e, thenblock, elseblock, loc) ->
96+
self#create_po_if context e thenblock elseblock loc
97+
98+
| Switch (e, b, _, loc) -> self#create_po_switch context e b loc
99+
100+
| Loop (b, loc, _, _) -> self#create_po_loop context#add_loop b loc
101+
102+
| Block b -> self#create_po_block context b
103+
104+
| Goto _ | Break _ | Continue _ -> ()
105+
106+
| TryFinally _ | TryExcept _ ->
107+
pr_debug [
108+
STR "proof obligations for TryFinally/TryExcept not supported"; NL]
109+
110+
method private create_po_loop
111+
(context: program_context_int) (b: block) (_loc: location) =
112+
self#create_po_block context b
113+
114+
method private create_po_switch
115+
(context: program_context_int)
116+
(e: exp)
117+
(b: block)
118+
(loc: location) =
119+
begin
120+
self#create_po_exp context#add_switch_expr e loc;
121+
self#create_po_block context b
122+
end
123+
124+
method private create_po_if
125+
(context: program_context_int)
126+
(e: exp)
127+
(tb: block)
128+
(eb: block)
129+
(loc: location) =
130+
begin
131+
self#create_po_exp context#add_if_expr e loc;
132+
self#create_po_block context#add_if_then tb;
133+
self#create_po_block context#add_if_else eb
134+
end
135+
136+
method private create_po_computed_goto
137+
(context: program_context_int) (e: exp) (loc: location) =
138+
self#create_po_exp context#add_goto e loc
139+
140+
method private create_po_return
141+
(context: program_context_int) (e:exp option) (loc: location) =
142+
let _ = self#spomanager#add_return loc context#add_return e in
143+
begin
144+
(match e with
145+
| Some x -> self#create_po_exp context#add_return x loc
146+
| _ -> ());
147+
(List.iter (fun vinfo ->
148+
begin
149+
self#add_ppo
150+
(POutputParameterInitialized vinfo) loc context#add_return;
151+
self#add_ppo
152+
(POutputParameterUnaltered vinfo) loc context#add_return
153+
end)
154+
self#pointer_parameters)
155+
end
156+
157+
method private create_po_instr (context: program_context_int) (i: instr) =
158+
match i with
159+
| Set (lval, e, loc) -> self#create_po_assignment context lval e loc
160+
| Call (lval_o, e, el, loc) -> self#create_po_call context lval_o e el loc
161+
| Asm _ -> ()
162+
| VarDecl _ -> ()
163+
164+
method private create_po_assignment
165+
(context: program_context_int)
166+
(lval: lval)
167+
(e: exp)
168+
(loc: location) =
169+
begin
170+
self#create_po_lval context#add_lhs lval loc;
171+
self#create_po_exp context#add_rhs e loc
172+
end
173+
174+
method private create_po_call
175+
(context: program_context_int)
176+
(lval_o: lval option)
177+
(e: exp)
178+
(el: exp list)
179+
(loc: location) =
180+
begin
181+
(match lval_o with
182+
| Some lval -> self#create_po_lval context#add_lhs lval loc
183+
| _ -> ());
184+
(match e with
185+
| Lval (Var (_vname, vid), NoOffset) ->
186+
self#spomanager#add_direct_call
187+
loc context (self#env#get_varinfo_by_vid vid) el;
188+
| _ ->
189+
begin
190+
self#create_po_exp context#add_ftarget e loc;
191+
self#spomanager#add_indirect_call loc context e el
192+
end);
193+
(List.iteri (fun i x ->
194+
let newcontext = context#add_arg (i + 1) in
195+
self#create_po_exp newcontext x loc) el)
196+
end
197+
198+
method private create_po_exp
199+
(context: program_context_int)
200+
(x: exp)
201+
(loc: location) =
202+
let has_struct_type vid =
203+
let vinfo = self#env#get_varinfo_by_vid vid in
204+
match fenv#get_type_unrolled vinfo.vtype with
205+
| TComp _ -> true
206+
| _ -> false in
207+
match x with
208+
| Const _ -> ()
209+
210+
| Lval (Var (vname, vid), NoOffset) when has_struct_type vid ->
211+
let vinfo = self#env#get_varinfo_by_vid vid in
212+
begin
213+
match fenv#get_type_unrolled vinfo.vtype with
214+
| TComp (tckey, _) ->
215+
let cinfo = fenv#get_comp tckey in
216+
begin
217+
List.iter (fun f ->
218+
self#add_ppo
219+
(PInitialized
220+
(Var (vname, vid), Field ((f.fname, f.fckey), NoOffset)))
221+
loc
222+
context)
223+
cinfo.cfields;
224+
self#create_po_lval context#add_lval (Var (vname, vid), NoOffset) loc
225+
end
226+
| _ -> ()
227+
end
228+
229+
| Lval ((Var _, NoOffset) as lval) ->
230+
self#add_ppo (PInitialized lval) loc context
231+
232+
| Lval lval ->
233+
begin
234+
(List.iter (fun vinfo ->
235+
self#add_ppo (PLocallyInitialized (vinfo, lval)) loc context)
236+
self#pointer_parameters);
237+
self#create_po_lval context#add_lval lval loc
238+
end
239+
240+
| SizeOf _ | SizeOfE _ | SizeOfStr _ -> ()
241+
242+
| AlignOf _ | AlignOfE _ -> ()
243+
244+
| UnOp (_, e, _t) -> self#create_po_exp context#add_unop e loc
245+
246+
| BinOp (binop, e1, e2, t) ->
247+
begin
248+
self#create_po_exp (context#add_binop 1) e1 loc;
249+
self#create_po_exp (context#add_binop 2) e2 loc;
250+
self#create_po_binop context binop e1 e2 t loc
251+
end
252+
253+
| Question (e1, e2, e3, _t) ->
254+
begin
255+
self#create_po_exp (context#add_question 1) e1 loc;
256+
self#create_po_exp (context#add_question 2) e2 loc;
257+
self#create_po_exp (context#add_question 3) e3 loc
258+
end
259+
260+
| CastE (_t, e) -> self#create_po_exp context#add_cast e loc
261+
262+
| AddrOf l -> self#create_po_lval context#add_addrof l loc
263+
264+
| AddrOfLabel _ -> ()
265+
266+
| StartOf l -> self#create_po_lval context#add_startof l loc
267+
268+
| FnApp _ | CnApp _ -> ()
269+
270+
method private create_po_lval
271+
(context: program_context_int)
272+
((host, offset): lval)
273+
(loc: location) =
274+
match host with
275+
| Var (_vname, vid) ->
276+
let ty = (self#env#get_varinfo_by_vid vid).vtype in
277+
self#create_po_offset context#add_var offset ty loc
278+
| Mem e -> self#create_po_exp context#add_mem e loc
279+
280+
method private create_po_offset
281+
(context: program_context_int)
282+
(o: offset)
283+
(hosttyp: typ)
284+
(loc: location) =
285+
match o with
286+
| NoOffset -> ()
287+
288+
| Field ((fname, ckey), oo) ->
289+
(match fenv#get_type_unrolled hosttyp with
290+
| TComp (tckey, _) ->
291+
if tckey = ckey then
292+
let ftype = fenv#get_field_type ckey fname in
293+
self#create_po_offset (context#add_field_offset fname) oo ftype loc
294+
else
295+
()
296+
| _ -> ())
297+
298+
| Index (exp, oo) ->
299+
(match fenv#get_type_unrolled hosttyp with
300+
| TArray (tt, Some _len, _) ->
301+
begin
302+
self#create_po_exp context#add_index exp loc;
303+
self#create_po_offset context#add_index_offset oo tt loc
304+
end
305+
| _ -> ())
306+
307+
method private create_po_binop
308+
(_context: program_context_int)
309+
(_binop: binop)
310+
(_e1: exp)
311+
(_e2: exp)
312+
(_t: typ)
313+
(_loc:location) =
314+
()
315+
316+
end
317+
318+
319+
let process_function (fname:string) =
320+
let _ = log_info "Process function %s [%s:%d]" fname __FILE__ __LINE__ in
321+
try
322+
let fundec = read_function_semantics fname in
323+
let fdecls = fundec.sdecls in
324+
let ftype = fundec.svar.vtype in
325+
let pointer_parameters =
326+
match ftype with
327+
| TFun (_, Some funargs, _, _) | TPtr (TFun (_, Some funargs, _, _), _) ->
328+
List.filter (fun (_, ty, _) ->
329+
(not (has_const_attribute ty))
330+
&& (match ty with
331+
| TPtr (tgt, _) -> not (has_const_attribute tgt)
332+
| _ -> false)) funargs
333+
| _ -> [] in
334+
let pointer_parameters =
335+
List.map (fun (vname, _, _) ->
336+
fdecls#get_varinfo_by_name vname) pointer_parameters in
337+
if (List.length pointer_parameters) > 0 then
338+
begin
339+
read_proof_files fname fdecls;
340+
(new po_creator_t fundec pointer_parameters)#create_proof_obligations;
341+
CCHCheckValid.process_function fname;
342+
save_proof_files fname;
343+
save_api fname;
344+
end
345+
with
346+
| CCHFailure p ->
347+
begin
348+
pr_debug [
349+
STR "Error in processing function "; STR fname; STR ": "; p; NL];
350+
ch_error_log#add
351+
"failure" (LBLOCK [STR "function "; STR fname; STR ": "; p])
352+
end
353+
| Invalid_argument s ->
354+
ch_error_log#add
355+
"failure" (LBLOCK [ STR "function "; STR fname; STR ": "; STR s])
356+
357+
358+
let output_parameter_po_process_file () =
359+
try
360+
let cfilename = system_settings#get_cfilename in
361+
let _ = read_cfile_dictionary () in
362+
let _ = read_cfile_interface_dictionary () in
363+
let cfile = read_cfile () in
364+
let _ = fenv#initialize cfile in
365+
let _ = cdeclarations#index_location call_sink in
366+
let functions = fenv#get_application_functions in
367+
let functions = List.filter (fun f -> not (f.vname = "main")) functions in
368+
let _ =
369+
log_info
370+
"Cfile %s initialized with %d functions [%s:%d]"
371+
cfilename (List.length functions)
372+
__FILE__ __LINE__ in
373+
let _ = read_cfile_contract () in
374+
let _ = file_contract#collect_file_attributes in
375+
begin
376+
List.iter (fun f -> process_function f.vname) functions;
377+
(* List.iter process_global cfile.globals; *)
378+
save_cfile_assignment_dictionary ();
379+
save_cfile_predicate_dictionary ();
380+
save_cfile_interface_dictionary();
381+
save_cfile_dictionary ();
382+
save_cfile_context ();
383+
end
384+
with
385+
| CHXmlReader.IllFormed ->
386+
ch_error_log#add "ill-formed content" (STR system_settings#get_cfilename)

0 commit comments

Comments
 (0)