Skip to content

malloc_null: Interprocedural analysis unsound #1691

Open
@michael-schwarz

Description

@michael-schwarz

While fixing the bug that surfaced in #1688, I realized that the interprocedural handling of the malloc_null analysis is completely broken.
Even without any top pointers involved, callees always seem to get the empty set of addresses.

// PARAM: --set ana.activated[+] malloc_null --set ana.path_sens[-] malloc_null
#include <stdlib.h>
#include <goblint.h>

void fun(int* a) {
        *a = 5; //WARN
}


int main(void) {
        int *x;

        x = malloc(sizeof(int));
        fun(x);
        *x =8; //WARN

        return 0;
}

In this example, we produce warnings at both program points. However, at the dereference of a only base warns

[Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (tests/regression/08-malloc_null/03-more.c:6:9-6:15)

while at the dereference of x, we also get a warning from malloc_null:

[Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (tests/regression/08-malloc_null/03-more.c:15:9-15:15)
[Warning][Behavior > Undefined > NullPointerDereference] Possible dereferencing of null on variable 'x'. (tests/regression/08-malloc_null/03-more.c:15:9-15:15)

I traced the problem part of the way already:

let remove_unreachable (ask: Queries.ask) (args: exp list) (st: D.t) : D.t =
let reachable =
let do_exp e a =
match ask.f (Queries.ReachableFrom e) with
| ad when not (Queries.AD.is_top ad) ->
ad
|> Queries.AD.filter (function
| Queries.AD.Addr.Addr _ -> true
| _ -> false)
|> Queries.AD.join a
(* Ignore soundness warnings, as invalidation proper will raise them. *)
| _ -> AD.empty ()
in
List.fold_right do_exp args (AD.empty ())
in
let vars =
reachable
|> AD.to_var_may
|> List.concat_map to_addrs
|> AD.of_list
in
if D.is_top st
then D.top ()
else D.filter (fun x -> AD.mem x vars) st

Here, vars correctly contains x, but it is somehow filtered out in the last step even though st supposedly also contains it.

The reason we have not seen any issues with this likely is that base now seems to duplicate the warnings of malloc_nulll anyway, which I guess means malloc_null is only useful for the fact that it causes path splitting.

What do we want to do here? Do we repair it? Or remove the warning facilities from the analysis and trim it down to a helper analysis that causes additional path-splitting?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions