diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index 9be61523de..6cae4a3f69 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -465,34 +465,22 @@ struct (* Give the set of reachables from argument. *) let reachables (ask: Queries.ask) es = let reachable e st = - match st with - | None -> None - | Some st -> - let ad = ask.f (Queries.ReachableFrom e) in - if Queries.AD.is_top ad then - None - else - Some (Queries.AD.join ad st) + let ad = ask.f (Queries.ReachableFrom e) in + Queries.AD.join ad st in - List.fold_right reachable es (Some (Queries.AD.empty ())) + List.fold_right reachable es (Queries.AD.empty ()) let forget_reachable man st es = let ask = Analyses.ask_of_man man in let rs = - match reachables ask es with - | None -> - (* top reachable, so try to invalidate everything *) - RD.vars st.rel - |> List.filter_map RV.to_cil_varinfo - |> List.map Cil.var - | Some ad -> - let to_cil addr rs = - match addr with - | Queries.AD.Addr.Addr mval -> (ValueDomain.Addr.Mval.to_cil mval) :: rs - | _ -> rs - in - Queries.AD.fold to_cil ad [] + let ad = reachables ask es in + let to_cil addr rs = + match addr with + | Queries.AD.Addr.Addr mval -> (ValueDomain.Addr.Mval.to_cil mval) :: rs + | _ -> rs + in + Queries.AD.fold to_cil ad [] in List.fold_left (fun st lval -> invalidate_one ask man st lval @@ -513,6 +501,36 @@ struct if RD.is_bot_env res then raise Deadcode; {st with rel = res} + let special_unknown_invalidate man f args = + (* No warning here, base already prodcues the appropriate warnings *) + let desc = LibraryFunctions.find f in + let shallow_addrs = LibraryDesc.Accesses.find desc.accs { kind = Write; deep = false } args in + let deep_addrs = LibraryDesc.Accesses.find desc.accs { kind = Write; deep = true } args in + let deep_addrs = + if List.mem LibraryDesc.InvalidateGlobals desc.attrs then ( + foldGlobals !Cilfacade.current_file (fun acc global -> + match global with + | GVar (vi, _, _) when not (BaseUtil.is_static vi) -> + mkAddrOf (Var vi, NoOffset) :: acc + (* TODO: what about GVarDecl? *) + | _ -> acc + ) deep_addrs + ) + else + deep_addrs + in + let lvallist e = + match man.ask (Queries.MayPointTo e) with + | ad when Queries.AD.is_top ad -> [] + | ad -> + Queries.AD.to_mval ad + |> List.map ValueDomain.Addr.Mval.to_cil + in + let st' = forget_reachable man man.local deep_addrs in + let shallow_lvals = List.concat_map lvallist shallow_addrs in + List.fold_left (invalidate_one (Analyses.ask_of_man man) man) st' shallow_lvals + + let special man r f args = let ask = Analyses.ask_of_man man in let st = man.local in @@ -548,31 +566,7 @@ struct assert_fn {man with local = st} (BinOp (Ge, Lval lv, zero, intType)) true | None -> st) | _, _ -> - let lvallist e = - match ask.f (Queries.MayPointTo e) with - | ad when Queries.AD.is_top ad -> [] - | ad -> - Queries.AD.to_mval ad - |> List.map ValueDomain.Addr.Mval.to_cil - in - let shallow_addrs = LibraryDesc.Accesses.find desc.accs { kind = Write; deep = false } args in - let deep_addrs = LibraryDesc.Accesses.find desc.accs { kind = Write; deep = true } args in - let deep_addrs = - if List.mem LibraryDesc.InvalidateGlobals desc.attrs then ( - foldGlobals !Cilfacade.current_file (fun acc global -> - match global with - | GVar (vi, _, _) when not (BaseUtil.is_static vi) -> - mkAddrOf (Var vi, NoOffset) :: acc - (* TODO: what about GVarDecl? *) - | _ -> acc - ) deep_addrs - ) - else - deep_addrs - in - let st' = forget_reachable man st deep_addrs in - let shallow_lvals = List.concat_map lvallist shallow_addrs in - let st' = List.fold_left (invalidate_one ask man) st' shallow_lvals in + let st' = special_unknown_invalidate man f args in (* invalidate lval if present *) match r with | Some lv -> invalidate_one ask man st' lv @@ -674,21 +668,19 @@ struct let threadenter man ~multiple lval f args = let st = man.local in + (* TODO: HACK: Simulate enter_multithreaded for first entering thread to publish global inits before analyzing thread. + Otherwise thread is analyzed with no global inits, reading globals gives bot, which turns into top, which might get published... + sync `Thread doesn't help us here, it's not specific to entering multithreaded mode. + EnterMultithreaded events only execute after threadenter and threadspawn. *) + if not (ThreadFlag.has_ever_been_multi (Analyses.ask_of_man man)) then + ignore (Priv.enter_multithreaded (Analyses.ask_of_man man) man.global man.sideg st); match Cilfacade.find_varinfo_fundec f with | fd -> - (* TODO: HACK: Simulate enter_multithreaded for first entering thread to publish global inits before analyzing thread. - Otherwise thread is analyzed with no global inits, reading globals gives bot, which turns into top, which might get published... - sync `Thread doesn't help us here, it's not specific to entering multithreaded mode. - EnterMultithreaded events only execute after threadenter and threadspawn. *) - if not (ThreadFlag.has_ever_been_multi (Analyses.ask_of_man man)) then - ignore (Priv.enter_multithreaded (Analyses.ask_of_man man) man.global man.sideg st); let st' = Priv.threadenter (Analyses.ask_of_man man) man.global st in let new_rel = make_callee_rel ~thread:true man fd args in [{st' with rel = new_rel}] | exception Not_found -> - (* Unknown functions *) - (* TODO: do something like base? *) - failwith "relation.threadenter: unknown function" + [special_unknown_invalidate man f args] let threadspawn man ~multiple lval f args fman = man.local diff --git a/tests/regression/46-apron2/98-invalidate-more.c b/tests/regression/46-apron2/98-invalidate-more.c new file mode 100644 index 0000000000..acf3944b10 --- /dev/null +++ b/tests/regression/46-apron2/98-invalidate-more.c @@ -0,0 +1,22 @@ +// SKIP PARAM: --set ana.activated[+] apron --set sem.int.signed_overflow assume_none +#include +#include +#include + +int debug; +int other; + +int main() { + int top; + + // Needed so Base & DefExc doesn't find this information because it invalidates less + if(top) { + debug = 3; + } + + fscanf(stdin, "%d", &other); + + // Use to fail as debug was invalidated + __goblint_check(debug <= 3); + return 0; +}