Skip to content

Pointer validity checks on __CPROVER_allocated_memory #6695

Open
@SaswatPadhi

Description

@SaswatPadhi

CBMC version: 3410558
Operating system: Linux, MacOS

Test case:

int main() {
    char *ptr;

    ptr = 0xFF;
    *ptr = '0';                                           // PASS: write succeeds without alloc?
    __CPROVER_allocated_memory(ptr, 0xFFFFFFFFFFFFFE);    // PASS: but overflow in offset space!
         assert(__CPROVER_w_ok(ptr, 0xFFFFFFFFFFFFFE));   // PASS: well, consistent with above
         assert(__CPROVER_w_ok(ptr, 0xFFFFFFFFFFFFFF00)); // FAIL: beyond alloc
         assert(__CPROVER_w_ok(ptr, 0xFFFFFFFFFFFFFF01)); // PASS: overflow beyond 64 bits!

    ptr = 0xFFFFFFFFFFFFFE;    // object bits unset
    *ptr = '0';                                   // PASS: write succeeds without alloc?
    __CPROVER_allocated_memory(ptr, 0xFF);        // PASS: but overflow in offset space!
         assert(__CPROVER_w_ok(ptr, 0xFF));       // PASS: well, consistent with above
         assert(__CPROVER_w_ok(ptr, 0xFFFF));     // PASS: but beyond alloc!
    
    ptr = 0xFFFFFFFFFFFFFFE;   // object bits set to 00001111
    *ptr = '0';                                   // PASS: write succeeds without alloc?
    __CPROVER_allocated_memory(ptr, 0xFF);        // PASS: but overflow in offset space!
         assert(__CPROVER_w_ok(ptr, 0xFF));       // PASS: well, consistent with above
         assert(__CPROVER_w_ok(ptr, 0xFFFF));     // PASS: but beyond alloc!
    
    assert(0);
}

Exact command line resulting in the issue:

cbmc --64 \
     --pointer-check --pointer-overflow-check --pointer-primitive-check \
     --signed-overflow-check --unsigned-overflow-check --conversion-check \
     --bounds-check \
     test.c

What behaviour did you expect:

I was expecting CBMC to flag the w_ok checks on regions beyond the allocated region.

I think there are at least 3 different issues here:

  1. @tautschnig pointed out on Slack that __CPROVER_allocated_memory is flow insensitive. I think that explains why the before alloc succeed in the test case above
  2. The __CPROVER_allocated_memory addresses break the (object id, offset) model for pointers. CBMC doesn't raise overflows on large allocations (overflowing into object bits) there, which matches my intuition, but I am not sure if it's for the right reasons. It looks like arithmetic on these pointers still takes object id and offset into account.
  3. Finally, I think there might be a separate issue with __CPROVER_w_ok, because it succeeds on regions beyond the allocated regions. If this somehow succeeds because of overflows into object bits, the overflows should be reported in some way.

I also tried checking each of the 3 blocks above independently, since the current flow insensitive __CPROVER_allocated_memory implementation would lead to overlapping allocations above. I don't see much of a difference though. The 1st and 3rd blocks behave exactly as before, only the __CPROVER_w_ok check in the 2nd block works as expected now.

1st block
int main() {
    char *ptr;

    ptr = 0xFF;
    *ptr = '0';                                           // PASS: write succeeds without alloc?
    __CPROVER_allocated_memory(ptr, 0xFFFFFFFFFFFFFE);    // PASS: but overflow in offset space!
         assert(__CPROVER_w_ok(ptr, 0xFFFFFFFFFFFFFE));   // PASS: well, consistent with above
         assert(__CPROVER_w_ok(ptr, 0xFFFFFFFFFFFFFF00)); // FAIL: beyond alloc
         assert(__CPROVER_w_ok(ptr, 0xFFFFFFFFFFFFFF01)); // PASS: overflow beyond 64 bits!

    assert(0);
}

2nd block

int main() {
    char *ptr;

    ptr = 0xFFFFFFFFFFFFFE;    // object bits unset
    *ptr = '0';                                   // PASS: write succeeds without alloc?
    __CPROVER_allocated_memory(ptr, 0xFF);        // PASS: but overflow in offset space!
         assert(__CPROVER_w_ok(ptr, 0xFF));       // PASS: well, consistent with above
         assert(__CPROVER_w_ok(ptr, 0xFFFF));     // FAIL: beyond alloc

    assert(0);
}
3rd block
int main() {
    char *ptr;

    ptr = 0xFFFFFFFFFFFFFFE;   // object bits set to 00001111
    *ptr = '0';                                   // PASS: write succeeds without alloc?
    __CPROVER_allocated_memory(ptr, 0xFF);        // PASS: but overflow in offset space!
         assert(__CPROVER_w_ok(ptr, 0xFF));       // PASS: well, consistent with above
         assert(__CPROVER_w_ok(ptr, 0xFFFF));     // PASS: but beyond alloc!
    
    assert(0);
}

Metadata

Metadata

Labels

awsBugs or features of importance to AWS CBMC users

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions