Skip to content

Commit

Permalink
Merge branch 'master' into even_even_more_library
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-schwarz authored Oct 3, 2023
2 parents da997a3 + 7e57562 commit 1fcbda9
Show file tree
Hide file tree
Showing 27 changed files with 764 additions and 190 deletions.
9 changes: 4 additions & 5 deletions goblint.opam
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,11 @@ dev-repo: "git+https://github.com/goblint/analyzer.git"
# on `dune build` goblint.opam will be generated from goblint.opam.template and dune-project
# also remember to generate/adjust goblint.opam.locked!
available: os-distribution != "alpine" & arch != "arm64"
# pin-depends: [
# published goblint-cil 2.0.2 is currently up-to-date, so no pin needed
# [ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#98598d94f796a63751e5a9d39c6b3a9fe1f32330" ]
pin-depends: [
[ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#398dca3d94a06a9026b3737aabf100ee3498229f" ]
# TODO: add back after release, only pinned for optimization (https://github.com/ocaml-ppx/ppx_deriving/pull/252)
# [ "ppx_deriving.5.2.1" "git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6" ]
# ]
[ "ppx_deriving.5.2.1" "git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6" ]
]
post-messages: [
"Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"}
]
11 changes: 11 additions & 0 deletions goblint.opam.locked
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,14 @@ conflicts: [
post-messages: [
"Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"}
]
# TODO: manually reordered to avoid opam pin crash: https://github.com/ocaml/opam/issues/4936
pin-depends: [
[
"goblint-cil.2.0.2"
"git+https://github.com/goblint/cil.git#398dca3d94a06a9026b3737aabf100ee3498229f"
]
[
"ppx_deriving.5.2.1"
"git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6"
]
]
9 changes: 4 additions & 5 deletions goblint.opam.template
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# on `dune build` goblint.opam will be generated from goblint.opam.template and dune-project
# also remember to generate/adjust goblint.opam.locked!
available: os-distribution != "alpine" & arch != "arm64"
# pin-depends: [
# published goblint-cil 2.0.2 is currently up-to-date, so no pin needed
# [ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#98598d94f796a63751e5a9d39c6b3a9fe1f32330" ]
pin-depends: [
[ "goblint-cil.2.0.2" "git+https://github.com/goblint/cil.git#398dca3d94a06a9026b3737aabf100ee3498229f" ]
# TODO: add back after release, only pinned for optimization (https://github.com/ocaml-ppx/ppx_deriving/pull/252)
# [ "ppx_deriving.5.2.1" "git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6" ]
# ]
[ "ppx_deriving.5.2.1" "git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6" ]
]
post-messages: [
"Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"}
]
37 changes: 26 additions & 11 deletions src/analyses/base.ml
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ struct

let longjmp_return = ref dummyFunDec.svar

let heap_var ctx =
let info = match (ctx.ask Q.HeapVar) with
let heap_var on_stack ctx =
let info = match (ctx.ask (Q.AllocVar {on_stack})) with
| `Lifted vinfo -> vinfo
| _ -> failwith("Ran without a malloc analysis.") in
info
Expand Down Expand Up @@ -1122,6 +1122,10 @@ struct

(* interpreter end *)

let is_not_heap_alloc_var ctx v =
let is_alloc = ctx.ask (Queries.IsAllocVar v) in
not is_alloc || (is_alloc && not (ctx.ask (Queries.IsHeapVar v)))

let query_invariant ctx context =
let cpa = ctx.local.BaseDomain.cpa in
let ask = Analyses.ask_of_ctx ctx in
Expand Down Expand Up @@ -1249,7 +1253,7 @@ struct
(* If there's a non-heap var or an offset in the lval set, we answer with bottom *)
(* If we're asking for the BlobSize from the base address, then don't check for offsets => we want to avoid getting bot *)
if AD.exists (function
| Addr (v,o) -> (not @@ ctx.ask (Queries.IsHeapVar v)) || (if not from_base_addr then o <> `NoOffset else false)
| Addr (v,o) -> is_not_heap_alloc_var ctx v || (if not from_base_addr then o <> `NoOffset else false)
| _ -> false) a then
Queries.Result.bot q
else (
Expand Down Expand Up @@ -1397,7 +1401,7 @@ struct
let t = match t_override with
| Some t -> t
| None ->
if a.f (Q.IsHeapVar x) then
if a.f (Q.IsAllocVar x) then
(* the vtype of heap vars will be TVoid, so we need to trust the pointer we got to this to be of the right type *)
(* i.e. use the static type of the pointer here *)
lval_type
Expand Down Expand Up @@ -1443,7 +1447,7 @@ struct
(* Optimization to avoid evaluating integer values when setting them.
The case when invariant = true requires the old_value to be sound for the meet.
Allocated blocks are representend by Blobs with additional information, so they need to be looked-up. *)
let old_value = if not invariant && Cil.isIntegralType x.vtype && not (a.f (IsHeapVar x)) && offs = `NoOffset then begin
let old_value = if not invariant && Cil.isIntegralType x.vtype && not (a.f (IsAllocVar x)) && offs = `NoOffset then begin
VD.bot_value ~varAttr:x.vattr lval_type
end else
Priv.read_global a priv_getg st x
Expand Down Expand Up @@ -2009,7 +2013,7 @@ struct

let check_invalid_mem_dealloc ctx special_fn ptr =
let has_non_heap_var = AD.exists (function
| Addr (v,_) -> not (ctx.ask (Q.IsHeapVar v))
| Addr (v,_) -> is_not_heap_alloc_var ctx v
| _ -> false)
in
let has_non_zero_offset = AD.exists (function
Expand All @@ -2026,6 +2030,7 @@ struct
M.warn ~category:(Behavior (Undefined InvalidMemoryDeallocation)) ~tags:[CWE 761] "Free of memory not at start of buffer in function %s for pointer %a" special_fn.vname d_exp ptr
| _ -> M.warn ~category:MessageCategory.Analyzer "Pointer %a in function %s doesn't evaluate to a valid address." d_exp ptr special_fn.vname


let special ctx (lv:lval option) (f: varinfo) (args: exp list) =
let invalidate_ret_lv st = match lv with
| Some lv ->
Expand Down Expand Up @@ -2110,7 +2115,7 @@ struct
let dest_a, dest_typ = addr_type_of_exp dest in
let value = VD.zero_init_value dest_typ in
set ~ctx (Analyses.ask_of_ctx ctx) gs st dest_a dest_typ value
| Memcpy { dest = dst; src }, _ ->
| Memcpy { dest = dst; src; n; }, _ -> (* TODO: use n *)
memory_copying dst src
(* strcpy(dest, src); *)
| Strcpy { dest = dst; src; n = None }, _ ->
Expand Down Expand Up @@ -2277,13 +2282,22 @@ struct
| Unknown, "__goblint_assume_join" ->
let id = List.hd args in
Priv.thread_join ~force:true (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) id st
| Alloca size, _ -> begin
match lv with
| Some lv ->
let heap_var = AD.of_var (heap_var true ctx) in
(* ignore @@ printf "alloca will allocate %a bytes\n" ID.pretty (eval_int ctx.ask gs st size); *)
set_many ~ctx (Analyses.ask_of_ctx ctx) gs st [(heap_var, TVoid [], Blob (VD.bot (), eval_int (Analyses.ask_of_ctx ctx) gs st size, true));
(eval_lv (Analyses.ask_of_ctx ctx) gs st lv, (Cilfacade.typeOfLval lv), Address heap_var)]
| _ -> st
end
| Malloc size, _ -> begin
match lv with
| Some lv ->
let heap_var =
if (get_bool "sem.malloc.fail")
then AD.join (AD.of_var (heap_var ctx)) AD.null_ptr
else AD.of_var (heap_var ctx)
then AD.join (AD.of_var (heap_var false ctx)) AD.null_ptr
else AD.of_var (heap_var false ctx)
in
(* ignore @@ printf "malloc will allocate %a bytes\n" ID.pretty (eval_int ctx.ask gs st size); *)
set_many ~ctx (Analyses.ask_of_ctx ctx) gs st [(heap_var, TVoid [], Blob (VD.bot (), eval_int (Analyses.ask_of_ctx ctx) gs st size, true));
Expand All @@ -2293,7 +2307,7 @@ struct
| Calloc { count = n; size }, _ ->
begin match lv with
| Some lv -> (* array length is set to one, as num*size is done when turning into `Calloc *)
let heap_var = heap_var ctx in
let heap_var = heap_var false ctx in
let add_null addr =
if get_bool "sem.malloc.fail"
then AD.join addr AD.null_ptr (* calloc can fail and return NULL *)
Expand Down Expand Up @@ -2336,7 +2350,7 @@ struct
let p_addr_get = get ask gs st p_addr' None in (* implicitly includes join of malloc value (VD.bot) *)
let size_int = eval_int ask gs st size in
let heap_val:value = Blob (p_addr_get, size_int, true) in (* copy old contents with new size *)
let heap_addr = AD.of_var (heap_var ctx) in
let heap_addr = AD.of_var (heap_var false ctx) in
let heap_addr' =
if get_bool "sem.malloc.fail" then
AD.join heap_addr AD.null_ptr
Expand Down Expand Up @@ -2584,6 +2598,7 @@ struct
| MayBeThreadReturn
| PartAccess _
| IsHeapVar _
| IsAllocVar _
| IsMultiple _
| CreatedThreads
| MustJoinedThreads ->
Expand Down
3 changes: 2 additions & 1 deletion src/analyses/libraryDesc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type math =
(** Type of special function, or {!Unknown}. *)
(* Use inline record if not single {!Cil.exp} argument. *)
type special =
| Alloca of Cil.exp
| Malloc of Cil.exp
| Calloc of { count: Cil.exp; size: Cil.exp; }
| Realloc of { ptr: Cil.exp; size: Cil.exp; }
Expand All @@ -67,7 +68,7 @@ type special =
| Math of { fun_args: math; }
| Memset of { dest: Cil.exp; ch: Cil.exp; count: Cil.exp; }
| Bzero of { dest: Cil.exp; count: Cil.exp; }
| Memcpy of { dest: Cil.exp; src: Cil.exp }
| Memcpy of { dest: Cil.exp; src: Cil.exp; n: Cil.exp; }
| Strcpy of { dest: Cil.exp; src: Cil.exp; n: Cil.exp option; }
| Strcat of { dest: Cil.exp; src: Cil.exp; n: Cil.exp option; }
| Strlen of Cil.exp
Expand Down
40 changes: 30 additions & 10 deletions src/analyses/libraryFunctions.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[
("memset", special [__ "dest" [w]; __ "ch" []; __ "count" []] @@ fun dest ch count -> Memset { dest; ch; count; });
("__builtin_memset", special [__ "dest" [w]; __ "ch" []; __ "count" []] @@ fun dest ch count -> Memset { dest; ch; count; });
("__builtin___memset_chk", special [__ "dest" [w]; __ "ch" []; __ "count" []; drop "os" []] @@ fun dest ch count -> Memset { dest; ch; count; });
("memcpy", special [__ "dest" [w]; __ "src" [r]; drop "n" []] @@ fun dest src -> Memcpy { dest; src }); (* TODO: use n *)
("__builtin_memcpy", special [__ "dest" [w]; __ "src" [r]; drop "n" []] @@ fun dest src -> Memcpy { dest; src });
("__builtin___memcpy_chk", special [__ "dest" [w]; __ "src" [r]; drop "n" []; drop "os" []] @@ fun dest src -> Memcpy { dest; src });
("memccpy", special [__ "dest" [w]; __ "src" [r]; drop "c" []; drop "n" []] @@ fun dest src -> Memcpy {dest; src}); (* C23 *) (* TODO: use n and c *)
("memmove", special [__ "dest" [w]; __ "src" [r]; drop "count" []] @@ fun dest src -> Memcpy { dest; src });
("__builtin_memmove", special [__ "dest" [w]; __ "src" [r]; drop "count" []] @@ fun dest src -> Memcpy { dest; src });
("__builtin___memmove_chk", special [__ "dest" [w]; __ "src" [r]; drop "count" []; drop "os" []] @@ fun dest src -> Memcpy { dest; src });
("memcpy", special [__ "dest" [w]; __ "src" [r]; __ "n" []] @@ fun dest src n -> Memcpy { dest; src; n; });
("__builtin_memcpy", special [__ "dest" [w]; __ "src" [r]; __ "n" []] @@ fun dest src n -> Memcpy { dest; src; n; });
("__builtin___memcpy_chk", special [__ "dest" [w]; __ "src" [r]; __ "n" []; drop "os" []] @@ fun dest src n -> Memcpy { dest; src; n; });
("memccpy", special [__ "dest" [w]; __ "src" [r]; drop "c" []; __ "n" []] @@ fun dest src n -> Memcpy {dest; src; n; }); (* C23 *) (* TODO: use c *)
("memmove", special [__ "dest" [w]; __ "src" [r]; __ "count" []] @@ fun dest src count -> Memcpy { dest; src; n = count; });
("__builtin_memmove", special [__ "dest" [w]; __ "src" [r]; __ "count" []] @@ fun dest src count -> Memcpy { dest; src; n = count; });
("__builtin___memmove_chk", special [__ "dest" [w]; __ "src" [r]; __ "count" []; drop "os" []] @@ fun dest src count -> Memcpy { dest; src; n = count; });
("strcpy", special [__ "dest" [w]; __ "src" [r]] @@ fun dest src -> Strcpy { dest; src; n = None; });
("__builtin_strcpy", special [__ "dest" [w]; __ "src" [r]] @@ fun dest src -> Strcpy { dest; src; n = None; });
("__builtin___strcpy_chk", special [__ "dest" [w]; __ "src" [r]; drop "os" []] @@ fun dest src -> Strcpy { dest; src; n = None; });
Expand Down Expand Up @@ -138,6 +138,12 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[
("atoll", unknown [drop "nptr" [r]]);
("setlocale", unknown [drop "category" []; drop "locale" [r]]);
("clock", unknown []);
("atomic_flag_clear", unknown [drop "obj" [w]]);
("atomic_flag_clear_explicit", unknown [drop "obj" [w]; drop "order" []]);
("atomic_flag_test_and_set", unknown [drop "obj" [r; w]]);
("atomic_flag_test_and_set_explicit", unknown [drop "obj" [r; w]; drop "order" []]);
("atomic_load", unknown [drop "obj" [r]]);
("atomic_store", unknown [drop "obj" [w]; drop "desired" []]);
]

(** C POSIX library functions.
Expand Down Expand Up @@ -491,11 +497,25 @@ let gcc_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[
("__builtin_popcountl", unknown [drop "x" []]);
("__builtin_popcountll", unknown [drop "x" []]);
("__atomic_store_n", unknown [drop "ptr" [w]; drop "val" []; drop "memorder" []]);
("__atomic_store", unknown [drop "ptr" [w]; drop "val" [r]; drop "memorder" []]);
("__atomic_load_n", unknown [drop "ptr" [r]; drop "memorder" []]);
("__atomic_load", unknown [drop "ptr" [r]; drop "ret" [w]; drop "memorder" []]);
("__atomic_clear", unknown [drop "ptr" [w]; drop "memorder" []]);
("__atomic_compare_exchange_n", unknown [drop "ptr" [r; w]; drop "expected" [r; w]; drop "desired" []; drop "weak" []; drop "success_memorder" []; drop "failure_memorder" []]);
("__atomic_compare_exchange", unknown [drop "ptr" [r; w]; drop "expected" [r; w]; drop "desired" [r]; drop "weak" []; drop "success_memorder" []; drop "failure_memorder" []]);
("__atomic_fetch_add", unknown [drop "ptr" [r; w]; drop "val" []; drop "memorder" []]);
("__atomic_fetch_sub", unknown [drop "ptr" [r; w]; drop "val" []; drop "memorder" []]);
("__atomic_fetch_and", unknown [drop "ptr" [r; w]; drop "val" []; drop "memorder" []]);
("__atomic_fetch_xor", unknown [drop "ptr" [r; w]; drop "val" []; drop "memorder" []]);
("__atomic_fetch_or", unknown [drop "ptr" [r; w]; drop "val" []; drop "memorder" []]);
("__atomic_fetch_nand", unknown [drop "ptr" [r; w]; drop "val" []; drop "memorder" []]);
("__atomic_test_and_set", unknown [drop "ptr" [r; w]; drop "memorder" []]);
("__atomic_thread_fence", unknown [drop "memorder" []]);
("__sync_fetch_and_add", unknown (drop "ptr" [r; w] :: drop "value" [] :: VarArgs (drop' [])));
("__sync_fetch_and_sub", unknown (drop "ptr" [r; w] :: drop "value" [] :: VarArgs (drop' [])));
("__builtin_va_copy", unknown [drop "dest" [w]; drop "src" [r]]);
("__builtin_alloca", special [__ "size" []] @@ fun size -> Malloc size);
("alloca", special [__ "size" []] @@ fun size -> Alloca size);
("__builtin_alloca", special [__ "size" []] @@ fun size -> Alloca size);
]

let glibc_desc_list: (string * LibraryDesc.t) list = LibraryDsl.[
Expand Down Expand Up @@ -536,8 +556,8 @@ let glibc_desc_list: (string * LibraryDesc.t) list = LibraryDsl.[
("strcasestr", unknown [drop "haystack" [r]; drop "needle" [r]]);
("inet_aton", unknown [drop "cp" [r]; drop "inp" [w]]);
("fopencookie", unknown [drop "cookie" []; drop "mode" [r]; drop "io_funcs" [s_deep]]); (* doesn't access cookie but passes it to io_funcs *)
("mempcpy", special [__ "dest" [w]; __ "src" [r]; drop "n" []] @@ fun dest src -> Memcpy { dest; src });
("__builtin___mempcpy_chk", special [__ "dest" [w]; __ "src" [r]; drop "n" []; drop "os" []] @@ fun dest src -> Memcpy { dest; src });
("mempcpy", special [__ "dest" [w]; __ "src" [r]; __ "n" []] @@ fun dest src n -> Memcpy { dest; src; n; });
("__builtin___mempcpy_chk", special [__ "dest" [w]; __ "src" [r]; __ "n" []; drop "os" []] @@ fun dest src n -> Memcpy { dest; src; n; });
("rawmemchr", unknown [drop "s" [r]; drop "c" []]);
("memrchr", unknown [drop "s" [r]; drop "c" []; drop "n" []]);
("memmem", unknown [drop "haystack" [r]; drop "haystacklen" []; drop "needle" [r]; drop "needlelen" [r]]);
Expand Down
4 changes: 3 additions & 1 deletion src/analyses/mCP.ml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ struct
let spawn_one v d =
List.iter (fun (lval, args) -> ctx.spawn lval v args) d
in
if not (get_bool "exp.single-threaded") then
if get_bool "exp.single-threaded" then
M.msg_final Error ~category:Unsound "Thread not spawned"
else
iter (uncurry spawn_one) @@ group_assoc_eq Basetype.Variables.equal xs

let do_sideg ctx (xs:(V.t * (WideningTokens.TS.t * G.t)) list) =
Expand Down
2 changes: 1 addition & 1 deletion src/analyses/mallocFresh.ml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct
| Malloc _
| Calloc _
| Realloc _ ->
begin match ctx.ask HeapVar with
begin match ctx.ask (AllocVar {on_stack = false}) with
| `Lifted var -> D.add var ctx.local
| _ -> ctx.local
end
Expand Down
4 changes: 2 additions & 2 deletions src/analyses/memLeak.ml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct
| Realloc _ ->
(* Warn about multi-threaded programs as soon as we encounter a dynamic memory allocation function *)
warn_for_multi_threaded ctx;
begin match ctx.ask Queries.HeapVar with
begin match ctx.ask (Queries.AllocVar {on_stack = false}) with
| `Lifted var -> D.add var state
| _ -> state
end
Expand All @@ -53,7 +53,7 @@ struct
| ad when not (Queries.AD.is_top ad) && Queries.AD.cardinal ad = 1 ->
(* Note: Need to always set "ana.malloc.unique_address_count" to a value > 0 *)
begin match Queries.AD.choose ad with
| Queries.AD.Addr.Addr (v,_) when ctx.ask (Queries.IsHeapVar v) && not @@ ctx.ask (Queries.IsMultiple v) -> D.remove v state (* Unique pointed to heap vars *)
| Queries.AD.Addr.Addr (v,_) when ctx.ask (Queries.IsAllocVar v) && ctx.ask (Queries.IsHeapVar v) && not @@ ctx.ask (Queries.IsMultiple v) -> D.remove v state (* Unique pointed to heap vars *)
| _ -> state
end
| _ -> state
Expand Down
Loading

0 comments on commit 1fcbda9

Please sign in to comment.