Description
#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.