Skip to content

Commit 711c2c3

Browse files
Inject ghost global variables from YAML witness into Cil file during init (#1998)
* Reject witness on duplicate ghost variable declarations * Fix ghost global initinfo construction * Fix Formatcil.cType partial application compilation error Agent-Logs-Url: https://github.com/goblint/analyzer/sessions/28884c57-57a6-4417-9509-264ab8dba17f Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com> * Add cram test for ghost variable injection from YAML witness Agent-Logs-Url: https://github.com/goblint/analyzer/sessions/9da67fc2-69ae-48ea-904b-4e7ae68c4735 Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com> * Move YamlWitness.init() before justcil check and update cram test to verify CIL output Agent-Logs-Url: https://github.com/goblint/analyzer/sessions/86acd990-3af7-4033-b7b4-95622c8d6391 Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com> * Fix cram test: match actual CIL printer output with extra spaces around initializer Agent-Logs-Url: https://github.com/goblint/analyzer/sessions/6246b7e7-f321-48b7-83ce-3fb435a854f5 Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
1 parent ad88403 commit 711c2c3

6 files changed

Lines changed: 97 additions & 2 deletions

File tree

src/framework/control.ml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,6 @@ struct
370370
(* real beginning of the [analyze] function *)
371371
if get_bool "ana.sv-comp.enabled" then
372372
Witness.init (module FileCfg); (* TODO: move this out of analyze_loop *)
373-
YamlWitness.init ();
374373

375374
AnalysisState.global_initialization := true;
376375
GobConfig.earlyglobs := get_bool "exp.earlyglobs";

src/maingoblint.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ let do_analyze change_info merged_AST =
541541
Messages.out := Legacy.open_out (get_string "outfile"));
542542

543543
let module L = Printable.Liszt (CilType.Fundec) in
544+
YamlWitness.init ();
544545
if get_bool "justcil" then
545546
(* if we only want to print the output created by CIL: *)
546547
Cilfacade.print merged_AST

src/witness/yamlWitness.ml

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,71 @@ let init () =
415415
if not (Sys.file_exists path) then (
416416
Logs.error "witness.yaml.validate: %s not found" path;
417417
Svcomp.errorwith "witness missing"
418-
)
418+
);
419+
let file = !Cilfacade.current_file in
420+
let global_vars =
421+
file.globals
422+
|> List.filter_map (function
423+
| Cil.GVar (v, _, _)
424+
| Cil.GVarDecl (v, _)
425+
| Cil.GFun ({svar = v; _}, _) -> Some (v.vname, Cil.Fv v)
426+
| _ -> None
427+
)
428+
in
429+
let has_global name =
430+
List.exists (function
431+
| Cil.GVar (v, _, _)
432+
| Cil.GVarDecl (v, _)
433+
| Cil.GFun ({svar = v; _}, _) -> String.equal v.vname name
434+
| _ -> false
435+
) file.globals
436+
in
437+
let parse_type (type_: string): Cil.typ option =
438+
try Some (Formatcil.cType type_ []) with
439+
| exn when GobExn.catch_all_filter exn ->
440+
M.warn_noloc ~category:Witness "ghost variable type parse failed: %s" type_;
441+
None
442+
in
443+
let parse_init (init: string): Cil.exp option =
444+
try Some (Formatcil.cExp init global_vars) with
445+
| exn when GobExn.catch_all_filter exn ->
446+
M.warn_noloc ~category:Witness "ghost variable initializer parse failed: %s" init;
447+
None
448+
in
449+
let instrument_ghost_variable (variable: YamlWitnessType.GhostInstrumentation.Variable.t): unit =
450+
if not (String.equal variable.scope "global") then (
451+
M.warn_noloc ~category:Witness "unsupported ghost variable scope: %s" variable.scope
452+
)
453+
else if has_global variable.name then (
454+
M.error_noloc ~category:Witness "ghost variable already declared in program: %s" variable.name;
455+
Svcomp.errorwith "witness error"
456+
)
457+
else
458+
match parse_type variable.type_, parse_init variable.initial.value with
459+
| Some typ, Some init ->
460+
let v = makeGlobalVar variable.name typ in
461+
let g = GVar (v, {init = Some (SingleInit init)}, locUnknown) in
462+
file.globals <- g :: file.globals
463+
| _ ->
464+
M.error_noloc ~category:Witness "failed to instrument ghost variable declaration: %s" variable.name
465+
in
466+
let instrument_ghost_variables yaml_entry =
467+
match YamlWitnessType.Entry.of_yaml yaml_entry with
468+
| Ok {entry_type = YamlWitnessType.EntryType.GhostInstrumentation {ghost_variables; _}; _} ->
469+
List.iter instrument_ghost_variable ghost_variables
470+
| Ok _ ->
471+
()
472+
| Error (`Msg m) ->
473+
M.error_noloc ~category:Witness "couldn't parse entry while extracting ghost instrumentation: %s" m
474+
in
475+
let yaml = match GobResult.Syntax.(Fpath.of_string path >>= Yaml_unix.of_file) with
476+
| Ok yaml -> yaml
477+
| Error (`Msg m) ->
478+
Logs.error "Yaml_unix.of_file: %s" m;
479+
Svcomp.errorwith "witness missing"
480+
in
481+
let yaml_entries = yaml |> GobYaml.list |> BatResult.get_ok in
482+
List.iter instrument_ghost_variables yaml_entries
419483

420484
let loc_of_location (location: YamlWitnessType.Location.t): Cil.location = {
421485
file = location.file_name;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
int main() {
2+
return 0;
3+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
- entry_type: ghost_instrumentation
2+
metadata:
3+
format_version: "2.1-goblint"
4+
uuid: 00000000-0000-0000-0000-000000000001
5+
creation_time: 2024-01-01T00:00:00Z
6+
producer:
7+
name: Test
8+
version: "0.0"
9+
task:
10+
input_files:
11+
- ghost.c
12+
input_file_hashes:
13+
ghost.c: "0000000000000000000000000000000000000000000000000000000000000000"
14+
data_model: LP64
15+
language: C
16+
content:
17+
ghost_variables:
18+
- name: m_locked
19+
scope: global
20+
type: int
21+
initial:
22+
value: "0"
23+
format: c_expression
24+
ghost_updates: []
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Ghost variables declared in a YAML witness are injected into the CIL file before analysis:
2+
3+
$ goblint --enable justcil --set dbg.justcil-printer clean --set witness.yaml.validate ghost.yml ghost.c | grep -E "m_locked"
4+
int m_locked = 0;

0 commit comments

Comments
 (0)