Skip to content

Integer to pointer casting behaviour? #8103

Open
@ShaleXIONG

Description

@ShaleXIONG
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

#define GRANULE_SIZE 8
#define RMM_MAX_GRANULES 2
unsigned char granules_buffer[GRANULE_SIZE * RMM_MAX_GRANULES]
                        __attribute__((__aligned__(GRANULE_SIZE)));

size_t nondet_size_t(void);
unsigned int nondet_unsigned_int(void);
bool nondet_bool(void);
uint64_t nondet_uint64_t(void);

#define ALIGNED(_size, _alignment)              \
                        (((unsigned long)(_size) % (_alignment)) == 0UL)

#define GRANULE_ALIGNED(_addr) ALIGNED((void *)(_addr), GRANULE_SIZE)

bool valid_pa(uint64_t addr)
{
    return GRANULE_ALIGNED(addr)
       && granules_buffer <= addr
       && addr < granules_buffer + sizeof(granules_buffer);
}

uint64_t pa_to_index(uint64_t addr)
{
    return (addr - (uint64_t)granules_buffer)/GRANULE_SIZE;
}


void* pa_to_granule_buffer_ptr(uint64_t addr)
{
#ifndef ERROR
    // NOTE: Has to do this strange computation and type cast so CBMC can handle.
    return (void*)granules_buffer + ((unsigned char *)addr - granules_buffer);
#else
    return (void*)addr;
#endif
}

const uint8_t SPECIAL_VALUE = 42;

void main()
{
    // Set up the initial state.
    //
    // Pick a valid and nondet index
    size_t index = nondet_size_t();
    __CPROVER_assume(index < RMM_MAX_GRANULES);
    // Inject the `SPECIAL_VALUE` to the chosen granule.
    size_t offset = index * GRANULE_SIZE;
    granules_buffer[offset] = SPECIAL_VALUE;

    // Pre-condition
    uint64_t rd = nondet_uint64_t();
    __CPROVER_assume(valid_pa(rd));
    __CPROVER_assume(pa_to_index(rd) == index);

    // Execution, also the buggy code for CBMC.
    uint8_t *rd_ptr = pa_to_granule_buffer_ptr(rd);

    // Post-condition
    __CPROVER_assert(*rd_ptr == SPECIAL_VALUE, "check");
}

We (together with @matetothpal) have some code (above) that has a strange result, especially in the function pa_to_granule_buffer_ptr.

Assume an addr is in the range of a global byte (char) array granules_buffer, the two expressions (void*)granules_buffer + ((unsigned char *)addr - granules_buffer) and (void*)addr, which has the same values, leads to different behaviour. The former gives us expected result, i.e. assert success, while the latter fails.

Although int-to-pointer case is implementation-dependent behaviour, my guess here is that CBMC represents an array as an abstract object, and we can only access this abstract object via some offset but not absolute address, despite that the address is valid?

CBMC version: 5.95.1
Operating system: MacOS
Exact command line resulting in the issue: cbmc main.c -DERROR
What behaviour did you expect: it should pass
What happened instead: report assert fail

We have this problem since almost a year ago, and we have tried several different versions of CBMC on both MacOS and Ubuntu.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions