Skip to content
8 changes: 4 additions & 4 deletions src/analyses/memOutOfBounds.ml
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ struct
`Top)

let get_ptr_deref_type ptr_typ =
match ptr_typ with
match Cil.unrollType ptr_typ with
| TPtr (t, _) -> Some t
| _ -> None

Expand Down Expand Up @@ -279,10 +279,10 @@ struct
M.warn "Size of lval dereference expression %a is bot. Out-of-bounds memory access may occur" d_exp e)
| `Lifted es ->
let casted_es = ID.cast_to (Cilfacade.ptrdiff_ikind ()) es in
let one = intdom_of_int 1 in
let casted_es = ID.sub casted_es one in
let casted_offs = ID.cast_to (Cilfacade.ptrdiff_ikind ()) offs_intdom in
let casted_offs = ID.div (ID.cast_to (Cilfacade.ptrdiff_ikind ()) offs_intdom) (ID.of_int (Cilfacade.ptrdiff_ikind ()) (Z.of_int 8)) in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, I guess this tended to kill us almost all of the time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also a documentation problem (by me) that might've contributed to this:

val to_index: ?typ:GoblintCil.typ -> t -> idx
(** Physical memory offset in bytes of the entire offset.
Used for {!semantic_equal}.
@param typ base type. *)

Contrary to the description, it returns the offset in bits (matching what CIL has). It was fine for semantic_equal because both would be in bits, but not for other uses (this is the only other one I think).

I'll have to open a follow-up PR to fix that. Changing the documentation would be easy, but it's not entirely the right thing: ptrdiff_t is large enough to fit offsets in bytes, but not necessarily in bits (in practice the difference might be irrelevant unless a program actually allocates more than 8th of the address space). Having to_index return bytes would be consistent with ptrdiff_ikind.

let ptr_size_lt_offs =
let one = intdom_of_int 1 in
let casted_es = ID.sub casted_es one in
begin try ID.lt casted_es casted_offs
with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind ()
end
Expand Down
2 changes: 1 addition & 1 deletion src/cdomain/value/cdomains/valueDomain.ml
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ struct
************************************************************)

(* is a cast t1 to t2 invertible, i.e., content-preserving in general? *)
let is_statically_safe_cast t2 t1 = match t2, t1 with
let is_statically_safe_cast t2 t1 = match unrollType t2, unrollType t1 with
(*| TPtr _, t -> bitsSizeOf t <= bitsSizeOf !upointType
| t, TPtr _ -> bitsSizeOf t >= bitsSizeOf !upointType*)
| TFloat (fk1,_), TFloat (fk2,_) when fk1 = fk2 -> true
Expand Down
32 changes: 32 additions & 0 deletions tests/regression/01-cpa/76-pointer-typedef.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// PARAM: --set ana.malloc.unique_address_count 2
// Extracted (using creduce) from SV-COMP task list-simple/dll2c_remove_all.i
#include <stdlib.h>
#include <goblint.h>

typedef struct node {
struct node *next;
struct node *prev;
} * DLL;

void dll_remove(DLL *head) {
DLL temp = (*head)->next;
if (temp == *head) {
__goblint_check(temp == *head);
__goblint_check(temp != *head); // FAIL
free(*head);
}
else {
__goblint_check(temp != *head);
__goblint_check(temp == *head); // FAIL
(*head)->prev->next = temp;
free(*head);
*head = temp;
}
}
main() {
DLL s = malloc(sizeof(struct node));
s->next = s->prev = malloc(sizeof(struct node));

dll_remove(&s);
dll_remove(&s);
}
17 changes: 17 additions & 0 deletions tests/regression/74-invalid_deref/32-dll2c_append_equal-mini.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// PARAM: --set ana.activated[+] memOutOfBounds
// Minimized version of SV-COMP task list-simple/dll2c_append_equal.i
#include <stdlib.h>

typedef struct node {
struct node *next;
struct node *prev;
int data;
} *DLL;

int main(void) {
DLL temp = (DLL) malloc(sizeof(struct node));
temp->next = NULL; // NOWARN
temp->prev = NULL; // NOWARN
temp->data = 1; // NOWARN
return temp;
}
Loading