Update VeriFast proofs (#836)

* Undo syntax changes preventing VeriFast parsing

* Update proofs inline with source changes

Outstanding:
  - xQueueGenericReset return code
  - Not using prvIncrementQueueTxLock or prvIncrementQueueRxLock macros

* Remove git hash check

* Document new changes between proven code and implementation

* Update copyright header

* VeriFast proofs: turn off uncrustify checks

Uncrustify requires formatting of comments that is at odds with VeriFast's
proof annotations, which are contained within comments.

* Update ci.yml

Co-authored-by: Joseph Julicher <jjulicher@mac.com>
Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
This commit is contained in:
Nathan Chong 2022-10-27 17:54:38 -04:00 committed by GitHub
parent 4e0fecaadd
commit 4f87f485d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 1877 additions and 1864 deletions

View file

@ -24,6 +24,8 @@
*
*/
/* *INDENT-OFF* */
#include "proof/queue.h"
/* Simplifying assumption: we do not verify queue initialisation in a
@ -37,37 +39,35 @@
/* The following intermediate queue predicates summarise states used by queue
* initialization but not used elsewhere so we confine them to these proofs
* locally. */
/*@
* predicate queue_init1(QueueHandle_t q;) =
* QUEUE_SHAPE(q, _, _, _, _) &*&
* queuelists(q)
* ;
*
* predicate queue_init2(QueueHandle_t q, int8_t *Storage, size_t N, size_t M;) =
* QUEUE_SHAPE(q, Storage, N, M, _) &*&
* queuelists(q) &*&
* 0 < N &*&
* chars(Storage, (N*M), _) &*&
* malloc_block(Storage, N*M) &*&
* Storage + N * M <= (int8_t *)UINTPTR_MAX &*&
* true
* ;
* @*/
predicate queue_init1(QueueHandle_t q;) =
QUEUE_SHAPE(q, _, _, _, _) &*&
queuelists(q)
;
predicate queue_init2(QueueHandle_t q, int8_t *Storage, size_t N, size_t M;) =
QUEUE_SHAPE(q, Storage, N, M, _) &*&
queuelists(q) &*&
0 < N &*&
chars(Storage, (N*M), _) &*&
malloc_block(Storage, N*M) &*&
Storage + N * M <= (int8_t *)UINTPTR_MAX &*&
true
;
@*/
BaseType_t xQueueGenericReset( QueueHandle_t xQueue,
BaseType_t xNewQueue )
/*@requires queue_init2(xQueue, ?Storage, ?N, ?M);@*/
/*@ensures 0 == M
* ? freertos_mutex(xQueue, Storage, N, 0)
* : queue(xQueue, Storage, N, M, 0, (N-1), 0, false, nil) &*& queuelists(xQueue);@*/
? freertos_mutex(xQueue, Storage, N, 0)
: queue(xQueue, Storage, N, M, 0, (N-1), 0, false, nil) &*& queuelists(xQueue);@*/
{
#ifdef VERIFAST /*< const pointer declaration */
Queue_t * pxQueue = xQueue;
#else
Queue_t * const pxQueue = xQueue;
#endif
#ifdef VERIFAST /*< const pointer declaration */
Queue_t * pxQueue = xQueue;
#else
Queue_t * const pxQueue = xQueue;
#endif
configASSERT( pxQueue );
@ -127,20 +127,18 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
Queue_t * pxNewQueue )
/*@requires queue_init1(pxNewQueue) &*&
* 0 < uxQueueLength &*& 0 < uxItemSize &*&
* malloc_block(pucQueueStorage, uxQueueLength * uxItemSize) &*&
* pucQueueStorage + uxQueueLength * uxItemSize <= (uint8_t *)UINTPTR_MAX &*&
* uchars(pucQueueStorage, uxQueueLength * uxItemSize,_);@*/
0 < uxQueueLength &*& 0 < uxItemSize &*&
malloc_block(pucQueueStorage, uxQueueLength * uxItemSize) &*&
pucQueueStorage + uxQueueLength * uxItemSize <= (uint8_t *)UINTPTR_MAX &*&
uchars(pucQueueStorage, uxQueueLength * uxItemSize,_);@*/
/*@ensures queue(pxNewQueue, ((int8_t *)(void *)pucQueueStorage), uxQueueLength, uxItemSize, 0, (uxQueueLength-1), 0, false, nil) &*&
* queuelists(pxNewQueue);@*/
queuelists(pxNewQueue);@*/
{
#ifndef VERIFAST /*< void cast of unused var */
/* Remove compiler warnings about unused parameters should
* configUSE_TRACE_FACILITY not be set to 1. */
( void ) ucQueueType;
#endif
#ifndef VERIFAST /*< void cast of unused var */
/* Remove compiler warnings about unused parameters should
* configUSE_TRACE_FACILITY not be set to 1. */
( void ) ucQueueType;
#endif
if( uxItemSize == ( UBaseType_t ) 0 )
{
@ -148,20 +146,20 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
* be set to NULL because NULL is used as a key to say the queue is used as
* a mutex. Therefore just set pcHead to point to the queue as a benign
* value that is known to be within the memory map. */
#ifdef VERIFAST /*< stricter casting */
pxNewQueue->pcHead = ( int8_t * ) ( void * ) pxNewQueue;
#else
pxNewQueue->pcHead = ( int8_t * ) pxNewQueue;
#endif
#ifdef VERIFAST /*< stricter casting */
pxNewQueue->pcHead = ( int8_t * ) ( void * ) pxNewQueue;
#else
pxNewQueue->pcHead = ( int8_t * ) pxNewQueue;
#endif
}
else
{
/* Set the head to the start of the queue storage area. */
#ifdef VERIFAST /*< stricter casting */
pxNewQueue->pcHead = ( int8_t * ) ( void * ) pucQueueStorage;
#else
pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage;
#endif
#ifdef VERIFAST /*< stricter casting */
pxNewQueue->pcHead = ( int8_t * ) ( void * ) pucQueueStorage;
#else
pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage;
#endif
}
/* Initialise the queue members as described where the queue type is
@ -169,11 +167,11 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
pxNewQueue->uxLength = uxQueueLength;
pxNewQueue->uxItemSize = uxItemSize;
/*@close queue_init2(pxNewQueue, _, uxQueueLength, uxItemSize);@*/
#ifdef VERIFAST /*< void cast of unused return value */
xQueueGenericReset( pxNewQueue, pdTRUE );
#else
( void ) xQueueGenericReset( pxNewQueue, pdTRUE );
#endif
#ifdef VERIFAST /*< void cast of unused return value */
xQueueGenericReset( pxNewQueue, pdTRUE );
#else
( void ) xQueueGenericReset( pxNewQueue, pdTRUE );
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
{
@ -190,93 +188,100 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
traceQUEUE_CREATE( pxNewQueue );
}
#define SIZE_MAX ( ( size_t ) -1 )
QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength,
const UBaseType_t uxItemSize,
const uint8_t ucQueueType )
/*@requires 0 < uxQueueLength &*&
* 0 < uxItemSize &*&
* 0 < uxQueueLength * uxItemSize &*&
* uxQueueLength * uxItemSize <= UINT_MAX;@*/
/*@ensures result == NULL
* ? true
* : queue(result, _, uxQueueLength, uxItemSize, 0, (uxQueueLength-1), 0, false, nil) &*&
* queuelists(result) &*&
* result->irqMask |-> _ &*&
* result->schedulerSuspend |-> _ &*&
* result->locked |-> _;@*/
{
Queue_t * pxNewQueue;
size_t xQueueSizeInBytes;
uint8_t * pucQueueStorage;
configASSERT( uxQueueLength > ( UBaseType_t ) 0 );
/* Allocate enough space to hold the maximum number of items that
* can be in the queue at any time. It is valid for uxItemSize to be
* zero in the case the queue is used as a semaphore. */
xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
/* Check for multiplication overflow. */
configASSERT( ( uxItemSize == 0 ) || ( uxQueueLength == ( xQueueSizeInBytes / uxItemSize ) ) );
/* Check for addition overflow. */
configASSERT( ( sizeof( Queue_t ) + xQueueSizeInBytes ) > xQueueSizeInBytes );
#ifdef VERIFAST /*< ***model single malloc of struct and buffer*** */
pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) );
#else
/* Allocate the queue and storage area. Justification for MISRA
* deviation as follows: pvPortMalloc() always ensures returned memory
* blocks are aligned per the requirements of the MCU stack. In this case
* pvPortMalloc() must return a pointer that is guaranteed to meet the
* alignment requirements of the Queue_t structure - which in this case
* is an int8_t *. Therefore, whenever the stack alignment requirements
* are greater than or equal to the pointer to char requirements the cast
* is safe. In other cases alignment requirements are not strict (one or
* two bytes). */
pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); /*lint !e9087 !e9079 see comment above. */
#endif
if( pxNewQueue != NULL )
QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength,
const UBaseType_t uxItemSize,
const uint8_t ucQueueType )
/*@requires 0 < uxQueueLength &*&
0 < uxItemSize &*&
0 < uxQueueLength * uxItemSize &*&
uxQueueLength * uxItemSize <= UINT_MAX;@*/
/*@ensures result == NULL
? true
: queue(result, _, uxQueueLength, uxItemSize, 0, (uxQueueLength-1), 0, false, nil) &*&
queuelists(result) &*&
result->irqMask |-> _ &*&
result->schedulerSuspend |-> _ &*&
result->locked |-> _;@*/
{
#ifdef VERIFAST /*< ***model single malloc of struct and buffer*** */
pucQueueStorage = ( uint8_t * ) pvPortMalloc( xQueueSizeInBytes );
#ifdef VERIFAST /*< ***model static initialization*** */
Queue_t * pxNewQueue = NULL;
#else
Queue_t * pxNewQueue;
#endif
size_t xQueueSizeInBytes;
uint8_t * pucQueueStorage;
if( pucQueueStorage == NULL )
{
vPortFree( pxNewQueue );
return NULL;
}
/*@malloc_block_limits(pucQueueStorage);@*/
#else
/* Jump past the queue structure to find the location of the queue
* storage area. */
pucQueueStorage = ( uint8_t * ) pxNewQueue;
pucQueueStorage += sizeof( Queue_t ); /*lint !e9016 Pointer arithmetic allowed on char types, especially when it assists conveying intent. */
#endif /* ifdef VERIFAST */
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
if( ( uxQueueLength > ( UBaseType_t ) 0 ) &&
/* Check for multiplication overflow. */
( ( SIZE_MAX / uxQueueLength ) >= uxItemSize ) &&
/* Check for addition overflow. */
( ( SIZE_MAX - sizeof( Queue_t ) ) >= ( uxQueueLength * uxItemSize ) ) )
{
/* Queues can be created either statically or dynamically, so
* note this task was created dynamically in case it is later
* deleted. */
pxNewQueue->ucStaticallyAllocated = pdFALSE;
/* Allocate enough space to hold the maximum number of items that
* can be in the queue at any time. It is valid for uxItemSize to be
* zero in the case the queue is used as a semaphore. */
xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
#ifdef VERIFAST /*< ***model single malloc of struct and buffer*** */
pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) );
#else
/* Allocate the queue and storage area. Justification for MISRA
* deviation as follows: pvPortMalloc() always ensures returned memory
* blocks are aligned per the requirements of the MCU stack. In this case
* pvPortMalloc() must return a pointer that is guaranteed to meet the
* alignment requirements of the Queue_t structure - which in this case
* is an int8_t *. Therefore, whenever the stack alignment requirements
* are greater than or equal to the pointer to char requirements the cast
* is safe. In other cases alignment requirements are not strict (one or
* two bytes). */
pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); /*lint !e9087 !e9079 see comment above. */
#endif
if( pxNewQueue != NULL )
{
#ifdef VERIFAST /*< ***model single malloc of struct and buffer*** */
pucQueueStorage = ( uint8_t * ) pvPortMalloc( xQueueSizeInBytes );
if( pucQueueStorage == NULL )
{
vPortFree( pxNewQueue );
return NULL;
}
/*@malloc_block_limits(pucQueueStorage);@*/
#else
/* Jump past the queue structure to find the location of the queue
* storage area. */
pucQueueStorage = ( uint8_t * ) pxNewQueue;
pucQueueStorage += sizeof( Queue_t ); /*lint !e9016 Pointer arithmetic allowed on char types, especially when it assists conveying intent. */
#endif
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{
/* Queues can be created either statically or dynamically, so
* note this task was created dynamically in case it is later
* deleted. */
pxNewQueue->ucStaticallyAllocated = pdFALSE;
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
}
else
{
traceQUEUE_CREATE_FAILED( ucQueueType );
mtCOVERAGE_TEST_MARKER();
}
}
else
{
configASSERT( pxNewQueue );
mtCOVERAGE_TEST_MARKER();
}
#endif /* configSUPPORT_STATIC_ALLOCATION */
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
}
else
{
traceQUEUE_CREATE_FAILED( ucQueueType );
mtCOVERAGE_TEST_MARKER();
return pxNewQueue;
}
return pxNewQueue;
}
/* *INDENT-ON* */