Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/analyses/base.ml
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ struct
* adding proper dependencies.
* For the exp argument it is always ok to put None. This means not using precise information about
* which part of an array is involved. *)
let rec get ?(full=false) a (gs: glob_fun) (st: store) (addrs:address) (exp:exp option): value =
let rec get ?(top=VD.top ()) ?(full=false) a (gs: glob_fun) (st: store) (addrs:address) (exp:exp option): value =
let at = AD.get_type addrs in
let firstvar = if M.tracing then match AD.to_var_may addrs with [] -> "" | x :: _ -> x.vname else "" in
if M.tracing then M.traceli "get" ~var:firstvar "Address: %a\nState: %a\n" AD.pretty addrs CPA.pretty st.cpa;
Expand All @@ -362,7 +362,7 @@ struct
let f = function
| Addr.Addr (x, o) -> f_addr (x, o)
| Addr.NullPtr -> VD.bot () (* TODO: why bot? *)
| Addr.UnknownPtr -> VD.top ()
| Addr.UnknownPtr -> top (* top may be more precise than VD.top, e.g. for address sets, such that known addresses are kept for soundness *)
| Addr.StrPtr _ -> `Int (ID.top_of IChar)
in
(* We form the collecting function by joining *)
Expand Down Expand Up @@ -720,10 +720,11 @@ struct
else
false
end
| NullPtr | UnknownPtr -> true (* TODO: are these sound? *)
| _ -> false
in
if AD.for_all cast_ok p then
get a gs st p (Some exp) (* downcasts are safe *)
get ~top:(VD.top_value t) a gs st p (Some exp) (* downcasts are safe *)
else
VD.top () (* upcasts not! *)
in
Expand Down
70 changes: 70 additions & 0 deletions tests/regression/02-base/74-pcwd-deref-unknown-fp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// PARAM: --disable sem.unknown_function.invalidate.globals --disable sem.unknown_function.spawn
// extracted from ddverify pcwd

// header declarations

struct file_operations {
void (*ioctl)();
};

struct miscdevice {
struct file_operations *fops;
};

struct cdev {
struct file_operations *ops;
};

// implementation stub

struct ddv_cdev {
struct cdev *cdevp;
};

#define MAX_CDEV_SUPPORT 1

struct cdev fixed_cdev[MAX_CDEV_SUPPORT];
struct ddv_cdev cdev_registered[MAX_CDEV_SUPPORT];

int cdev_add(struct cdev *p)
{
cdev_registered[0].cdevp = p;
return 0;
}

int misc_register(struct miscdevice *misc) {
fixed_cdev[0].ops = misc->fops;
return cdev_add(&fixed_cdev[0]);
}

void call_cdev_functions()
{
int cdev_no = 0;
if (cdev_registered[cdev_no].cdevp->ops->ioctl) {
(* cdev_registered[cdev_no].cdevp->ops->ioctl)();
}
}

// concrete program

void pcwd_ioctl() {
assert(1); // reachable
}

static const struct file_operations pcwd_fops = {
.ioctl = pcwd_ioctl
};

static struct miscdevice pcwd_miscdev = {
.fops = &pcwd_fops
};

int main() {
misc_register(&pcwd_miscdev);

void (*fp)(struct ddv_cdev*); // unknown function pointer
fp(&cdev_registered); // invalidates argument!

call_cdev_functions();
return 0;
}